RootInputFile.cc
Go to the documentation of this file.
2 // vim: set sw=2 expandtab :
3 
42 #include "canvas_root_io/Streamers/ProductIDStreamer.h"
43 #include "canvas_root_io/Utilities/DictionaryChecker.h"
44 #include "cetlib/compiler_macros.h"
46 #include "fhiclcpp/ParameterSet.h"
51 
52 #include "TBranch.h"
53 #include "TFile.h"
54 #include "TLeaf.h"
55 #include "TTree.h"
56 
57 #include <algorithm>
58 #include <iomanip>
59 #include <iostream>
60 #include <string>
61 #include <utility>
62 
63 extern "C" {
64 #include "sqlite3.h"
65 }
66 
67 using namespace cet;
68 using namespace std;
69 
70 namespace {
71 
72  bool
73  have_table(sqlite3* db, string const& table, string const& filename)
74  {
75  bool result = false;
76  sqlite3_stmt* stmt = nullptr;
77  string const ddl{
78  "select 1 from sqlite_master where type='table' and name='" + table +
79  "';"};
80  auto rc = sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt, nullptr);
81  if (rc == SQLITE_OK) {
82  switch (rc = sqlite3_step(stmt)) {
83  case SQLITE_ROW:
84  result = true; // Found the table.
86  case SQLITE_DONE:
87  rc = SQLITE_OK; // No such table.
88  break;
89  default:
90  break;
91  }
92  }
93  rc = sqlite3_finalize(stmt);
94  if (rc != SQLITE_OK) {
96  << "Unexpected status (" << rc
97  << ") when interrogating SQLite3 DB in file " << filename << ":\n"
98  << sqlite3_errmsg(db) << '\n';
99  }
100  return result;
101  }
102 
103 } // unnamed namespace
104 
105 namespace art {
106 
107  using std::swap;
108 
109  namespace detail {
110 
111  void
113  {
114  left.mergeAuxiliary(right);
115  }
116 
117  void
119  {
120  left.mergeAuxiliary(right);
121  }
122 
123  } // namespace detail
124 
125  RootInputFile::RootInputTree::~RootInputTree() {}
126 
127  RootInputFile::RootInputTree::RootInputTree(
128  cet::exempt_ptr<TFile> filePtr,
129  BranchType const branchType,
130  int64_t /*saveMemoryObjectThreshold*/,
131  cet::exempt_ptr<RootInputFile> /*primaryFile*/,
132  bool const missingOK /*=false*/)
133  {
134  if (filePtr) {
135  tree_ = static_cast<TTree*>(
136  filePtr->Get(BranchTypeToProductTreeName(branchType).c_str()));
137  metaTree_ = static_cast<TTree*>(
138  filePtr->Get(BranchTypeToMetaDataTreeName(branchType).c_str()));
139  }
140  if (tree_) {
141  auxBranch_ =
142  tree_->GetBranch(BranchTypeToAuxiliaryBranchName(branchType).c_str());
143  entries_ = tree_->GetEntries();
144  }
145  if (metaTree_) {
146  productProvenanceBranch_ =
147  metaTree_->GetBranch(productProvenanceBranchName(branchType).c_str());
148  }
149  if (!missingOK && !isValid()) {
151  << "RootInputTree for branch type " << BranchTypeToString(branchType)
152  << " could not be initialized correctly from input file.\n";
153  }
154  }
155 
156  TBranch*
157  RootInputFile::RootInputTree::auxBranch() const
158  {
159  return auxBranch_;
160  }
161 
163  RootInputFile::RootInputTree::entries() const
164  {
165  return entries_;
166  }
167 
168  TTree*
170  {
171  return tree_;
172  }
173 
174  TTree*
175  RootInputFile::RootInputTree::metaTree() const
176  {
177  return metaTree_;
178  }
179 
181  RootInputFile::RootInputTree::branches() const
182  {
183  return branches_;
184  }
185 
186  TBranch*
187  RootInputFile::RootInputTree::productProvenanceBranch() const
188  {
189  return productProvenanceBranch_;
190  }
191 
192  bool
193  RootInputFile::RootInputTree::isValid() const
194  {
195  if ((metaTree_ == nullptr) || (metaTree_->GetNbranches() == 0)) {
196  return tree_ && auxBranch_ && (tree_->GetNbranches() == 1);
197  }
198  return tree_ && auxBranch_ && metaTree_ && productProvenanceBranch_;
199  }
200 
201  void
202  RootInputFile::RootInputTree::addBranch(BranchDescription const& bd)
203  {
204  assert(isValid());
205  TBranch* branch = tree_->GetBranch(bd.branchName().c_str());
206  assert(bd.present() == (branch != nullptr));
207  assert(bd.dropped() == (branch == nullptr));
208  input::BranchInfo info{bd, branch};
209  branches_.emplace(bd.productID(), std::move(info));
210  }
211 
212  void
213  RootInputFile::RootInputTree::dropBranch(string const& branchName)
214  {
215  TBranch* branch = tree_->GetBranch(branchName.c_str());
216  if (branch == nullptr) {
217  return;
218  }
219  TObjArray* leaves = tree_->GetListOfLeaves();
220  if (leaves == nullptr) {
221  return;
222  }
223  int entries = leaves->GetEntries();
224  for (int i = 0; i < entries; ++i) {
225  TLeaf* leaf = reinterpret_cast<TLeaf*>((*leaves)[i]);
226  if (leaf == nullptr) {
227  continue;
228  }
229  TBranch* br = leaf->GetBranch();
230  if (br == nullptr) {
231  continue;
232  }
233  if (br->GetMother() == branch) {
234  leaves->Remove(leaf);
235  }
236  }
237  leaves->Compress();
238  tree_->GetListOfBranches()->Remove(branch);
239  tree_->GetListOfBranches()->Compress();
240  delete branch;
241  branch = nullptr;
242  }
243 
244  RootInputFile::~RootInputFile() {}
245 
246  RootInputFile::RootInputFile(string const& fileName,
247  string const& catalogName,
248  ProcessConfiguration const& processConfiguration,
249  string const& logicalFileName,
250  unique_ptr<TFile>&& filePtr,
251  EventID const& origEventID,
252  unsigned int eventsToSkip,
253  bool const compactSubRunRanges,
254  FastCloningInfoProvider const& fcip,
255  unsigned int treeCacheSize,
256  int64_t treeMaxVirtualSize,
257  int64_t saveMemoryObjectThreshold,
258  bool delayedReadEventProducts,
259  bool delayedReadSubRunProducts,
260  bool delayedReadRunProducts,
261  InputSource::ProcessingMode processingMode,
262  int forcedRunOffset,
263  bool noEventSort,
264  GroupSelectorRules const& groupSelectorRules,
265  shared_ptr<DuplicateChecker> duplicateChecker,
266  bool dropDescendants,
267  bool const readIncomingParameterSets,
268  exempt_ptr<RootInputFile> primaryFile,
269  vector<string> const& secondaryFileNames,
270  RootInputFileSequence* rifSequence,
271  UpdateOutputCallbacks& outputCallbacks)
272  : fileName_{fileName}
273  , catalog_{catalogName}
274  , processConfiguration_{processConfiguration}
275  , logicalFileName_{logicalFileName}
276  , filePtr_{move(filePtr)}
277  , origEventID_{origEventID}
278  , eventsToSkip_{eventsToSkip}
279  , compactSubRunRanges_{compactSubRunRanges}
280  , treePointers_{{make_unique<RootInputTree>(filePtr_.get(),
281  InEvent,
282  saveMemoryObjectThreshold,
283  this,
284  false),
285  make_unique<RootInputTree>(filePtr_.get(),
286  InSubRun,
287  saveMemoryObjectThreshold,
288  this,
289  false),
290  make_unique<RootInputTree>(filePtr_.get(),
291  InRun,
292  saveMemoryObjectThreshold,
293  this,
294  false),
295  make_unique<RootInputTree>(filePtr_.get(),
296  InResults,
297  saveMemoryObjectThreshold,
298  this,
299  true)}}
300  , delayedReadEventProducts_{delayedReadEventProducts}
301  , delayedReadSubRunProducts_{delayedReadSubRunProducts}
302  , delayedReadRunProducts_{delayedReadRunProducts}
303  , processingMode_{processingMode}
304  , forcedRunOffset_{forcedRunOffset}
305  , noEventSort_{noEventSort}
306  , duplicateChecker_{duplicateChecker}
307  , primaryFile_{primaryFile ? primaryFile : this}
308  , secondaryFileNames_{secondaryFileNames}
309  , rifSequence_{rifSequence}
310  , saveMemoryObjectThreshold_{saveMemoryObjectThreshold}
311  {
312  secondaryFiles_.resize(secondaryFileNames_.size());
313  if (treeMaxVirtualSize >= 0) {
314  eventTree().tree()->SetMaxVirtualSize(
315  static_cast<Long64_t>(treeMaxVirtualSize));
316  }
317  if (treeMaxVirtualSize >= 0) {
318  subRunTree().tree()->SetMaxVirtualSize(
319  static_cast<Long64_t>(treeMaxVirtualSize));
320  }
321  if (treeMaxVirtualSize >= 0) {
322  runTree().tree()->SetMaxVirtualSize(
323  static_cast<Long64_t>(treeMaxVirtualSize));
324  }
325  eventTree().tree()->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
326  subRunTree().tree()->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
327  runTree().tree()->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
328  if (resultsTree().isValid()) {
329  if (treeMaxVirtualSize >= 0) {
330  resultsTree().tree()->SetMaxVirtualSize(
331  static_cast<Long64_t>(treeMaxVirtualSize));
332  }
333  resultsTree().tree()->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
334  }
335  // Retrieve the metadata tree.
336  auto metaDataTree =
337  static_cast<TTree*>(filePtr_->Get(rootNames::metaDataTreeName().c_str()));
338  if (!metaDataTree) {
341  }
342  metaDataTree->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
343  using namespace art::rootNames;
344  fileFormatVersion_ = detail::readMetadata<FileFormatVersion>(metaDataTree);
345  // Read file index
346  auto findexPtr = &fileIndex_;
347  detail::readFileIndex(filePtr_.get(), metaDataTree, findexPtr);
348  // To support files that contain BranchIDLists
349  BranchIDLists branchIDLists;
350  if (detail::readMetadata(metaDataTree, branchIDLists)) {
351  branchIDLists_ = make_unique<BranchIDLists>(move(branchIDLists));
352  configureProductIDStreamer(branchIDLists_.get());
353  }
354  // Read the ParameterSets if there are any on a branch.
355  {
356  ParameterSetMap psetMap;
357  if (readIncomingParameterSets &&
358  detail::readMetadata(metaDataTree, psetMap)) {
359  // Merge into the hashed registries.
360  for (auto const& psEntry : psetMap) {
361  fhicl::ParameterSet pset;
362  fhicl::make_ParameterSet(psEntry.second.pset_, pset);
363  // Note ParameterSet::id() has the side effect of making
364  // sure the parameter set *has* an ID.
365  pset.id();
367  }
368  }
369  }
370  // Read the ProcessHistory
371  {
372  auto pHistMap = detail::readMetadata<ProcessHistoryMap>(metaDataTree);
373  ProcessHistoryRegistry::put(pHistMap);
374  }
375  // Check the, "Era" of the input file (new since art v0.5.0). If it
376  // does not match what we expect we cannot read the file. Required
377  // since we reset the file versioning since forking off from
378  // CMS. Files written by art prior to v0.5.0 will *also* not be
379  // readable because they do not have this datum and because the run,
380  // subrun and event-number handling has changed significantly.
381  string const& expected_era = art::getFileFormatEra();
382  if (fileFormatVersion_.era_ != expected_era) {
384  << "Can only read files written during the \"" << expected_era
385  << "\" era: "
386  << "Era of "
387  << "\"" << fileName_ << "\" was "
388  << (fileFormatVersion_.era_.empty() ?
389  "not set" :
390  ("set to \"" + fileFormatVersion_.era_ + "\" "))
391  << ".\n";
392  }
393  // Also need to check RootFileDB if we have one.
394  if (fileFormatVersion_.value_ >= 5) {
395  sqliteDB_.reset(
397  "RootFileDB", filePtr_.get()));
398  if (readIncomingParameterSets &&
399  have_table(*sqliteDB_, "ParameterSets", fileName_)) {
401  }
402  if (ServiceRegistry::isAvailable<art::FileCatalogMetadata>() &&
403  have_table(*sqliteDB_, "FileCatalog_metadata", fileName_)) {
404  sqlite3_stmt* stmt{nullptr};
405  sqlite3_prepare_v2(*sqliteDB_,
406  "SELECT Name, Value from FileCatalog_metadata;",
407  -1,
408  &stmt,
409  nullptr);
410  vector<pair<string, string>> md;
411  while (sqlite3_step(stmt) == SQLITE_ROW) {
412  string const name{
413  reinterpret_cast<char const*>(sqlite3_column_text(stmt, 0))};
414  string const value{
415  reinterpret_cast<char const*>(sqlite3_column_text(stmt, 1))};
416  md.emplace_back(name, value);
417  }
418  int const finalize_status = sqlite3_finalize(stmt);
419  if (finalize_status != SQLITE_OK) {
421  << "Unexpected status (" << finalize_status
422  << ") from DB status cleanup:\n"
423  << sqlite3_errmsg(*sqliteDB_) << '\n';
424  }
426  ->setMetadataFromInput(md);
427  }
428  }
429  validateFile();
430  // Read the parentage tree. Old format files are handled
431  // internally in readParentageTree().
432  readParentageTree(treeCacheSize);
433  initializeDuplicateChecker();
434  if (noEventSort_) {
435  fileIndex_.sortBy_Run_SubRun_EventEntry();
436  }
437  fiIter_ = fileIndex_.begin();
438  fiBegin_ = fileIndex_.begin();
439  fiEnd_ = fileIndex_.end();
440  readEventHistoryTree(treeCacheSize);
441 
442  // Read the ProductList
443  // -- The 'false' value signifies that we do not check for a
444  // dictionary here. The reason is that the BranchDescription
445  // class has an enumeration data member, and current checking
446  // for enum dictionaries is problematic.
447  auto productList =
448  detail::readMetadata<ProductRegistry>(metaDataTree, false).productList_;
449 
450  // Create product table for present products
451  auto const& descriptions = make_product_descriptions(productList);
452  presentProducts_ = ProductTables{descriptions};
453  dropOnInput(groupSelectorRules, dropDescendants, presentProducts_);
454 
455  // Adjust validity of BranchDescription objects: if the branch
456  // does not exist in the input file, but its BranchDescription is
457  // still persisted to disk (and read here), the product must be
458  // marked as "dropped". See notes in RootOutputFile.cc
459  // (particularly for branchesWithStoredHistory_ insertion) to see
460  // how this can happen. We then add the branch to the tree using
461  // the updated validity of the product.
462  auto set_validity_then_add_branch = [this](BranchType const bt) {
463  for (auto& prod : presentProducts_.get(bt).descriptions) {
464  auto& pd = prod.second;
465  if (treePointers_[bt]->tree()->GetBranch(pd.branchName().c_str()) ==
466  nullptr) {
467  pd.setValidity(BranchDescription::Transients::Dropped);
468  }
469  treePointers_[bt]->addBranch(pd);
470  }
471  };
472  for_each_branch_type(set_validity_then_add_branch);
473 
474  // Invoke output callbacks with adjusted BranchDescription
475  // validity values.
476  outputCallbacks.invoke(presentProducts_);
477 
478  // Determine if this file is fast clonable.
479  fastClonable_ = setIfFastClonable(fcip);
480  reportOpened();
481 
482  // Check if dictionaries exist for the auxiliary objects
483  root::DictionaryChecker checker{};
484  checker.checkDictionaries<EventAuxiliary>();
485  checker.checkDictionaries<SubRunAuxiliary>();
486  checker.checkDictionaries<RunAuxiliary>();
487  checker.checkDictionaries<ResultsAuxiliary>();
488  checker.reportMissingDictionaries();
489 
490  // FIXME: This probably is unnecessary!
491  configureProductIDStreamer();
492  }
493 
494  bool
495  RootInputFile::setEntry_Event(EventID const& id, bool exact /*= true*/)
496  {
497  fiIter_ = fileIndex_.findPosition(id, exact);
498  if (fiIter_ == fiEnd_) {
499  return false;
500  }
501  return true;
502  }
503 
504  bool
505  RootInputFile::setEntry_SubRun(SubRunID const& id, bool exact /*= true*/)
506  {
507  fiIter_ = fileIndex_.findPosition(id, exact);
508  if (fiIter_ == fiEnd_) {
509  return false;
510  }
511  return true;
512  }
513 
514  bool
515  RootInputFile::setEntry_Run(RunID const& id, bool exact /*= true*/)
516  {
517  fiIter_ = fileIndex_.findPosition(id, exact);
518  if (fiIter_ == fiEnd_) {
519  return false;
520  }
521  return true;
522  }
523 
525  RootInputFile::eventTree() const
526  {
527  return *treePointers_[InEvent];
528  }
529 
531  RootInputFile::subRunTree() const
532  {
533  return *treePointers_[InSubRun];
534  }
535 
537  RootInputFile::runTree() const
538  {
539  return *treePointers_[InRun];
540  }
541 
543  RootInputFile::resultsTree() const
544  {
545  return *treePointers_[InResults];
546  }
547 
549  RootInputFile::eventTree()
550  {
551  return *treePointers_[InEvent];
552  }
553 
555  RootInputFile::subRunTree()
556  {
557  return *treePointers_[InSubRun];
558  }
559 
561  RootInputFile::runTree()
562  {
563  return *treePointers_[InRun];
564  }
565 
567  RootInputFile::resultsTree()
568  {
569  return *treePointers_[InResults];
570  }
571 
572  void
573  RootInputFile::fillAuxiliary_Event(EntryNumber const entry)
574  {
575  auto auxbr = treePointers_[InEvent]->auxBranch();
576  auto pAux = &eventAux_;
577  auxbr->SetAddress(&pAux);
578  input::getEntry(auxbr, entry);
579  }
580 
581  void
582  RootInputFile::fillAuxiliary_SubRun(EntryNumber const entry)
583  {
584  auto auxbr = treePointers_[InSubRun]->auxBranch();
585  auto pAux = &subRunAux_;
586  auxbr->SetAddress(&pAux);
587  input::getEntry(auxbr, entry);
588  }
589 
590  void
591  RootInputFile::fillAuxiliary_Run(EntryNumber const entry)
592  {
593  auto auxbr = treePointers_[InRun]->auxBranch();
594  auto pAux = &runAux_;
595  auxbr->SetAddress(&pAux);
596  input::getEntry(auxbr, entry);
597  }
598 
599  void
600  RootInputFile::fillAuxiliary_Results(EntryNumber const entry)
601  {
602  auto auxbr = treePointers_[InResults]->auxBranch();
603  auto pAux = &resultsAux_;
604  auxbr->SetAddress(&pAux);
605  input::getEntry(auxbr, entry);
606  }
607 
608  unique_ptr<RangeSetHandler>
609  RootInputFile::fillAuxiliary_SubRun(EntryNumbers const& entries)
610  {
611  SubRunAuxiliary auxResult{};
612  {
613  auto auxbr = treePointers_[InSubRun]->auxBranch();
614  auto pAux = &auxResult;
615  auxbr->SetAddress(&pAux);
616  input::getEntry(auxbr, entries[0]);
617  }
618  if (fileFormatVersion_.value_ < 9) {
619  swap(subRunAux_, auxResult);
620  return make_unique<OpenRangeSetHandler>(subRunAux_.run());
621  }
622  auto resolve_info = [this](auto const id) {
623  return detail::resolveRangeSetInfo(*sqliteDB_,
624  this->fileName_,
625  SubRunAuxiliary::branch_type,
626  id,
627  compactSubRunRanges_);
628  };
629  auto rangeSetInfo = resolve_info(auxResult.rangeSetID());
630  for (auto i = entries.cbegin() + 1, e = entries.cend(); i != e; ++i) {
631  SubRunAuxiliary tmpAux{};
632  {
633  auto auxbr = treePointers_[InSubRun]->auxBranch();
634  auto pAux = &tmpAux;
635  auxbr->SetAddress(&pAux);
636  input::getEntry(auxbr, *i);
637  }
638  detail::mergeAuxiliary(auxResult, tmpAux);
639  rangeSetInfo.update(resolve_info(tmpAux.rangeSetID()),
640  compactSubRunRanges_);
641  }
642  auxResult.setRangeSetID(-1u); // Range set of new auxiliary is invalid
643  swap(subRunAux_, auxResult);
644  return make_unique<ClosedRangeSetHandler>(resolveRangeSet(rangeSetInfo));
645  }
646 
647  unique_ptr<RangeSetHandler>
648  RootInputFile::fillAuxiliary_Run(EntryNumbers const& entries)
649  {
650  RunAuxiliary auxResult{};
651  {
652  auto auxbr = treePointers_[InRun]->auxBranch();
653  auto pAux = &auxResult;
654  auxbr->SetAddress(&pAux);
655  input::getEntry(auxbr, entries[0]);
656  }
657  if (fileFormatVersion_.value_ < 9) {
658  swap(runAux_, auxResult);
659  return make_unique<OpenRangeSetHandler>(runAux_.run());
660  }
661  auto resolve_info = [this](auto const id) {
662  return detail::resolveRangeSetInfo(*sqliteDB_,
663  this->fileName_,
664  RunAuxiliary::branch_type,
665  id,
666  compactSubRunRanges_);
667  };
668  auto rangeSetInfo = resolve_info(auxResult.rangeSetID());
669  for (auto i = entries.cbegin() + 1, e = entries.cend(); i != e; ++i) {
670  RunAuxiliary tmpAux{};
671  {
672  auto auxbr = treePointers_[InRun]->auxBranch();
673  auto pAux = &tmpAux;
674  auxbr->SetAddress(&pAux);
675  input::getEntry(auxbr, *i);
676  }
677  detail::mergeAuxiliary(auxResult, tmpAux);
678  rangeSetInfo.update(resolve_info(tmpAux.rangeSetID()),
679  compactSubRunRanges_);
680  }
681  auxResult.setRangeSetID(-1u); // Range set of new auxiliary is invalid
682  swap(runAux_, auxResult);
683  return make_unique<ClosedRangeSetHandler>(resolveRangeSet(rangeSetInfo));
684  }
685 
686  string const&
687  RootInputFile::fileName() const
688  {
689  return fileName_;
690  }
691 
693  RootInputFile::treePointers()
694  {
695  return treePointers_;
696  }
697 
699  RootInputFile::fileFormatVersion() const
700  {
701  return fileFormatVersion_;
702  }
703 
704  bool
705  RootInputFile::fastClonable() const
706  {
707  return fastClonable_;
708  }
709 
710  void
711  RootInputFile::rewind()
712  {
713  fiIter_ = fiBegin_;
714  // FIXME: Rewinding the trees is suspicious!
715  // FIXME: They should be positioned based on the new iter pos.
716  // eventTree().rewind();
717  // subRunTree().rewind();
718  // runTree().rewind();
719  }
720 
721  void
722  RootInputFile::setToLastEntry()
723  {
724  fiIter_ = fiEnd_;
725  }
726 
727  void
728  RootInputFile::nextEntry()
729  {
730  ++fiIter_;
731  }
732 
733  void
734  RootInputFile::previousEntry()
735  {
736  --fiIter_;
737  }
738 
739  void
740  RootInputFile::advanceEntry(size_t n)
741  {
742  while (n-- != 0) {
743  nextEntry();
744  }
745  }
746 
747  unsigned int
748  RootInputFile::eventsToSkip() const
749  {
750  return eventsToSkip_;
751  }
752 
753  shared_ptr<FileIndex>
754  RootInputFile::fileIndexSharedPtr() const
755  {
756  return fileIndexSharedPtr_;
757  }
758 
759  vector<string> const&
760  RootInputFile::secondaryFileNames() const
761  {
762  return secondaryFileNames_;
763  }
764 
765  vector<unique_ptr<RootInputFile>> const&
766  RootInputFile::secondaryFiles() const
767  {
768  return secondaryFiles_;
769  }
770 
771  void
772  RootInputFile::readParentageTree(unsigned int const treeCacheSize)
773  {
774  //
775  // Auxiliary routine for the constructor.
776  //
777  auto parentageTree = static_cast<TTree*>(
778  filePtr_->Get(rootNames::parentageTreeName().c_str()));
779  if (!parentageTree) {
782  }
783  parentageTree->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
784  auto idBuffer = root::getObjectRequireDict<ParentageID>();
785  auto pidBuffer = &idBuffer;
786  parentageTree->SetBranchAddress(rootNames::parentageIDBranchName().c_str(),
787  &pidBuffer);
788 
789  auto parentageBuffer = root::getObjectRequireDict<Parentage>();
790  auto pParentageBuffer = &parentageBuffer;
791  parentageTree->SetBranchAddress(rootNames::parentageBranchName().c_str(),
792  &pParentageBuffer);
793 
794  // Fill the registry
795  for (EntryNumber i = 0, numEntries = parentageTree->GetEntries();
796  i < numEntries;
797  ++i) {
798  input::getEntry(parentageTree, i);
799  if (idBuffer != parentageBuffer.id()) {
801  << "Corruption of Parentage tree detected.\n";
802  }
803  ParentageRegistry::emplace(parentageBuffer.id(), parentageBuffer);
804  }
805 
806  parentageTree->SetBranchAddress(rootNames::parentageIDBranchName().c_str(),
807  nullptr);
808  parentageTree->SetBranchAddress(rootNames::parentageBranchName().c_str(),
809  nullptr);
810  }
811 
812  EventID
813  RootInputFile::eventIDForFileIndexPosition() const
814  {
815  if (fiIter_ == fiEnd_) {
816  return EventID{};
817  }
818  return fiIter_->eventID_;
819  }
820 
821  bool
822  RootInputFile::setIfFastClonable(FastCloningInfoProvider const& fcip) const
823  {
824  if (!fcip.fastCloningPermitted()) {
825  return false;
826  }
827  if (secondaryFileNames_.size() != 0) {
828  return false;
829  }
830  if (!fileIndex_.allEventsInEntryOrder()) {
831  return false;
832  }
833  if (eventsToSkip_ != 0) {
834  return false;
835  }
836  if ((fcip.remainingEvents() >= 0) &&
837  (eventTree().entries() > fcip.remainingEvents())) {
838  return false;
839  }
840  if ((fcip.remainingSubRuns() >= 0) &&
841  (subRunTree().entries() > fcip.remainingSubRuns())) {
842  return false;
843  }
844  if (processingMode_ != InputSource::RunsSubRunsAndEvents) {
845  return false;
846  }
847  if (forcedRunOffset_ != 0) {
848  return false;
849  }
850  // Find entry for first event in file.
851  auto it = fiBegin_;
852  while ((it != fiEnd_) && (it->getEntryType() != FileIndex::kEvent)) {
853  ++it;
854  }
855  if (it == fiEnd_) {
856  return false;
857  }
858  if (it->eventID_ < origEventID_) {
859  return false;
860  }
861  return true;
862  }
863 
864  int
865  RootInputFile::setForcedRunOffset(RunNumber_t const& forcedRunNumber)
866  {
867  if (fiBegin_ == fiEnd_) {
868  return 0;
869  }
870  forcedRunOffset_ = 0;
871  if (!RunID(forcedRunNumber).isValid()) {
872  return 0;
873  }
874  forcedRunOffset_ = forcedRunNumber - fiBegin_->eventID_.run();
875  if (forcedRunOffset_ != 0) {
876  fastClonable_ = false;
877  }
878  return forcedRunOffset_;
879  }
880 
881  unique_ptr<FileBlock>
882  RootInputFile::createFileBlock()
883  {
884  return std::make_unique<RootFileBlock>(
885  fileFormatVersion_,
886  fileName_,
887  readResults(),
888  cet::make_exempt_ptr(eventTree().tree()),
889  fastClonable());
890  }
891 
893  RootInputFile::getEntryType() const
894  {
895  if (fiIter_ == fiEnd_) {
896  return FileIndex::kEnd;
897  }
898  return fiIter_->getEntryType();
899  }
900 
902  RootInputFile::getNextEntryTypeWanted()
903  {
904  auto entryType = getEntryType();
905  if (entryType == FileIndex::kEnd) {
906  return FileIndex::kEnd;
907  }
908  RunID currentRun(fiIter_->eventID_.runID());
909  if (!currentRun.isValid()) {
910  return FileIndex::kEnd;
911  }
912  if (entryType == FileIndex::kRun) {
913  // Skip any runs before the first run specified
914  if (currentRun < origEventID_.runID()) {
915  fiIter_ = fileIndex_.findPosition(origEventID_.runID(), false);
916  return getNextEntryTypeWanted();
917  }
918  return FileIndex::kRun;
919  }
920  if (processingMode_ == InputSource::Runs) {
921  fiIter_ = fileIndex_.findPosition(
922  currentRun.isValid() ? currentRun.next() : currentRun, false);
923  return getNextEntryTypeWanted();
924  }
925  SubRunID const& currentSubRun = fiIter_->eventID_.subRunID();
926  if (entryType == FileIndex::kSubRun) {
927  // Skip any subRuns before the first subRun specified
928  if ((currentRun == origEventID_.runID()) &&
929  (currentSubRun < origEventID_.subRunID())) {
930  fiIter_ = fileIndex_.findSubRunOrRunPosition(origEventID_.subRunID());
931  return getNextEntryTypeWanted();
932  }
933  return FileIndex::kSubRun;
934  }
935  if (processingMode_ == InputSource::RunsAndSubRuns) {
936  fiIter_ = fileIndex_.findSubRunOrRunPosition(currentSubRun.next());
937  return getNextEntryTypeWanted();
938  }
939  assert(entryType == FileIndex::kEvent);
940  // Skip any events before the first event specified
941  if (fiIter_->eventID_ < origEventID_) {
942  fiIter_ = fileIndex_.findPosition(origEventID_);
943  return getNextEntryTypeWanted();
944  }
945  if (duplicateChecker_.get() && duplicateChecker_->isDuplicateAndCheckActive(
946  fiIter_->eventID_, fileName_)) {
947  nextEntry();
948  return getNextEntryTypeWanted();
949  }
950  if (eventsToSkip_ == 0) {
951  return FileIndex::kEvent;
952  }
953  // We have specified a count of events to skip, keep skipping
954  // events in this subRun block until we reach the end of the
955  // subRun block or the full count of the number of events to skip.
956  while ((eventsToSkip_ != 0) && (fiIter_ != fiEnd_) &&
957  (getEntryType() == FileIndex::kEvent)) {
958  nextEntry();
959  --eventsToSkip_;
960  while ((eventsToSkip_ != 0) && (fiIter_ != fiEnd_) &&
961  (fiIter_->getEntryType() == FileIndex::kEvent) &&
962  duplicateChecker_.get() &&
963  duplicateChecker_->isDuplicateAndCheckActive(fiIter_->eventID_,
964  fileName_)) {
965  nextEntry();
966  }
967  }
968  return getNextEntryTypeWanted();
969  }
970 
971  void
972  RootInputFile::validateFile()
973  {
974  if (!fileFormatVersion_.isValid()) {
975  fileFormatVersion_.value_ = 0;
976  }
977  if (!eventTree().isValid()) {
979  << "'Events' tree is corrupted or not present\n"
980  << "in the input file.\n";
981  }
982  if (fileIndex_.empty()) {
984  << "FileIndex information is missing for the input file.\n";
985  }
986  }
987 
988  void
989  RootInputFile::reportOpened()
990  {}
991 
992  void
993  RootInputFile::close(bool reallyClose)
994  {
995  if (!reallyClose) {
996  return;
997  }
998  filePtr_->Close();
999  for (auto const& sf : secondaryFiles_) {
1000  if (!sf) {
1001  continue;
1002  }
1003  sf->filePtr_->Close();
1004  }
1005  }
1006 
1007  void
1008  RootInputFile::fillHistory(EntryNumber const entry, History& history)
1009  {
1010  // We could consider doing delayed reading, but because we have to
1011  // store this History object in a different tree than the event
1012  // data tree, this is too hard to do in this first version.
1013  auto pHistory = &history;
1014  auto eventHistoryBranch =
1015  eventHistoryTree_->GetBranch(rootNames::eventHistoryBranchName().c_str());
1016  if (!eventHistoryBranch) {
1018  << "Failed to find history branch in event history tree.\n";
1019  }
1020  eventHistoryBranch->SetAddress(&pHistory);
1021  input::getEntry(eventHistoryTree_, entry);
1022  }
1023 
1024  int
1025  RootInputFile::skipEvents(int offset)
1026  {
1027  while ((offset > 0) && (fiIter_ != fiEnd_)) {
1028  if (fiIter_->getEntryType() == FileIndex::kEvent) {
1029  --offset;
1030  }
1031  nextEntry();
1032  }
1033  while ((offset < 0) && (fiIter_ != fiBegin_)) {
1034  previousEntry();
1035  if (fiIter_->getEntryType() == FileIndex::kEvent) {
1036  ++offset;
1037  }
1038  }
1039  while ((fiIter_ != fiEnd_) &&
1040  (fiIter_->getEntryType() != FileIndex::kEvent)) {
1041  nextEntry();
1042  }
1043  return offset;
1044  }
1045 
1046  // readEvent() is responsible for creating, and setting up, the
1047  // EventPrincipal.
1048  //
1049  // 1. create an EventPrincipal with a unique EventID
1050  // 2. For each entry in the provenance, put in one Group,
1051  // holding the Provenance for the corresponding EDProduct.
1052  // 3. set up the caches in the EventPrincipal to know about this
1053  // Group.
1054  //
1055  // We do *not* create the EDProduct instance (the equivalent of
1056  // reading the branch containing this EDProduct). That will be done
1057  // by the Delayed Reader, when it is asked to do so.
1058  //
1059  unique_ptr<EventPrincipal>
1060  RootInputFile::readEvent()
1061  {
1062  assert(fiIter_ != fiEnd_);
1063  assert(fiIter_->getEntryType() == FileIndex::kEvent);
1064  assert(fiIter_->eventID_.runID().isValid());
1065  auto const& entryNumbers = getEntryNumbers(InEvent);
1066  auto ep = readCurrentEvent(entryNumbers);
1067  assert(ep);
1068  assert(eventAux_.run() == fiIter_->eventID_.run() + forcedRunOffset_);
1069  assert(eventAux_.subRunID() == fiIter_->eventID_.subRunID());
1070  nextEntry();
1071  return ep;
1072  }
1073 
1074  // Reads event at the current entry in the tree.
1075  // Note: This function neither uses nor sets fiIter_.
1076  unique_ptr<EventPrincipal>
1077  RootInputFile::readCurrentEvent(pair<EntryNumbers, bool> const& entryNumbers)
1078  {
1079  assert(entryNumbers.first.size() == 1ull);
1080  fillAuxiliary_Event(entryNumbers.first.front());
1081  assert(eventAux_.eventID() == fiIter_->eventID_);
1082  unique_ptr<History> history = make_unique<History>();
1083  fillHistory(entryNumbers.first.front(), *history);
1084  overrideRunNumber(const_cast<EventID&>(eventAux_.eventID()),
1085  eventAux_.isRealData());
1086  auto ep = make_unique<EventPrincipal>(
1087  eventAux_,
1088  processConfiguration_,
1089  &presentProducts_.get(InEvent),
1090  move(history),
1091  make_unique<RootDelayedReader>(fileFormatVersion_,
1092  nullptr,
1093  entryNumbers.first,
1094  &eventTree().branches(),
1095  eventTree().productProvenanceBranch(),
1096  saveMemoryObjectThreshold_,
1097  this,
1098  branchIDLists_.get(),
1099  InEvent,
1100  eventAux_.eventID(),
1101  compactSubRunRanges_),
1102  entryNumbers.second);
1103  if (!delayedReadEventProducts_) {
1104  ep->readImmediate();
1105  }
1106  primaryEP_ = make_exempt_ptr(ep.get());
1107  return ep;
1108  }
1109 
1110  bool
1111  RootInputFile::readEventForSecondaryFile(EventID eID)
1112  {
1113  // Used just after opening a new secondary file in response to a
1114  // failed product lookup. Synchronize the file index to the event
1115  // needed and create a secondary EventPrincipal for it.
1116  if (!setEntry_Event(eID, /*exact=*/true)) {
1117  // Error, could not find specified event in file.
1118  return false;
1119  }
1120  auto const& entryNumbers = getEntryNumbers(InEvent);
1121  assert(entryNumbers.first.size() == 1ull);
1122  fillAuxiliary_Event(entryNumbers.first.front());
1123  unique_ptr<History> history = make_unique<History>();
1124  fillHistory(entryNumbers.first.front(), *history);
1125  overrideRunNumber(const_cast<EventID&>(eventAux_.eventID()),
1126  eventAux_.isRealData());
1127  auto ep = make_unique<EventPrincipal>(
1128  eventAux_,
1129  processConfiguration_,
1130  &presentProducts_.get(InEvent),
1131  move(history),
1132  make_unique<RootDelayedReader>(fileFormatVersion_,
1133  nullptr,
1134  entryNumbers.first,
1135  &eventTree().branches(),
1136  eventTree().productProvenanceBranch(),
1137  saveMemoryObjectThreshold_,
1138  this,
1139  branchIDLists_.get(),
1140  InEvent,
1141  eventAux_.eventID(),
1142  compactSubRunRanges_),
1143  entryNumbers.second);
1144  primaryFile_->primaryEP_->addSecondaryPrincipal(move(ep));
1145  return true;
1146  }
1147 
1148  unique_ptr<RangeSetHandler>
1149  RootInputFile::runRangeSetHandler()
1150  {
1151  return move(runRangeSetHandler_);
1152  }
1153 
1154  unique_ptr<RunPrincipal>
1155  RootInputFile::readRun()
1156  {
1157  assert(fiIter_ != fiEnd_);
1158  assert(fiIter_->getEntryType() == FileIndex::kRun);
1159  assert(fiIter_->eventID_.runID().isValid());
1160  auto const& entryNumbers = getEntryNumbers(InRun).first;
1161  auto rp = readCurrentRun(entryNumbers);
1162  advanceEntry(entryNumbers.size());
1163  return rp;
1164  }
1165 
1166  unique_ptr<RunPrincipal>
1167  RootInputFile::readCurrentRun(EntryNumbers const& entryNumbers)
1168  {
1169  runRangeSetHandler_ = fillAuxiliary_Run(entryNumbers);
1170  assert(runAux_.runID() == fiIter_->eventID_.runID());
1171  overrideRunNumber(runAux_);
1172  if (runAux_.beginTime() == Timestamp::invalidTimestamp()) {
1173  runAux_.beginTime(eventAux_.time());
1174  runAux_.endTime(Timestamp::invalidTimestamp());
1175  }
1176  auto rp = make_unique<RunPrincipal>(
1177  runAux_,
1178  processConfiguration_,
1179  &presentProducts_.get(InRun),
1180  make_unique<RootDelayedReader>(fileFormatVersion_,
1181  *sqliteDB_,
1182  entryNumbers,
1183  &runTree().branches(),
1184  runTree().productProvenanceBranch(),
1185  saveMemoryObjectThreshold_,
1186  this,
1187  nullptr,
1188  InRun,
1189  fiIter_->eventID_,
1190  compactSubRunRanges_));
1191  if (!delayedReadRunProducts_) {
1192  rp->readImmediate();
1193  }
1194  primaryRP_ = make_exempt_ptr(rp.get());
1195  return rp;
1196  }
1197 
1198  bool
1199  RootInputFile::readRunForSecondaryFile(RunID rID)
1200  {
1201  // Used just after opening a new secondary file in response to a failed
1202  // product lookup. Synchronize the file index to the run needed and
1203  // create a secondary RunPrincipal for it.
1204  if (!setEntry_Run(rID)) {
1205  // Error, could not find specified run in file.
1206  return false;
1207  }
1208  auto const& entryNumbers = getEntryNumbers(InRun).first;
1209  assert(fiIter_ != fiEnd_);
1210  assert(fiIter_->getEntryType() == FileIndex::kRun);
1211  assert(fiIter_->eventID_.runID().isValid());
1212  runRangeSetHandler_ = fillAuxiliary_Run(entryNumbers);
1213  assert(runAux_.runID() == fiIter_->eventID_.runID());
1214  overrideRunNumber(runAux_);
1215  if (runAux_.beginTime() == Timestamp::invalidTimestamp()) {
1216  runAux_.beginTime(eventAux_.time());
1217  runAux_.endTime(Timestamp::invalidTimestamp());
1218  }
1219  auto rp = make_unique<RunPrincipal>(
1220  runAux_,
1221  processConfiguration_,
1222  &presentProducts_.get(InRun),
1223  make_unique<RootDelayedReader>(fileFormatVersion_,
1224  *sqliteDB_,
1225  entryNumbers,
1226  &runTree().branches(),
1227  runTree().productProvenanceBranch(),
1228  saveMemoryObjectThreshold_,
1229  this,
1230  nullptr,
1231  InRun,
1232  fiIter_->eventID_,
1233  compactSubRunRanges_));
1234  if (!delayedReadRunProducts_) {
1235  rp->readImmediate();
1236  }
1237  primaryFile_->primaryRP_->addSecondaryPrincipal(move(rp));
1238  return true;
1239  }
1240 
1241  unique_ptr<RangeSetHandler>
1242  RootInputFile::subRunRangeSetHandler()
1243  {
1244  return move(subRunRangeSetHandler_);
1245  }
1246 
1247  unique_ptr<SubRunPrincipal>
1248  RootInputFile::readSubRun(cet::exempt_ptr<RunPrincipal const> rp)
1249  {
1250  assert(fiIter_ != fiEnd_);
1251  assert(fiIter_->getEntryType() == FileIndex::kSubRun);
1252  auto const& entryNumbers = getEntryNumbers(InSubRun).first;
1253  auto srp = readCurrentSubRun(entryNumbers, rp);
1254  advanceEntry(entryNumbers.size());
1255  return srp;
1256  }
1257 
1258  unique_ptr<SubRunPrincipal>
1259  RootInputFile::readCurrentSubRun(
1260  EntryNumbers const& entryNumbers,
1261  cet::exempt_ptr<RunPrincipal const> rp[[gnu::unused]])
1262  {
1263  subRunRangeSetHandler_ = fillAuxiliary_SubRun(entryNumbers);
1264  assert(subRunAux_.subRunID() == fiIter_->eventID_.subRunID());
1265  overrideRunNumber(subRunAux_.id_);
1266  assert(subRunAux_.runID() == rp->runID());
1267  if (subRunAux_.beginTime() == Timestamp::invalidTimestamp()) {
1268  subRunAux_.beginTime_ = eventAux_.time();
1269  subRunAux_.endTime_ = Timestamp::invalidTimestamp();
1270  }
1271  auto srp = make_unique<SubRunPrincipal>(
1272  subRunAux_,
1273  processConfiguration_,
1274  &presentProducts_.get(InSubRun),
1275  make_unique<RootDelayedReader>(fileFormatVersion_,
1276  *sqliteDB_,
1277  entryNumbers,
1278  &subRunTree().branches(),
1279  subRunTree().productProvenanceBranch(),
1280  saveMemoryObjectThreshold_,
1281  this,
1282  nullptr,
1283  InSubRun,
1284  fiIter_->eventID_,
1285  compactSubRunRanges_));
1286  if (!delayedReadSubRunProducts_) {
1287  srp->readImmediate();
1288  }
1289  primarySRP_ = make_exempt_ptr(srp.get());
1290  return srp;
1291  }
1292 
1293  bool
1294  RootInputFile::readSubRunForSecondaryFile(SubRunID srID)
1295  {
1296  // Used just after opening a new secondary file in response to a failed
1297  // product lookup. Synchronize the file index to the subRun needed and
1298  // create a secondary SubRunPrincipal for it.
1299  if (!setEntry_SubRun(srID)) {
1300  // Error, could not find specified subRun in file.
1301  return false;
1302  }
1303  auto const& entryNumbers = getEntryNumbers(InSubRun).first;
1304  assert(fiIter_ != fiEnd_);
1305  assert(fiIter_->getEntryType() == FileIndex::kSubRun);
1306  subRunRangeSetHandler_ = fillAuxiliary_SubRun(entryNumbers);
1307  assert(subRunAux_.subRunID() == fiIter_->eventID_.subRunID());
1308  overrideRunNumber(subRunAux_.id_);
1309  if (subRunAux_.beginTime() == Timestamp::invalidTimestamp()) {
1310  subRunAux_.beginTime_ = eventAux_.time();
1311  subRunAux_.endTime_ = Timestamp::invalidTimestamp();
1312  }
1313  auto srp = make_unique<SubRunPrincipal>(
1314  subRunAux_,
1315  processConfiguration_,
1316  &presentProducts_.get(InSubRun),
1317  make_unique<RootDelayedReader>(fileFormatVersion_,
1318  *sqliteDB_,
1319  entryNumbers,
1320  &subRunTree().branches(),
1321  subRunTree().productProvenanceBranch(),
1322  saveMemoryObjectThreshold_,
1323  this,
1324  nullptr,
1325  InSubRun,
1326  fiIter_->eventID_,
1327  compactSubRunRanges_));
1328  if (!delayedReadSubRunProducts_) {
1329  srp->readImmediate();
1330  }
1331  primaryFile_->primarySRP_->addSecondaryPrincipal(move(srp));
1332  return true;
1333  }
1334 
1335  void
1336  RootInputFile::overrideRunNumber(RunAuxiliary& aux)
1337  {
1338  if (forcedRunOffset_ != 0) {
1339  aux.runID(RunID(aux.run() + forcedRunOffset_));
1340  }
1341  if (aux.runID() < RunID::firstRun()) {
1342  aux.runID(RunID::firstRun());
1343  }
1344  }
1345 
1346  void
1347  RootInputFile::overrideRunNumber(SubRunID& id)
1348  {
1349  if (forcedRunOffset_ != 0) {
1350  id = SubRunID(id.run() + forcedRunOffset_, id.subRun());
1351  }
1352  }
1353 
1354  void
1355  RootInputFile::overrideRunNumber(EventID& id, bool isRealData)
1356  {
1357  if (forcedRunOffset_ == 0) {
1358  return;
1359  }
1360  if (isRealData) {
1362  "RootInputFile::overrideRunNumber()"}
1363  << "The 'setRunNumber' parameter of RootInput cannot "
1364  << "be used with real data.\n";
1365  }
1366  id = EventID(id.run() + forcedRunOffset_, id.subRun(), id.event());
1367  }
1368 
1369  void
1370  RootInputFile::readEventHistoryTree(unsigned int treeCacheSize)
1371  {
1372  // Read in the event history tree, if we have one...
1373  eventHistoryTree_ = static_cast<TTree*>(
1374  filePtr_->Get(rootNames::eventHistoryTreeName().c_str()));
1375  if (!eventHistoryTree_) {
1377  << "Failed to find the event history tree.\n";
1378  }
1379  eventHistoryTree_->SetCacheSize(static_cast<Long64_t>(treeCacheSize));
1380  }
1381 
1382  void
1383  RootInputFile::initializeDuplicateChecker()
1384  {
1385  if (duplicateChecker_.get() == nullptr) {
1386  return;
1387  }
1388  if (eventTree().entries()) {
1389  // FIXME: We don't initialize the duplicate checker if there are no
1390  // events!
1391  fillAuxiliary_Event(0);
1392  duplicateChecker_->init(eventAux_.isRealData(), fileIndex_);
1393  }
1394  }
1395 
1396  pair<RootInputFile::EntryNumbers, bool>
1397  RootInputFile::getEntryNumbers(BranchType const bt)
1398  {
1399  EntryNumbers enumbers;
1400  if (fiIter_ == fiEnd_) {
1401  return pair<EntryNumbers, bool>{enumbers, true};
1402  }
1403  auto const eid = fiIter_->eventID_;
1404  auto iter = fiIter_;
1405  for (; (iter != fiEnd_) && (iter->eventID_ == eid); ++iter) {
1406  enumbers.push_back(iter->entry_);
1407  }
1408  if ((bt == InEvent) && (enumbers.size() > 1ul)) {
1409  throw Exception{errors::FileReadError} << "File " << fileName_
1410  << " has multiple entries for\n"
1411  << eid << '\n';
1412  }
1413  bool const lastInSubRun{(iter == fiEnd_) ||
1414  (iter->eventID_.subRun() != eid.subRun())};
1415  return pair<EntryNumbers, bool>{enumbers, lastInSubRun};
1416  }
1417 
1418  void
1419  RootInputFile::dropOnInput(GroupSelectorRules const& rules,
1420  bool const dropDescendants,
1421  ProductTables& tables)
1422  {
1423  auto dropOnInputForBranchType =
1424  [this, &rules, dropDescendants, &tables](BranchType const bt) {
1425  auto& prodList = tables.get(bt).descriptions;
1426 
1427  // This is the selector for drop on input.
1428  GroupSelector const groupSelector{rules, prodList};
1429  // Do drop on input. On the first pass, just fill in a set of
1430  // branches to be dropped. Use the BranchChildren class to
1431  // assemble list of children to drop.
1432  BranchChildren children;
1433  set<ProductID> branchesToDrop;
1434  for (auto const& prod : prodList) {
1435  auto const& pd = prod.second;
1436  if (!groupSelector.selected(pd)) {
1437  if (dropDescendants) {
1438  children.appendToDescendants(pd.productID(), branchesToDrop);
1439  } else {
1440  branchesToDrop.insert(pd.productID());
1441  }
1442  }
1443  }
1444 
1445  // On this pass, actually drop the branches.
1446  auto branchesToDropEnd = branchesToDrop.cend();
1447  for (auto I = prodList.begin(), E = prodList.end(); I != E;) {
1448  auto const& bd = I->second;
1449  bool drop = branchesToDrop.find(bd.productID()) != branchesToDropEnd;
1450  if (!drop) {
1451  ++I;
1452  checkDictionaries(bd);
1453  continue;
1454  }
1455  if (groupSelector.selected(bd)) {
1456  mf::LogWarning("RootInputFile")
1457  << "Branch '" << bd.branchName()
1458  << "' is being dropped from the input\n"
1459  << "of file '" << fileName_
1460  << "' because it is dependent on a branch\n"
1461  << "that was explicitly dropped.\n";
1462  }
1463  treePointers_[bt]->dropBranch(bd.branchName());
1464  auto icopy = I++;
1465  prodList.erase(icopy);
1466  }
1467  };
1468  for_each_branch_type(dropOnInputForBranchType);
1469  }
1470 
1471  void
1472  RootInputFile::openSecondaryFile(int const idx)
1473  {
1474  secondaryFiles_[idx] =
1475  rifSequence_->openSecondaryFile(secondaryFileNames_[idx], this);
1476  }
1477 
1478  unique_ptr<art::ResultsPrincipal>
1479  RootInputFile::readResults()
1480  {
1481  unique_ptr<art::ResultsPrincipal> resp;
1482  if (!resultsTree().isValid()) {
1483  resp = make_unique<ResultsPrincipal>(
1484  ResultsAuxiliary{}, processConfiguration_, nullptr);
1485  return resp;
1486  }
1487 
1488  EntryNumbers const& entryNumbers{
1489  0}; // FIXME: Not sure hard-coding 0 is the right thing to do.
1490  assert(entryNumbers.size() == 1ull);
1491  fillAuxiliary_Results(entryNumbers.front());
1492  resp = std::make_unique<ResultsPrincipal>(
1493  resultsAux_,
1494  processConfiguration_,
1495  &presentProducts_.get(InResults),
1496  make_unique<RootDelayedReader>(fileFormatVersion_,
1497  nullptr,
1498  entryNumbers,
1499  &resultsTree().branches(),
1500  resultsTree().productProvenanceBranch(),
1501  saveMemoryObjectThreshold_,
1502  this,
1503  nullptr,
1504  InResults,
1505  EventID{},
1506  compactSubRunRanges_));
1507  return resp;
1508  }
1509 
1510 } // namespace art
std::string const & BranchTypeToProductTreeName(BranchType const bt)
Definition: BranchType.cc:71
std::string const & productProvenanceBranchName(BranchType const bt)
Definition: BranchType.cc:91
std::vector< BranchIDList > BranchIDLists
Definition: BranchIDList.h:18
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
RangeSetInfo resolveRangeSetInfo(sqlite3 *, std::string const &filename, BranchType, unsigned RangeSetID, bool compact)
void appendToDescendants(ProductID parent, ProductIDSet &descendants) const
static ParameterSetID const & put(ParameterSet const &ps)
RunID const & runID() const noexcept
RootInputTree::EntryNumbers EntryNumbers
Definition: RootInputFile.h:99
T * get() const
Definition: ServiceHandle.h:64
void readFileIndex(TFile *file, TTree *metaDataTree, FileIndex *&findexPtr)
Definition: readFileIndex.h:22
std::string const & parentageTreeName()
Definition: rootNames.cc:21
std::string const & BranchTypeToMetaDataTreeName(BranchType const bt)
Definition: BranchType.cc:77
std::array< std::unique_ptr< RootInputTree >, NumBranchTypes > RootInputTreePtrArray
Definition: RootInputFile.h:97
void mergeAuxiliary(SubRunAuxiliary &left, SubRunAuxiliary const &right)
std::string const & eventHistoryTreeName()
Definition: rootNames.cc:54
STL namespace.
auto & get(BranchType const bt)
Definition: ProductTables.h:47
void make_ParameterSet(intermediate_table const &tbl, ParameterSet &ps)
bool present() const noexcept
std::string const & BranchTypeToAuxiliaryBranchName(BranchType const bt)
Definition: BranchType.cc:83
RangeSet resolveRangeSet(RangeSetInfo const &rs)
RunNumber_t run() const
Definition: EventID.h:99
#define FALLTHROUGH
std::string couldNotFindTree(std::string const &treename)
Definition: rootErrMsgs.h:9
bool mergeAuxiliary(RunAuxiliary const &)
SubRunID next() const
Definition: SubRunID.h:110
std::string const & metaDataTreeName()
Definition: rootNames.cc:40
const double e
void swap(Handle< T > &a, Handle< T > &b)
exempt_ptr< E > make_exempt_ptr(E *) noexcept
std::string const & parentageBranchName()
Definition: rootNames.cc:33
bool mergeAuxiliary(SubRunAuxiliary const &)
bool dropped() const noexcept
std::string const & parentageIDBranchName()
Definition: rootNames.cc:27
void invoke(ProductTables const &)
ParameterSetID id() const
std::string const & getFileFormatEra()
std::string const & BranchTypeToString(BranchType const bt)
Definition: BranchType.cc:65
void swap(exempt_ptr< E > &, exempt_ptr< E > &) noexcept
Definition: exempt_ptr.h:190
RunNumber_t run() const noexcept
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:96
std::string const & eventHistoryBranchName()
Definition: rootNames.cc:61
void checkDictionaries(BranchDescription const &productDesc)
RootInputTree::EntryNumber EntryNumber
Definition: RootInputFile.h:98
signed __int64 int64_t
Definition: stdint.h:131
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
BranchType
Definition: BranchType.h:18
Int_t getEntry(TBranch *branch, EntryNumber entryNumber)
Definition: getEntry.cc:20
void for_each_branch_type(F f)
Definition: BranchType.h:36
std::map< fhicl::ParameterSetID, ParameterSetBlob > ParameterSetMap
auto make_product_descriptions(ProductList const &productList)
Definition: ProductList.h:19
std::string const & branchName() const noexcept
ProductID productID() const noexcept
T readMetadata(TTree *md, bool const requireDict=true)
Definition: readMetadata.h:14
unsigned int run
IDNumber_t< Level::Run > RunNumber_t
Definition: IDNumber.h:120
static void importFrom(sqlite3 *db)