CMS 3D CMS Logo

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