Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:31:46

0001 #include "Utilities/LStoreAdaptor/interface/LStoreFile.h"
0002 #include "FWCore/Utilities/interface/Exception.h"
0003 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0004 #include <cassert>
0005 #include <vector>
0006 #include <unistd.h>
0007 #include <fcntl.h>
0008 #include <pthread.h>
0009 #include <dlfcn.h>
0010 #include <iostream>
0011 #include <cstring>
0012 
0013 using namespace edm::storage;
0014 
0015 // dlsym isn't reentrant, need a locak around it
0016 pthread_mutex_t LStoreFile::m_dlopen_lock = PTHREAD_MUTEX_INITIALIZER;
0017 
0018 LStoreFile::LStoreFile(void)
0019     : m_fd(nullptr),
0020       m_close(false),
0021       m_name(),
0022       m_library_handle(nullptr),
0023       m_is_loaded(false),
0024       redd_init(nullptr),
0025       redd_read(nullptr),
0026       redd_close(nullptr),
0027       redd_lseek(nullptr),
0028       redd_open(nullptr),
0029       redd_write(nullptr),
0030       redd_term(nullptr),
0031       redd_errno(nullptr),
0032       redd_strerror(nullptr) {
0033   loadLibrary();
0034 }
0035 
0036 LStoreFile::LStoreFile(void *fd)
0037     : m_fd(fd),
0038       m_close(true),
0039       m_name(),
0040       m_library_handle(nullptr),
0041       m_is_loaded(false),
0042       redd_init(nullptr),
0043       redd_read(nullptr),
0044       redd_close(nullptr),
0045       redd_lseek(nullptr),
0046       redd_open(nullptr),
0047       redd_write(nullptr),
0048       redd_term(nullptr),
0049       redd_errno(nullptr),
0050       redd_strerror(nullptr) {
0051   loadLibrary();
0052 }
0053 
0054 LStoreFile::LStoreFile(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */)
0055     : m_fd(nullptr), m_close(false), m_is_loaded(false) {
0056   loadLibrary();
0057   open(name, flags, perms);
0058 }
0059 
0060 LStoreFile::LStoreFile(const std::string &name, int flags /* = IOFlags::OpenRead*/, int perms /* = 066 */)
0061     : m_fd(nullptr), m_close(false), m_is_loaded(false) {
0062   loadLibrary();
0063   open(name.c_str(), flags, perms);
0064 }
0065 
0066 LStoreFile::~LStoreFile(void) {
0067   if (m_close)
0068     edm::LogError("LStoreFileError") << "Destructor called on LStore file '" << m_name
0069                                      << "' but the file is still open";
0070   closeLibrary();
0071 }
0072 
0073 // Helper macro to perform dlsym()
0074 // Double cast is supposed to be more compliant
0075 // otherwise, GCC complains with the pointer conversion
0076 #define REDD_LOAD_SYMBOL(NAME, TYPE)                                                                        \
0077   dlerror();                                                                                                \
0078   NAME = reinterpret_cast<TYPE>(reinterpret_cast<size_t>(dlsym(m_library_handle, #NAME)));                  \
0079   if ((retval = dlerror())) {                                                                               \
0080     throw cms::Exception("LStoreFile::loadLibrary()") << "Failed to load dlsym LStore library: " << retval; \
0081   }                                                                                                         \
0082   if (NAME == NULL) {                                                                                       \
0083     throw cms::Exception("LStoreFile::loadLibrary()") << "Got a null pointer back from dlsym()\n";          \
0084   }
0085 
0086 void LStoreFile::loadLibrary() {
0087   edm::LogError("LStoreFile::loadLibrary()") << "Loading library\n";
0088   LStoreFile::MutexWrapper lockObj(&this->m_dlopen_lock);
0089   // until ACCRE removes the java dependency from their client libs,
0090   // we'll dlopen() them so they don't need to be brought along with cmssw
0091   // if you're running LStore at your site, you will have the libs anyway
0092   // TODO add wrappers to make this work in OSX as well (CMSSW's getting ported?)
0093   // TODO   should be easy, just need to know the "proper" way to do #if OSX
0094   // -Melo
0095 
0096   m_library_handle = dlopen("libreddnet.so", RTLD_LAZY);
0097   if (m_library_handle == nullptr) {
0098     throw cms::Exception("LStoreFile::loadLibrary()") << "Can't dlopen() LStore libraries: " << dlerror();
0099   }
0100 
0101   char *retval = nullptr;
0102   // Explicitly state the size of these values, keeps weird 64/32 bit stuff away
0103   REDD_LOAD_SYMBOL(redd_init, int32_t(*)());
0104   REDD_LOAD_SYMBOL(redd_read, int64_t(*)(void *, char *, int64_t));
0105   REDD_LOAD_SYMBOL(redd_lseek, int64_t(*)(void *, int64_t, uint32_t));
0106   REDD_LOAD_SYMBOL(redd_open, void *(*)(const char *, int, int));
0107   REDD_LOAD_SYMBOL(redd_write, int64_t(*)(void *, const char *, int64_t));
0108   REDD_LOAD_SYMBOL(redd_term, int32_t(*)());
0109   REDD_LOAD_SYMBOL(redd_errno, int32_t(*)());
0110   REDD_LOAD_SYMBOL(redd_strerror, const std::string &(*)());
0111 
0112   if ((*redd_init)()) {
0113     throw cms::Exception("LStoreFile::loadLibrary()") << "Error in redd_init: " << (*redd_strerror)();
0114   }
0115   m_is_loaded = true;
0116 }
0117 
0118 void LStoreFile::closeLibrary() {
0119   try {
0120     LStoreFile::MutexWrapper lockObj(&this->m_dlopen_lock);
0121 
0122     // What is the correct idiom for propagating error messages
0123     // in functions that are exclusively called in destructors?
0124     // Seriously. I have no idea
0125     // melo
0126     if (m_is_loaded) {
0127       if ((*redd_term)()) {
0128         throw cms::Exception("LStoreFile::closeLibrary()") << "Error in redd_term: " << (*redd_strerror)();
0129       }
0130     }
0131     if (m_library_handle != nullptr) {
0132       if (dlclose(m_library_handle)) {
0133         throw cms::Exception("LStoreFile::closeLibrary()") << "Error on dlclose(): " << dlerror();
0134       }
0135     }
0136   } catch (cms::Exception &e) {
0137     edm::LogError("LStoreFileError") << "LStoreFile had an error in its destructor: " << e;
0138   }
0139   m_is_loaded = false;
0140 }
0141 
0142 //////////////////////////////////////////////////////////////////////
0143 void LStoreFile::create(const char *name, bool exclusive /* = false */, int perms /* = 066 */) {
0144   open(name,
0145        (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0146        perms);
0147 }
0148 
0149 void LStoreFile::create(const std::string &name, bool exclusive /* = false */, int perms /* = 066 */) {
0150   open(name.c_str(),
0151        (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate | (exclusive ? IOFlags::OpenExclusive : 0)),
0152        perms);
0153 }
0154 
0155 void LStoreFile::open(const std::string &name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
0156   open(name.c_str(), flags, perms);
0157 }
0158 
0159 void LStoreFile::open(const char *name, int flags /* = IOFlags::OpenRead */, int perms /* = 066 */) {
0160   // Actual open
0161   if ((name == nullptr) || (*name == 0))
0162     throw cms::Exception("LStoreFile::open()") << "Cannot open a file without a name";
0163 
0164   if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0)
0165     throw cms::Exception("LStoreFile::open()") << "Must open file '" << name << "' at least for read or write";
0166 
0167   // If I am already open, close old file first
0168   if (m_fd != nullptr && m_close)
0169     close();
0170 
0171   // Translate our flags to system flags
0172   int openflags = 0;
0173 
0174   if ((flags & IOFlags::OpenRead) && (flags & IOFlags::OpenWrite))
0175     openflags |= O_RDWR;
0176   else if (flags & IOFlags::OpenRead)
0177     openflags |= O_RDONLY;
0178   else if (flags & IOFlags::OpenWrite)
0179     openflags |= O_WRONLY;
0180 
0181   if (flags & IOFlags::OpenNonBlock)
0182     openflags |= O_NONBLOCK;
0183 
0184   if (flags & IOFlags::OpenAppend)
0185     openflags |= O_APPEND;
0186 
0187   if (flags & IOFlags::OpenCreate)
0188     openflags |= O_CREAT;
0189 
0190   if (flags & IOFlags::OpenExclusive)
0191     openflags |= O_EXCL;
0192 
0193   if (flags & IOFlags::OpenTruncate)
0194     openflags |= O_TRUNC;
0195 
0196   void *newfd = nullptr;
0197   if ((newfd = (*redd_open)(name, openflags, perms)) == nullptr)
0198     throw cms::Exception("LStoreFile::open()")
0199         << "redd_open(name='" << name << "', flags=0x" << std::hex << openflags << ", permissions=0" << std::oct
0200         << perms << std::dec << ") => error '" << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
0201 
0202   m_name = name;
0203   m_fd = newfd;
0204 
0205   m_close = true;
0206 
0207   edm::LogInfo("LStoreFileInfo") << "Opened " << m_name;
0208 }
0209 
0210 void LStoreFile::close(void) {
0211   if (m_fd == nullptr) {
0212     edm::LogError("LStoreFileError") << "LStoreFile::close(name='" << m_name << "') called but the file is not open";
0213     m_close = false;
0214     return;
0215   }
0216   edm::LogInfo("LStoreFile::close()") << "closing " << m_name << std::endl;
0217   if ((*redd_close)(m_fd) == -1)
0218     edm::LogWarning("LStoreFileWarning") << "redd_close(name='" << m_name << "') failed with error '"
0219                                          << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
0220 
0221   m_close = false;
0222   m_fd = nullptr;
0223 
0224   // Caused hang.  Will be added back after problem is fixed.
0225   // edm::LogInfo("LStoreFileInfo") << "Closed " << m_name;
0226 }
0227 
0228 void LStoreFile::abort(void) {
0229   if (m_fd != nullptr)
0230     (*redd_close)(m_fd);
0231 
0232   m_close = false;
0233   m_fd = nullptr;
0234 }
0235 
0236 IOSize LStoreFile::read(void *into, IOSize n) {
0237   IOSize done = 0;
0238   while (done < n) {
0239     ssize_t s = (*redd_read)(m_fd, (char *)into + done, n - done);
0240     if (s == -1)
0241       throw cms::Exception("LStoreFile::read()")
0242           << "redd_read(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << (*redd_strerror)()
0243           << "' (redd_errno=" << (*redd_errno)() << ")";
0244     done += s;
0245   }
0246   return done;
0247 }
0248 
0249 IOSize LStoreFile::write(const void *from, IOSize n) {
0250   IOSize done = 0;
0251   while (done < n) {
0252     ssize_t s = (*redd_write)(m_fd, (const char *)from + done, n - done);
0253     if (s == -1)
0254       throw cms::Exception("LStoreFile::write()")
0255           << "redd_write(name='" << m_name << "', n=" << (n - done) << ") failed with error '" << (*redd_strerror)()
0256           << "' (redd_errno=" << (*redd_errno)() << ")";
0257     done += s;
0258   }
0259 
0260   return done;
0261 }
0262 //////////////////////////////////////////////////////////////////////
0263 //////////////////////////////////////////////////////////////////////
0264 //////////////////////////////////////////////////////////////////////
0265 IOOffset LStoreFile::position(IOOffset offset, Relative whence /* = SET */) {
0266   if (m_fd == nullptr)
0267     throw cms::Exception("LStoreFile::position()") << "LStoreFile::position() called on a closed file";
0268   if (whence != CURRENT && whence != SET && whence != END)
0269     throw cms::Exception("LStoreFile::position()") << "LStoreFile::position() called with incorrect 'whence' parameter";
0270 
0271   IOOffset result;
0272   uint32_t mywhence = (whence == SET ? SEEK_SET : whence == CURRENT ? SEEK_CUR : SEEK_END);
0273   if ((result = (*redd_lseek)(m_fd, (off_t)offset, (uint32_t)mywhence)) == -1)
0274     throw cms::Exception("LStoreFile::position()")
0275         << "redd_lseek64(name='" << m_name << "', offset=" << offset << ", whence=" << mywhence
0276         << ") failed with error '" << (*redd_strerror)() << "' (redd_errno=" << (*redd_errno)() << ")";
0277   return result;
0278 }
0279 
0280 void LStoreFile::resize(IOOffset /* size */) {
0281   throw cms::Exception("LStoreFile::resize()") << "LStoreFile::resize(name='" << m_name << "') not implemented";
0282 }
0283 
0284 ////////////////////////////////////////////////////////////////////
0285 
0286 LStoreFile::MutexWrapper::MutexWrapper(pthread_mutex_t *target) {
0287   m_lock = target;
0288   pthread_mutex_lock(m_lock);  // never fails
0289 }
0290 
0291 LStoreFile::MutexWrapper::~MutexWrapper() {
0292   int retval;
0293   if ((retval = pthread_mutex_unlock(m_lock))) {
0294     // congrats. pthread_mutex_lock failed and we're in a destructor
0295     // I don't know what to do here
0296     // Then again, if the mutex is jammed, things are already boned
0297     // Cry for a second, then continue with life, I guess
0298     // melo
0299 
0300     char buf[1024];
0301     edm::LogError("LStoreFileError") << "LStoreFile couldn't unlock a mutex. Not good."
0302                                      << strerror_r(retval, buf, 1024);
0303   }
0304 }