CMS 3D CMS Logo

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