CMS 3D CMS Logo

DCacheFile.cc
Go to the documentation of this file.
5 #include <cassert>
6 #include <vector>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <dcap.h>
10 
11 using namespace edm::storage;
12 
13 DCacheFile::DCacheFile(void) : m_fd(EDM_IOFD_INVALID), m_close(false) {}
14 
15 DCacheFile::DCacheFile(IOFD fd) : m_fd(fd), m_close(true) {}
16 
17 DCacheFile::DCacheFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
18  : m_fd(EDM_IOFD_INVALID), m_close(false) {
19  open(name, flags, perms);
20 }
21 
22 DCacheFile::DCacheFile(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
23  : m_fd(EDM_IOFD_INVALID), m_close(false) {
24  open(name.c_str(), flags, perms);
25 }
26 
28  if (m_close)
29  edm::LogError("DCacheFileError") << "Destructor called on dCache file '" << m_name
30  << "' but the file is still open";
31 }
32 
34 void DCacheFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
35  open(name,
37  perms);
38 }
39 
40 void DCacheFile::create(const std::string &name, bool exclusive /* = false */, int perms /* = 066 */) {
41  open(name.c_str(),
43  perms);
44 }
45 
46 void DCacheFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
47  open(name.c_str(), flags, perms);
48 }
49 
50 void DCacheFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
51  // Actual open
52  if ((name == nullptr) || (*name == 0)) {
54  ex << "Cannot open a file without a name";
55  ex.addContext("Calling DCacheFile::open()");
56  throw ex;
57  }
58 
59  if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
61  ex << "Must open file '" << name << "' at least for read or write";
62  ex.addContext("Calling DCacheFile::open()");
63  throw ex;
64  }
65 
66  // If I am already open, close old file first
67  if (m_fd != EDM_IOFD_INVALID && m_close)
68  close();
69 
70  // Translate our flags to system flags
71  int openflags = 0;
72 
74  openflags |= O_RDWR;
75  else if (flags & IOFlags::OpenRead)
76  openflags |= O_RDONLY;
77  else if (flags & IOFlags::OpenWrite)
78  openflags |= O_WRONLY;
79 
81  openflags |= O_NONBLOCK;
82 
84  openflags |= O_APPEND;
85 
87  openflags |= O_CREAT;
88 
90  openflags |= O_EXCL;
91 
93  openflags |= O_TRUNC;
94 
95  IOFD newfd = EDM_IOFD_INVALID;
96  dc_errno = 0;
97  if ((newfd = dc_open(name, openflags, perms)) == -1) {
99  ex << "dc_open(name='" << name << "', flags=0x" << std::hex << openflags << ", permissions=0" << std::oct << perms
100  << std::dec << ") => error '" << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
101  ex.addContext("Calling DCacheFile::open()");
102  throw ex;
103  }
104 
105  m_name = name;
106  m_fd = newfd;
107 
108  // Turn off read-ahead, or adjust read-ahead size depending on
109  // whether buffering has been requested. This is a very tricky
110  // balance here. Without read-ahead data processing appears to
111  // become exceedingly slow, and with default (1MB) read-ahead
112  // it appears to saturate disk servers and network. Try tread
113  // reasonable middle ground here.
115  dc_noBuffering(m_fd);
116  else
117  dc_setBufferSize(m_fd, 64000);
118 
119  m_close = true;
120 
121  edm::LogInfo("DCacheFileInfo") << "Opened " << m_name;
122 }
123 
124 void DCacheFile::close(void) {
125  if (m_fd == EDM_IOFD_INVALID) {
126  edm::LogError("DCacheFileError") << "DCacheFile::close(name='" << m_name << "') called but the file is not open";
127  m_close = false;
128  return;
129  }
130 
131  dc_errno = 0;
132  if (dc_close(m_fd) == -1)
133  edm::LogWarning("DCacheFileWarning") << "dc_close(name='" << m_name << "') failed with error '"
134  << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
135 
136  m_close = false;
138 
139  // Caused hang. Will be added back after problem is fixed.
140  // edm::LogInfo("DCacheFileInfo") << "Closed " << m_name;
141 }
142 
143 void DCacheFile::abort(void) {
144  if (m_fd != EDM_IOFD_INVALID)
145  dc_close(m_fd);
146 
147  m_close = false;
149 }
150 
152 static const int BUGLINE = __LINE__ + 1;
153 // Apparently dc_read can return short reads; I don't know if dc_write
154 // will also return short writes. This is a bug in dCache. POSIX,
155 // apparently contrary to the understanding of dCache authors, does
156 // not allow reads from files to return short, and in fact no network
157 // file system returns short reads. For more details please refer to
158 // http://www.opengroup.org/onlinepubs/000095399/functions/read.html:
159 // The value returned may be less than nbyte if the number of
160 // bytes left in the file is less than nbyte, if the read()
161 // request was interrupted by a signal, or if the file is a
162 // pipe or FIFO or special file and has fewer than nbyte bytes
163 // immediately available for reading.
164 // (In other words, barring signals (which should use SA_RESTART and
165 // in any case should not affect dCache) the only way a read from a
166 // file can return short is when there is nothing left to read.)
168  IOSize done = 0;
169  while (done < n) {
170  dc_errno = 0;
171  ssize_t s = dc_read(m_fd, (char *)into + done, n - done);
172  if (s == -1) {
174  ex << "dc_read(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << dc_strerror(dc_errno)
175  << "' (dc_errno=" << dc_errno << ")";
176  ex.addContext("Calling DCacheFile::read()");
177  throw ex;
178  } else if (s == 0)
179  // end of file
180  break;
181  else if (s < ssize_t(n - done))
182  edm::LogInfo("DCacheFileWarning") << "dc_read(name='" << m_name << "', n=" << (n - done)
183  << ") returned a short read of " << s << " bytes; "
184  << "please report a bug in dCache referencing the "
185  << "comment on line " << BUGLINE << " of " << __FILE__;
186  done += s;
187  }
188 
189  return done;
190 }
191 
192 IOSize DCacheFile::write(const void *from, IOSize n) {
193  IOSize done = 0;
194  while (done < n) {
195  dc_errno = 0;
196  ssize_t s = dc_write(m_fd, (const char *)from + done, n - done);
197  if (s == -1) {
199  ex << "dc_write(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << dc_strerror(dc_errno)
200  << "' (dc_errno=" << dc_errno << ")";
201  ex.addContext("Calling DCacheFile::write()");
202  throw ex;
203  } else if (s < ssize_t(n - done))
204  edm::LogInfo("DCacheFileWarning") << "dc_write(name='" << m_name << "', n=" << (n - done)
205  << ") returned a short write of " << s << " bytes; "
206  << "please report a bug in dCache referencing the "
207  << "comment on line " << BUGLINE << " of " << __FILE__;
208  done += s;
209  }
210 
211  return done;
212 }
213 
215  assert(!buffers || into);
216 
217  // readv may not support zero buffers.
218  if (!buffers)
219  return 0;
220 
221  // Convert the buffers to system format.
222  std::vector<iovec> bufs(buffers);
223  for (IOSize i = 0; i < buffers; ++i) {
224  bufs[i].iov_len = into[i].size();
225  bufs[i].iov_base = (caddr_t)into[i].data();
226  }
227 
228  // Read as long as signals cancel the read before doing anything.
229  dc_errno = 0;
230  ssize_t n = dc_readv(m_fd, &bufs[0], buffers);
231 
232  // If it was serious error, throw it.
233  if (n == -1) {
235  ex << "dc_readv(name='" << m_name << "', iov[" << buffers << "]) failed with error '" << dc_strerror(dc_errno)
236  << "' (dc_errno=" << dc_errno << ")";
237  ex.addContext("Calling DCacheFile::readv()");
238  throw ex;
239  }
240 
241  // Return the number of bytes actually read.
242  return n;
243 }
244 
246  assert(!buffers || into);
247 
248  // readv may not support zero buffers.
249  if (!buffers)
250  return 0;
251 
252  // Convert the buffers to system format.
253  std::vector<iovec2> bufs(buffers);
254  IOSize total = 0;
255  for (IOSize i = 0; i < buffers; ++i) {
256  bufs[i].offset = into[i].offset();
257  bufs[i].len = into[i].size();
258  bufs[i].buf = (char *)into[i].data();
259  total += into[i].size();
260  }
261 
262  // Read as long as signals cancel the read before doing anything.
263  dc_errno = 0;
264  ssize_t n = dc_readv2(m_fd, &bufs[0], buffers);
265 
266  // If it was serious error, throw it.
267  if (n == -1) {
269  ex << "dc_readv2(name='" << m_name << "', iov2[" << buffers << "]) failed with error '" << dc_strerror(dc_errno)
270  << "' (dc_errno=" << dc_errno << ")";
271  ex.addContext("Calling DCacheFile::readv()");
272  throw ex;
273  }
274  // dc_readv2 returns 0 on success.
275  return (n == 0) ? total : 0;
276 }
277 
282  if (m_fd == EDM_IOFD_INVALID) {
283  cms::Exception ex("FilePositionError");
284  ex << "DCacheFile::position() called on a closed file";
285  throw ex;
286  }
287  if (whence != CURRENT && whence != SET && whence != END) {
288  cms::Exception ex("FilePositionError");
289  ex << "DCacheFile::position() called with incorrect 'whence' parameter";
290  throw ex;
291  }
293  int mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
294 
295  dc_errno = 0;
296  if ((result = dc_lseek64(m_fd, offset, mywhence)) == -1) {
297  cms::Exception ex("FilePositionError");
298  ex << "dc_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence << ") failed with error '"
299  << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
300  ex.addContext("Calling DCacheFile::position()");
301  throw ex;
302  }
303  // FIXME: dCache returns incorrect value on SEEK_END.
304  // Remove this hack when dcap has been fixed.
305  if (whence == SEEK_END && (result = dc_lseek64(m_fd, result, SEEK_SET)) == -1) {
306  cms::Exception ex("FilePositionError");
307  ex << "dc_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << SEEK_SET << ") failed with error '"
308  << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
309  ex.addContext("Calling DCacheFile::position()");
310  throw ex;
311  }
312  return result;
313 }
314 
315 void DCacheFile::resize(IOOffset /* size */) {
316  cms::Exception ex("FileResizeError");
317  ex << "DCacheFile::resize(name='" << m_name << "') not implemented";
318  throw ex;
319 }
int64_t IOOffset
Definition: IOTypes.h:20
void resize(IOOffset size) override
Definition: DCacheFile.cc:315
IOSize readv(IOBuffer *into, IOSize buffers) override
Definition: DCacheFile.cc:214
virtual void open(const char *name, int flags=IOFlags::OpenRead, int perms=0666)
Definition: DCacheFile.cc:50
Log< level::Error, false > LogError
assert(be >=bs)
IOOffset offset() const
Definition: IOPosBuffer.h:41
static const int BUGLINE
Definition: DCacheFile.cc:152
~DCacheFile(void) override
Definition: DCacheFile.cc:27
virtual void create(const char *name, bool exclusive=false, int perms=0666)
Definition: DCacheFile.cc:34
IOSize write(const void *from, IOSize n) override
Definition: DCacheFile.cc:192
void close(void) override
Definition: DCacheFile.cc:124
IOSize size() const
Definition: IOBuffer.h:36
virtual void abort(void)
Definition: DCacheFile.cc:143
Log< level::Info, false > LogInfo
size_t IOSize
Definition: IOTypes.h:15
void addContext(std::string const &context)
Definition: Exception.cc:165
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:79
constexpr int EDM_IOFD_INVALID
Definition: IOTypes.h:9
virtual IOOffset position() const
Definition: Storage.cc:504
int IOFD
Definition: IOTypes.h:23
#define O_NONBLOCK
Definition: SysFile.h:23
Log< level::Warning, false > LogWarning
fd
Definition: ztee.py:136