CMS 3D CMS Logo

CMSSW_4_4_3_patch1/src/IOPool/Input/src/RootInputFileSequence.cc

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