Thrill  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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.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  LOG1 << "Error: open()ing " << filename_ << " with DIRECT mode required, but the system does not support it.";
72  file_des_ = -1;
73  return;
74  }
75  else {
76  LOG1 << "Warning: open()ing " << filename_ << " without DIRECT mode, as the system does not support it.";
77  }
78 #endif
79  }
80 
81  if (mode & SYNC)
82  {
83  flags |= O_RSYNC;
84  flags |= O_DSYNC;
85  flags |= O_SYNC;
86  }
87 
88 #if FOXXLL_WINDOWS
89  flags |= O_BINARY; // the default in MS is TEXT mode
90 #endif
91 
92 #if FOXXLL_WINDOWS || defined(__MINGW32__)
93  const int perms = S_IREAD | S_IWRITE;
94 #else
95  const int perms = S_IREAD | S_IWRITE | S_IRGRP | S_IWGRP;
96 #endif
97 
98  if ((file_des_ = ::open(filename_.c_str(), flags, perms)) >= 0)
99  {
100  need_alignment_ = (mode & DIRECT) != 0;
101  _after_open();
102  return;
103  }
104 
105 #if !FOXXLL_DIRECT_IO_OFF
106  if ((mode & DIRECT) && !(mode & REQUIRE_DIRECT) && errno == EINVAL)
107  {
108  LOG1 << "open() error on path=" << filename_
109  << " flags=" << flags << ", retrying without O_DIRECT.";
110 
111  flags &= ~O_DIRECT;
112  mode &= ~DIRECT;
113 
114  if ((file_des_ = ::open(filename_.c_str(), flags, perms)) >= 0)
115  {
116  _after_open();
117  return;
118  }
119  }
120 #endif
121 
123  io_error, "open() rc=" << file_des_
124  << " path=" << filename_ << " flags=" << flags
125  );
126 }
127 
129 {
130  close();
131 }
132 
134 {
135  // stat file type
136 #if FOXXLL_WINDOWS || defined(__MINGW32__)
137  struct _stat64 st;
139  ::_fstat64(file_des_, &st), io_error,
140  "_fstat64() path=" << filename_ << " fd=" << file_des_
141  );
142 #else
143  struct stat st;
145  ::fstat(file_des_, &st), io_error,
146  "fstat() path=" << filename_ << " fd=" << file_des_
147  );
148 #endif
149  is_device_ = S_ISBLK(st.st_mode) ? true : false;
150 
151 #ifdef __APPLE__
152  if (mode_ & REQUIRE_DIRECT) {
154  fcntl(file_des_, F_NOCACHE, 1), io_error,
155  "fcntl() path=" << filename_ << " fd=" << file_des_
156  );
158  fcntl(file_des_, F_RDAHEAD, 0), io_error,
159  "fcntl() path=" << filename_ << " fd=" << file_des_
160  );
161  }
162  else if (mode_ & DIRECT) {
163  if (fcntl(file_des_, F_NOCACHE, 1) != 0) {
164  LOG1 << "fcntl(fd,F_NOCACHE,1) failed on path=" << filename_ <<
165  " fd=" << file_des_ << " : " << strerror(errno);
166  }
167  if (fcntl(file_des_, F_RDAHEAD, 0) != 0) {
168  LOG1 << "fcntl(fd,F_RDAHEAD,0) failed on path=" << filename_ <<
169  " fd=" << file_des_ << " : " << strerror(errno);
170  }
171  }
172 #endif
173 
174  // successfully opened file descriptor
175  if (!(mode_ & NO_LOCK))
176  lock();
177 }
178 
180 {
181  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
182 
183  if (file_des_ == -1)
184  return;
185 
186  if (::close(file_des_) < 0)
187  FOXXLL_THROW_ERRNO(io_error, "close() fd=" << file_des_);
188 
189  file_des_ = -1;
190 }
191 
193 {
194 #if FOXXLL_WINDOWS || defined(__MINGW32__)
195  // not yet implemented
196 #else
197  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
198  struct flock lock_struct;
199  lock_struct.l_type = static_cast<short>(mode_ & RDONLY ? F_RDLCK : F_RDLCK | F_WRLCK);
200  lock_struct.l_whence = SEEK_SET;
201  lock_struct.l_start = 0;
202  lock_struct.l_len = 0; // lock all bytes
203  if ((::fcntl(file_des_, F_SETLK, &lock_struct)) < 0)
204  FOXXLL_THROW_ERRNO(io_error, "fcntl(,F_SETLK,) path=" << filename_ << " fd=" << file_des_);
205 #endif
206 }
207 
209 {
210  // We use lseek SEEK_END to find the file size. This works for raw devices
211  // (where stat() returns zero), and we need not reset the position because
212  // serve() always lseek()s before read/write.
213 
214  off_t rc = ::lseek(file_des_, 0, SEEK_END);
215  if (rc < 0)
216  FOXXLL_THROW_ERRNO(io_error, "lseek(fd,0,SEEK_END) path=" << filename_ << " fd=" << file_des_);
217 
218  // return value is already the total size
219  return rc;
220 }
221 
223 {
224  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
225  return _size();
226 }
227 
229 {
230  std::unique_lock<std::mutex> fd_lock(fd_mutex_);
231  return _set_size(newsize);
232 }
233 
235 {
236  offset_type cur_size = _size();
237 
238  if (!(mode_ & RDONLY) && !is_device_)
239  {
240 #if FOXXLL_WINDOWS || defined(__MINGW32__)
241  HANDLE hfile = (HANDLE)::_get_osfhandle(file_des_);
243  (hfile == INVALID_HANDLE_VALUE), io_error,
244  "_get_osfhandle() path=" << filename_ << " fd=" << file_des_
245  );
246 
247  LARGE_INTEGER desired_pos;
248  desired_pos.QuadPart = newsize;
249 
250  if (!SetFilePointerEx(hfile, desired_pos, nullptr, FILE_BEGIN))
251  FOXXLL_THROW_WIN_LASTERROR(
252  io_error,
253  "SetFilePointerEx in ufs_file_base::set_size(..) oldsize=" << cur_size <<
254  " newsize=" << newsize << " "
255  );
256 
257  if (!SetEndOfFile(hfile))
258  FOXXLL_THROW_WIN_LASTERROR(
259  io_error,
260  "SetEndOfFile oldsize=" << cur_size <<
261  " newsize=" << newsize << " "
262  );
263 #else
265  ::ftruncate(file_des_, newsize), io_error,
266  "ftruncate() path=" << filename_ << " fd=" << file_des_
267  );
268 #endif
269  }
270 
271 #if !FOXXLL_WINDOWS
272  if (newsize > cur_size)
274  ::lseek(file_des_, newsize - 1, SEEK_SET) < 0, io_error,
275  "lseek() path=" << filename_ << " fd=" << file_des_ << " pos=" << newsize - 1
276  );
277 #endif
278 }
279 
281 {
282  close();
283 
284  if (is_device_) {
285  LOG1 << "remove() path=" << filename_ << " skipped as file is device node";
286  return;
287  }
288 
289  if (::remove(filename_.c_str()) != 0)
290  LOG1 << "remove() error on path=" << filename_ << " error=" << strerror(errno);
291 }
292 
294 {
295  if (is_device_) {
296  LOG1 << "unlink() path=" << filename_ << " skipped as file is device node";
297  return;
298  }
299 
300  if (::unlink(filename_.c_str()) != 0)
301  FOXXLL_THROW_ERRNO(io_error, "unlink() path=" << filename_ << " fd=" << file_des_);
302 }
303 
305 {
306  return is_device_;
307 }
308 
309 } // namespace foxxll
310 
311 /**************************************************************************/
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)
bool is_device() const
return true if file is special device node
void close_remove() final
close and remove file
#define LOG1
Definition: logger.hpp:145
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]".
std::basic_string< char, std::char_traits< char >, Allocator< char > > string
string with Manager tracking
Definition: allocator.hpp:220
offset_type size() final
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 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:33
#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.