CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_4_1_8_patch12/src/IOPool/Input/src/RootInputFileSequence.cc

Go to the documentation of this file.
00001 /*----------------------------------------------------------------------
00002 ----------------------------------------------------------------------*/
00003 #include "RootInputFileSequence.h"
00004 #include "PoolSource.h"
00005 #include "RootFile.h"
00006 #include "RootTree.h"
00007 #include "DuplicateChecker.h"
00008 
00009 #include "FWCore/Catalog/interface/SiteLocalConfig.h"
00010 #include "FWCore/Framework/interface/EventPrincipal.h"
00011 #include "FWCore/Framework/interface/FileBlock.h"
00012 #include "FWCore/Framework/src/PrincipalCache.h"
00013 #include "FWCore/MessageLogger/interface/MessageLogger.h"
00014 #include "DataFormats/Provenance/interface/ProductRegistry.h"
00015 #include "FWCore/ParameterSet/interface/ParameterSet.h"
00016 #include "FWCore/ServiceRegistry/interface/Service.h"
00017 #include "FWCore/Utilities/interface/RandomNumberGenerator.h"
00018 #include "Utilities/StorageFactory/interface/StorageFactory.h"
00019 #include "FWCore/ParameterSet/interface/ParameterSetDescription.h"
00020 
00021 #include "CLHEP/Random/RandFlat.h"
00022 #include "InputFile.h"
00023 #include "TSystem.h"
00024 
00025 namespace edm {
00026   RootInputFileSequence::RootInputFileSequence(
00027                 ParameterSet const& pset,
00028                 PoolSource const& input,
00029                 InputFileCatalog const& catalog,
00030                 PrincipalCache& cache,
00031                 bool primaryFiles) :
00032     input_(input),
00033     catalog_(catalog),
00034     firstFile_(true),
00035     fileIterBegin_(fileCatalogItems().begin()),
00036     fileIterEnd_(fileCatalogItems().end()),
00037     fileIter_(fileIterEnd_),
00038     fileIterLastOpened_(fileIterEnd_),
00039     rootFile_(),
00040     parametersMustMatch_(BranchDescription::Permissive),
00041     branchesMustMatch_(BranchDescription::Permissive),
00042     flatDistribution_(),
00043     indexesIntoFiles_(fileCatalogItems().size()),
00044     orderedProcessHistoryIDs_(),
00045     eventSkipperByID_(primaryFiles ? EventSkipperByID::create(pset).release() : 0),
00046     eventsRemainingInFile_(0),
00047     // The default value provided as the second argument to the getUntrackedParameter function call
00048     // is not used when the ParameterSet has been validated and the parameters are not optional
00049     // in the description.  This is currently true when PoolSource is the primary input source.
00050     // The modules that use PoolSource as a SecSource have not defined their fillDescriptions function
00051     // yet, so the ParameterSet does not get validated yet.  As soon as all the modules with a SecSource
00052     // have defined descriptions, the defaults in the getUntrackedParameterSet function calls can
00053     // and should be deleted from the code.
00054     numberOfEventsToSkip_(primaryFiles ? pset.getUntrackedParameter<unsigned int>("skipEvents", 0U) : 0U),
00055     noEventSort_(primaryFiles ? pset.getUntrackedParameter<bool>("noEventSort", true) : false),
00056     skipBadFiles_(pset.getUntrackedParameter<bool>("skipBadFiles", false)),
00057     treeCacheSize_(pset.getUntrackedParameter<unsigned int>("cacheSize", input::defaultCacheSize)),
00058     treeMaxVirtualSize_(pset.getUntrackedParameter<int>("treeMaxVirtualSize", -1)),
00059     setRun_(pset.getUntrackedParameter<unsigned int>("setRunNumber", 0U)),
00060     groupSelectorRules_(pset, "inputCommands", "InputSource"),
00061     primaryFiles_(primaryFiles),
00062     duplicateChecker_(primaryFiles ? new DuplicateChecker(pset) : 0),
00063     dropDescendants_(pset.getUntrackedParameter<bool>("dropDescendantsOfDroppedBranches", primary())),
00064     usingGoToEvent_(false) {
00065 
00066     //we now allow the site local config to specify what the TTree cache size should be
00067     edm::Service<edm::SiteLocalConfig> pSLC;
00068     if(pSLC.isAvailable() && pSLC->sourceTTreeCacheSize()) {
00069       treeCacheSize_=*(pSLC->sourceTTreeCacheSize());
00070     }
00071     StorageFactory *factory = StorageFactory::get();
00072     for(fileIter_ = fileIterBegin_; fileIter_ != fileIterEnd_; ++fileIter_) {
00073       factory->activateTimeout(fileIter_->fileName());
00074       factory->stagein(fileIter_->fileName());
00075     }
00076 
00077     std::string parametersMustMatch = pset.getUntrackedParameter<std::string>("parametersMustMatch", std::string("permissive"));
00078     if(parametersMustMatch == std::string("strict")) parametersMustMatch_ = BranchDescription::Strict;
00079 
00080     std::string branchesMustMatch = pset.getUntrackedParameter<std::string>("branchesMustMatch", std::string("permissive"));
00081     if(branchesMustMatch == std::string("strict")) branchesMustMatch_ = BranchDescription::Strict;
00082 
00083     if(primary()) {
00084       for(fileIter_ = fileIterBegin_; fileIter_ != fileIterEnd_; ++fileIter_) {
00085         initFile(skipBadFiles_);
00086         if(rootFile_) break;
00087       }
00088       if(rootFile_) {
00089         productRegistryUpdate().updateFromInput(rootFile_->productRegistry()->productList());
00090         if(numberOfEventsToSkip_ != 0) {
00091           skipEvents(numberOfEventsToSkip_, cache);
00092         }
00093       }
00094     }
00095   }
00096 
00097   std::vector<FileCatalogItem> const&
00098   RootInputFileSequence::fileCatalogItems() const {
00099     return catalog_.fileCatalogItems();
00100   }
00101 
00102   void
00103   RootInputFileSequence::endJob() {
00104     closeFile_();
00105   }
00106 
00107   boost::shared_ptr<FileBlock>
00108   RootInputFileSequence::readFile_(PrincipalCache& cache) {
00109     if(firstFile_) {
00110       // The first input file has already been opened.
00111       firstFile_ = false;
00112       if(!rootFile_) {
00113         initFile(skipBadFiles_);
00114       }
00115     } else {
00116       if(!nextFile(cache)) {
00117         assert(0);
00118       }
00119     }
00120     if(!rootFile_) {
00121       return boost::shared_ptr<FileBlock>(new FileBlock);
00122     }
00123     return rootFile_->createFileBlock();
00124   }
00125 
00126   void RootInputFileSequence::closeFile_() {
00127     // close the currently open file, if any, and delete the RootFile object.
00128     if(rootFile_) {
00129       if (primary()) {
00130         assert(rootFile_.unique());
00131         std::auto_ptr<InputSource::FileCloseSentry>
00132         sentry((primaryFiles_) ? new InputSource::FileCloseSentry(input_) : 0);
00133         rootFile_->close();
00134         if(duplicateChecker_) duplicateChecker_->inputFileClosed();
00135       }
00136       rootFile_.reset();
00137     }
00138   }
00139 
00140   void RootInputFileSequence::initFile(bool skipBadFiles) {
00141     // We are really going to close the open file.
00142 
00143     // If this is the primary sequence, we are not duplicate checking across files
00144     // and we are not using random access to find events, then we can delete the
00145     // IndexIntoFile for the file we are closing. If we can't delete all of it,
00146     // then we can delete the parts we do not need.
00147     if (fileIterLastOpened_ != fileIterEnd_) {
00148       size_t currentIndexIntoFile = fileIterLastOpened_ - fileIterBegin_;
00149       bool needIndexesForDuplicateChecker = duplicateChecker_ && duplicateChecker_->checkingAllFiles() && !duplicateChecker_->checkDisabled();
00150       bool deleteIndexIntoFile = primaryFiles_ &&
00151                                  !needIndexesForDuplicateChecker &&
00152                                  !usingGoToEvent_;
00153       if (deleteIndexIntoFile) {
00154               indexesIntoFiles_[currentIndexIntoFile].reset();
00155       } else {
00156               if (indexesIntoFiles_[currentIndexIntoFile]) indexesIntoFiles_[currentIndexIntoFile]->inputFileClosed();
00157       }
00158       fileIterLastOpened_ = fileIterEnd_;
00159     }
00160     closeFile_();
00161 
00162     // Determine whether we have a fallback URL specified; if so, prepare it;
00163     // Only valid if it is non-empty and differs from the original filename.
00164     std::string fallbackName = fileIter_->fallbackFileName();
00165     bool hasFallbackUrl = (!fallbackName.empty()) || (fallbackName == fileIter_->fileName());
00166 
00167     boost::shared_ptr<InputFile> filePtr;
00168     try {
00169       std::auto_ptr<InputSource::FileOpenSentry>
00170         sentry(primaryFiles_ ? new InputSource::FileOpenSentry(input_) : 0);
00171       filePtr.reset(new InputFile(gSystem->ExpandPathName(fileIter_->fileName().c_str()), "  Initiating request to open file "));
00172     }
00173     catch (cms::Exception const& e) {
00174       if(!skipBadFiles  && !hasFallbackUrl) {
00175         throw edm::Exception(edm::errors::FileOpenError) << e.explainSelf() << "\n" <<
00176            "RootInputFileSequence::initFile(): Input file " << fileIter_->fileName() << " was not found or could not be opened.\n";
00177       }
00178     }
00179     if(!filePtr && (hasFallbackUrl)) {
00180       try {
00181         std::auto_ptr<InputSource::FileOpenSentry>
00182           sentry(primaryFiles_ ? new InputSource::FileOpenSentry(input_) : 0);
00183         filePtr.reset(new InputFile(gSystem->ExpandPathName(fallbackName.c_str()), "  Fallback request to file "));
00184       }
00185       catch (cms::Exception const& e) {
00186         if(!skipBadFiles) {
00187           throw edm::Exception(edm::errors::FileOpenError) << e.explainSelf() << "\n" <<
00188              "RootInputFileSequence::initFile(): Input fallback file " << fallbackName << " was not found or could not be opened.\n";
00189         }
00190       }
00191     }
00192     if(filePtr) {
00193       std::vector<boost::shared_ptr<IndexIntoFile> >::size_type currentIndexIntoFile = fileIter_ - fileIterBegin_;
00194       rootFile_ = RootFileSharedPtr(new RootFile(fileIter_->fileName(),
00195           processConfiguration(), fileIter_->logicalFileName(), filePtr,
00196           eventSkipperByID_, numberOfEventsToSkip_ != 0,
00197           remainingEvents(), remainingLuminosityBlocks(), treeCacheSize_, treeMaxVirtualSize_,
00198           input_.processingMode(),
00199           setRun_,
00200           noEventSort_,
00201           groupSelectorRules_, !primaryFiles_, duplicateChecker_, dropDescendants_,
00202                                                  indexesIntoFiles_, currentIndexIntoFile, orderedProcessHistoryIDs_, usingGoToEvent_));
00203 
00204       fileIterLastOpened_ = fileIter_;
00205       indexesIntoFiles_[currentIndexIntoFile] = rootFile_->indexIntoFileSharedPtr();
00206       rootFile_->reportOpened(primary() ?
00207          (primaryFiles_ ? "primaryFiles" : "secondaryFiles") : "mixingFiles");
00208     } else {
00209       if(!skipBadFiles) {
00210         throw edm::Exception(edm::errors::FileOpenError) <<
00211            "RootInputFileSequence::initFile(): Input file " << fileIter_->fileName() << " was not found or could not be opened.\n";
00212       }
00213       LogWarning("") << "Input file: " << fileIter_->fileName() << " was not found or could not be opened, and will be skipped.\n";
00214     }
00215   }
00216 
00217   boost::shared_ptr<ProductRegistry const>
00218   RootInputFileSequence::fileProductRegistry() const {
00219     return rootFile_->productRegistry();
00220   }
00221 
00222   bool RootInputFileSequence::nextFile(PrincipalCache& cache) {
00223     if(fileIter_ != fileIterEnd_) ++fileIter_;
00224     if(fileIter_ == fileIterEnd_) {
00225       if(primaryFiles_) {
00226         return false;
00227       } else {
00228         fileIter_ = fileIterBegin_;
00229       }
00230     }
00231 
00232     initFile(skipBadFiles_);
00233 
00234     if(primaryFiles_ && rootFile_) {
00235       size_t size = productRegistry()->size();
00236       // make sure the new product registry is compatible with the main one
00237       std::string mergeInfo = productRegistryUpdate().merge(*rootFile_->productRegistry(),
00238                                                             fileIter_->fileName(),
00239                                                             parametersMustMatch_,
00240                                                             branchesMustMatch_);
00241       if(!mergeInfo.empty()) {
00242         throw edm::Exception(errors::MismatchedInputFiles,"RootInputFileSequence::nextFile()") << mergeInfo;
00243       }
00244       if (productRegistry()->size() > size) {
00245         cache.adjustIndexesAfterProductRegistryAddition();
00246       }
00247       cache.adjustEventToNewProductRegistry(productRegistry());
00248     }
00249     return true;
00250   }
00251 
00252   bool RootInputFileSequence::previousFile(PrincipalCache& cache) {
00253     if(fileIter_ == fileIterBegin_) {
00254       if(primaryFiles_) {
00255         return false;
00256       } else {
00257         fileIter_ = fileIterEnd_;
00258       }
00259     }
00260     --fileIter_;
00261 
00262     initFile(false);
00263 
00264     if(primaryFiles_ && rootFile_) {
00265       size_t size = productRegistry()->size();
00266       // make sure the new product registry is compatible to the main one
00267       std::string mergeInfo = productRegistryUpdate().merge(*rootFile_->productRegistry(),
00268                                                             fileIter_->fileName(),
00269                                                             parametersMustMatch_,
00270                                                             branchesMustMatch_);
00271       if(!mergeInfo.empty()) {
00272         throw edm::Exception(errors::MismatchedInputFiles,"RootInputFileSequence::previousEvent()") << mergeInfo;
00273       }
00274       if (productRegistry()->size() > size) {
00275         cache.adjustIndexesAfterProductRegistryAddition();
00276       }
00277       cache.adjustEventToNewProductRegistry(productRegistry());
00278     }
00279     if(rootFile_) rootFile_->setToLastEntry();
00280     return true;
00281   }
00282 
00283   RootInputFileSequence::~RootInputFileSequence() {
00284   }
00285 
00286   boost::shared_ptr<RunAuxiliary>
00287   RootInputFileSequence::readRunAuxiliary_() {
00288     boost::shared_ptr<RunAuxiliary> aux = rootFile_->readRunAuxiliary_();
00289     return aux;
00290   }
00291 
00292   boost::shared_ptr<LuminosityBlockAuxiliary>
00293   RootInputFileSequence::readLuminosityBlockAuxiliary_() {
00294     boost::shared_ptr<LuminosityBlockAuxiliary> aux = rootFile_->readLuminosityBlockAuxiliary_();
00295     return aux;
00296   }
00297 
00298   boost::shared_ptr<RunPrincipal>
00299   RootInputFileSequence::readRun_(boost::shared_ptr<RunPrincipal> rpCache) {
00300     return rootFile_->readRun_(rpCache);
00301   }
00302 
00303   boost::shared_ptr<LuminosityBlockPrincipal>
00304   RootInputFileSequence::readLuminosityBlock_(boost::shared_ptr<LuminosityBlockPrincipal> lbCache) {
00305     return rootFile_->readLumi(lbCache);
00306   }
00307 
00308   // readEvent() is responsible for setting up the EventPrincipal.
00309   //
00310   //   1. create an EventPrincipal with a unique EventID
00311   //   2. For each entry in the provenance, put in one Group,
00312   //      holding the Provenance for the corresponding EDProduct.
00313   //   3. set up the caches in the EventPrincipal to know about this
00314   //      Group.
00315   //
00316   // We do *not* create the EDProduct instance (the equivalent of reading
00317   // the branch containing this EDProduct. That will be done by the Delayed Reader,
00318   //  when it is asked to do so.
00319   //
00320 
00321   EventPrincipal*
00322   RootInputFileSequence::readEvent(EventPrincipal& cache, boost::shared_ptr<LuminosityBlockPrincipal> lb) {
00323     return rootFile_->readEvent(cache, lb);
00324   }
00325 
00326   InputSource::ItemType
00327   RootInputFileSequence::getNextItemType() {
00328     if(fileIter_ == fileIterEnd_) {
00329       return InputSource::IsStop;
00330     }
00331     if(firstFile_) {
00332       return InputSource::IsFile;
00333     }
00334     if(rootFile_) {
00335       IndexIntoFile::EntryType entryType = rootFile_->getNextEntryTypeWanted();
00336       if(entryType == IndexIntoFile::kEvent) {
00337         return InputSource::IsEvent;
00338       } else if(entryType == IndexIntoFile::kLumi) {
00339         return InputSource::IsLumi;
00340       } else if(entryType == IndexIntoFile::kRun) {
00341         return InputSource::IsRun;
00342       }
00343       assert(entryType == IndexIntoFile::kEnd);
00344     }
00345     if(fileIter_ + 1 == fileIterEnd_) {
00346       return InputSource::IsStop;
00347     }
00348     return InputSource::IsFile;
00349   }
00350 
00351   // Rewind to before the first event that was read.
00352   void
00353   RootInputFileSequence::rewind_() {
00354     if (fileIter_ != fileIterBegin_) {
00355       closeFile_();
00356       fileIter_ = fileIterBegin_;
00357     }
00358     if (!rootFile_) {
00359       initFile(false);
00360     }
00361     rewindFile();
00362     firstFile_ = true;
00363   }
00364 
00365   // Rewind to the beginning of the current file
00366   void
00367   RootInputFileSequence::rewindFile() {
00368     rootFile_->rewind();
00369   }
00370 
00371   void
00372   RootInputFileSequence::reset(PrincipalCache& cache) {
00373     //NOTE: Need to handle duplicate checker
00374     // Also what if skipBadFiles_==true and the first time we succeeded but after a reset we fail?
00375     if(primary()) {
00376       firstFile_ = true;
00377       for(fileIter_ = fileIterBegin_; fileIter_ != fileIterEnd_; ++fileIter_) {
00378         initFile(skipBadFiles_);
00379         if(rootFile_) break;
00380       }
00381       if(rootFile_) {
00382         if(numberOfEventsToSkip_ != 0) {
00383           skipEvents(numberOfEventsToSkip_, cache);
00384         }
00385       }
00386     }
00387   }
00388 
00389   // Advance "offset" events.  Offset can be positive or negative (or zero).
00390   bool
00391   RootInputFileSequence::skipEvents(int offset, PrincipalCache& cache) {
00392     assert (numberOfEventsToSkip_ == 0 || numberOfEventsToSkip_ == offset);
00393     numberOfEventsToSkip_ = offset;
00394     while(numberOfEventsToSkip_ != 0) {
00395       bool atEnd = rootFile_->skipEvents(numberOfEventsToSkip_);
00396       if((numberOfEventsToSkip_ > 0 || atEnd) && !nextFile(cache)) {
00397         numberOfEventsToSkip_ = 0;
00398         return false;
00399       }
00400       if(numberOfEventsToSkip_ < 0 && !previousFile(cache)) {
00401         numberOfEventsToSkip_ = 0;
00402         fileIter_ = fileIterEnd_;
00403         return false;
00404       }
00405     }
00406     return true;
00407   }
00408 
00409   bool
00410   RootInputFileSequence::goToEvent(EventID const& eventID, PrincipalCache& cache) {
00411     usingGoToEvent_ = true;
00412     if (rootFile_) {
00413       if (rootFile_->goToEvent(eventID)) {
00414         return true;
00415       }
00416       // If only one input file, give up now, to save time.
00417       if(rootFile_ && indexesIntoFiles_.size() == 1) {
00418         return false;
00419       }
00420       // Save the current file and position so that we can restore them
00421       // if we fail to restore the desired event
00422       bool closedOriginalFile = false;
00423       std::vector<FileCatalogItem>::const_iterator originalFile = fileIter_;
00424       IndexIntoFile::IndexIntoFileItr originalPosition = rootFile_->indexIntoFileIter();
00425 
00426       // Look for item (run/lumi/event) in files previously opened without reopening unnecessary files.
00427       typedef std::vector<boost::shared_ptr<IndexIntoFile> >::const_iterator Iter;
00428       for(Iter it = indexesIntoFiles_.begin(), itEnd = indexesIntoFiles_.end(); it != itEnd; ++it) {
00429         if(*it && (*it)->containsItem(eventID.run(), eventID.luminosityBlock(), eventID.event())) {
00430           // We found it. Close the currently open file, and open the correct one.
00431           fileIter_ = fileIterBegin_ + (it - indexesIntoFiles_.begin());
00432           initFile(false);
00433           // Now get the item from the correct file.
00434           bool found = rootFile_->goToEvent(eventID);
00435           assert (found);
00436           return true;
00437         }
00438       }
00439       // Look for item in files not yet opened.
00440       for(Iter it = indexesIntoFiles_.begin(), itEnd = indexesIntoFiles_.end(); it != itEnd; ++it) {
00441         if(!*it) {
00442           fileIter_ = fileIterBegin_ + (it - indexesIntoFiles_.begin());
00443           initFile(false);
00444           closedOriginalFile = true;
00445           if ((*it)->containsItem(eventID.run(), eventID.luminosityBlock(), eventID.event())) {
00446             if  (rootFile_->goToEvent(eventID)) {
00447               return true;
00448             }
00449           }
00450         }
00451       }
00452       if (closedOriginalFile) {
00453         fileIter_ = originalFile;
00454         initFile(false);
00455         rootFile_->setPosition(originalPosition);
00456       }
00457     }
00458     return false;
00459   }
00460 
00461   bool
00462   RootInputFileSequence::skipToItem(RunNumber_t run, LuminosityBlockNumber_t lumi, EventNumber_t event) {
00463     // Attempt to find item in currently open input file.
00464     bool found = rootFile_ && rootFile_->setEntryAtItem(run, lumi, event);
00465     if(!found) {
00466       // If only one input file, give up now, to save time.
00467       if(rootFile_ && indexesIntoFiles_.size() == 1) {
00468         return false;
00469       }
00470       // Look for item (run/lumi/event) in files previously opened without reopening unnecessary files.
00471       typedef std::vector<boost::shared_ptr<IndexIntoFile> >::const_iterator Iter;
00472       for(Iter it = indexesIntoFiles_.begin(), itEnd = indexesIntoFiles_.end(); it != itEnd; ++it) {
00473         if(*it && (*it)->containsItem(run, lumi, event)) {
00474           // We found it. Close the currently open file, and open the correct one.
00475           fileIter_ = fileIterBegin_ + (it - indexesIntoFiles_.begin());
00476           initFile(false);
00477           // Now get the item from the correct file.
00478           found = rootFile_->setEntryAtItem(run, lumi, event);
00479           assert (found);
00480           return true;
00481         }
00482       }
00483       // Look for item in files not yet opened.
00484       for(Iter it = indexesIntoFiles_.begin(), itEnd = indexesIntoFiles_.end(); it != itEnd; ++it) {
00485         if(!*it) {
00486           fileIter_ = fileIterBegin_ + (it - indexesIntoFiles_.begin());
00487           initFile(false);
00488           found = rootFile_->setEntryAtItem(run, lumi, event);
00489           if(found) {
00490             return true;
00491           }
00492         }
00493       }
00494       // Not found
00495       return false;
00496     }
00497     return true;
00498   }
00499 
00500   bool const
00501   RootInputFileSequence::primary() const {
00502     return input_.primary();
00503   }
00504 
00505   ProcessConfiguration const&
00506   RootInputFileSequence::processConfiguration() const {
00507     return input_.processConfiguration();
00508   }
00509 
00510   int
00511   RootInputFileSequence::remainingEvents() const {
00512     return input_.remainingEvents();
00513   }
00514 
00515   int
00516   RootInputFileSequence::remainingLuminosityBlocks() const {
00517     return input_.remainingLuminosityBlocks();
00518   }
00519 
00520   ProductRegistry &
00521   RootInputFileSequence::productRegistryUpdate() const{
00522     return input_.productRegistryUpdate();
00523   }
00524 
00525   boost::shared_ptr<ProductRegistry const>
00526   RootInputFileSequence::productRegistry() const{
00527     return input_.productRegistry();
00528   }
00529 
00530   void
00531   RootInputFileSequence::dropUnwantedBranches_(std::vector<std::string> const& wantedBranches) {
00532     std::vector<std::string> rules;
00533     rules.reserve(wantedBranches.size() + 1);
00534     rules.push_back(std::string("drop *"));
00535     for(std::vector<std::string>::const_iterator it = wantedBranches.begin(), itEnd = wantedBranches.end();
00536         it != itEnd; ++it) {
00537       rules.push_back("keep " + *it + "_*");
00538     }
00539     ParameterSet pset;
00540     pset.addUntrackedParameter("inputCommands", rules);
00541     groupSelectorRules_ = GroupSelectorRules(pset, "inputCommands", "InputSource");
00542   }
00543 
00544   void
00545   RootInputFileSequence::readMany(int number, EventPrincipalVector& result) {
00546     for(int i = 0; i < number; ++i) {
00547       boost::shared_ptr<EventPrincipal> ep(new EventPrincipal(rootFile_->productRegistry(), processConfiguration()));
00548       EventPrincipal* ev = rootFile_->readCurrentEvent(*ep);
00549       if(ev == 0) {
00550         return;
00551       }
00552       assert(ev == ep.get());
00553       result.push_back(ep);
00554       rootFile_->nextEventEntry();
00555     }
00556   }
00557 
00558   void
00559   RootInputFileSequence::readManyRandom(int number, EventPrincipalVector& result, unsigned int& fileSeqNumber) {
00560     result.reserve(number);
00561     if (!flatDistribution_) {
00562       Service<RandomNumberGenerator> rng;
00563       CLHEP::HepRandomEngine& engine = rng->getEngine();
00564       flatDistribution_.reset(new CLHEP::RandFlat(engine));
00565     }
00566     skipBadFiles_ = false;
00567     unsigned int currentSeqNumber = fileIter_ - fileIterBegin_;
00568     while(eventsRemainingInFile_ < number) {
00569       fileIter_ = fileIterBegin_ + flatDistribution_->fireInt(fileCatalogItems().size());
00570       unsigned int newSeqNumber = fileIter_ - fileIterBegin_;
00571       if(newSeqNumber != currentSeqNumber) {
00572         initFile(false);
00573       }
00574       eventsRemainingInFile_ = rootFile_->eventTree().entries();
00575       if(eventsRemainingInFile_ == 0) {
00576         throw edm::Exception(edm::errors::NotFound) <<
00577            "RootInputFileSequence::readManyRandom_(): Secondary Input file " << fileIter_->fileName() << " contains no events.\n";
00578       }
00579       rootFile_->setAtEventEntry(flatDistribution_->fireInt(eventsRemainingInFile_));
00580     }
00581     fileSeqNumber = fileIter_ - fileIterBegin_;
00582     for(int i = 0; i < number; ++i) {
00583       boost::shared_ptr<EventPrincipal> ep(new EventPrincipal(rootFile_->productRegistry(), processConfiguration()));
00584       EventPrincipal* ev = rootFile_->readCurrentEvent(*ep);
00585       if(ev == 0) {
00586         rewindFile();
00587         ev = rootFile_->readCurrentEvent(*ep);
00588         assert(ev != 0);
00589       }
00590       assert(ev == ep.get());
00591       result.push_back(ep);
00592       --eventsRemainingInFile_;
00593       rootFile_->nextEventEntry();
00594     }
00595   }
00596 
00597   void
00598   RootInputFileSequence::readManySequential(int number, EventPrincipalVector& result, unsigned int& fileSeqNumber) {
00599     result.reserve(number);
00600     skipBadFiles_ = false;
00601     if (fileIter_ == fileIterEnd_ || !rootFile_) {
00602       fileIter_ = fileIterBegin_;
00603       initFile(false);
00604       rootFile_->setAtEventEntry(0);
00605     }
00606     fileSeqNumber = fileIter_ - fileIterBegin_;
00607     unsigned int numberRead = 0;
00608     for(int i = 0; i < number; ++i) {
00609       boost::shared_ptr<EventPrincipal> ep(new EventPrincipal(rootFile_->productRegistry(), processConfiguration()));
00610       EventPrincipal* ev = rootFile_->readCurrentEvent(*ep);
00611       if(ev == 0) {
00612         if (numberRead == 0) {
00613           ++fileIter_;
00614           fileSeqNumber = fileIter_ - fileIterBegin_;
00615           if (fileIter_ == fileIterEnd_) {
00616             return;
00617           }
00618           initFile(false);
00619           rootFile_->setAtEventEntry(0);
00620           return readManySequential(number, result, fileSeqNumber);
00621         }
00622         return;
00623       }
00624       assert(ev == ep.get());
00625       result.push_back(ep);
00626       ++numberRead;
00627       rootFile_->nextEventEntry();
00628     }
00629   }
00630 
00631   void
00632   RootInputFileSequence::readManySpecified(std::vector<EventID> const& events, EventPrincipalVector& result) {
00633     skipBadFiles_ = false;
00634     result.reserve(events.size());
00635     for (std::vector<EventID>::const_iterator it = events.begin(), itEnd = events.end(); it != itEnd; ++it) {
00636       bool found = skipToItem(it->run(), it->luminosityBlock(), it->event());
00637       if (!found) {
00638         throw edm::Exception(edm::errors::NotFound) <<
00639            "RootInputFileSequence::readManySpecified_(): Secondary Input file " <<
00640            fileIter_->fileName() <<
00641            " does not contain specified event:\n" << *it << "\n";
00642       }
00643       boost::shared_ptr<EventPrincipal> ep(new EventPrincipal(rootFile_->productRegistry(), processConfiguration()));
00644       EventPrincipal* ev = rootFile_->readCurrentEvent(*ep);
00645       if (ev == 0) {
00646         throw edm::Exception(edm::errors::EventCorruption) <<
00647            "RootInputFileSequence::readManySpecified_(): Secondary Input file " <<
00648            fileIter_->fileName() <<
00649            " contains specified event " << *it << " that cannot be read.\n";
00650       }
00651       assert(ev == ep.get());
00652       result.push_back(ep);
00653     }
00654   }
00655 
00656   void
00657   RootInputFileSequence::fillDescription(ParameterSetDescription & desc) {
00658     desc.addUntracked<unsigned int>("skipEvents", 0U)
00659         ->setComment("Skip the first 'skipEvents' events that otherwise would have been processed.");
00660     desc.addUntracked<bool>("noEventSort", true)
00661         ->setComment("True:  Process runs, lumis and events in the order they appear in the file (but see notes 1 and 2).\n"
00662                      "False: Process runs, lumis and events in each file in numerical order (run#, lumi#, event#) (but see note 3).\n"
00663                      "Note 1: Events within the same lumi will always be processed contiguously.\n"
00664                      "Note 2: Lumis within the same run will always be processed contiguously.\n"
00665                      "Note 3: Any sorting occurs independently in each input file (no sorting across input files).");
00666     desc.addUntracked<bool>("skipBadFiles", false)
00667         ->setComment("True:  Ignore any missing or unopenable input file.\n"
00668                      "False: Throw exception if missing or unopenable input file.");
00669     desc.addUntracked<unsigned int>("cacheSize", input::defaultCacheSize)
00670         ->setComment("Size of ROOT TTree prefetch cache.  Affects performance.");
00671     desc.addUntracked<int>("treeMaxVirtualSize", -1)
00672         ->setComment("Size of ROOT TTree TBasket cache.  Affects performance.");
00673     desc.addUntracked<unsigned int>("setRunNumber", 0U)
00674         ->setComment("If non-zero, change number of first run to this number. Apply same offset to all runs.  Allowed only for simulation.");
00675     desc.addUntracked<bool>("dropDescendantsOfDroppedBranches", true)
00676         ->setComment("If True, also drop on input any descendent of any branch dropped on input.");
00677     std::string defaultString("permissive");
00678     desc.addUntracked<std::string>("parametersMustMatch", defaultString)
00679         ->setComment("'strict':     Values of tracked parameters must be unique across all input files.\n"
00680                      "'permissive': Values of tracked parameters may differ across or within files.");
00681     desc.addUntracked<std::string>("branchesMustMatch", defaultString)
00682         ->setComment("'strict':     Branches in each input file must match those in the first file.\n"
00683                      "'permissive': Branches in each input file may be any subset of those in the first file.");
00684 
00685     GroupSelectorRules::fillDescription(desc, "inputCommands");
00686     EventSkipperByID::fillDescription(desc);
00687     DuplicateChecker::fillDescription(desc);
00688   }
00689 
00690   ProcessingController::ForwardState
00691   RootInputFileSequence::forwardState() const {
00692     if (rootFile_) {
00693       if (!rootFile_->wasLastEventJustRead()) {
00694         return ProcessingController::kEventsAheadInFile;
00695       }
00696       std::vector<FileCatalogItem>::const_iterator itr(fileIter_);
00697       if (itr != fileIterEnd_) ++itr;
00698       if (itr != fileIterEnd_) {
00699         return ProcessingController::kNextFileExists;
00700       }
00701       return ProcessingController::kAtLastEvent;
00702     }
00703     return ProcessingController::kUnknownForward;
00704   }
00705 
00706   ProcessingController::ReverseState
00707   RootInputFileSequence::reverseState() const {
00708     if (rootFile_) {
00709       if (!rootFile_->wasFirstEventJustRead()) {
00710         return ProcessingController::kEventsBackwardsInFile;
00711       }
00712       if (fileIter_ != fileIterBegin_) {
00713         return ProcessingController::kPreviousFileExists;
00714       }
00715       return ProcessingController::kAtFirstEvent;
00716     }
00717     return ProcessingController::kUnknownReverse;
00718   }
00719 }