CMS 3D CMS Logo

TStorageFactoryFile.cc

Go to the documentation of this file.
00001 #include "IOPool/TFileAdaptor/interface/TStorageFactoryFile.h"
00002 #include "Utilities/StorageFactory/interface/Storage.h"
00003 #include "Utilities/StorageFactory/interface/StorageFactory.h"
00004 #include "Utilities/StorageFactory/interface/StorageAccount.h"
00005 #include "FWCore/Utilities/interface/EDMException.h"
00006 #include "TFileCacheRead.h"
00007 #include "TFileCacheWrite.h"
00008 #include "TFileCacheRead.h"
00009 #include "TSystem.h"
00010 #include "TROOT.h"
00011 #include <errno.h>
00012 #include <sys/stat.h>
00013 #include <unistd.h>
00014 #include <fcntl.h>
00015 
00016 #if 0
00017 #include "TTreeCache.h"
00018 #include "TTree.h"
00019 #include <iostream>
00020 
00021 class TTreeCacheDebug : public TTreeCache {
00022 public:
00023   void dump(const char *label, const char *trailer)
00024   {
00025     Long64_t entry = fOwner->GetReadEntry();
00026     std::cerr
00027       << label << ": " << entry << " "
00028       << "{ fEntryMin=" << fEntryMin
00029       << ", fEntryMax=" << fEntryMax
00030       << ", fEntryNext=" << fEntryNext
00031       << ", fZipBytes=" << fZipBytes
00032       << ", fNbranches=" << fNbranches
00033       << ", fNReadOk=" << fNReadOk
00034       << ", fNReadMiss=" << fNReadMiss
00035       << ", fNReadPref=" << fNReadPref
00036       << ", fBranches=" << fBranches
00037       << ", fBrNames=" << fBrNames
00038       << ", fOwner=" << fOwner
00039       << ", fTree=" << fTree
00040       << ", fIsLearning=" << fIsLearning
00041       << ", fIsManual=" << fIsManual
00042       << "; fBufferSizeMin=" << fBufferSizeMin
00043       << ", fBufferSize=" << fBufferSize
00044       << ", fBufferLen=" << fBufferLen
00045       << ", fBytesToPrefetch=" << fBytesToPrefetch
00046       << ", fFirstIndexToPrefetch=" << fFirstIndexToPrefetch
00047       << ", fAsyncReading=" << fAsyncReading
00048       << ", fNseek=" << fNseek
00049       << ", fNtot=" << fNtot
00050       << ", fNb=" << fNb
00051       << ", fSeekSize=" << fSeekSize
00052       << ", fSeek=" << fSeek
00053       << ", fSeekIndex=" << fSeekIndex
00054       << ", fSeekSort=" << fSeekSort
00055       << ", fPos=" << fPos
00056       << ", fSeekLen=" << fSeekLen
00057       << ", fSeekSortLen=" << fSeekSortLen
00058       << ", fSeekPos=" << fSeekPos
00059       << ", fLen=" << fLen
00060       << ", fFile=" << fFile
00061       << ", fBuffer=" << (void *) fBuffer
00062       << ", fIsSorted=" << fIsSorted
00063       << " }\n" << trailer;
00064   }
00065 };
00066 #endif
00067 
00068 ClassImp(TStorageFactoryFile)
00069 static StorageAccount::Counter *s_statsCtor = 0;
00070 static StorageAccount::Counter *s_statsOpen = 0;
00071 static StorageAccount::Counter *s_statsClose = 0;
00072 static StorageAccount::Counter *s_statsFlush = 0;
00073 static StorageAccount::Counter *s_statsStat = 0;
00074 static StorageAccount::Counter *s_statsSeek = 0;
00075 static StorageAccount::Counter *s_statsRead = 0;
00076 static StorageAccount::Counter *s_statsCRead = 0;
00077 static StorageAccount::Counter *s_statsCPrefetch = 0;
00078 static StorageAccount::Counter *s_statsARead = 0;
00079 static StorageAccount::Counter *s_statsXRead = 0;
00080 static StorageAccount::Counter *s_statsVRead = 0;
00081 static StorageAccount::Counter *s_statsWrite = 0;
00082 static StorageAccount::Counter *s_statsCWrite = 0;
00083 static StorageAccount::Counter *s_statsXWrite = 0;
00084 
00085 static inline StorageAccount::Counter &
00086 storageCounter(StorageAccount::Counter *&c, const char *label)
00087 {
00088   if (! c) c = &StorageAccount::counter("tstoragefile", label);
00089   return *c;
00090 }
00091 
00092 TStorageFactoryFile::TStorageFactoryFile(void)
00093   : storage_(0)
00094 {
00095   StorageAccount::Stamp stats(storageCounter(s_statsCtor, "construct"));
00096   stats.tick(0);
00097 }
00098 
00099 
00100 TStorageFactoryFile::TStorageFactoryFile(const char *path,
00101                                          Option_t *option /* = "" */,
00102                                          const char *ftitle /* = "" */,
00103                                          Int_t compress /* = 1 */)
00104   : TFile(path, "NET", ftitle, compress), // Pass "NET" to prevent local access in base class
00105     storage_(0)
00106 {
00107   StorageAccount::Stamp stats(storageCounter(s_statsCtor, "construct"));
00108 
00109   // Parse options; at the moment we only accept read!
00110   fOption = option;
00111   fOption.ToUpper();
00112 
00113   if (fOption == "NEW")
00114     fOption = "CREATE";
00115 
00116   Bool_t create   = (fOption == "CREATE");
00117   Bool_t recreate = (fOption == "RECREATE");
00118   Bool_t update   = (fOption == "UPDATE");
00119   Bool_t read     = (fOption == "READ");
00120 
00121   if (!create && !recreate && !update && !read)
00122   {
00123     read = true;
00124     fOption = "READ";
00125   }
00126 
00127   if (recreate)
00128   {
00129     if (!gSystem->AccessPathName(path, kFileExists))
00130       gSystem->Unlink(path);
00131 
00132     recreate = false;
00133     create   = true;
00134     fOption  = "CREATE";
00135   }
00136 
00137   if (update && gSystem->AccessPathName(path, kFileExists))
00138   {
00139     update = kFALSE;
00140     create = kTRUE;
00141   }
00142 
00143   int           openFlags = IOFlags::OpenRead;
00144   if (!read)    openFlags |= IOFlags::OpenWrite;
00145   if (create)   openFlags |= IOFlags::OpenCreate;
00146   if (recreate) openFlags |= IOFlags::OpenCreate | IOFlags::OpenTruncate;
00147 
00148   // Open storage
00149   if (! (storage_ = StorageFactory::get()->open(path, openFlags)))
00150   {
00151      MakeZombie();
00152      gDirectory = gROOT;
00153      throw cms::Exception("TStorageFactoryFile::TStorageFactoryFile()")
00154        << "Cannot open file '" << path << "'";
00155   }
00156 
00157   fRealName = path;
00158   fD = 0; // sorry, meaningless
00159   fWritable = read ? kFALSE : kTRUE;
00160 
00161   Init(create);
00162 
00163   stats.tick(0);
00164 }
00165 
00166 TStorageFactoryFile::~TStorageFactoryFile(void)
00167 {
00168   Close();
00169   delete storage_;
00170 }
00171 
00175 Bool_t
00176 TStorageFactoryFile::ReadBuffer(char *buf, Int_t len)
00177 {
00178   // Check that it's valid to access this file.
00179   if (IsZombie())
00180   {
00181     Error("ReadBuffer", "Cannot read from a zombie file");
00182     return kTRUE;
00183   }
00184 
00185   if (! IsOpen())
00186   {
00187     Error("ReadBuffer", "Cannot read from a file that is not open");
00188     return kTRUE;
00189   }
00190 
00191   // Read specified byte range from the storage.  Returns kTRUE in
00192   // case of error.  Note that ROOT uses this function recursively
00193   // to fill the cache; we use a flag to make sure our accounting
00194   // is reflected in a comprehensible manner.  The "read" counter
00195   // will include both, "readc" indicates how much read from the
00196   // cache, "readu" indicates how much we failed to read from the
00197   // cache (excluding those recursive reads), and "readx" counts
00198   // the amount actually passed to read from the storage object.
00199   StorageAccount::Stamp stats(storageCounter(s_statsRead, "read"));
00200 
00201   // If we have a cache, read from there first.  This returns 0
00202   // if the block hasn't been prefetched, 1 if it was in cache,
00203   // and 2 if there was an error.
00204   if (TFileCacheRead *c = GetCacheRead())
00205   {
00206     Long64_t here = GetRelOffset();
00207     Bool_t   async = c->IsAsyncReading();
00208 
00209     StorageAccount::Stamp cstats(async
00210                                  ? storageCounter(s_statsCPrefetch, "read-prefetch-to-cache")
00211                                  : storageCounter(s_statsCRead, "read-via-cache"));
00212 
00213     Int_t st = ReadBufferViaCache(async ? 0 : buf, len);
00214 
00215     if (st == 2)
00216       return kTRUE;
00217 
00218     if (st == 1)
00219       if (async)
00220       {
00221         cstats.tick(len);
00222         Seek(here);
00223       }
00224       else
00225       {
00226         cstats.tick(len);
00227         stats.tick(len);
00228         return kFALSE;
00229       }
00230   }
00231 
00232   // FIXME: Re-enable read-ahead if the data wasn't in cache.
00233   // if (! st) storage_->caching(true, -1, s_readahead);
00234 
00235   // A real read
00236   StorageAccount::Stamp xstats(storageCounter(s_statsXRead, "read-actual"));
00237   IOSize n = storage_->xread(buf, len);
00238   xstats.tick(n);
00239   stats.tick(n);
00240   return n ? kFALSE : kTRUE;
00241 }
00242 
00243 Bool_t
00244 TStorageFactoryFile::ReadBufferAsync(Long64_t off, Int_t len)
00245 {
00246   // Check that it's valid to access this file.
00247   if (IsZombie())
00248   {
00249     Error("ReadBufferAsync", "Cannot read from a zombie file");
00250     return kTRUE;
00251   }
00252 
00253   if (! IsOpen())
00254   {
00255     Error("ReadBufferAsync", "Cannot read from a file that is not open");
00256     return kTRUE;
00257   }
00258 
00259   StorageAccount::Stamp stats(storageCounter(s_statsARead, "read-async"));
00260 
00261   // If asynchronous reading is disabled, bail out now, regardless
00262   // whether the underlying storage supports prefetching.  If it is
00263   // forced on, pretend it's on, even if the storage doesn't support
00264   // it, as this turns off the caching in ROOT's side.
00265   StorageFactory *f = StorageFactory::get();
00266   switch (f->cacheHint())
00267   {
00268   case StorageFactory::CACHE_HINT_APPLICATION:
00269     return kTRUE;
00270   case StorageFactory::CACHE_HINT_STORAGE:
00271     return kFALSE;
00272   default:
00273     break;
00274   }
00275 
00276   // Let the I/O method indicate if it can do client-side prefetch.
00277   // If it does, then for example TTreeCache will drop its own cache
00278   // and will use the client-side cache of the actual I/O layer.
00279   // If len is zero ROOT is probing for prefetch support.
00280   if (len)
00281     // FIXME: Synchronise caching.
00282     // storage_->caching(true, -1, 0);
00283     ;
00284 
00285   IOPosBuffer iov(off, (void *) 0, len ? len : 4096);
00286   if (storage_->prefetch(&iov, 1))
00287   {
00288     stats.tick(len);
00289     return kFALSE;
00290   }
00291 
00292   // Prefetching not available right now.
00293   return kTRUE;
00294 }
00295 
00296 Bool_t
00297 TStorageFactoryFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
00298 {
00299   // Check that it's valid to access this file.
00300   if (IsZombie())
00301   {
00302     Error("ReadBuffers", "Cannot read from a zombie file");
00303     return kTRUE;
00304   }
00305 
00306   if (! IsOpen())
00307   {
00308     Error("ReadBuffers", "Cannot read from a file that is not open");
00309     return kTRUE;
00310   }
00311 
00312   // Read from underlying storage.
00313   Int_t total = 0;
00314   std::vector<IOPosBuffer> iov;
00315   iov.reserve(nbuf);
00316   for (Int_t i = 0; i < nbuf; ++i)
00317   {
00318     iov.push_back(IOPosBuffer(pos[i], buf ? buf + total : 0, len[i]));
00319     total += len[i];
00320   }
00321 
00322   // Null buffer means asynchronous reads into I/O system's cache.
00323   bool success;
00324   if (buf)
00325   {
00326     StorageAccount::Stamp stats(storageCounter(s_statsVRead, "readv-actual"));
00327     IOSize n = storage_->readv(&iov[0], nbuf);
00328     success = (n > 0); // FIXME: what if it's short!?
00329     stats.tick(n);
00330   }
00331   else
00332   {
00333     StorageAccount::Stamp astats(storageCounter(s_statsARead, "read-async"));
00334     // Synchronise low-level cache with the supposed cache in TFile.
00335     // storage_->caching(true, -1, 0);
00336     success = storage_->prefetch(&iov[0], nbuf);
00337     astats.tick(total);
00338   }
00339 
00340   // If it didn't suceeed, pass down to the base class.
00341   return success ? kFALSE : TFile::ReadBuffers(buf, pos, len, nbuf);
00342 }
00343 
00344 Bool_t
00345 TStorageFactoryFile::WriteBuffer(const char *buf, Int_t len)
00346 {
00347   // Check that it's valid to access this file.
00348   if (IsZombie())
00349   {
00350     Error("WriteBuffer", "Cannot write to a zombie file");
00351     return kTRUE;
00352   }
00353 
00354   if (! IsOpen())
00355   {
00356     Error("WriteBuffer", "Cannot write to a file that is not open");
00357     return kTRUE;
00358   }
00359 
00360   if (! fWritable)
00361   {
00362     Error("WriteBuffer", "File is not writable");
00363     return kTRUE;
00364   }
00365 
00366   StorageAccount::Stamp stats(storageCounter(s_statsWrite, "write"));
00367   StorageAccount::Stamp cstats(storageCounter(s_statsCWrite, "write-via-cache"));
00368 
00369   // Try first writing via a cache, and if that's not possible, directly.
00370   Int_t st;
00371   switch ((st = WriteBufferViaCache(buf, len)))
00372   {
00373   case 0:
00374     // Actual write.
00375     {
00376       StorageAccount::Stamp xstats(storageCounter(s_statsXWrite, "write-actual"));
00377       IOSize n = storage_->xwrite(buf, len);
00378       xstats.tick(n);
00379       stats.tick(n);
00380 
00381       // FIXME: What if it's a short write?
00382       return n > 0 ? kFALSE : kTRUE;
00383     }
00384 
00385   case 1:
00386     cstats.tick(len);
00387     stats.tick(len);
00388     return kFALSE;
00389 
00390   case 2:
00391   default:
00392     Error("WriteBuffer", "Error writing to cache");
00393     return kTRUE;
00394   }
00395 }
00396 
00400 // FIXME: Override GetBytesToPrefetch() so XROOTD can suggest how
00401 // large a prefetch cache to use.
00402 // FIXME: Asynchronous open support?
00403 
00407 Int_t
00408 TStorageFactoryFile::SysOpen(const char *pathname, Int_t flags, UInt_t mode)
00409 {
00410   StorageAccount::Stamp stats(storageCounter(s_statsOpen, "open"));
00411 
00412   if (storage_)
00413   {
00414     storage_->close();
00415     delete storage_;
00416     storage_ = 0;
00417   }
00418 
00419   int                      openFlags = IOFlags::OpenRead;
00420   if (flags & O_WRONLY)    openFlags = IOFlags::OpenWrite;
00421   else if (flags & O_RDWR) openFlags |= IOFlags::OpenWrite;
00422   if (flags & O_CREAT)     openFlags |= IOFlags::OpenCreate;
00423   if (flags & O_APPEND)    openFlags |= IOFlags::OpenAppend;
00424   if (flags & O_EXCL)      openFlags |= IOFlags::OpenExclusive;
00425   if (flags & O_TRUNC)     openFlags |= IOFlags::OpenTruncate;
00426   if (flags & O_NONBLOCK)  openFlags |= IOFlags::OpenNonBlock;
00427 
00428   if (! (storage_ = StorageFactory::get()->open(pathname, openFlags)))
00429   {
00430      MakeZombie();
00431      gDirectory = gROOT;
00432      throw cms::Exception("TStorageFactoryFile::SysOpen()")
00433        << "Cannot open file '" << pathname << "'";
00434   }
00435 
00436   stats.tick();
00437   return 0;
00438 }
00439 
00440 Int_t
00441 TStorageFactoryFile::SysClose(Int_t /* fd */)
00442 {
00443   StorageAccount::Stamp stats(storageCounter(s_statsClose, "close"));
00444 
00445   if (storage_)
00446   {
00447     storage_->close();
00448     delete storage_;
00449     storage_ = 0;
00450   }
00451 
00452   stats.tick();
00453   return 0;
00454 }
00455 
00456 Long64_t
00457 TStorageFactoryFile::SysSeek(Int_t /* fd */, Long64_t offset, Int_t whence)
00458 {
00459   StorageAccount::Stamp stats(storageCounter(s_statsSeek, "seek"));
00460   Storage::Relative rel = (whence == SEEK_SET ? Storage::SET
00461                            : whence == SEEK_CUR ? Storage::CURRENT
00462                            : Storage::END);
00463 
00464   offset = storage_->position(offset, rel);
00465   stats.tick();
00466   return offset;
00467 }
00468 
00469 Int_t
00470 TStorageFactoryFile::SysSync(Int_t /* fd */)
00471 {
00472   StorageAccount::Stamp stats(storageCounter(s_statsFlush, "flush"));
00473   storage_->flush();
00474   stats.tick();
00475   return 0;
00476 }
00477 
00478 Int_t
00479 TStorageFactoryFile::SysStat(Int_t /* fd */, Long_t *id, Long64_t *size,
00480                       Long_t *flags, Long_t *modtime)
00481 {
00482   StorageAccount::Stamp stats(storageCounter(s_statsStat, "stat"));
00483   // FIXME: Most of this is unsupported or makes no sense with Storage
00484   *id = ::Hash(fRealName);
00485   *size = storage_->size();
00486   *flags = 0;
00487   *modtime = 0;
00488   stats.tick();
00489   return 0;
00490 }
00491 
00492 void
00493 TStorageFactoryFile::ResetErrno(void) const
00494 {
00495   TSystem::ResetErrno();
00496 }

Generated on Tue Jun 9 17:39:20 2009 for CMSSW by  doxygen 1.5.4