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 )
00104 : TFile(path, "NET", ftitle, compress),
00105 storage_(0)
00106 {
00107 StorageAccount::Stamp stats(storageCounter(s_statsCtor, "construct"));
00108
00109
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
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;
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
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
00192
00193
00194
00195
00196
00197
00198
00199 StorageAccount::Stamp stats(storageCounter(s_statsRead, "read"));
00200
00201
00202
00203
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
00233
00234
00235
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
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
00262
00263
00264
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
00277
00278
00279
00280 if (len)
00281
00282
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
00293 return kTRUE;
00294 }
00295
00296 Bool_t
00297 TStorageFactoryFile::ReadBuffers(char *buf, Long64_t *pos, Int_t *len, Int_t nbuf)
00298 {
00299
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
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
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);
00329 stats.tick(n);
00330 }
00331 else
00332 {
00333 StorageAccount::Stamp astats(storageCounter(s_statsARead, "read-async"));
00334
00335
00336 success = storage_->prefetch(&iov[0], nbuf);
00337 astats.tick(total);
00338 }
00339
00340
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
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
00370 Int_t st;
00371 switch ((st = WriteBufferViaCache(buf, len)))
00372 {
00373 case 0:
00374
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
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
00401
00402
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 )
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 , 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 )
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 , Long_t *id, Long64_t *size,
00480 Long_t *flags, Long_t *modtime)
00481 {
00482 StorageAccount::Stamp stats(storageCounter(s_statsStat, "stat"));
00483
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 }