CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
RootOutputTree.cc
Go to the documentation of this file.
1 
2 #include "RootOutputTree.h"
3 
14 
15 #include "TBranch.h"
16 #include "TBranchElement.h"
17 #include "TCollection.h"
18 #include "TFile.h"
19 #include "TTreeCloner.h"
20 #include "Rtypes.h"
21 #include "RVersion.h"
22 
23 #include <limits>
24 
25 namespace edm {
26 
40  {
41  public:
43  : tree_(tree)
44  {
45  dup();
46  }
47 
48  TTree *tree() const {return mytree_ ? mytree_.get() : tree_;}
49 
50  private:
51  DuplicateTreeSentry(DuplicateTreeSentry const&) = delete; // Disallow copying and moving
53  struct CloseBeforeDelete { void operator()(TFile* iFile) const { if( iFile) { iFile->Close(); } delete iFile; } };
54 
55  void dup()
56  {
58  if (!pSLC.isAvailable()) {return;}
59  if (pSLC->sourceCacheHint() && *(pSLC->sourceCacheHint()) == "lazy-download") {return;}
60  if (!pSLC->sourceCloneCacheHint() || *(pSLC->sourceCloneCacheHint()) != "lazy-download") {return;}
61  edm::LogWarning("DuplicateTreeSentry") << "Re-opening file for fast-cloning";
62 
63  TFile *file = tree_->GetCurrentFile();
64  const TUrl *url = file->GetEndpointUrl();
65  if (!url)
66  {
67  return;
68  }
69  file_.reset(TFile::Open(url->GetUrl(), "READWRAP")); // May throw an exception.
70  if (!file_)
71  {
72  return;
73  }
74  mytree_.reset(dynamic_cast<TTree*>(file_->Get(tree_->GetName())));
75  if (!mytree_) {return;}
76  }
77 
82  std::unique_ptr<TFile, CloseBeforeDelete> file_;
83  TTree *tree_ = nullptr;
84  std::unique_ptr<TTree> mytree_ = nullptr;
85  };
86 
88  std::shared_ptr<TFile> filePtr,
89  BranchType const& branchType,
90  int splitLevel,
91  int treeMaxVirtualSize) :
92  filePtr_(filePtr),
93  tree_(makeTTree(filePtr.get(), BranchTypeToProductTreeName(branchType), splitLevel)),
94  producedBranches_(),
95  readBranches_(),
96  auxBranches_(),
97  unclonedReadBranches_(),
98  clonedReadBranchNames_(),
99  currentlyFastCloning_(),
100  fastCloneAuxBranches_(false) {
101 
102  if(treeMaxVirtualSize >= 0) tree_->SetMaxVirtualSize(treeMaxVirtualSize);
103  }
104 
105  TTree*
106  RootOutputTree::assignTTree(TFile* filePtr, TTree* tree) {
107  tree->SetDirectory(filePtr);
108  // Turn off autosaving because it is such a memory hog and we are not using
109  // this check-pointing feature anyway.
110  tree->SetAutoSave(std::numeric_limits<Long64_t>::max());
111  return tree;
112  }
113 
114  TTree*
115  RootOutputTree::makeTTree(TFile* filePtr, std::string const& name, int splitLevel) {
116  TTree* tree = new TTree(name.c_str(), "", splitLevel);
117  if(!tree) throw edm::Exception(errors::FatalRootError)
118  << "Failed to create the tree: " << name << "\n";
119  if(tree->IsZombie())
121  << "Tree: " << name << " is a zombie." << "\n";
122 
123  return assignTTree(filePtr, tree);
124  }
125 
126  bool
128 
129  assert(inputTree != nullptr);
130 
131  // Do the split level and basket size match in the input and output?
132  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
133  it != itEnd; ++it) {
134 
135  TBranch* outputBranch = *it;
136  if(outputBranch != nullptr) {
137  TBranch* inputBranch = inputTree->GetBranch(outputBranch->GetName());
138 
139  if(inputBranch != nullptr) {
140  if(inputBranch->GetSplitLevel() != outputBranch->GetSplitLevel() ||
141  inputBranch->GetBasketSize() != outputBranch->GetBasketSize()) {
142  return false;
143  }
144  }
145  }
146  }
147  return true;
148  }
149 
150  namespace {
151  bool checkMatchingBranches(TBranchElement* inputBranch, TBranchElement* outputBranch) {
152  if(inputBranch->GetStreamerType() != outputBranch->GetStreamerType()) {
153  return false;
154  }
155  TObjArray* inputArray = inputBranch->GetListOfBranches();
156  TObjArray* outputArray = outputBranch->GetListOfBranches();
157 
158  if(outputArray->GetSize() < inputArray->GetSize()) {
159  return false;
160  }
161  TIter iter(outputArray);
162  TObject* obj = nullptr;
163  while((obj = iter.Next()) != nullptr) {
164  TBranchElement* outBranch = dynamic_cast<TBranchElement*>(obj);
165  if(outBranch) {
166  TBranchElement* inBranch = dynamic_cast<TBranchElement*>(inputArray->FindObject(outBranch->GetName()));
167  if(!inBranch) {
168  return false;
169  }
170  if(!checkMatchingBranches(inBranch, outBranch)) {
171  return false;
172  }
173  }
174  }
175  return true;
176  }
177  }
178 
179  bool RootOutputTree::checkIfFastClonable(TTree* inputTree) const {
180 
181  if(inputTree == nullptr) return false;
182 
183  // Do the sub-branches match in the input and output. Extra sub-branches in the input are OK for fast cloning, but not in the output.
184  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end(); it != itEnd; ++it) {
185  TBranchElement* outputBranch = dynamic_cast<TBranchElement*>(*it);
186  if(outputBranch != nullptr) {
187  TBranchElement* inputBranch = dynamic_cast<TBranchElement*>(inputTree->GetBranch(outputBranch->GetName()));
188  if(inputBranch != nullptr) {
189  // We have a matching top level branch. Do the recursive check on subbranches.
190  if(!checkMatchingBranches(inputBranch, outputBranch)) {
191  LogInfo("FastCloning")
192  << "Fast Cloning disabled because a data member has been added to split branch: " << inputBranch->GetName() << "\n.";
193  return false;
194  }
195  }
196  }
197  }
198  return true;
199  }
200 
201  bool RootOutputTree::checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const {
202  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end(); it != itEnd; ++it) {
203  if((*it)->GetEntries() != expectedNumberOfEntries) {
204  return false;
205  }
206  }
207  return true;
208  }
209 
210  void
212  if(in->GetEntries() != 0) {
213  TObjArray* branches = tree_->GetListOfBranches();
214  // If any products were produced (not just event products), the EventAuxiliary will be modified.
215  // In that case, don't fast copy auxiliary branches. Remove them, and add back after fast copying.
216  std::map<Int_t, TBranch *> auxIndexes;
217  bool mustRemoveSomeAuxs = false;
218  if(!fastCloneAuxBranches_) {
219  for(std::vector<TBranch *>::const_iterator it = auxBranches_.begin(), itEnd = auxBranches_.end();
220  it != itEnd; ++it) {
221  int auxIndex = branches->IndexOf(*it);
222  assert (auxIndex >= 0);
223  auxIndexes.insert(std::make_pair(auxIndex, *it));
224  branches->RemoveAt(auxIndex);
225  }
226  mustRemoveSomeAuxs = true;
227  }
228 
229  //Deal with any aux branches which can never be cloned
230  for(std::vector<TBranch *>::const_iterator it = unclonedAuxBranches_.begin(),
231  itEnd = unclonedAuxBranches_.end();
232  it != itEnd; ++it) {
233  int auxIndex = branches->IndexOf(*it);
234  assert (auxIndex >= 0);
235  auxIndexes.insert(std::make_pair(auxIndex, *it));
236  branches->RemoveAt(auxIndex);
237  mustRemoveSomeAuxs = true;
238  }
239 
240  if(mustRemoveSomeAuxs) {
241  branches->Compress();
242  }
243 
244  DuplicateTreeSentry dupTree(in);
245  TTreeCloner cloner(dupTree.tree(), tree_, option.c_str(), TTreeCloner::kNoWarnings|TTreeCloner::kIgnoreMissingTopLevel);
246 
247  if(!cloner.IsValid()) {
248  // Let's check why
249  static const char* okerror = "One of the export branch";
250  if(strncmp(cloner.GetWarning(), okerror, strlen(okerror)) == 0) {
251  // That's fine we will handle it;
252  } else {
254  << "invalid TTreeCloner (" << cloner.GetWarning() << ")\n";
255  }
256  }
257  tree_->SetEntries(tree_->GetEntries() + in->GetEntries());
258  Service<RootHandlers> rootHandler;
259  rootHandler->ignoreWarningsWhileDoing([&cloner] { cloner.Exec(); });
260 
261  if(mustRemoveSomeAuxs) {
262  for(std::map<Int_t, TBranch *>::const_iterator it = auxIndexes.begin(), itEnd = auxIndexes.end();
263  it != itEnd; ++it) {
264  // Add the auxiliary branches back after fast copying the rest of the tree.
265  Int_t last = branches->GetLast();
266  if(last >= 0) {
267  branches->AddAtAndExpand(branches->At(last), last+1);
268  for(Int_t ind = last-1; ind >= it->first; --ind) {
269  branches->AddAt(branches->At(ind), ind+1);
270  };
271  branches->AddAt(it->second, it->first);
272  } else {
273  branches->Add(it->second);
274  }
275  }
276  }
277  }
278  }
279 
280  void
282  if(tree->GetNbranches() != 0) {
283  tree->SetEntries(-1);
284  }
285  setRefCoreStreamer(true);
286  tree->AutoSave("FlushBaskets");
287  }
288 
289  void
290  RootOutputTree::fillTTree(std::vector<TBranch*> const& branches) {
291  for_all(branches, std::bind(&TBranch::Fill, std::placeholders::_1));
292  }
293 
294  void
296  writeTTree(tree_);
297  }
298 
299  void
300  RootOutputTree::maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree* tree, std::string const& option) {
301  unclonedReadBranches_.clear();
302  clonedReadBranchNames_.clear();
303  currentlyFastCloning_ = canFastClone && !readBranches_.empty();
305  fastCloneAuxBranches_ = canFastCloneAux;
306  fastCloneTTree(tree, option);
307  for(std::vector<TBranch*>::const_iterator it = readBranches_.begin(), itEnd = readBranches_.end();
308  it != itEnd; ++it) {
309  if((*it)->GetEntries() == tree_->GetEntries()) {
310  clonedReadBranchNames_.insert(std::string((*it)->GetName()));
311  } else {
312  unclonedReadBranches_.push_back(*it);
313  }
314  }
315  Service<JobReport> reportSvc;
316  reportSvc->reportFastClonedBranches(clonedReadBranchNames_, tree_->GetEntries());
317  }
318  }
319 
320  void
327  } else {
328  tree_->Fill();
329  }
330  }
331 
332  void
334  std::string const& className,
335  void const*& pProd,
336  int splitLevel,
337  int basketSize,
338  bool produced) {
339  assert(splitLevel != BranchDescription::invalidSplitLevel);
340  assert(basketSize != BranchDescription::invalidBasketSize);
341  TBranch* branch = tree_->Branch(branchName.c_str(),
342  className.c_str(),
343  &pProd,
344  basketSize,
345  splitLevel);
346  assert(branch != nullptr);
347  if(pProd != nullptr) {
348  // Delete the product that ROOT has allocated.
349  WrapperBase const* edp = static_cast<WrapperBase const *>(pProd);
350  delete edp;
351  pProd = nullptr;
352  }
353  if(produced) {
354  producedBranches_.push_back(branch);
355  } else {
356  readBranches_.push_back(branch);
357  }
358  }
359 
360  void
362  // The TFile was just closed.
363  // Just to play it safe, zero all pointers to quantities in the file.
364  auxBranches_.clear();
365  unclonedAuxBranches_.clear();
366  producedBranches_.clear();
367  readBranches_.clear();
368  unclonedReadBranches_.clear();
369  tree_ = nullptr;
370  filePtr_.reset();
371  }
372 }
std::set< std::string > clonedReadBranchNames_
void writeTree() const
static int const invalidSplitLevel
DuplicateTreeSentry(TTree *tree)
void fillTree() const
static int const invalidBasketSize
static void fillTTree(std::vector< TBranch * > const &branches)
bool checkSplitLevelsAndBasketSizes(TTree *inputTree) const
void setRefCoreStreamer(bool resetAll=false)
std::shared_ptr< TFile > filePtr_
std::vector< TBranch * > unclonedAuxBranches_
bool checkIfFastClonable(TTree *inputTree) const
BranchType
Definition: BranchType.h:11
std::vector< TBranch * > producedBranches_
std::vector< TBranch * > auxBranches_
Func for_all(ForwardSequence &s, Func f)
wrapper for std::for_each
Definition: Algorithms.h:16
std::unique_ptr< TTree > mytree_
RootOutputTree(std::shared_ptr< TFile > filePtr, BranchType const &branchType, int splitLevel, int treeMaxVirtualSize)
static TTree * assignTTree(TFile *file, TTree *tree)
void addBranch(std::string const &branchName, std::string const &className, void const *&pProd, int splitLevel, int basketSize, bool produced)
void Fill(HcalDetId &id, double val, std::vector< TH2F > &depth)
bool isAvailable() const
Definition: Service.h:46
virtual std::string const * sourceCloneCacheHint() const =0
std::vector< TBranch * > unclonedReadBranches_
bool checkEntriesInReadBranches(Long64_t expectedNumberOfEntries) const
std::string const & BranchTypeToProductTreeName(BranchType const &branchType)
Definition: BranchType.cc:103
static TTree * makeTTree(TFile *filePtr, std::string const &name, int splitLevel)
eventsetup::produce::Produce produced
Definition: ESProducts.cc:20
DuplicateTreeSentry & operator=(DuplicateTreeSentry const &)=delete
static void writeTTree(TTree *tree)
std::vector< TBranch * > readBranches_
TTree * tree() const
virtual std::string const * sourceCacheHint() const =0
volatile std::atomic< bool > shutdown_flag false
void maybeFastCloneTree(bool canFastClone, bool canFastCloneAux, TTree *tree, std::string const &option)
T get(const Candidate &c)
Definition: component.h:55
std::string className(const T &t)
Definition: ClassName.h:30
void fastCloneTTree(TTree *in, std::string const &option)
std::unique_ptr< TFile, CloseBeforeDelete > file_