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