Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2025-06-06 01:33:27

0001 #include "DataFormats/Provenance/interface/BranchType.h"
0002 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0003 #include "FWCore/Utilities/interface/EDMException.h"
0004 #include "FWCore/Utilities/interface/Exception.h"
0005 #include "IOPool/Common/interface/getWrapperBasePtr.h"
0006 
0007 #include "InputFile.h"
0008 #include "RootTree.h"
0009 #include "RootDelayedReader.h"
0010 #include "RootPromptReadDelayedReader.h"
0011 
0012 #include "TTree.h"
0013 #include "TTreeCache.h"
0014 #include "TLeaf.h"
0015 
0016 #include "oneapi/tbb/task_arena.h"
0017 #include <cassert>
0018 
0019 namespace edm {
0020   namespace {
0021     TBranch* getAuxiliaryBranch(TTree* tree, BranchType const& branchType) {
0022       TBranch* branch = tree->GetBranch(BranchTypeToAuxiliaryBranchName(branchType).c_str());
0023       if (branch == nullptr) {
0024         branch = tree->GetBranch(BranchTypeToAuxBranchName(branchType).c_str());
0025       }
0026       return branch;
0027     }
0028     TBranch* getProductProvenanceBranch(TTree* tree, BranchType const& branchType) {
0029       TBranch* branch = tree->GetBranch(BranchTypeToBranchEntryInfoBranchName(branchType).c_str());
0030       return branch;
0031     }
0032 
0033     std::unique_ptr<RootDelayedReaderBase> makeRootDelayedReader(RootTree const& tree,
0034                                                                  std::shared_ptr<InputFile> filePtr,
0035                                                                  InputType inputType,
0036                                                                  unsigned int nIndexes,
0037                                                                  bool promptRead) {
0038       if (promptRead) {
0039         return std::make_unique<RootPromptReadDelayedReader>(tree, filePtr, inputType, nIndexes);
0040       }
0041       return std::make_unique<RootDelayedReader>(tree, filePtr, inputType);
0042     }
0043   }  // namespace
0044 
0045   // Used for all RootTrees
0046   // All the other constructors delegate to this one
0047   RootTree::RootTree(std::shared_ptr<InputFile> filePtr,
0048                      BranchType const& branchType,
0049                      unsigned int nIndexes,
0050                      unsigned int learningEntries,
0051                      bool enablePrefetching,
0052                      bool promptRead,
0053                      InputType inputType)
0054       : filePtr_(filePtr),
0055         branchType_(branchType),
0056         entryNumberForIndex_(std::make_unique<std::vector<EntryNumber>>(nIndexes, IndexIntoFile::invalidEntry)),
0057         learningEntries_(learningEntries),
0058         enablePrefetching_(enablePrefetching),
0059         enableTriggerCache_(branchType_ == InEvent),
0060         promptRead_(promptRead),
0061         rootDelayedReader_(makeRootDelayedReader(*this, filePtr, inputType, nIndexes, promptRead)) {}
0062 
0063   // Used for Event/Lumi/Run RootTrees
0064   RootTree::RootTree(std::shared_ptr<InputFile> filePtr,
0065                      BranchType const& branchType,
0066                      unsigned int nIndexes,
0067                      Options const& options,
0068                      unsigned int learningEntries,
0069                      InputType inputType)
0070       : RootTree(
0071             filePtr, branchType, nIndexes, learningEntries, options.enablePrefetching, options.promptReading, inputType) {
0072     init(BranchTypeToProductTreeName(branchType), options.treeMaxVirtualSize, options.treeCacheSize);
0073     metaTree_ = dynamic_cast<TTree*>(filePtr_->Get(BranchTypeToMetaDataTreeName(branchType).c_str()));
0074     auxBranch_ = getAuxiliaryBranch(tree_, branchType_);
0075     branchEntryInfoBranch_ =
0076         metaTree_ ? getProductProvenanceBranch(metaTree_, branchType_) : getProductProvenanceBranch(tree_, branchType_);
0077     infoTree_ =
0078         dynamic_cast<TTree*>(filePtr->Get(BranchTypeToInfoTreeName(branchType).c_str()));  // backward compatibility
0079   }
0080 
0081   // Used for ProcessBlock RootTrees
0082   RootTree::RootTree(std::shared_ptr<InputFile> filePtr,
0083                      BranchType const& branchType,
0084                      std::string const& processName,
0085                      unsigned int nIndexes,
0086                      Options const& options,
0087                      unsigned int learningEntries,
0088                      InputType inputType)
0089       : RootTree(
0090             filePtr, branchType, nIndexes, learningEntries, options.enablePrefetching, options.promptReading, inputType) {
0091     processName_ = processName;
0092     init(BranchTypeToProductTreeName(branchType, processName), options.treeMaxVirtualSize, options.treeCacheSize);
0093   }
0094 
0095   void RootTree::init(std::string const& productTreeName, unsigned int maxVirtualSize, unsigned int cacheSize) {
0096     if (filePtr_.get() != nullptr) {
0097       tree_ = dynamic_cast<TTree*>(filePtr_->Get(productTreeName.c_str()));
0098     }
0099     if (not tree_) {
0100       throw cms::Exception("WrongFileFormat")
0101           << "The ROOT file does not contain a TTree named " << productTreeName
0102           << "\n This is either not an edm ROOT file or is one that has been corrupted.";
0103     }
0104     entries_ = tree_->GetEntries();
0105 
0106     // On merged files in older releases of ROOT, the autoFlush setting is always negative; we must guess.
0107     // TODO: On newer merged files, we should be able to get this from the cluster iterator.
0108     long treeAutoFlush = tree_->GetAutoFlush();
0109     if (treeAutoFlush < 0) {
0110       // The "+1" is here to avoid divide-by-zero in degenerate cases.
0111       Long64_t averageEventSizeBytes = tree_->GetZipBytes() / (tree_->GetEntries() + 1) + 1;
0112       treeAutoFlush_ = cacheSize / averageEventSizeBytes + 1;
0113     } else {
0114       treeAutoFlush_ = treeAutoFlush;
0115     }
0116     if (treeAutoFlush_ < learningEntries_) {
0117       learningEntries_ = treeAutoFlush_;
0118     }
0119     setTreeMaxVirtualSize(maxVirtualSize);
0120     setCacheSize(cacheSize);
0121     if (branchType_ == InEvent) {
0122       Int_t branchCount = tree_->GetListOfBranches()->GetEntriesFast();
0123       trainedSet_.reserve(branchCount);
0124       triggerSet_.reserve(branchCount);
0125     }
0126   }
0127 
0128   RootTree::~RootTree() {}
0129 
0130   RootTree::EntryNumber const& RootTree::entryNumberForIndex(unsigned int index) const {
0131     assert(index < entryNumberForIndex_->size());
0132     return (*entryNumberForIndex_)[index];
0133   }
0134 
0135   void RootTree::insertEntryForIndex(unsigned int index) {
0136     assert(index < entryNumberForIndex_->size());
0137     (*entryNumberForIndex_)[index] = entryNumber();
0138   }
0139 
0140   bool RootTree::isValid() const {
0141     // ProcessBlock
0142     if (branchType_ == InProcess) {
0143       return tree_ != nullptr;
0144     }
0145     // Run/Lumi/Event
0146     if (metaTree_ == nullptr || metaTree_->GetNbranches() == 0) {
0147       return tree_ != nullptr && auxBranch_ != nullptr;
0148     }
0149     // Backward compatibility for Run/Lumi/Event
0150     if (tree_ != nullptr && auxBranch_ != nullptr && metaTree_ != nullptr) {  // backward compatibility
0151       if (branchEntryInfoBranch_ != nullptr || infoTree_ != nullptr)
0152         return true;  // backward compatibility
0153       return (entries_ == metaTree_->GetEntries() &&
0154               tree_->GetNbranches() <= metaTree_->GetNbranches() + 1);  // backward compatibility
0155     }  // backward compatibility
0156     return false;
0157   }
0158 
0159   DelayedReader* RootTree::resetAndGetRootDelayedReader() const {
0160     rootDelayedReader_->reset();
0161     return rootDelayedReader_.get();
0162   }
0163 
0164   RootDelayedReaderBase* RootTree::rootDelayedReader() const { return rootDelayedReader_.get(); }
0165 
0166   void RootTree::setPresence(ProductDescription& prod, std::string const& oldBranchName) {
0167     assert(isValid());
0168     if (tree_->GetBranch(oldBranchName.c_str()) == nullptr) {
0169       prod.setDropped(true);
0170     }
0171   }
0172 
0173   void roottree::BranchInfo::setBranch(TBranch* branch, TClass const* wrapperBaseTClass) {
0174     productBranch_ = branch;
0175     if (branch) {
0176       classCache_ = TClass::GetClass(productDescription_.wrappedName().c_str());
0177       offsetToWrapperBase_ = classCache_->GetBaseClassOffset(wrapperBaseTClass);
0178     }
0179   }
0180   std::unique_ptr<WrapperBase> roottree::BranchInfo::newWrapper() const {
0181     assert(nullptr != classCache_);
0182     void* p = classCache_->New();
0183     return getWrapperBasePtr(p, offsetToWrapperBase_);
0184   }
0185 
0186   void RootTree::addBranch(ProductDescription const& prod, std::string const& oldBranchName) {
0187     assert(isValid());
0188     static TClass const* const wrapperBaseTClass = TClass::GetClass("edm::WrapperBase");
0189     //use the translated branch name
0190     TBranch* branch = tree_->GetBranch(oldBranchName.c_str());
0191     roottree::BranchInfo info = roottree::BranchInfo(prod);
0192     info.productBranch_ = nullptr;
0193     if (prod.present()) {
0194       info.setBranch(branch, wrapperBaseTClass);
0195       //we want the new branch name for the JobReport
0196       branchNames_.push_back(prod.branchName());
0197     }
0198     branches_.insert(prod.branchID(), info);
0199   }
0200 
0201   void RootTree::dropBranch(std::string const& oldBranchName) {
0202     //use the translated branch name
0203     TBranch* branch = tree_->GetBranch(oldBranchName.c_str());
0204     if (branch != nullptr) {
0205       TObjArray* leaves = tree_->GetListOfLeaves();
0206       int entries = leaves->GetEntries();
0207       for (int i = 0; i < entries; ++i) {
0208         TLeaf* leaf = (TLeaf*)(*leaves)[i];
0209         if (leaf == nullptr)
0210           continue;
0211         TBranch* br = leaf->GetBranch();
0212         if (br == nullptr)
0213           continue;
0214         if (br->GetMother() == branch) {
0215           leaves->Remove(leaf);
0216         }
0217       }
0218       leaves->Compress();
0219       tree_->GetListOfBranches()->Remove(branch);
0220       tree_->GetListOfBranches()->Compress();
0221       delete branch;
0222     }
0223   }
0224 
0225   roottree::BranchMap const& RootTree::branches() const { return branches_; }
0226 
0227   std::shared_ptr<TTreeCache> RootTree::createCacheWithSize(unsigned int cacheSize) const {
0228     return filePtr_->createCacheWithSize(*tree_, cacheSize);
0229   }
0230 
0231   void RootTree::setCacheSize(unsigned int cacheSize) {
0232     cacheSize_ = cacheSize;
0233     treeCache_ = createCacheWithSize(cacheSize);
0234     if (treeCache_)
0235       treeCache_->SetEnablePrefetching(enablePrefetching_);
0236     rawTreeCache_.reset();
0237   }
0238 
0239   void RootTree::setTreeMaxVirtualSize(int treeMaxVirtualSize) {
0240     if (treeMaxVirtualSize >= 0)
0241       tree_->SetMaxVirtualSize(static_cast<Long64_t>(treeMaxVirtualSize));
0242   }
0243 
0244   bool RootTree::nextWithCache() {
0245     bool returnValue = ++entryNumber_ < entries_;
0246     if (returnValue) {
0247       setEntryNumber(entryNumber_);
0248     }
0249     return returnValue;
0250   }
0251 
0252   void RootTree::setEntryNumber(EntryNumber theEntryNumber) {
0253     {
0254       auto guard = filePtr_->setCacheReadTemporarily(treeCache_.get(), tree_);
0255 
0256       // Detect a backward skip.  If the skip is sufficiently large, we roll the dice and reset the treeCache.
0257       // This will cause some amount of over-reading: we pre-fetch all the events in some prior cluster.
0258       // However, because reading one event in the cluster is supposed to be equivalent to reading all events in the cluster,
0259       // we're not incurring additional over-reading - we're just doing it more efficiently.
0260       // NOTE: Constructor guarantees treeAutoFlush_ is positive, even if TTree->GetAutoFlush() is negative.
0261       if (theEntryNumber < entryNumber_ and theEntryNumber >= 0) {
0262         //We started reading the file near the end, now we need to correct for the learning length
0263         if (switchOverEntry_ > tree_->GetEntries()) {
0264           switchOverEntry_ = switchOverEntry_ - tree_->GetEntries();
0265           if (rawTreeCache_) {
0266             rawTreeCache_->SetEntryRange(theEntryNumber, switchOverEntry_);
0267             rawTreeCache_->FillBuffer();
0268           }
0269         }
0270         if (performedSwitchOver_ and triggerTreeCache_) {
0271           //We are using the triggerTreeCache_ not the rawTriggerTreeCache_.
0272           //The triggerTreeCache was originally told to start from an entry further in the file.
0273           triggerTreeCache_->SetEntryRange(theEntryNumber, tree_->GetEntries());
0274         } else if (rawTriggerTreeCache_) {
0275           //move the switch point to the end of the cluster holding theEntryNumber
0276           rawTriggerSwitchOverEntry_ = -1;
0277           TTree::TClusterIterator clusterIter = tree_->GetClusterIterator(theEntryNumber);
0278           while ((rawTriggerSwitchOverEntry_ < theEntryNumber) || (rawTriggerSwitchOverEntry_ <= 0)) {
0279             rawTriggerSwitchOverEntry_ = clusterIter();
0280           }
0281           rawTriggerTreeCache_->SetEntryRange(theEntryNumber, rawTriggerSwitchOverEntry_);
0282         }
0283       }
0284       if ((theEntryNumber < static_cast<EntryNumber>(entryNumber_ - treeAutoFlush_)) && (treeCache_) &&
0285           (!treeCache_->IsLearning()) && (entries_ > 0) && (switchOverEntry_ >= 0)) {
0286         treeCache_->SetEntryRange(theEntryNumber, entries_);
0287         treeCache_->FillBuffer();
0288       }
0289 
0290       entryNumber_ = theEntryNumber;
0291       tree_->LoadTree(entryNumber_);
0292       //want guard to end here
0293     }
0294     if (treeCache_ && trainNow_ && entryNumber_ >= 0) {
0295       startTraining();
0296       trainNow_ = false;
0297       trainedSet_.clear();
0298       triggerSet_.clear();
0299       rawTriggerSwitchOverEntry_ = -1;
0300     }
0301     if (not promptRead_ && treeCache_ && treeCache_->IsLearning() && switchOverEntry_ >= 0 &&
0302         entryNumber_ >= switchOverEntry_) {
0303       stopTraining();
0304     }
0305   }
0306 
0307   // The actual implementation is done below; it's split in this strange
0308   // manner in order to keep a by-definition-rare code path out of the instruction cache.
0309   inline TTreeCache* RootTree::checkTriggerCache(TBranch* branch, EntryNumber entryNumber) const {
0310     if (!treeCache_->IsAsyncReading() && enableTriggerCache_ && (trainedSet_.find(branch) == trainedSet_.end())) {
0311       return checkTriggerCacheImpl(branch, entryNumber);
0312     } else {
0313       return nullptr;
0314     }
0315   }
0316 
0317   // See comments in the header.  If this function is called, we already know
0318   // the trigger cache is active and it was a cache miss for the regular cache.
0319   TTreeCache* RootTree::checkTriggerCacheImpl(TBranch* branch, EntryNumber entryNumber) const {
0320     // This branch is not going to be in the cache.
0321     // Assume this is a "trigger pattern".
0322     // Always make sure the branch is added to the trigger set.
0323     if (triggerSet_.find(branch) == triggerSet_.end()) {
0324       triggerSet_.insert(branch);
0325       if (triggerTreeCache_.get()) {
0326         triggerTreeCache_->AddBranch(branch, kTRUE);
0327       }
0328     }
0329 
0330     if (rawTriggerSwitchOverEntry_ < 0) {
0331       // The trigger has never fired before.  Take everything not in the
0332       // trainedSet and load it from disk
0333 
0334       // Calculate the end of the next cluster; triggers in the next cluster
0335       // will use the triggerCache, not the rawTriggerCache.
0336       //
0337       // Guarantee that rawTriggerSwitchOverEntry_ is positive (non-zero) after completion
0338       // of this if-block.
0339       TTree::TClusterIterator clusterIter = tree_->GetClusterIterator(entryNumber);
0340       while ((rawTriggerSwitchOverEntry_ < entryNumber) || (rawTriggerSwitchOverEntry_ <= 0)) {
0341         rawTriggerSwitchOverEntry_ = clusterIter();
0342       }
0343 
0344       // ROOT will automatically expand the cache to fit one cluster; hence, we use
0345       // 5 MB as the cache size below
0346       rawTriggerTreeCache_ = createCacheWithSize(5 * 1024 * 1024);
0347       if (rawTriggerTreeCache_)
0348         rawTriggerTreeCache_->SetEnablePrefetching(false);
0349       TObjArray* branches = tree_->GetListOfBranches();
0350       int branchCount = branches->GetEntriesFast();
0351 
0352       // Train the rawTriggerCache to have everything not in the regular cache.
0353       rawTriggerTreeCache_->SetLearnEntries(0);
0354       rawTriggerTreeCache_->SetEntryRange(entryNumber, rawTriggerSwitchOverEntry_);
0355       for (int i = 0; i < branchCount; i++) {
0356         TBranch* tmp_branch = (TBranch*)branches->UncheckedAt(i);
0357         if (trainedSet_.find(tmp_branch) != trainedSet_.end()) {
0358           continue;
0359         }
0360         rawTriggerTreeCache_->AddBranch(tmp_branch, kTRUE);
0361       }
0362       performedSwitchOver_ = false;
0363       rawTriggerTreeCache_->StopLearningPhase();
0364 
0365       return rawTriggerTreeCache_.get();
0366     } else if (!performedSwitchOver_ and entryNumber_ < rawTriggerSwitchOverEntry_) {
0367       // The raw trigger has fired and it contents are valid.
0368       return rawTriggerTreeCache_.get();
0369     } else if (rawTriggerSwitchOverEntry_ > 0) {
0370       // The raw trigger has fired, but we are out of the cache.  Use the
0371       // triggerCache instead.
0372       if (!performedSwitchOver_) {
0373         rawTriggerTreeCache_.reset();
0374         performedSwitchOver_ = true;
0375 
0376         // Train the triggerCache
0377         triggerTreeCache_ = createCacheWithSize(5 * 1024 * 1024);
0378         triggerTreeCache_->SetEnablePrefetching(false);
0379         triggerTreeCache_->SetLearnEntries(0);
0380         triggerTreeCache_->SetEntryRange(entryNumber, tree_->GetEntries());
0381         for (std::unordered_set<TBranch*>::const_iterator it = triggerSet_.begin(), itEnd = triggerSet_.end();
0382              it != itEnd;
0383              it++) {
0384           triggerTreeCache_->AddBranch(*it, kTRUE);
0385         }
0386         triggerTreeCache_->StopLearningPhase();
0387       }
0388       return triggerTreeCache_.get();
0389     }
0390 
0391     // By construction, this case should be impossible.
0392     assert(false);
0393     return nullptr;
0394   }
0395 
0396   inline TTreeCache* RootTree::selectCache(TBranch* branch, EntryNumber entryNumber) const {
0397     TTreeCache* triggerCache = nullptr;
0398     if (promptRead_) {
0399       return rawTreeCache_.get();
0400     }
0401     if (!treeCache_) {
0402       return nullptr;
0403     } else if (treeCache_->IsLearning() && rawTreeCache_) {
0404       treeCache_->AddBranch(branch, kTRUE);
0405       trainedSet_.insert(branch);
0406       return rawTreeCache_.get();
0407     } else if ((triggerCache = checkTriggerCache(branch, entryNumber))) {
0408       // A NULL return value from checkTriggerCache indicates the trigger cache case
0409       // does not apply, and we should continue below.
0410       return triggerCache;
0411     } else {
0412       // The "normal" TTreeCache case.
0413       return treeCache_.get();
0414     }
0415   }
0416   TTreeCache* RootTree::getAuxCache(TBranch* auxBranch) const {
0417     if (not auxCache_ and cacheSize_ > 0) {
0418       auxCache_ = createCacheWithSize(1 * 1024 * 1024);
0419       if (auxCache_) {
0420         auxCache_->SetEnablePrefetching(enablePrefetching_);
0421         auxCache_->SetLearnEntries(0);
0422         auxCache_->StartLearningPhase();
0423         auxCache_->SetEntryRange(0, tree_->GetEntries());
0424         auxCache_->AddBranch(auxBranch->GetName(), kTRUE);
0425         auxCache_->StopLearningPhase();
0426       }
0427     }
0428     return auxCache_.get();
0429   }
0430 
0431   void RootTree::getEntryForAllBranches() const {
0432     oneapi::tbb::this_task_arena::isolate([&]() {
0433       auto guard = filePtr_->setCacheReadTemporarily(treeCache_.get(), tree_);
0434       tree_->GetEntry(entryNumber_);
0435     });
0436   }
0437 
0438   void RootTree::getEntry(TBranch* branch, EntryNumber entryNumber) const {
0439     getEntryUsingCache(branch, entryNumber, selectCache(branch, entryNumber));
0440   }
0441 
0442   inline void RootTree::getEntryUsingCache(TBranch* branch, EntryNumber entryNumber, TTreeCache* cache) const {
0443     LogTrace("IOTrace").format(
0444         "RootTree::getEntryUsingCache() begin for branch {} entry {}", branch->GetName(), entryNumber);
0445     try {
0446       auto guard = filePtr_->setCacheReadTemporarily(cache, tree_);
0447       branch->GetEntry(entryNumber);
0448     } catch (cms::Exception const& e) {
0449       // We make sure the treeCache_ is detached from the file,
0450       // so that ROOT does not also delete it.
0451       Exception t(errors::FileReadError, "", e);
0452       t.addContext(std::string("Reading branch ") + branch->GetName());
0453       throw t;
0454     } catch (std::exception const& e) {
0455       Exception t(errors::FileReadError);
0456       t << e.what();
0457       t.addContext(std::string("Reading branch ") + branch->GetName());
0458       throw t;
0459     } catch (...) {
0460       Exception t(errors::FileReadError);
0461       t << "An exception of unknown type was thrown.";
0462       t.addContext(std::string("Reading branch ") + branch->GetName());
0463       throw t;
0464     }
0465     LogTrace("IOTrace").format(
0466         "RootTree::getEntryUsingCache() end for branch {} entry {}", branch->GetName(), entryNumber);
0467   }
0468 
0469   bool RootTree::skipEntries(unsigned int& offset) {
0470     entryNumber_ += offset;
0471     bool retval = (entryNumber_ < entries_);
0472     if (retval) {
0473       offset = 0;
0474     } else {
0475       // Not enough entries in the file to skip.
0476       // The +1 is needed because entryNumber_ is -1 at the initialization of the tree, not 0.
0477       long long overshoot = entryNumber_ + 1 - entries_;
0478       entryNumber_ = entries_;
0479       offset = overshoot;
0480     }
0481     return retval;
0482   }
0483 
0484   void RootTree::startTraining() {
0485     if (cacheSize_ == 0) {
0486       return;
0487     }
0488     assert(treeCache_);
0489     assert(branchType_ == InEvent);
0490     assert(!rawTreeCache_);
0491     treeCache_->SetLearnEntries(learningEntries_);
0492     rawTreeCache_ = createCacheWithSize(cacheSize_);
0493     rawTreeCache_->SetEnablePrefetching(false);
0494     rawTreeCache_->SetLearnEntries(0);
0495     if (promptRead_) {
0496       switchOverEntry_ = entries_;
0497     } else {
0498       switchOverEntry_ = entryNumber_ + learningEntries_;
0499     }
0500     auto rawStart = entryNumber_;
0501     auto rawEnd = switchOverEntry_;
0502     auto treeStart = switchOverEntry_;
0503     if (switchOverEntry_ >= tree_->GetEntries()) {
0504       treeStart = switchOverEntry_ - tree_->GetEntries();
0505       rawEnd = tree_->GetEntries();
0506     }
0507     rawTreeCache_->StartLearningPhase();
0508     rawTreeCache_->SetEntryRange(rawStart, rawEnd);
0509     rawTreeCache_->AddBranch("*", kTRUE);
0510     rawTreeCache_->StopLearningPhase();
0511 
0512     treeCache_->StartLearningPhase();
0513     treeCache_->SetEntryRange(treeStart, tree_->GetEntries());
0514     // Make sure that 'branchListIndexes' branch exist in input file
0515     if (filePtr_->Get(poolNames::branchListIndexesBranchName().c_str()) != nullptr) {
0516       treeCache_->AddBranch(poolNames::branchListIndexesBranchName().c_str(), kTRUE);
0517     }
0518     treeCache_->AddBranch(BranchTypeToAuxiliaryBranchName(branchType_).c_str(), kTRUE);
0519     trainedSet_.clear();
0520     triggerSet_.clear();
0521     assert(treeCache_->GetTree() == tree_);
0522   }
0523 
0524   void RootTree::stopTraining() {
0525     auto guard = filePtr_->setCacheReadTemporarily(treeCache_.get(), tree_);
0526     treeCache_->StopLearningPhase();
0527     rawTreeCache_.reset();
0528   }
0529 
0530   void RootTree::close() {
0531     // The TFile is about to be closed, and destructed.
0532     // Just to play it safe, zero all pointers to quantities that are owned by the TFile.
0533     auxBranch_ = branchEntryInfoBranch_ = nullptr;
0534     tree_ = metaTree_ = infoTree_ = nullptr;
0535     // We own the treeCache_.
0536     // We make sure the treeCache_ is detached from the file,
0537     // so that ROOT does not also delete it.
0538     filePtr_->clearCacheRead(tree_);
0539     // We *must* delete the TTreeCache here because the TFilePrefetch object
0540     // references the TFile.  If TFile is closed, before the TTreeCache is
0541     // deleted, the TFilePrefetch may continue to do TFile operations, causing
0542     // deadlocks or exceptions.
0543     treeCache_.reset();
0544     rawTreeCache_.reset();
0545     triggerTreeCache_.reset();
0546     rawTriggerTreeCache_.reset();
0547     auxCache_.reset();
0548     // We give up our shared ownership of the TFile itself.
0549     filePtr_.reset();
0550   }
0551 
0552   void RootTree::trainCache(char const* branchNames) {
0553     if (cacheSize_ == 0) {
0554       return;
0555     }
0556     tree_->LoadTree(0);
0557     assert(treeCache_);
0558     {
0559       auto guard = filePtr_->setCacheReadTemporarily(treeCache_.get(), tree_);
0560       treeCache_->StartLearningPhase();
0561       treeCache_->SetEntryRange(0, tree_->GetEntries());
0562       treeCache_->AddBranch(branchNames, kTRUE);
0563       treeCache_->StopLearningPhase();
0564       assert(treeCache_->GetTree() == tree_);
0565       // We own the treeCache_.
0566       // We make sure the treeCache_ is detached from the file,
0567       // so that ROOT does not also delete it.
0568 
0569       //want guard to end here
0570     }
0571 
0572     if (branchType_ == InEvent) {
0573       // Must also manually add things to the trained set.
0574       TObjArray* branches = tree_->GetListOfBranches();
0575       int branchCount = branches->GetEntriesFast();
0576       for (int i = 0; i < branchCount; i++) {
0577         TBranch* branch = (TBranch*)branches->UncheckedAt(i);
0578         if ((branchNames[0] == '*') || (strcmp(branchNames, branch->GetName()) == 0)) {
0579           trainedSet_.insert(branch);
0580         }
0581       }
0582     }
0583   }
0584 
0585   void RootTree::setSignals(
0586       signalslot::Signal<void(StreamContext const&, ModuleCallingContext const&)> const* preEventReadSource,
0587       signalslot::Signal<void(StreamContext const&, ModuleCallingContext const&)> const* postEventReadSource) {
0588     rootDelayedReader_->setSignals(preEventReadSource, postEventReadSource);
0589   }
0590 
0591   namespace roottree {
0592     Int_t getEntry(TBranch* branch, EntryNumber entryNumber) {
0593       Int_t n = 0;
0594       try {
0595         n = branch->GetEntry(entryNumber);
0596       } catch (cms::Exception const& e) {
0597         throw Exception(errors::FileReadError, "", e);
0598       }
0599       return n;
0600     }
0601 
0602     Int_t getEntry(TTree* tree, EntryNumber entryNumber) {
0603       Int_t n = 0;
0604       try {
0605         n = tree->GetEntry(entryNumber);
0606       } catch (cms::Exception const& e) {
0607         throw Exception(errors::FileReadError, "", e);
0608       }
0609       return n;
0610     }
0611 
0612     std::unique_ptr<TTreeCache> trainCache(TTree* tree,
0613                                            InputFile& file,
0614                                            unsigned int cacheSize,
0615                                            char const* branchNames) {
0616       tree->LoadTree(0);
0617       std::unique_ptr<TTreeCache> treeCache = file.createCacheWithSize(*tree, cacheSize);
0618       if (nullptr != treeCache.get()) {
0619         treeCache->StartLearningPhase();
0620         treeCache->SetEntryRange(0, tree->GetEntries());
0621         treeCache->AddBranch(branchNames, kTRUE);
0622         treeCache->StopLearningPhase();
0623       }
0624       return treeCache;
0625     }
0626   }  // namespace roottree
0627 }  // namespace edm