CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/Utilities/LStoreAdaptor/src/LStoreFile.cc

Go to the documentation of this file.
00001 #include "Utilities/LStoreAdaptor/interface/LStoreFile.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 <pthread.h>
00009 #include <dlfcn.h>
00010 #include <iostream>
00011 #include <string.h>
00012 
00013 // dlsym isn't reentrant, need a locak around it
00014 pthread_mutex_t LStoreFile::m_dlopen_lock = PTHREAD_MUTEX_INITIALIZER;
00015 
00016 LStoreFile::LStoreFile (void)
00017   : m_fd (NULL),
00018     m_close (false),
00019         m_is_loaded(false)
00020 {
00021         loadLibrary();  
00022 }
00023 
00024 LStoreFile::LStoreFile (void * fd)
00025   : m_fd (fd),
00026     m_close (true),
00027         m_is_loaded(false)
00028 {
00029         loadLibrary();  
00030 }
00031 
00032 LStoreFile::LStoreFile (const char *name,
00033             int flags /* = IOFlags::OpenRead */,
00034             int perms /* = 066 */ )
00035   : m_fd (NULL),
00036     m_close (false),
00037         m_is_loaded(false)
00038 {   loadLibrary();
00039         open (name, flags, perms); }
00040 
00041 LStoreFile::LStoreFile (const std::string &name,
00042             int flags /* = IOFlags::OpenRead*/, 
00043             int perms /* = 066 */)
00044   : m_fd (NULL),
00045     m_close (false),
00046         m_is_loaded(false)
00047 {   loadLibrary();
00048         open (name.c_str (), flags, perms); }
00049 
00050 LStoreFile::~LStoreFile (void)
00051 {
00052   if (m_close)
00053     edm::LogError("LStoreFileError")
00054       << "Destructor called on LStore file '" << m_name
00055       << "' but the file is still open";
00056   closeLibrary();
00057 }
00058 
00059 
00060 // Helper macro to perform dlsym()
00061 // Double cast is supposed to be more compliant
00062 // otherwise, GCC complains with the pointer conversion
00063 #define REDD_LOAD_SYMBOL( NAME, TYPE )  dlerror();\
00064     NAME = reinterpret_cast<TYPE>(reinterpret_cast<size_t>( \
00065                                 dlsym(m_library_handle, #NAME))); \
00066         if ( (retval = dlerror()) ) {\
00067                 throw cms::Exception("LStoreFile::loadLibrary()") <<\
00068                         "Failed to load dlsym LStore library: " << retval;\
00069         }\
00070         if ( NAME == NULL) {\
00071                 throw cms::Exception("LStoreFile::loadLibrary()") <<\
00072                         "Got a null pointer back from dlsym()\n";\
00073         }
00074 
00075 void LStoreFile::loadLibrary() {
00076         edm::LogError("LStoreFile::loadLibrary()") << "Loading library\n";
00077         LStoreFile::MutexWrapper lockObj( & this->m_dlopen_lock );
00078         // until ACCRE removes the java dependency from their client libs,
00079         // we'll dlopen() them so they don't need to be brought along with cmssw
00080         // if you're running LStore at your site, you will have the libs anyway
00081         // TODO add wrappers to make this work in OSX as well (CMSSW's getting ported?)
00082         // TODO   should be easy, just need to know the "proper" way to do #if OSX
00083         // -Melo
00084 
00085         m_library_handle =
00086              dlopen("libreddnet.so", RTLD_LAZY);
00087         if (m_library_handle == NULL) {
00088                 throw cms::Exception("LStoreFile::loadLibrary()")
00089                         << "Can't dlopen() LStore libraries: " << dlerror();
00090         }
00091 
00092         char * retval = NULL;
00093         // Explicitly state the size of these values, keeps weird 64/32 bit stuff away
00094         REDD_LOAD_SYMBOL( redd_init, int32_t(*)()); 
00095         REDD_LOAD_SYMBOL( redd_read, int64_t(*)(void *, char*, int64_t));
00096         REDD_LOAD_SYMBOL( redd_lseek, int64_t(*)(void*, int64_t, uint32_t));
00097         REDD_LOAD_SYMBOL( redd_open, void*(*)(const char*,int,int));
00098         REDD_LOAD_SYMBOL( redd_write, int64_t(*)(void *, const char *, int64_t));
00099         REDD_LOAD_SYMBOL( redd_term, int32_t(*)());
00100         REDD_LOAD_SYMBOL( redd_errno,  int32_t(*)());
00101         REDD_LOAD_SYMBOL( redd_strerror, const std::string & (*)());
00102 
00103         if ( (*redd_init)() ) {
00104                 throw cms::Exception("LStoreFile::loadLibrary()")
00105                         << "Error in redd_init: " << (*redd_strerror)();
00106         }
00107         m_is_loaded = true;
00108 
00109 }
00110 
00111 void LStoreFile::closeLibrary() {
00112         try {
00113                 LStoreFile::MutexWrapper lockObj( & this->m_dlopen_lock );
00114                 
00115                 // What is the correct idiom for propagating error messages 
00116                 // in functions that are exclusively called in destructors?
00117                 // Seriously. I have no idea
00118                 // melo
00119                 if ( m_is_loaded ) {
00120                         if ( (*redd_term)() ) {
00121                                 throw cms::Exception("LStoreFile::closeLibrary()")
00122                                         << "Error in redd_term: " << (*redd_strerror)();
00123                         }
00124                 }
00125                 if ( m_library_handle != NULL ) {
00126                         if ( dlclose( m_library_handle ) ) {
00127                                 throw cms::Exception("LStoreFile::closeLibrary()")
00128                                         << "Error on dlclose(): " << dlerror();
00129                         }
00130                 }
00131         } catch (cms::Exception & e) {
00132                 edm::LogError("LStoreFileError")
00133               << "LStoreFile had an error in its destructor: " << e;
00134         }
00135         m_is_loaded = false;
00136 }
00137 
00138 
00140 void
00141 LStoreFile::create (const char *name,
00142                     bool exclusive /* = false */,
00143                     int perms /* = 066 */)
00144 {
00145   open (name,
00146         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00147          | (exclusive ? IOFlags::OpenExclusive : 0)),
00148         perms);
00149 }
00150 
00151 void
00152 LStoreFile::create (const std::string &name,
00153                     bool exclusive /* = false */,
00154                     int perms /* = 066 */)
00155 {
00156   open (name.c_str (),
00157         (IOFlags::OpenCreate | IOFlags::OpenWrite | IOFlags::OpenTruncate
00158          | (exclusive ? IOFlags::OpenExclusive : 0)),
00159         perms);
00160 }
00161 
00162 void
00163 LStoreFile::open (const std::string &name,
00164                   int flags /* = IOFlags::OpenRead */,
00165                   int perms /* = 066 */)
00166 { open (name.c_str (), flags, perms); }
00167 
00168 void
00169 LStoreFile::open (const char *name,
00170                   int flags /* = IOFlags::OpenRead */,
00171                   int perms /* = 066 */)
00172 {
00173   m_name = name;
00174 
00175   // Actual open
00176   if ((name == 0) || (*name == 0))
00177     throw cms::Exception("LStoreFile::open()")
00178       << "Cannot open a file without a name";
00179 
00180   if ((flags & (IOFlags::OpenRead | IOFlags::OpenWrite)) == 0)
00181     throw cms::Exception("LStoreFile::open()")
00182       << "Must open file '" << name << "' at least for read or write";
00183 
00184   // If I am already open, close old file first
00185   if (m_fd != NULL && m_close)
00186     close ();
00187 
00188   // Translate our flags to system flags
00189   int openflags = 0;
00190 
00191   if ((flags & IOFlags::OpenRead) && (flags & IOFlags::OpenWrite))
00192     openflags |= O_RDWR;
00193   else if (flags & IOFlags::OpenRead)
00194     openflags |= O_RDONLY;
00195   else if (flags & IOFlags::OpenWrite)
00196     openflags |= O_WRONLY;
00197 
00198   if (flags & IOFlags::OpenNonBlock)
00199     openflags |= O_NONBLOCK;
00200 
00201   if (flags & IOFlags::OpenAppend)
00202     openflags |= O_APPEND;
00203 
00204   if (flags & IOFlags::OpenCreate)
00205     openflags |= O_CREAT;
00206 
00207   if (flags & IOFlags::OpenExclusive)
00208     openflags |= O_EXCL;
00209 
00210   if (flags & IOFlags::OpenTruncate)
00211     openflags |= O_TRUNC;
00212 
00213   void * newfd = NULL;
00214   if ((newfd = (*redd_open) (name, openflags, perms)) == NULL)
00215     throw cms::Exception("LStoreFile::open()")
00216       << "redd_open(name='" << name
00217       << "', flags=0x" << std::hex << openflags
00218       << ", permissions=0" << std::oct << perms << std::dec
00219       << ") => error '" << (*redd_strerror)()
00220       << "' (redd_errno=" << (*redd_errno)() << ")";
00221 
00222   m_fd = newfd;
00223 
00224   m_close = true;
00225 
00226   edm::LogInfo("LStoreFileInfo") << "Opened " << m_name;
00227 }
00228 
00229 void
00230 LStoreFile::close (void)
00231 {
00232   if (m_fd == NULL)
00233   {
00234     edm::LogError("LStoreFileError")
00235       << "LStoreFile::close(name='" << m_name
00236       << "') called but the file is not open";
00237     m_close = false;
00238     return;
00239   }
00240   edm::LogInfo("LStoreFile::close()") << "closing " << m_name << std::endl;
00241   if ((*redd_close) (m_fd) == -1)
00242     edm::LogWarning("LStoreFileWarning")
00243       << "redd_close(name='" << m_name
00244       << "') failed with error '" << (*redd_strerror) ()
00245       << "' (redd_errno=" << (*redd_errno)() << ")";
00246 
00247   m_close = false;
00248   m_fd = NULL;
00249 
00250   // Caused hang.  Will be added back after problem is fixed.
00251   // edm::LogInfo("LStoreFileInfo") << "Closed " << m_name;
00252 }
00253 
00254 void
00255 LStoreFile::abort (void)
00256 {
00257   if (m_fd != NULL)
00258     (*redd_close) (m_fd);
00259 
00260   m_close = false;
00261   m_fd = NULL;
00262 }
00263 
00264 
00265 IOSize
00266 LStoreFile::read (void *into, IOSize n)
00267 {
00268   IOSize done = 0;
00269   while (done < n)
00270   {
00271     ssize_t s = (*redd_read) (m_fd, (char *) into + done, n - done);
00272     if (s == -1)
00273       throw cms::Exception("LStoreFile::read()")
00274         << "redd_read(name='" << m_name << "', n=" << (n-done)
00275         << ") failed with error '" << (*redd_strerror)()
00276         << "' (redd_errno=" << (*redd_errno)() << ")";
00277    done += s;
00278   }
00279   return done;
00280 }
00281 
00282 IOSize
00283 LStoreFile::write (const void *from, IOSize n)
00284 {
00285   IOSize done = 0;
00286   while (done < n)
00287   {
00288     ssize_t s = (*redd_write) (m_fd, (const char *) from + done, n - done);
00289     if (s == -1)
00290       throw cms::Exception("LStoreFile::write()")
00291         << "redd_write(name='" << m_name << "', n=" << (n-done)
00292         << ") failed with error '" << (*redd_strerror)()
00293         << "' (redd_errno=" << (*redd_errno)() << ")";
00294     done += s;
00295   }
00296 
00297   return done;
00298 }
00302 IOOffset
00303 LStoreFile::position (IOOffset offset, Relative whence /* = SET */)
00304 {
00305   if (m_fd == NULL)
00306     throw cms::Exception("LStoreFile::position()")
00307       << "LStoreFile::position() called on a closed file";
00308   if (whence != CURRENT && whence != SET && whence != END)
00309     throw cms::Exception("LStoreFile::position()")
00310       << "LStoreFile::position() called with incorrect 'whence' parameter";
00311 
00312   IOOffset      result;
00313   uint32_t              mywhence = (whence == SET ? SEEK_SET
00314                             : whence == CURRENT ? SEEK_CUR
00315                             : SEEK_END);
00316   if ((result = (*redd_lseek) (m_fd, (off_t) offset, (uint32_t)mywhence)) == -1)
00317     throw cms::Exception("LStoreFile::position()")
00318       << "redd_lseek64(name='" << m_name << "', offset=" << offset
00319       << ", whence=" << mywhence << ") failed with error '"
00320       << (*redd_strerror) () << "' (redd_errno=" << (*redd_errno)() << ")";
00321   return result;
00322 }
00323 
00324 void
00325 LStoreFile::resize (IOOffset /* size */)
00326 {
00327   throw cms::Exception("LStoreFile::resize()")
00328     << "LStoreFile::resize(name='" << m_name << "') not implemented";
00329 }
00330 
00331 
00333 
00334 LStoreFile::MutexWrapper::MutexWrapper( pthread_mutex_t * target ) 
00335 {
00336         m_lock = target;
00337         pthread_mutex_lock( m_lock ); // never fails
00338 }
00339 
00340 LStoreFile::MutexWrapper::~MutexWrapper()
00341 {
00342         int retval;
00343         if ( (retval = pthread_mutex_unlock( m_lock )) ) {
00344                 // congrats. pthread_mutex_lock failed and we're in a destructor
00345                 // I don't know what to do here
00346                 // Then again, if the mutex is jammed, things are already boned
00347                 // Cry for a second, then continue with life, I guess
00348         // melo
00349 
00350                 char buf[1024];
00351                 edm::LogError("LStoreFileError")
00352               << "LStoreFile couldn't unlock a mutex. Not good." 
00353                   << strerror_r( retval, buf, 1024 );
00354         }
00355 }
00356