CMS 3D CMS Logo

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