CMS 3D CMS Logo

/afs/cern.ch/work/a/aaltunda/public/www/CMSSW_5_3_14/src/IOPool/Input/src/RootTree.cc

Go to the documentation of this file.
00001 #include "RootTree.h"
00002 #include "RootDelayedReader.h"
00003 #include "FWCore/Utilities/interface/EDMException.h"
00004 #include "FWCore/Utilities/interface/Exception.h"
00005 #include "DataFormats/Provenance/interface/BranchDescription.h"
00006 #include "InputFile.h"
00007 #include "TTree.h"
00008 #include "TTreeIndex.h"
00009 #include "TTreeCache.h"
00010 
00011 #include <iostream>
00012 
00013 namespace edm {
00014   namespace {
00015     TBranch* getAuxiliaryBranch(TTree* tree, BranchType const& branchType) {
00016       TBranch* branch = tree->GetBranch(BranchTypeToAuxiliaryBranchName(branchType).c_str());
00017       if (branch == 0) {
00018         branch = tree->GetBranch(BranchTypeToAuxBranchName(branchType).c_str());
00019       }
00020       return branch;
00021     }
00022     TBranch* getProductProvenanceBranch(TTree* tree, BranchType const& branchType) {
00023       TBranch* branch = tree->GetBranch(BranchTypeToBranchEntryInfoBranchName(branchType).c_str());
00024       return branch;
00025     }
00026   }
00027   RootTree::RootTree(boost::shared_ptr<InputFile> filePtr,
00028                      BranchType const& branchType,
00029                      unsigned int maxVirtualSize,
00030                      unsigned int cacheSize,
00031                      unsigned int learningEntries) :
00032     filePtr_(filePtr),
00033     tree_(dynamic_cast<TTree*>(filePtr_.get() != 0 ? filePtr_->Get(BranchTypeToProductTreeName(branchType).c_str()) : 0)),
00034     metaTree_(dynamic_cast<TTree*>(filePtr_.get() != 0 ? filePtr_->Get(BranchTypeToMetaDataTreeName(branchType).c_str()) : 0)),
00035     branchType_(branchType),
00036     auxBranch_(tree_ ? getAuxiliaryBranch(tree_, branchType_) : 0),
00037     treeCache_(),
00038     rawTreeCache_(),
00039     entries_(tree_ ? tree_->GetEntries() : 0),
00040     entryNumber_(-1),
00041     branchNames_(),
00042     branches_(new BranchMap),
00043     trainNow_(false),
00044     switchOverEntry_(-1),
00045     learningEntries_(learningEntries),
00046     cacheSize_(cacheSize),
00047     treeAutoFlush_(tree_ ? tree_->GetAutoFlush() : 0),
00048     rootDelayedReader_(new RootDelayedReader(*this, filePtr)),
00049     branchEntryInfoBranch_(metaTree_ ? getProductProvenanceBranch(metaTree_, branchType_) : (tree_ ? getProductProvenanceBranch(tree_, branchType_) : 0)),
00050     infoTree_(dynamic_cast<TTree*>(filePtr_.get() != 0 ? filePtr->Get(BranchTypeToInfoTreeName(branchType).c_str()) : 0)) // backward compatibility
00051     {
00052       assert(tree_);
00053       // On merged files in older releases of ROOT, the autoFlush setting is always negative; we must guess.
00054       // TODO: On newer merged files, we should be able to get this from the cluster iterator.
00055       if (treeAutoFlush_ < 0) {
00056         // The "+1" is here to avoid divide-by-zero in degenerate cases.
00057         Long64_t averageEventSizeBytes = tree_->GetZipBytes() / (tree_->GetEntries()+1) + 1;
00058         treeAutoFlush_ = cacheSize_/averageEventSizeBytes+1;
00059       }
00060       setTreeMaxVirtualSize(maxVirtualSize);
00061       setCacheSize(cacheSize);
00062   }
00063 
00064   RootTree::~RootTree() {
00065   }
00066 
00067   bool
00068   RootTree::isValid() const {
00069     if (metaTree_ == 0 || metaTree_->GetNbranches() == 0) {
00070       return tree_ != 0 && auxBranch_ != 0;
00071     }
00072     if (tree_ != 0 && auxBranch_ != 0 && metaTree_ != 0) { // backward compatibility
00073       if (branchEntryInfoBranch_ != 0 || infoTree_ != 0) return true; // backward compatibility
00074       return (entries_ == metaTree_->GetEntries() && tree_->GetNbranches() <= metaTree_->GetNbranches() + 1);  // backward compatibility
00075     } // backward compatibility
00076     return false;
00077   }
00078 
00079   DelayedReader*
00080   RootTree::rootDelayedReader() const {
00081     rootDelayedReader_->reset();
00082     return rootDelayedReader_.get();
00083   }  
00084 
00085   void
00086   RootTree::setPresence(BranchDescription const& prod, std::string const& oldBranchName) {
00087       assert(isValid());
00088       prod.init();
00089       if(tree_->GetBranch(oldBranchName.c_str()) == 0){
00090         prod.setDropped();
00091       }
00092   }
00093 
00094   void
00095   RootTree::addBranch(BranchKey const& key,
00096                       BranchDescription const& prod,
00097                       std::string const& oldBranchName) {
00098       assert(isValid());
00099       prod.init();
00100       //use the translated branch name
00101       TBranch* branch = tree_->GetBranch(oldBranchName.c_str());
00102       roottree::BranchInfo info = roottree::BranchInfo(ConstBranchDescription(prod));
00103       info.productBranch_ = 0;
00104       if (prod.present()) {
00105         info.productBranch_ = branch;
00106         //we want the new branch name for the JobReport
00107         branchNames_.push_back(prod.branchName());
00108       }
00109       TTree* provTree = (metaTree_ != 0 ? metaTree_ : tree_);
00110       info.provenanceBranch_ = provTree->GetBranch(oldBranchName.c_str());
00111       branches_->insert(std::make_pair(key, info));
00112   }
00113 
00114   void
00115   RootTree::dropBranch(std::string const& oldBranchName) {
00116       //use the translated branch name
00117       TBranch* branch = tree_->GetBranch(oldBranchName.c_str());
00118       if (branch != 0) {
00119         TObjArray* leaves = tree_->GetListOfLeaves();
00120         int entries = leaves->GetEntries();
00121         for (int i = 0; i < entries; ++i) {
00122           TLeaf* leaf = (TLeaf*)(*leaves)[i];
00123           if (leaf == 0) continue;
00124           TBranch* br = leaf->GetBranch();
00125           if (br == 0) continue;
00126           if (br->GetMother() == branch) {
00127             leaves->Remove(leaf);
00128           }
00129         }
00130         leaves->Compress();
00131         tree_->GetListOfBranches()->Remove(branch);
00132         tree_->GetListOfBranches()->Compress();
00133         delete branch;
00134       }
00135   }
00136 
00137   roottree::BranchMap const&
00138   RootTree::branches() const {return *branches_;}
00139 
00140   void
00141   RootTree::setCacheSize(unsigned int cacheSize) {
00142     cacheSize_ = cacheSize;
00143     tree_->SetCacheSize(static_cast<Long64_t>(cacheSize));
00144     treeCache_.reset(dynamic_cast<TTreeCache*>(filePtr_->GetCacheRead()));
00145     filePtr_->SetCacheRead(0);
00146     rawTreeCache_.reset();
00147   }
00148 
00149   void
00150   RootTree::setTreeMaxVirtualSize(int treeMaxVirtualSize) {
00151     if (treeMaxVirtualSize >= 0) tree_->SetMaxVirtualSize(static_cast<Long64_t>(treeMaxVirtualSize));
00152   }
00153 
00154   void
00155   RootTree::setEntryNumber(EntryNumber theEntryNumber) {
00156     filePtr_->SetCacheRead(treeCache_.get());
00157 
00158     // Detect a backward skip.  If the skip is sufficiently large, we roll the dice and reset the treeCache.
00159     // This will cause some amount of over-reading: we pre-fetch all the events in some prior cluster.
00160     // However, because reading one event in the cluster is supposed to be equivalent to reading all events in the cluster,
00161     // we're not incurring additional over-reading - we're just doing it more efficiently.
00162     // NOTE: Constructor guarantees treeAutoFlush_ is positive, even if TTree->GetAutoFlush() is negative.
00163     if ((theEntryNumber < static_cast<EntryNumber>(entryNumber_-treeAutoFlush_)) &&
00164         (treeCache_) && (!treeCache_->IsLearning()) && (entries_ > 0) && (switchOverEntry_ >= 0)) {
00165       treeCache_->SetEntryRange(theEntryNumber, entries_);
00166       treeCache_->FillBuffer();
00167     }
00168 
00169     entryNumber_ = theEntryNumber;
00170     tree_->LoadTree(entryNumber_);
00171     filePtr_->SetCacheRead(0);
00172     if(treeCache_ && trainNow_ && entryNumber_ >= 0) {
00173       startTraining();
00174       trainNow_ = false;
00175     }
00176     if (treeCache_ && treeCache_->IsLearning() && switchOverEntry_ >= 0 && entryNumber_ >= switchOverEntry_) {
00177       stopTraining();
00178     }
00179   }
00180 
00181   void
00182   RootTree::getEntry(TBranch* branch, EntryNumber entryNumber) const {
00183     try {
00184       if (!treeCache_) {
00185         filePtr_->SetCacheRead(0);
00186         branch->GetEntry(entryNumber);
00187       } else if (treeCache_->IsLearning() && rawTreeCache_) {
00188         treeCache_->AddBranch(branch, kTRUE);
00189         filePtr_->SetCacheRead(rawTreeCache_.get());
00190         branch->GetEntry(entryNumber);
00191         filePtr_->SetCacheRead(0);
00192       } else {
00193         filePtr_->SetCacheRead(treeCache_.get());
00194         branch->GetEntry(entryNumber);
00195         filePtr_->SetCacheRead(0);
00196       }
00197     } catch(cms::Exception const& e) {
00198       // We make sure the treeCache_ is detached from the file,
00199       // so that ROOT does not also delete it.
00200       filePtr_->SetCacheRead(0);
00201       Exception t(errors::FileReadError, "", e);
00202       t.addContext(std::string("Reading branch ")+branch->GetName());
00203       throw t;
00204     }
00205   }
00206 
00207   void
00208   RootTree::startTraining() {
00209     if (cacheSize_ == 0) {
00210       return;
00211     }
00212     assert(treeCache_ && treeCache_->GetOwner() == tree_);
00213     assert(branchType_ == InEvent);
00214     assert(!rawTreeCache_);
00215     treeCache_->SetLearnEntries(learningEntries_);
00216     tree_->SetCacheSize(static_cast<Long64_t>(cacheSize_));
00217     rawTreeCache_.reset(dynamic_cast<TTreeCache *>(filePtr_->GetCacheRead()));
00218     filePtr_->SetCacheRead(0);
00219     rawTreeCache_->SetLearnEntries(0);
00220     switchOverEntry_ = entryNumber_ + learningEntries_;
00221     rawTreeCache_->StartLearningPhase();
00222     rawTreeCache_->SetEntryRange(entryNumber_, switchOverEntry_);
00223     rawTreeCache_->AddBranch("*", kTRUE);
00224     rawTreeCache_->StopLearningPhase();
00225     treeCache_->StartLearningPhase();
00226     treeCache_->SetEntryRange(switchOverEntry_, tree_->GetEntries());
00227     treeCache_->AddBranch(poolNames::branchListIndexesBranchName().c_str(), kTRUE);
00228     treeCache_->AddBranch(BranchTypeToAuxiliaryBranchName(branchType_).c_str(), kTRUE);
00229   }
00230 
00231   void
00232   RootTree::stopTraining() {
00233     filePtr_->SetCacheRead(treeCache_.get());
00234     treeCache_->StopLearningPhase();
00235     rawTreeCache_.reset();
00236   }
00237 
00238   void
00239   RootTree::close () {
00240     // The TFile is about to be closed, and destructed.
00241     // Just to play it safe, zero all pointers to quantities that are owned by the TFile.
00242     auxBranch_  = branchEntryInfoBranch_ = 0;
00243     tree_ = metaTree_ = infoTree_ = 0;
00244     // We own the treeCache_.
00245     // We make sure the treeCache_ is detached from the file,
00246     // so that ROOT does not also delete it.
00247     filePtr_->SetCacheRead(0);
00248     // We give up our shared ownership of the TFile itself.
00249     filePtr_.reset();
00250   }
00251 
00252   void
00253   RootTree::trainCache(char const* branchNames) {
00254     if (cacheSize_ == 0) {
00255       return;
00256     }
00257     tree_->LoadTree(0);
00258     assert(treeCache_);
00259     filePtr_->SetCacheRead(treeCache_.get());
00260     assert(treeCache_->GetOwner() == tree_);
00261     treeCache_->StartLearningPhase();
00262     treeCache_->SetEntryRange(0, tree_->GetEntries());
00263     treeCache_->AddBranch(branchNames, kTRUE);
00264     treeCache_->StopLearningPhase();
00265     // We own the treeCache_.
00266     // We make sure the treeCache_ is detached from the file,
00267     // so that ROOT does not also delete it.
00268     filePtr_->SetCacheRead(0);
00269   }
00270 
00271   namespace roottree {
00272     Int_t
00273     getEntry(TBranch* branch, EntryNumber entryNumber) {
00274       Int_t n = 0;
00275       try {
00276         n = branch->GetEntry(entryNumber);
00277       }
00278       catch(cms::Exception const& e) {
00279         throw Exception(errors::FileReadError, "", e);
00280       }
00281       return n;
00282     }
00283 
00284     Int_t
00285     getEntry(TTree* tree, EntryNumber entryNumber) {
00286       Int_t n = 0;
00287       try {
00288         n = tree->GetEntry(entryNumber);
00289       }
00290       catch(cms::Exception const& e) {
00291         throw Exception (errors::FileReadError, "", e);
00292       }
00293       return n;
00294     }
00295 
00296     std::unique_ptr<TTreeCache>
00297     trainCache(TTree* tree, InputFile& file, unsigned int cacheSize, char const* branchNames) {
00298       tree->LoadTree(0);
00299       tree->SetCacheSize(cacheSize);
00300       std::unique_ptr<TTreeCache> treeCache(dynamic_cast<TTreeCache*>(file.GetCacheRead()));
00301       if (0 != treeCache.get()) {
00302         treeCache->StartLearningPhase();
00303         treeCache->SetEntryRange(0, tree->GetEntries());
00304         treeCache->AddBranch(branchNames, kTRUE);
00305         treeCache->StopLearningPhase();
00306       }
00307       // We own the treeCache_.
00308       // We make sure the treeCache_ is detached from the file,
00309       // so that ROOT does not also delete it.
00310       file.SetCacheRead(0);
00311       return treeCache;
00312     }
00313   }
00314 }