Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2021-10-01 22:41:10

0001 #include "Utilities/DCacheAdaptor/interface/DCacheFile.h"
0002 #include "FWCore/Utilities/interface/Exception.h"
0003 #include "FWCore/Utilities/interface/EDMException.h"
0004 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0005 #include <cassert>
0006 #include <vector>
0007 #include <unistd.h>
0008 #include <fcntl.h>
0009 #include <dcap.h>
0010 
0011 using namespace edm::storage;
0012 
0013 DCacheFile::DCacheFile(void) : m_fd(EDM_IOFD_INVALID), m_close(false) {}
0014 
0015 DCacheFile::DCacheFile(IOFD fd) : m_fd(fd), m_close(true) {}
0016 
0017 DCacheFile::DCacheFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
0018     : m_fd(EDM_IOFD_INVALID), m_close(false) {
0019   open(name, flags, perms);
0020 }
0021 
0022 DCacheFile::DCacheFile(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
0023     : m_fd(EDM_IOFD_INVALID), m_close(false) {
0024   open(name.c_str(), flags, perms);
0025 }
0026 
0027 DCacheFile::~DCacheFile(void) {
0028   if (m_close)
0029     edm::LogError("DCacheFileError") << "Destructor called on dCache file '" << m_name
0030                                      << "' but the file is still open";
0031 }
0032 
0033 //////////////////////////////////////////////////////////////////////
0034 void DCacheFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
0035   open(name,
0036        (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0037        perms);
0038 }
0039 
0040 void DCacheFile::create(const std::string &name, bool exclusive /* = false */, int perms /* = 066 */) {
0041   open(name.c_str(),
0042        (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0043        perms);
0044 }
0045 
0046 void DCacheFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
0047   open(name.c_str(), flags, perms);
0048 }
0049 
0050 void DCacheFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
0051   // Actual open
0052   if ((name == nullptr) || (*name == 0)) {
0053     edm::Exception ex(edm::errors::FileOpenError);
0054     ex << "Cannot open a file without a name";
0055     ex.addContext("Calling DCacheFile::open()");
0056     throw ex;
0057   }
0058 
0059   if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0) {
0060     edm::Exception ex(edm::errors::FileOpenError);
0061     ex << "Must open file '" << name << "' at least for read or write";
0062     ex.addContext("Calling DCacheFile::open()");
0063     throw ex;
0064   }
0065 
0066   // If I am already open, close old file first
0067   if (m_fd != EDM_IOFD_INVALID && m_close)
0068     close();
0069 
0070   // Translate our flags to system flags
0071   int openflags = 0;
0072 
0073   if ((flags & IOFlags::OpenRead) && (flags & IOFlags::OpenWrite))
0074     openflags |= O_RDWR;
0075   else if (flags & IOFlags::OpenRead)
0076     openflags |= O_RDONLY;
0077   else if (flags & IOFlags::OpenWrite)
0078     openflags |= O_WRONLY;
0079 
0080   if (flags & IOFlags::OpenNonBlock)
0081     openflags |= O_NONBLOCK;
0082 
0083   if (flags & IOFlags::OpenAppend)
0084     openflags |= O_APPEND;
0085 
0086   if (flags & IOFlags::OpenCreate)
0087     openflags |= O_CREAT;
0088 
0089   if (flags & IOFlags::OpenExclusive)
0090     openflags |= O_EXCL;
0091 
0092   if (flags & IOFlags::OpenTruncate)
0093     openflags |= O_TRUNC;
0094 
0095   IOFD newfd = EDM_IOFD_INVALID;
0096   dc_errno = 0;
0097   if ((newfd = dc_open(name, openflags, perms)) == -1) {
0098     edm::Exception ex(edm::errors::FileOpenError);
0099     ex << "dc_open(name='" << name << "', flags=0x" << std::hex << openflags << ", permissions=0" << std::oct << perms
0100        << std::dec << ") => error '" << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
0101     ex.addContext("Calling DCacheFile::open()");
0102     throw ex;
0103   }
0104 
0105   m_name = name;
0106   m_fd = newfd;
0107 
0108   // Turn off read-ahead, or adjust read-ahead size depending on
0109   // whether buffering has been requested.  This is a very tricky
0110   // balance here.  Without read-ahead data processing appears to
0111   // become exceedingly slow, and with default (1MB) read-ahead
0112   // it appears to saturate disk servers and network.  Try tread
0113   // reasonable middle ground here.
0114   if (flags & IOFlags::OpenUnbuffered)
0115     dc_noBuffering(m_fd);
0116   else
0117     dc_setBufferSize(m_fd, 64000);
0118 
0119   m_close = true;
0120 
0121   edm::LogInfo("DCacheFileInfo") << "Opened " << m_name;
0122 }
0123 
0124 void DCacheFile::close(void) {
0125   if (m_fd == EDM_IOFD_INVALID) {
0126     edm::LogError("DCacheFileError") << "DCacheFile::close(name='" << m_name << "') called but the file is not open";
0127     m_close = false;
0128     return;
0129   }
0130 
0131   dc_errno = 0;
0132   if (dc_close(m_fd) == -1)
0133     edm::LogWarning("DCacheFileWarning") << "dc_close(name='" << m_name << "') failed with error '"
0134                                          << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
0135 
0136   m_close = false;
0137   m_fd = EDM_IOFD_INVALID;
0138 
0139   // Caused hang.  Will be added back after problem is fixed.
0140   // edm::LogInfo("DCacheFileInfo") << "Closed " << m_name;
0141 }
0142 
0143 void DCacheFile::abort(void) {
0144   if (m_fd != EDM_IOFD_INVALID)
0145     dc_close(m_fd);
0146 
0147   m_close = false;
0148   m_fd = EDM_IOFD_INVALID;
0149 }
0150 
0151 //////////////////////////////////////////////////////////////////////
0152 static const int BUGLINE = __LINE__ + 1;
0153 // Apparently dc_read can return short reads; I don't know if dc_write
0154 // will also return short writes.  This is a bug in dCache.  POSIX,
0155 // apparently contrary to the understanding of dCache authors, does
0156 // not allow reads from files to return short, and in fact no network
0157 // file system returns short reads.  For more details please refer to
0158 // http://www.opengroup.org/onlinepubs/000095399/functions/read.html:
0159 //    The value returned may be less than nbyte if the number of
0160 //    bytes left in the file is less than nbyte, if the read()
0161 //    request was interrupted by a signal, or if the file is a
0162 //    pipe or FIFO or special file and has fewer than nbyte bytes
0163 //    immediately available for reading.
0164 // (In other words, barring signals (which should use SA_RESTART and
0165 // in any case should not affect dCache) the only way a read from a
0166 // file can return short is when there is nothing left to read.)
0167 IOSize DCacheFile::read(void *into, IOSize n) {
0168   IOSize done = 0;
0169   while (done < n) {
0170     dc_errno = 0;
0171     ssize_t s = dc_read(m_fd, (char *)into + done, n - done);
0172     if (s == -1) {
0173       edm::Exception ex(edm::errors::FileReadError);
0174       ex << "dc_read(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << dc_strerror(dc_errno)
0175          << "' (dc_errno=" << dc_errno << ")";
0176       ex.addContext("Calling DCacheFile::read()");
0177       throw ex;
0178     } else if (s == 0)
0179       // end of file
0180       break;
0181     else if (s < ssize_t(n - done))
0182       edm::LogInfo("DCacheFileWarning") << "dc_read(name='" << m_name << "', n=" << (n - done)
0183                                         << ") returned a short read of " << s << " bytes; "
0184                                         << "please report a bug in dCache referencing the "
0185                                         << "comment on line " << BUGLINE << " of " << __FILE__;
0186     done += s;
0187   }
0188 
0189   return done;
0190 }
0191 
0192 IOSize DCacheFile::write(const void *from, IOSize n) {
0193   IOSize done = 0;
0194   while (done < n) {
0195     dc_errno = 0;
0196     ssize_t s = dc_write(m_fd, (const char *)from + done, n - done);
0197     if (s == -1) {
0198       edm::Exception ex(edm::errors::FileWriteError);
0199       ex << "dc_write(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << dc_strerror(dc_errno)
0200          << "' (dc_errno=" << dc_errno << ")";
0201       ex.addContext("Calling DCacheFile::write()");
0202       throw ex;
0203     } else if (s < ssize_t(n - done))
0204       edm::LogInfo("DCacheFileWarning") << "dc_write(name='" << m_name << "', n=" << (n - done)
0205                                         << ") returned a short write of " << s << " bytes; "
0206                                         << "please report a bug in dCache referencing the "
0207                                         << "comment on line " << BUGLINE << " of " << __FILE__;
0208     done += s;
0209   }
0210 
0211   return done;
0212 }
0213 
0214 IOSize DCacheFile::readv(IOBuffer *into, IOSize buffers) {
0215   assert(!buffers || into);
0216 
0217   // readv may not support zero buffers.
0218   if (!buffers)
0219     return 0;
0220 
0221   // Convert the buffers to system format.
0222   std::vector<iovec> bufs(buffers);
0223   for (IOSize i = 0; i < buffers; ++i) {
0224     bufs[i].iov_len = into[i].size();
0225     bufs[i].iov_base = (caddr_t)into[i].data();
0226   }
0227 
0228   // Read as long as signals cancel the read before doing anything.
0229   dc_errno = 0;
0230   ssize_t n = dc_readv(m_fd, &bufs[0], buffers);
0231 
0232   // If it was serious error, throw it.
0233   if (n == -1) {
0234     edm::Exception ex(edm::errors::FileReadError);
0235     ex << "dc_readv(name='" << m_name << "', iov[" << buffers << "]) failed with error '" << dc_strerror(dc_errno)
0236        << "' (dc_errno=" << dc_errno << ")";
0237     ex.addContext("Calling DCacheFile::readv()");
0238     throw ex;
0239   }
0240 
0241   // Return the number of bytes actually read.
0242   return n;
0243 }
0244 
0245 IOSize DCacheFile::readv(IOPosBuffer *into, IOSize buffers) {
0246   assert(!buffers || into);
0247 
0248   // readv may not support zero buffers.
0249   if (!buffers)
0250     return 0;
0251 
0252   // Convert the buffers to system format.
0253   std::vector<iovec2> bufs(buffers);
0254   IOSize total = 0;
0255   for (IOSize i = 0; i < buffers; ++i) {
0256     bufs[i].offset = into[i].offset();
0257     bufs[i].len = into[i].size();
0258     bufs[i].buf = (char *)into[i].data();
0259     total += into[i].size();
0260   }
0261 
0262   // Read as long as signals cancel the read before doing anything.
0263   dc_errno = 0;
0264   ssize_t n = dc_readv2(m_fd, &bufs[0], buffers);
0265 
0266   // If it was serious error, throw it.
0267   if (n == -1) {
0268     edm::Exception ex(edm::errors::FileReadError);
0269     ex << "dc_readv2(name='" << m_name << "', iov2[" << buffers << "]) failed with error '" << dc_strerror(dc_errno)
0270        << "' (dc_errno=" << dc_errno << ")";
0271     ex.addContext("Calling DCacheFile::readv()");
0272     throw ex;
0273   }
0274   // dc_readv2 returns 0 on success.
0275   return (n == 0) ? total : 0;
0276 }
0277 
0278 //////////////////////////////////////////////////////////////////////
0279 //////////////////////////////////////////////////////////////////////
0280 //////////////////////////////////////////////////////////////////////
0281 IOOffset DCacheFile::position(IOOffset offset, Relative whence /* = SET */) {
0282   if (m_fd == EDM_IOFD_INVALID) {
0283     cms::Exception ex("FilePositionError");
0284     ex << "DCacheFile::position() called on a closed file";
0285     throw ex;
0286   }
0287   if (whence != CURRENT && whence != SET && whence != END) {
0288     cms::Exception ex("FilePositionError");
0289     ex << "DCacheFile::position() called with incorrect 'whence' parameter";
0290     throw ex;
0291   }
0292   IOOffset result;
0293   int mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
0294 
0295   dc_errno = 0;
0296   if ((result = dc_lseek64(m_fd, offset, mywhence)) == -1) {
0297     cms::Exception ex("FilePositionError");
0298     ex << "dc_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence << ") failed with error '"
0299        << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
0300     ex.addContext("Calling DCacheFile::position()");
0301     throw ex;
0302   }
0303   // FIXME: dCache returns incorrect value on SEEK_END.
0304   // Remove this hack when dcap has been fixed.
0305   if (whence == SEEK_END && (result = dc_lseek64(m_fd, result, SEEK_SET)) == -1) {
0306     cms::Exception ex("FilePositionError");
0307     ex << "dc_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << SEEK_SET << ") failed with error '"
0308        << dc_strerror(dc_errno) << "' (dc_errno=" << dc_errno << ")";
0309     ex.addContext("Calling DCacheFile::position()");
0310     throw ex;
0311   }
0312   return result;
0313 }
0314 
0315 void DCacheFile::resize(IOOffset /* size */) {
0316   cms::Exception ex("FileResizeError");
0317   ex << "DCacheFile::resize(name='" << m_name << "') not implemented";
0318   throw ex;
0319 }