CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/Utilities/DCacheAdaptor/src/DCacheFile.cc

Go to the documentation of this file.
00001 #include "Utilities/DCacheAdaptor/interface/DCacheFile.h"
00002 #include "FWCore/Utilities/interface/Exception.h"
00003 #include "FWCore/Utilities/interface/EDMException.h"
00004 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00005 #include <cassert>
00006 #include <vector>
00007 #include <unistd.h>
00008 #include <fcntl.h>
00009 #include <dcap.h>
00010 
00011 DCacheFile::DCacheFile (void)
00012   : m_fd (EDM_IOFD_INVALID),
00013     m_close (false)
00014 {}
00015 
00016 DCacheFile::DCacheFile (IOFD fd)
00017   : m_fd (fd),
00018     m_close (true)
00019 {}
00020 
00021 DCacheFile::DCacheFile (const char *name,
00022             int flags /* = IOFlags::OpenRead */,
00023             int perms /* = 066 */)
00024   : m_fd (EDM_IOFD_INVALID),
00025     m_close (false)
00026 { open (name, flags, perms); }
00027 
00028 DCacheFile::DCacheFile (const std::string &name,
00029             int flags /* = IOFlags::OpenRead */,
00030             int perms /* = 066 */)
00031   : m_fd (EDM_IOFD_INVALID),
00032     m_close (false)
00033 { open (name.c_str (), flags, perms); }
00034 
00035 DCacheFile::~DCacheFile (void)
00036 {
00037   if (m_close)
00038     edm::LogError("DCacheFileError")
00039       << "Destructor called on dCache file '" << m_name
00040       << "' but the file is still open";
00041 }
00042 
00044 void
00045 DCacheFile::create (const char *name,
00046                     bool exclusive /* = false */,
00047                     int perms /* = 066 */)
00048 {
00049   open (name,
00050         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00051          | (exclusive ? IOFlags::OpenExclusive : 0)),
00052         perms);
00053 }
00054 
00055 void
00056 DCacheFile::create (const std::string &name,
00057                     bool exclusive /* = false */,
00058                     int perms /* = 066 */)
00059 {
00060   open (name.c_str (),
00061         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00062          | (exclusive ? IOFlags::OpenExclusive : 0)),
00063         perms);
00064 }
00065 
00066 void
00067 DCacheFile::open (const std::string &name,
00068                   int flags /* = IOFlags::OpenRead */,
00069                   int perms /* = 066 */)
00070 { open (name.c_str (), flags, perms); }
00071 
00072 void
00073 DCacheFile::open (const char *name,
00074                   int flags /* = IOFlags::OpenRead */,
00075                   int perms /* = 066 */)
00076 {
00077   m_name = name;
00078 
00079   // Actual open
00080   if ((name == 0) || (*name == 0)) {
00081     edm::Exception ex(edm::errors::FileOpenError);
00082     ex << "Cannot open a file without a name";
00083     ex.addContext("Calling DCacheFile::open()");
00084     throw ex;
00085   }
00086 
00087   if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
00088     edm::Exception ex(edm::errors::FileOpenError);
00089     ex << "Must open file '" << name << "' at least for read or write";
00090     ex.addContext("Calling DCacheFile::open()");
00091     throw ex;
00092   }
00093 
00094   // If I am already open, close old file first
00095   if (m_fd != EDM_IOFD_INVALID && m_close)
00096     close ();
00097 
00098   // Translate our flags to system flags
00099   int openflags = 0;
00100 
00101   if ((flags & IOFlags::OpenRead) && (flags & IOFlags::OpenWrite))
00102     openflags |= O_RDWR;
00103   else if (flags & IOFlags::OpenRead)
00104     openflags |= O_RDONLY;
00105   else if (flags & IOFlags::OpenWrite)
00106     openflags |= O_WRONLY;
00107 
00108   if (flags & IOFlags::OpenNonBlock)
00109     openflags |= O_NONBLOCK;
00110 
00111   if (flags & IOFlags::OpenAppend)
00112     openflags |= O_APPEND;
00113 
00114   if (flags & IOFlags::OpenCreate)
00115     openflags |= O_CREAT;
00116 
00117   if (flags & IOFlags::OpenExclusive)
00118     openflags |= O_EXCL;
00119 
00120   if (flags & IOFlags::OpenTruncate)
00121     openflags |= O_TRUNC;
00122 
00123   IOFD newfd = EDM_IOFD_INVALID;
00124   dc_errno = 0;
00125   if ((newfd = dc_open (name, openflags, perms)) == -1) {
00126     edm::Exception ex(edm::errors::FileOpenError);
00127     ex << "dc_open(name='" << name
00128        << "', flags=0x" << std::hex << openflags
00129        << ", permissions=0" << std::oct << perms << std::dec
00130        << ") => error '" << dc_strerror(dc_errno)
00131        << "' (dc_errno=" << dc_errno << ")";
00132     ex.addContext("Calling DCacheFile::open()");
00133     throw ex;
00134   }
00135 
00136   m_fd = newfd;
00137 
00138   // Turn off read-ahead, or adjust read-ahead size depending on
00139   // whether buffering has been requested.  This is a very tricky
00140   // balance here.  Without read-ahead data processing appears to
00141   // become exceedingly slow, and with default (1MB) read-ahead
00142   // it appears to saturate disk servers and network.  Try tread
00143   // reasonable middle ground here.
00144   if (flags & IOFlags::OpenUnbuffered)
00145     dc_noBuffering(m_fd);
00146   else
00147     dc_setBufferSize(m_fd, 64000);
00148 
00149   m_close = true;
00150 
00151   edm::LogInfo("DCacheFileInfo") << "Opened " << m_name;
00152 }
00153 
00154 void
00155 DCacheFile::close (void)
00156 {
00157   if (m_fd == EDM_IOFD_INVALID)
00158   {
00159     edm::LogError("DCacheFileError")
00160       << "DCacheFile::close(name='" << m_name
00161       << "') called but the file is not open";
00162     m_close = false;
00163     return;
00164   }
00165 
00166   dc_errno = 0;
00167   if (dc_close (m_fd) == -1)
00168     edm::LogWarning("DCacheFileWarning")
00169       << "dc_close(name='" << m_name
00170       << "') failed with error '" << dc_strerror (dc_errno)
00171       << "' (dc_errno=" << dc_errno << ")";
00172 
00173   m_close = false;
00174   m_fd = EDM_IOFD_INVALID;
00175 
00176   // Caused hang.  Will be added back after problem is fixed.
00177   // edm::LogInfo("DCacheFileInfo") << "Closed " << m_name;
00178 }
00179 
00180 void
00181 DCacheFile::abort (void)
00182 {
00183   if (m_fd != EDM_IOFD_INVALID)
00184     dc_close (m_fd);
00185 
00186   m_close = false;
00187   m_fd = EDM_IOFD_INVALID;
00188 }
00189 
00191 static const int BUGLINE = __LINE__ + 1;
00192 // Apparently dc_read can return short reads; I don't know if dc_write
00193 // will also return short writes.  This is a bug in dCache.  POSIX,
00194 // apparently contrary to the understanding of dCache authors, does
00195 // not allow reads from files to return short, and in fact no network
00196 // file system returns short reads.  For more details please refer to
00197 // https://www.opengroup.org/onlinepubs/000095399/functions/read.html:
00198 //    The value returned may be less than nbyte if the number of
00199 //    bytes left in the file is less than nbyte, if the read()
00200 //    request was interrupted by a signal, or if the file is a
00201 //    pipe or FIFO or special file and has fewer than nbyte bytes
00202 //    immediately available for reading.
00203 // (In other words, barring signals (which should use SA_RESTART and
00204 // in any case should not affect dCache) the only way a read from a
00205 // file can return short is when there is nothing left to read.)
00206 IOSize
00207 DCacheFile::read (void *into, IOSize n)
00208 {
00209   IOSize done = 0;
00210   while (done < n)
00211   {
00212     dc_errno = 0;
00213     ssize_t s = dc_read (m_fd, (char *) into + done, n - done);
00214     if (s == -1) {
00215       edm::Exception ex(edm::errors::FileReadError);
00216       ex << "dc_read(name='" << m_name << "', n=" << (n-done)
00217          << ") failed with error '" << dc_strerror(dc_errno)
00218          << "' (dc_errno=" << dc_errno << ")";
00219       ex.addContext("Calling DCacheFile::read()");
00220       throw ex;
00221     }
00222     else if (s == 0)
00223       // end of file
00224       break;
00225     else if (s < ssize_t (n-done))
00226       edm::LogInfo("DCacheFileWarning")
00227         << "dc_read(name='" << m_name << "', n=" << (n-done)
00228         << ") returned a short read of " << s << " bytes; "
00229         << "please report a bug in dCache referencing the "
00230         << "comment on line " << BUGLINE << " of " << __FILE__;
00231     done += s;
00232   }
00233 
00234   return done;
00235 }
00236 
00237 IOSize
00238 DCacheFile::write (const void *from, IOSize n)
00239 {
00240   IOSize done = 0;
00241   while (done < n)
00242   {
00243     dc_errno = 0;
00244     ssize_t s = dc_write (m_fd, (const char *) from + done, n - done);
00245     if (s == -1) {
00246       cms::Exception ex("FileWriteError");
00247       ex << "dc_write(name='" << m_name << "', n=" << (n-done)
00248          << ") failed with error '" << dc_strerror(dc_errno)
00249          << "' (dc_errno=" << dc_errno << ")";
00250       ex.addContext("Calling DCacheFile::write()");
00251       throw ex;
00252     }
00253     else if (s < ssize_t (n-done))
00254       edm::LogInfo("DCacheFileWarning")
00255         << "dc_write(name='" << m_name << "', n=" << (n-done)
00256         << ") returned a short write of " << s << " bytes; "
00257         << "please report a bug in dCache referencing the "
00258         << "comment on line " << BUGLINE << " of " << __FILE__;
00259     done += s;
00260   }
00261 
00262   return done;
00263 }
00264 
00265 IOSize
00266 DCacheFile::readv (IOBuffer *into, IOSize buffers)
00267 {
00268   assert (! buffers || into);
00269 
00270   // readv may not support zero buffers.
00271   if (! buffers)
00272     return 0;
00273 
00274   // Convert the buffers to system format.
00275   std::vector<iovec> bufs (buffers);
00276   for (IOSize i = 0; i < buffers; ++i)
00277   {
00278     bufs [i].iov_len  = into [i].size ();
00279     bufs [i].iov_base = (caddr_t) into [i].data ();
00280   }
00281 
00282   // Read as long as signals cancel the read before doing anything.
00283   dc_errno = 0;
00284   ssize_t n = dc_readv (m_fd, &bufs [0], buffers);
00285 
00286   // If it was serious error, throw it.
00287   if (n == -1) {
00288     edm::Exception ex(edm::errors::FileReadError);
00289     ex << "dc_readv(name='" << m_name << "', iov[" << buffers
00290        << "]) failed with error '" << dc_strerror(dc_errno)
00291        << "' (dc_errno=" << dc_errno << ")";
00292     ex.addContext("Calling DCacheFile::readv()");
00293     throw ex;
00294   }
00295 
00296   // Return the number of bytes actually read.
00297   return n;
00298 }
00299 
00300 IOSize
00301 DCacheFile::readv (IOPosBuffer *into, IOSize buffers)
00302 {
00303   assert (! buffers || into);
00304 
00305   // readv may not support zero buffers.
00306   if (! buffers)
00307     return 0;
00308 
00309   // Convert the buffers to system format.
00310   std::vector<iovec2> bufs (buffers);
00311   for (IOSize i = 0; i < buffers; ++i)
00312   {
00313     bufs [i].offset = into [i].offset ();
00314     bufs [i].len    = into [i].size ();
00315     bufs [i].buf    = (char *) into [i].data ();
00316   }
00317 
00318   // Read as long as signals cancel the read before doing anything.
00319   dc_errno = 0;
00320   ssize_t n = dc_readv2 (m_fd, &bufs [0], buffers);
00321 
00322   // If it was serious error, throw it.
00323   if (n == -1) {
00324     edm::Exception ex(edm::errors::FileReadError);
00325     ex << "dc_readv2(name='" << m_name << "', iov2[" << buffers
00326        << "]) failed with error '" << dc_strerror(dc_errno)
00327        << "' (dc_errno=" << dc_errno << ")";
00328     ex.addContext("Calling DCacheFile::readv()");
00329     throw ex;
00330   }
00331   // Return the number of bytes actually read.
00332   return n;
00333 }
00334 
00338 IOOffset
00339 DCacheFile::position (IOOffset offset, Relative whence /* = SET */)
00340 {
00341   if (m_fd == EDM_IOFD_INVALID) {
00342     cms::Exception ex("FilePositionError");
00343     ex << "DCacheFile::position() called on a closed file";
00344     throw ex;
00345   }
00346   if (whence != CURRENT && whence != SET && whence != END) {
00347     cms::Exception ex("FilePositionError");
00348     ex << "DCacheFile::position() called with incorrect 'whence' parameter";
00349     throw ex;
00350   }
00351   IOOffset      result;
00352   int           mywhence = (whence == SET ? SEEK_SET
00353                             : whence == CURRENT ? SEEK_CUR
00354                             : SEEK_END);
00355 
00356   dc_errno = 0;
00357   if ((result = dc_lseek64 (m_fd, offset, mywhence)) == -1) {
00358     cms::Exception ex("FilePositionError");
00359     ex << "dc_lseek64(name='" << m_name << "', offset=" << offset
00360        << ", whence=" << mywhence << ") failed with error '"
00361        << dc_strerror (dc_errno) << "' (dc_errno=" << dc_errno << ")";
00362     ex.addContext("Calling DCacheFile::position()");
00363     throw ex;
00364   }
00365   // FIXME: dCache returns incorrect value on SEEK_END.
00366   // Remove this hack when dcap has been fixed.
00367   if (whence == SEEK_END && (result = dc_lseek64 (m_fd, result, SEEK_SET)) == -1) {
00368     cms::Exception ex("FilePositionError");
00369     ex << "dc_lseek64(name='" << m_name << "', offset=" << offset
00370        << ", whence=" << SEEK_SET << ") failed with error '"
00371        << dc_strerror (dc_errno) << "' (dc_errno=" << dc_errno << ")";
00372     ex.addContext("Calling DCacheFile::position()");
00373     throw ex;
00374   }
00375   return result;
00376 }
00377 
00378 void
00379 DCacheFile::resize (IOOffset /* size */)
00380 {
00381   cms::Exception ex("FileResizeError");
00382   ex << "DCacheFile::resize(name='" << m_name << "') not implemented";
00383   throw ex;
00384 }