Thrill  0.1
ufs_file_base.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * foxxll/io/ufs_file_base.cpp
3  *
4  * Part of FOXXLL. See http://foxxll.org
5  *
6  * Copyright (C) 2002, 2005, 2008 Roman Dementiev <[email protected]>
7  * Copyright (C) 2008 Ilja Andronov <[email protected]>
8  * Copyright (C) 2008-2010 Andreas Beckmann <[email protected]>
9  * Copyright (C) 2009 Johannes Singler <[email protected]>
10  * Copyright (C) 2013 Timo Bingmann <[email protected]>
11  *
12  * Distributed under the Boost Software License, Version 1.0.
13  * (See accompanying file LICENSE_1_0.txt or copy at
14  * http://www.boost.org/LICENSE_1_0.txt)
15  **************************************************************************/
16 
17 #include <tlx/logger/core.hpp>
18 
21 #include <foxxll/config.hpp>
22 #include <foxxll/io/file.hpp>
25 
26 namespace foxxll {
27 
28 const char* ufs_file_base::io_type() const
29 {
30  return "ufs_base";
31 }
32 
33 ufs_file_base::ufs_file_base(const std::string& filename, int mode)
34  : file_des_(-1), mode_(mode), filename_(filename)
35 {
36  int flags = 0;
37 
38  if (mode & RDONLY)
39  {
40  flags |= O_RDONLY;
41  }
42 
43  if (mode & WRONLY)
44  {
45  flags |= O_WRONLY;
46  }
47 
48  if (mode & RDWR)
49  {
50  flags |= O_RDWR;
51  }
52 
53  if (mode & CREAT)
54  {
55  flags |= O_CREAT;
56  }
57 
58  if (mode & TRUNC)
59  {
60  flags |= O_TRUNC;
61  }
62 
63  if ((mode & DIRECT) || (mode & REQUIRE_DIRECT))
64  {
65 #ifdef __APPLE__
66  // no additional open flags are required for Mac OS X
67 #elif !FOXXLL_DIRECT_IO_OFF
68  flags |= O_DIRECT;
69 #else
70  if (mode & REQUIRE_DIRECT) {
71  TLX_LOG1 << "Error: open()ing " << filename_
72  << " with DIRECT mode required, but the system does not support it.";
73  file_des_ = -1;
74  return;
75  }
76  else {
77  TLX_LOG1 << "Warning: open()ing " << filename_
78  << " without DIRECT mode, as the system does not support it.";
79  }
80 #endif
81  }
82 
83  if (mode & SYNC)
84  {
85  flags |= O_RSYNC;
86  flags |= O_DSYNC;
87  flags |= O_SYNC;
88  }
89 
90 #if FOXXLL_WINDOWS
91  flags |= O_BINARY; // the default in MS is TEXT mode
92 #endif
93 
94 #if FOXXLL_WINDOWS || defined(__MINGW32__)
95  const int perms = S_IREAD | S_IWRITE;
96 #else
97  const int perms = S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP;
98 #endif
99 
100  if ((file_des_ = ::open(filename_.c_str(), flags, perms)) >= 0)
101  {
102  need_alignment_ = (mode & DIRECT) != 0;
103  _after_open();
104  return;
105  }
106 
107 #if !FOXXLL_DIRECT_IO_OFF
108  if ((mode & DIRECT) && !(mode & REQUIRE_DIRECT) && errno == EINVAL)
109  {
110  TLX_LOG1 << "open() error on path=" << filename_
111  << " flags=" << flags << ", retrying without O_DIRECT.";
112 
113  flags &= ~O_DIRECT;
114  mode &= ~DIRECT;
115 
116  if ((file_des_ = ::open(filename_.c_str(), flags, perms)) >= 0)
117  {
118  _after_open();
119  return;
120  }
121  }
122 #endif
123 
125  io_error, "open() rc=" << file_des_
126  << " path=" << filename_ << " flags=" << flags
127  );
128 }
129 
131 {
132  close();
133 }
134 
136 {
137  // stat file type
138 #if FOXXLL_WINDOWS || defined(__MINGW32__)
139  struct _stat64 st;
141  ::_fstat64(file_des_, &st), io_error,
142  "_fstat64() path=" << filename_ << " fd=" << file_des_
143  );
144 #else
145  struct stat st;
147  ::fstat(file_des_, &st), io_error,
148  "fstat() path=" << filename_ << " fd=" << file_des_
149  );
150 #endif
151  is_device_ = S_ISBLK(st.st_mode) ? true : false;
152 
153 #ifdef __APPLE__
154  if (mode_ & REQUIRE_DIRECT) {
156  fcntl(file_des_, F_NOCACHE, 1), io_error,
157  "fcntl() path=" << filename_ << " fd=" << file_des_
158  );
160  fcntl(file_des_, F_RDAHEAD, 0), io_error,
161  "fcntl() path=" << filename_ << " fd=" << file_des_
162  );
163  }
164  else if (mode_ & DIRECT) {
165  if (fcntl(file_des_, F_NOCACHE, 1) != 0) {
166  TLX_LOG1
167  << "fcntl(fd,F_NOCACHE,1) failed on path=" << filename_
168  << " fd=" << file_des_ << " : " << strerror(errno);
169  }
170  if (fcntl(file_des_, F_RDAHEAD, 0) != 0) {
171  TLX_LOG1 << "fcntl(fd,F_RDAHEAD,0) failed on path=" << filename_
172  << " fd=" << file_des_ << " : " << strerror(errno);
173  }
174  }
175 #endif
176 
177  // successfully opened file descriptor
178  if (!(mode_ & NO_LOCK))
179  lock();
180 }
181 
183 {
184  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
185 
186  if (file_des_ == -1)
187  return;
188 
189  if (::close(file_des_) < 0)
190  FOXXLL_THROW_ERRNO(io_error, "close() fd=" << file_des_);
191 
192  file_des_ = -1;
193 }
194 
196 {
197 #if FOXXLL_WINDOWS || defined(__MINGW32__)
198  // not yet implemented
199 #else
200  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
201  struct flock lock_struct;
202  lock_struct.l_type = static_cast<short>(mode_ & RDONLY ? F_RDLCK : F_RDLCK | F_WRLCK);
203  lock_struct.l_whence = SEEK_SET;
204  lock_struct.l_start = 0;
205  lock_struct.l_len = 0; // lock all bytes
206  if ((::fcntl(file_des_, F_SETLK, &lock_struct)) < 0)
207  FOXXLL_THROW_ERRNO(io_error, "fcntl(,F_SETLK,) path=" << filename_ << " fd=" << file_des_);
208 #endif
209 }
210 
212 {
213  // We use lseek SEEK_END to find the file size. This works for raw devices
214  // (where stat() returns zero), and we need not reset the position because
215  // serve() always lseek()s before read/write.
216 
217  off_t rc = ::lseek(file_des_, 0, SEEK_END);
218  if (rc < 0)
219  FOXXLL_THROW_ERRNO(io_error, "lseek(fd,0,SEEK_END) path=" << filename_ << " fd=" << file_des_);
220 
221  // return value is already the total size
222  return rc;
223 }
224 
226 {
227  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
228  return _size();
229 }
230 
232 {
233  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
234  return _set_size(newsize);
235 }
236 
238 {
239  offset_type cur_size = _size();
240 
241  if (!(mode_ & RDONLY) && !is_device_)
242  {
243 #if FOXXLL_WINDOWS || defined(__MINGW32__)
244  HANDLE hfile = (HANDLE)::_get_osfhandle(file_des_);
246  (hfile == INVALID_HANDLE_VALUE), io_error,
247  "_get_osfhandle() path=" << filename_ << " fd=" << file_des_
248  );
249 
250  LARGE_INTEGER desired_pos;
251  desired_pos.QuadPart = newsize;
252 
253  if (!SetFilePointerEx(hfile, desired_pos, nullptr, FILE_BEGIN))
254  FOXXLL_THROW_WIN_LASTERROR(
255  io_error,
256  "SetFilePointerEx in ufs_file_base::set_size(..) oldsize=" << cur_size <<
257  " newsize=" << newsize << " "
258  );
259 
260  if (!SetEndOfFile(hfile))
261  FOXXLL_THROW_WIN_LASTERROR(
262  io_error,
263  "SetEndOfFile oldsize=" << cur_size <<
264  " newsize=" << newsize << " "
265  );
266 #else
268  ::ftruncate(file_des_, newsize), io_error,
269  "ftruncate() path=" << filename_ << " fd=" << file_des_
270  );
271 #endif
272  }
273 
274 #if !FOXXLL_WINDOWS
275  if (newsize > cur_size)
277  ::lseek(file_des_, newsize - 1, SEEK_SET) < 0, io_error,
278  "lseek() path=" << filename_ << " fd=" << file_des_ << " pos=" << newsize - 1
279  );
280 #endif
281 }
282 
284 {
285  close();
286 
287  if (is_device_) {
288  TLX_LOG1 << "remove() path=" << filename_
289  << " skipped as file is device node";
290  return;
291  }
292 
293  if (::remove(filename_.c_str()) != 0)
294  TLX_LOG1 << "remove() error on path=" << filename_
295  << " error=" << strerror(errno);
296 }
297 
299 {
300  if (is_device_) {
301  TLX_LOG1 << "unlink() path=" << filename_
302  << " skipped as file is device node";
303  return;
304  }
305 
306  if (::unlink(filename_.c_str()) != 0)
307  FOXXLL_THROW_ERRNO(io_error, "unlink() path=" << filename_ << " fd=" << file_des_);
308 }
309 
311 {
312  return is_device_;
313 }
314 
315 } // namespace foxxll
316 
317 /**************************************************************************/
only reading of the file is allowed
Definition: file.hpp:67
only writing of the file is allowed
Definition: file.hpp:69
#define S_ISBLK(x)
void close_remove() final
close and remove file
request::offset_type offset_type
the offset of a request, also the size of the file
Definition: file.hpp:58
do not acquire an exclusive lock by default
Definition: file.hpp:84
implies DIRECT, fail if opening with DIRECT flag does not work.
Definition: file.hpp:86
bool is_device_
is special device node
void set_size(offset_type newsize) final
#define FOXXLL_THROW_ERRNO(exception_type, error_message)
Throws exception_type with "Error in [function] : [error_message] : [errno message]".
FOXXLL library namespace
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
offset_type size() final
bool is_device() const
return true if file is special device node
ufs_file_base(const std::string &filename, int mode)
#define O_DIRECT
const char * io_type() const override
#define FOXXLL_THROW_IF(expr, exception_type, error_message)
Throws exception_type if (expr) with "Error in [function] : [error_message]".
void lock() final
Locks file for reading and writing (acquires a lock in the file system).
#define TLX_LOG1
Definition: core.hpp:145
#define O_SYNC
const std::string filename_
bool need_alignment_
Flag whether read/write operations REQUIRE alignment.
Definition: file.hpp:192
#define O_BINARY
Definition: sys_file.cpp:34
#define O_DSYNC
once file is opened its length becomes zero
Definition: file.hpp:80
read and write of the file are allowed
Definition: file.hpp:71
#define FOXXLL_THROW_ERRNO_NE_0(expr, exception_type, error_message)
Throws exception_type if (expr != 0) with "Error in [function] : [error_message] : [errno message]"...
#define O_RSYNC
open the file with O_SYNC | O_DSYNC | O_RSYNC flags set
Definition: file.hpp:82
void _set_size(offset_type newsize)
void unlink()
unlink file without closing it.