Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:19:08

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