Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2022-05-06 00:35:39

0001 /*----------------------------------------------------------------------
0002 ----------------------------------------------------------------------*/
0003 
0004 #include "RootFile.h"
0005 #include "DuplicateChecker.h"
0006 #include "InputFile.h"
0007 #include "ProvenanceAdaptor.h"
0008 #include "RunHelper.h"
0009 
0010 #include "DataFormats/Common/interface/setIsMergeable.h"
0011 #include "DataFormats/Common/interface/ThinnedAssociation.h"
0012 #include "DataFormats/Provenance/interface/BranchDescription.h"
0013 #include "DataFormats/Provenance/interface/BranchIDListHelper.h"
0014 #include "DataFormats/Provenance/interface/BranchType.h"
0015 #include "DataFormats/Provenance/interface/EventEntryInfo.h"
0016 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
0017 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
0018 #include "DataFormats/Provenance/interface/ProcessHistoryID.h"
0019 #include "DataFormats/Provenance/interface/ProcessHistoryRegistry.h"
0020 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0021 #include "DataFormats/Provenance/interface/StoredMergeableRunProductMetadata.h"
0022 #include "DataFormats/Provenance/interface/StoredProcessBlockHelper.h"
0023 #include "DataFormats/Provenance/interface/StoredProductProvenance.h"
0024 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0025 #include "DataFormats/Provenance/interface/RunID.h"
0026 #include "FWCore/Common/interface/ProcessBlockHelper.h"
0027 #include "FWCore/Framework/interface/FileBlock.h"
0028 #include "FWCore/Framework/interface/EventPrincipal.h"
0029 #include "FWCore/Framework/interface/ProductSelector.h"
0030 #include "FWCore/Framework/interface/LuminosityBlockPrincipal.h"
0031 #include "FWCore/Framework/interface/MergeableRunProductMetadata.h"
0032 #include "FWCore/Framework/interface/ProcessBlockPrincipal.h"
0033 #include "FWCore/Framework/interface/RunPrincipal.h"
0034 #include "FWCore/Framework/interface/SharedResourcesAcquirer.h"
0035 #include "FWCore/Framework/interface/SharedResourcesRegistry.h"
0036 #include "FWCore/Framework/interface/DelayedReader.h"
0037 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0038 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0039 #include "FWCore/ParameterSet/interface/Registry.h"
0040 #include "FWCore/Sources/interface/EventSkipperByID.h"
0041 #include "FWCore/Sources/interface/DaqProvenanceHelper.h"
0042 #include "FWCore/ServiceRegistry/interface/ServiceRegistry.h"
0043 #include "FWCore/Utilities/interface/Algorithms.h"
0044 #include "FWCore/Utilities/interface/do_nothing_deleter.h"
0045 #include "FWCore/Utilities/interface/EDMException.h"
0046 #include "FWCore/Utilities/interface/FriendlyName.h"
0047 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
0048 #include "FWCore/Utilities/interface/ReleaseVersion.h"
0049 #include "FWCore/Utilities/interface/stemFromPath.h"
0050 #include "FWCore/Utilities/interface/thread_safety_macros.h"
0051 #include "FWCore/Version/interface/GetReleaseVersion.h"
0052 #include "IOPool/Common/interface/getWrapperBasePtr.h"
0053 
0054 #include "FWCore/Concurrency/interface/WaitingTaskHolder.h"
0055 #include "FWCore/ServiceRegistry/interface/ModuleCallingContext.h"
0056 
0057 //used for backward compatibility
0058 #include "DataFormats/Provenance/interface/EventAux.h"
0059 #include "DataFormats/Provenance/interface/LuminosityBlockAux.h"
0060 #include "DataFormats/Provenance/interface/RunAux.h"
0061 #include "FWCore/ParameterSet/interface/ParameterSetConverter.h"
0062 
0063 #include "Rtypes.h"
0064 #include "TClass.h"
0065 #include "TString.h"
0066 #include "TTree.h"
0067 #include "TTreeCache.h"
0068 
0069 #include <algorithm>
0070 #include <cassert>
0071 #include <list>
0072 
0073 namespace edm {
0074 
0075   // Algorithm classes for making ProvenanceReader:
0076   class MakeDummyProvenanceReader : public MakeProvenanceReader {
0077   public:
0078     std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree,
0079                                                      DaqProvenanceHelper const* daqProvenanceHelper) const override;
0080   };
0081   class MakeOldProvenanceReader : public MakeProvenanceReader {
0082   public:
0083     MakeOldProvenanceReader(std::unique_ptr<EntryDescriptionMap>&& entryDescriptionMap)
0084         : MakeProvenanceReader(), entryDescriptionMap_(std::move(entryDescriptionMap)) {}
0085     std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree,
0086                                                      DaqProvenanceHelper const* daqProvenanceHelper) const override;
0087 
0088   private:
0089     edm::propagate_const<std::unique_ptr<EntryDescriptionMap>> entryDescriptionMap_;
0090   };
0091   class MakeFullProvenanceReader : public MakeProvenanceReader {
0092   public:
0093     std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree,
0094                                                      DaqProvenanceHelper const* daqProvenanceHelper) const override;
0095   };
0096   class MakeReducedProvenanceReader : public MakeProvenanceReader {
0097   public:
0098     MakeReducedProvenanceReader(std::vector<ParentageID> const& parentageIDLookup)
0099         : parentageIDLookup_(parentageIDLookup) {}
0100     std::unique_ptr<ProvenanceReaderBase> makeReader(RootTree& eventTree,
0101                                                      DaqProvenanceHelper const* daqProvenanceHelper) const override;
0102 
0103   private:
0104     std::vector<ParentageID> const& parentageIDLookup_;
0105   };
0106 
0107   namespace {
0108     void checkReleaseVersion(std::vector<ProcessHistory> processHistoryVector, std::string const& fileName) {
0109       std::string releaseVersion = getReleaseVersion();
0110       releaseversion::DecomposedReleaseVersion currentRelease(releaseVersion);
0111       for (auto const& ph : processHistoryVector) {
0112         for (auto const& pc : ph) {
0113           if (releaseversion::isEarlierRelease(currentRelease, pc.releaseVersion())) {
0114             throw Exception(errors::FormatIncompatibility)
0115                 << "The release you are using, " << getReleaseVersion() << " , predates\n"
0116                 << "a release (" << pc.releaseVersion() << ") used in writing the input file, " << fileName << ".\n"
0117                 << "Forward compatibility cannot be supported.\n";
0118           }
0119         }
0120       }
0121     }
0122   }  // namespace
0123 
0124   // This is a helper class for IndexIntoFile.
0125   class RootFileEventFinder : public IndexIntoFile::EventFinder {
0126   public:
0127     explicit RootFileEventFinder(RootTree& eventTree) : eventTree_(eventTree) {}
0128     ~RootFileEventFinder() override {}
0129 
0130     EventNumber_t getEventNumberOfEntry(roottree::EntryNumber entry) const override {
0131       roottree::EntryNumber saveEntry = eventTree_.entryNumber();
0132       eventTree_.setEntryNumber(entry);
0133       EventAuxiliary eventAux;
0134       EventAuxiliary* pEvAux = &eventAux;
0135       eventTree_.fillAux<EventAuxiliary>(pEvAux);
0136       eventTree_.setEntryNumber(saveEntry);
0137       return eventAux.event();
0138     }
0139 
0140   private:
0141     RootTree& eventTree_;
0142   };
0143 
0144   //---------------------------------------------------------------------
0145   RootFile::RootFile(std::string const& fileName,
0146                      ProcessConfiguration const& processConfiguration,
0147                      std::string const& logicalFileName,
0148                      std::shared_ptr<InputFile> filePtr,
0149                      std::shared_ptr<EventSkipperByID> eventSkipperByID,
0150                      bool skipAnyEvents,
0151                      int remainingEvents,
0152                      int remainingLumis,
0153                      unsigned int nStreams,
0154                      unsigned int treeCacheSize,
0155                      int treeMaxVirtualSize,
0156                      InputSource::ProcessingMode processingMode,
0157                      RunHelperBase* runHelper,
0158                      bool noRunLumiSort,
0159                      bool noEventSort,
0160                      ProductSelectorRules const& productSelectorRules,
0161                      InputType inputType,
0162                      std::shared_ptr<BranchIDListHelper> branchIDListHelper,
0163                      ProcessBlockHelper* processBlockHelper,
0164                      std::shared_ptr<ThinnedAssociationsHelper> thinnedAssociationsHelper,
0165                      std::vector<BranchID> const* associationsFromSecondary,
0166                      std::shared_ptr<DuplicateChecker> duplicateChecker,
0167                      bool dropDescendants,
0168                      ProcessHistoryRegistry& processHistoryRegistry,
0169                      std::vector<std::shared_ptr<IndexIntoFile>> const& indexesIntoFiles,
0170                      std::vector<std::shared_ptr<IndexIntoFile>>::size_type currentIndexIntoFile,
0171                      std::vector<ProcessHistoryID>& orderedProcessHistoryIDs,
0172                      bool bypassVersionCheck,
0173                      bool labelRawDataLikeMC,
0174                      bool usingGoToEvent,
0175                      bool enablePrefetching,
0176                      bool enforceGUIDInFileName)
0177       : file_(fileName),
0178         logicalFile_(logicalFileName),
0179         processConfiguration_(processConfiguration),
0180         processHistoryRegistry_(&processHistoryRegistry),
0181         filePtr_(filePtr),
0182         eventSkipperByID_(eventSkipperByID),
0183         fileFormatVersion_(),
0184         fid_(),
0185         indexIntoFileSharedPtr_(new IndexIntoFile),
0186         indexIntoFile_(*indexIntoFileSharedPtr_),
0187         orderedProcessHistoryIDs_(orderedProcessHistoryIDs),
0188         indexIntoFileBegin_(indexIntoFile_.begin(
0189             noRunLumiSort ? IndexIntoFile::entryOrder
0190                           : (noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder))),
0191         indexIntoFileEnd_(indexIntoFileBegin_),
0192         indexIntoFileIter_(indexIntoFileBegin_),
0193         storedMergeableRunProductMetadata_((inputType == InputType::Primary) ? new StoredMergeableRunProductMetadata
0194                                                                              : nullptr),
0195         eventProcessHistoryIDs_(),
0196         eventProcessHistoryIter_(eventProcessHistoryIDs_.begin()),
0197         savedRunAuxiliary_(),
0198         skipAnyEvents_(skipAnyEvents),
0199         noRunLumiSort_(noRunLumiSort),
0200         noEventSort_(noEventSort),
0201         enforceGUIDInFileName_(enforceGUIDInFileName),
0202         whyNotFastClonable_(0),
0203         hasNewlyDroppedBranch_(),
0204         branchListIndexesUnchanged_(false),
0205         eventAuxCache_(),
0206         eventTree_(filePtr,
0207                    InEvent,
0208                    nStreams,
0209                    treeMaxVirtualSize,
0210                    treeCacheSize,
0211                    roottree::defaultLearningEntries,
0212                    enablePrefetching,
0213                    inputType),
0214         lumiTree_(filePtr,
0215                   InLumi,
0216                   1,
0217                   treeMaxVirtualSize,
0218                   roottree::defaultNonEventCacheSize,
0219                   roottree::defaultNonEventLearningEntries,
0220                   enablePrefetching,
0221                   inputType),
0222         runTree_(filePtr,
0223                  InRun,
0224                  1,
0225                  treeMaxVirtualSize,
0226                  roottree::defaultNonEventCacheSize,
0227                  roottree::defaultNonEventLearningEntries,
0228                  enablePrefetching,
0229                  inputType),
0230         treePointers_(),
0231         lastEventEntryNumberRead_(IndexIntoFile::invalidEntry),
0232         productRegistry_(),
0233         branchIDLists_(),
0234         branchIDListHelper_(branchIDListHelper),
0235         processBlockHelper_(processBlockHelper),
0236         fileThinnedAssociationsHelper_(),
0237         thinnedAssociationsHelper_(thinnedAssociationsHelper),
0238         processingMode_(processingMode),
0239         runHelper_(runHelper),
0240         newBranchToOldBranch_(),
0241         eventHistoryTree_(nullptr),
0242         eventToProcessBlockIndexesBranch_(
0243             inputType == InputType::Primary
0244                 ? eventTree_.tree()->GetBranch(poolNames::eventToProcessBlockIndexesBranchName().c_str())
0245                 : nullptr),
0246         history_(),
0247         branchChildren_(new BranchChildren),
0248         duplicateChecker_(duplicateChecker),
0249         provenanceAdaptor_(),
0250         provenanceReaderMaker_(),
0251         eventProductProvenanceRetrievers_(),
0252         parentageIDLookup_(),
0253         daqProvenanceHelper_(),
0254         edProductClass_(TypeWithDict::byName("edm::WrapperBase").getClass()),
0255         inputType_(inputType) {
0256     hasNewlyDroppedBranch_.fill(false);
0257 
0258     treePointers_.resize(3);
0259     treePointers_[InEvent] = &eventTree_;
0260     treePointers_[InLumi] = &lumiTree_;
0261     treePointers_[InRun] = &runTree_;
0262 
0263     // Read the metadata tree.
0264     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
0265     std::unique_ptr<TTree> metaDataTree(dynamic_cast<TTree*>(filePtr_->Get(poolNames::metaDataTreeName().c_str())));
0266     if (nullptr == metaDataTree.get()) {
0267       throw Exception(errors::FileReadError)
0268           << "Could not find tree " << poolNames::metaDataTreeName() << " in the input file.\n";
0269     }
0270 
0271     // To keep things simple, we just read in every possible branch that exists.
0272     // We don't pay attention to which branches exist in which file format versions
0273 
0274     FileFormatVersion* fftPtr = &fileFormatVersion_;
0275     if (metaDataTree->FindBranch(poolNames::fileFormatVersionBranchName().c_str()) != nullptr) {
0276       TBranch* fft = metaDataTree->GetBranch(poolNames::fileFormatVersionBranchName().c_str());
0277       fft->SetAddress(&fftPtr);
0278       roottree::getEntry(fft, 0);
0279       metaDataTree->SetBranchAddress(poolNames::fileFormatVersionBranchName().c_str(), &fftPtr);
0280     }
0281 
0282     FileID* fidPtr = &fid_;
0283     if (metaDataTree->FindBranch(poolNames::fileIdentifierBranchName().c_str()) != nullptr) {
0284       metaDataTree->SetBranchAddress(poolNames::fileIdentifierBranchName().c_str(), &fidPtr);
0285     }
0286 
0287     IndexIntoFile* iifPtr = &indexIntoFile_;
0288     if (metaDataTree->FindBranch(poolNames::indexIntoFileBranchName().c_str()) != nullptr) {
0289       metaDataTree->SetBranchAddress(poolNames::indexIntoFileBranchName().c_str(), &iifPtr);
0290     }
0291 
0292     storedProcessBlockHelper_ = std::make_unique<StoredProcessBlockHelper>();
0293     StoredProcessBlockHelper& storedProcessBlockHelper = *storedProcessBlockHelper_;
0294     StoredProcessBlockHelper* pStoredProcessBlockHelper = storedProcessBlockHelper_.get();
0295     if (inputType == InputType::Primary) {
0296       if (metaDataTree->FindBranch(poolNames::processBlockHelperBranchName().c_str()) != nullptr) {
0297         metaDataTree->SetBranchAddress(poolNames::processBlockHelperBranchName().c_str(), &pStoredProcessBlockHelper);
0298       }
0299     }
0300 
0301     StoredMergeableRunProductMetadata* smrc = nullptr;
0302     if (inputType == InputType::Primary) {
0303       smrc = &*storedMergeableRunProductMetadata_;
0304       if (metaDataTree->FindBranch(poolNames::mergeableRunProductMetadataBranchName().c_str()) != nullptr) {
0305         metaDataTree->SetBranchAddress(poolNames::mergeableRunProductMetadataBranchName().c_str(), &smrc);
0306       }
0307     }
0308 
0309     // Need to read to a temporary registry so we can do a translation of the BranchKeys.
0310     // This preserves backward compatibility against friendly class name algorithm changes.
0311     ProductRegistry inputProdDescReg;
0312     ProductRegistry* ppReg = &inputProdDescReg;
0313     metaDataTree->SetBranchAddress(poolNames::productDescriptionBranchName().c_str(), (&ppReg));
0314 
0315     using PsetMap = std::map<ParameterSetID, ParameterSetBlob>;
0316     PsetMap psetMap;
0317     PsetMap* psetMapPtr = &psetMap;
0318     if (metaDataTree->FindBranch(poolNames::parameterSetMapBranchName().c_str()) != nullptr) {
0319       //backward compatibility
0320       assert(!fileFormatVersion().parameterSetsTree());
0321       metaDataTree->SetBranchAddress(poolNames::parameterSetMapBranchName().c_str(), &psetMapPtr);
0322     } else {
0323       assert(fileFormatVersion().parameterSetsTree());
0324       // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
0325       std::unique_ptr<TTree> psetTree(dynamic_cast<TTree*>(filePtr_->Get(poolNames::parameterSetsTreeName().c_str())));
0326       if (nullptr == psetTree.get()) {
0327         throw Exception(errors::FileReadError)
0328             << "Could not find tree " << poolNames::parameterSetsTreeName() << " in the input file.\n";
0329       }
0330 
0331       using IdToBlobs = std::pair<ParameterSetID, ParameterSetBlob>;
0332       IdToBlobs idToBlob;
0333       IdToBlobs* pIdToBlob = &idToBlob;
0334       psetTree->SetBranchAddress(poolNames::idToParameterSetBlobsBranchName().c_str(), &pIdToBlob);
0335 
0336       std::unique_ptr<TTreeCache> psetTreeCache =
0337           roottree::trainCache(psetTree.get(), *filePtr_, roottree::defaultNonEventCacheSize, "*");
0338       psetTreeCache->SetEnablePrefetching(false);
0339       filePtr_->SetCacheRead(psetTreeCache.get());
0340       for (Long64_t i = 0; i != psetTree->GetEntries(); ++i) {
0341         psetTree->GetEntry(i);
0342         psetMap.insert(idToBlob);
0343       }
0344       filePtr_->SetCacheRead(nullptr);
0345     }
0346 
0347     // backward compatibility
0348     ProcessHistoryRegistry::collection_type pHistMap;
0349     ProcessHistoryRegistry::collection_type* pHistMapPtr = &pHistMap;
0350     if (metaDataTree->FindBranch(poolNames::processHistoryMapBranchName().c_str()) != nullptr) {
0351       metaDataTree->SetBranchAddress(poolNames::processHistoryMapBranchName().c_str(), &pHistMapPtr);
0352     }
0353 
0354     ProcessHistoryRegistry::vector_type pHistVector;
0355     ProcessHistoryRegistry::vector_type* pHistVectorPtr = &pHistVector;
0356     if (metaDataTree->FindBranch(poolNames::processHistoryBranchName().c_str()) != nullptr) {
0357       metaDataTree->SetBranchAddress(poolNames::processHistoryBranchName().c_str(), &pHistVectorPtr);
0358     }
0359 
0360     // backward compatibility
0361     ProcessConfigurationVector processConfigurations;
0362     ProcessConfigurationVector* procConfigVectorPtr = &processConfigurations;
0363     if (metaDataTree->FindBranch(poolNames::processConfigurationBranchName().c_str()) != nullptr) {
0364       metaDataTree->SetBranchAddress(poolNames::processConfigurationBranchName().c_str(), &procConfigVectorPtr);
0365     }
0366 
0367     auto branchIDListsAPtr = std::make_unique<BranchIDLists>();
0368     BranchIDLists* branchIDListsPtr = branchIDListsAPtr.get();
0369     if (metaDataTree->FindBranch(poolNames::branchIDListBranchName().c_str()) != nullptr) {
0370       metaDataTree->SetBranchAddress(poolNames::branchIDListBranchName().c_str(), &branchIDListsPtr);
0371     }
0372 
0373     ThinnedAssociationsHelper* thinnedAssociationsHelperPtr;  // must remain in scope through getEntry()
0374     if (inputType != InputType::SecondarySource) {
0375       fileThinnedAssociationsHelper_ =
0376           std::make_unique<ThinnedAssociationsHelper>();  // propagate_const<T> has no reset() function
0377       thinnedAssociationsHelperPtr = fileThinnedAssociationsHelper_.get();
0378       if (metaDataTree->FindBranch(poolNames::thinnedAssociationsHelperBranchName().c_str()) != nullptr) {
0379         metaDataTree->SetBranchAddress(poolNames::thinnedAssociationsHelperBranchName().c_str(),
0380                                        &thinnedAssociationsHelperPtr);
0381       }
0382     }
0383 
0384     BranchChildren* branchChildrenBuffer = branchChildren_.get();
0385     if (metaDataTree->FindBranch(poolNames::productDependenciesBranchName().c_str()) != nullptr) {
0386       metaDataTree->SetBranchAddress(poolNames::productDependenciesBranchName().c_str(), &branchChildrenBuffer);
0387     }
0388 
0389     // backward compatibility
0390     std::vector<EventProcessHistoryID>* eventHistoryIDsPtr = &eventProcessHistoryIDs_;
0391     if (metaDataTree->FindBranch(poolNames::eventHistoryBranchName().c_str()) != nullptr) {
0392       metaDataTree->SetBranchAddress(poolNames::eventHistoryBranchName().c_str(), &eventHistoryIDsPtr);
0393     }
0394 
0395     if (metaDataTree->FindBranch(poolNames::moduleDescriptionMapBranchName().c_str()) != nullptr) {
0396       if (metaDataTree->GetBranch(poolNames::moduleDescriptionMapBranchName().c_str())->GetSplitLevel() != 0) {
0397         metaDataTree->SetBranchStatus((poolNames::moduleDescriptionMapBranchName() + ".*").c_str(), false);
0398       } else {
0399         metaDataTree->SetBranchStatus(poolNames::moduleDescriptionMapBranchName().c_str(), false);
0400       }
0401     }
0402 
0403     // Here we read the metadata tree
0404     roottree::getEntry(metaDataTree.get(), 0);
0405 
0406     eventProcessHistoryIter_ = eventProcessHistoryIDs_.begin();
0407 
0408     // Here we read the event history tree, if we have one.
0409     readEventHistoryTree();
0410 
0411     ParameterSetConverter::ParameterSetIdConverter psetIdConverter;
0412     if (!fileFormatVersion().triggerPathsTracked()) {
0413       ParameterSetConverter converter(psetMap, psetIdConverter, fileFormatVersion().parameterSetsByReference());
0414     } else {
0415       // Merge into the parameter set registry.
0416       pset::Registry& psetRegistry = *pset::Registry::instance();
0417       for (auto const& psetEntry : psetMap) {
0418         ParameterSet pset(psetEntry.second.pset());
0419         pset.setID(psetEntry.first);
0420         // For thread safety, don't update global registries when a secondary source opens a file.
0421         if (inputType != InputType::SecondarySource) {
0422           psetRegistry.insertMapped(pset);
0423         }
0424       }
0425     }
0426     if (!fileFormatVersion().splitProductIDs()) {
0427       // Old provenance format input file.  Create a provenance adaptor.
0428       // propagate_const<T> has no reset() function
0429       provenanceAdaptor_ = std::make_unique<ProvenanceAdaptor>(
0430           inputProdDescReg, pHistMap, pHistVector, processConfigurations, psetIdConverter, true);
0431       // Fill in the branchIDLists branch from the provenance adaptor
0432       branchIDLists_ = provenanceAdaptor_->branchIDLists();
0433     } else {
0434       if (!fileFormatVersion().triggerPathsTracked()) {
0435         // New provenance format, but change in ParameterSet Format. Create a provenance adaptor.
0436         // propagate_const<T> has no reset() function
0437         provenanceAdaptor_ = std::make_unique<ProvenanceAdaptor>(
0438             inputProdDescReg, pHistMap, pHistVector, processConfigurations, psetIdConverter, false);
0439       }
0440       // New provenance format input file. The branchIDLists branch was read directly from the input file.
0441       if (metaDataTree->FindBranch(poolNames::branchIDListBranchName().c_str()) == nullptr) {
0442         throw Exception(errors::EventCorruption) << "Failed to find branchIDLists branch in metaData tree.\n";
0443       }
0444       branchIDLists_.reset(branchIDListsAPtr.release());
0445     }
0446 
0447     if (fileFormatVersion().hasThinnedAssociations()) {
0448       if (metaDataTree->FindBranch(poolNames::thinnedAssociationsHelperBranchName().c_str()) == nullptr) {
0449         throw Exception(errors::EventCorruption)
0450             << "Failed to find thinnedAssociationsHelper branch in metaData tree.\n";
0451       }
0452     }
0453 
0454     if (!bypassVersionCheck) {
0455       checkReleaseVersion(pHistVector, file());
0456     }
0457 
0458     if (labelRawDataLikeMC) {
0459       std::string const rawData("FEDRawDataCollection");
0460       std::string const source("source");
0461       ProductRegistry::ProductList& pList = inputProdDescReg.productListUpdator();
0462       BranchKey finder(rawData, source, "", "");
0463       ProductRegistry::ProductList::iterator it = pList.lower_bound(finder);
0464       if (it != pList.end() && it->first.friendlyClassName() == rawData && it->first.moduleLabel() == source) {
0465         // We found raw data with a module label of source.
0466         // We need to change the module label and process name.
0467         // Create helper.
0468         it->second.init();
0469         // propagate_const<T> has no reset() function
0470         daqProvenanceHelper_ = std::make_unique<DaqProvenanceHelper>(it->second.unwrappedTypeID());
0471         // Create the new branch description
0472         BranchDescription const& newBD = daqProvenanceHelper_->branchDescription();
0473         // Save info from the old and new branch descriptions
0474         daqProvenanceHelper_->saveInfo(it->second, newBD);
0475         // Map the new branch name to the old branch name.
0476         newBranchToOldBranch_.insert(std::make_pair(newBD.branchName(), it->second.branchName()));
0477         // Remove the old branch description from the product Registry.
0478         pList.erase(it);
0479         // Check that there was only one.
0480         it = pList.lower_bound(finder);
0481         assert(!(it != pList.end() && it->first.friendlyClassName() == rawData && it->first.moduleLabel() == source));
0482         // Insert the new branch description into the product registry.
0483         inputProdDescReg.copyProduct(newBD);
0484         // Fix up other per file metadata.
0485         daqProvenanceHelper_->fixMetaData(processConfigurations, pHistVector);
0486         daqProvenanceHelper_->fixMetaData(*branchIDLists_);
0487         daqProvenanceHelper_->fixMetaData(*branchChildren_);
0488       }
0489     }
0490 
0491     for (auto const& history : pHistVector) {
0492       processHistoryRegistry.registerProcessHistory(history);
0493     }
0494 
0495     eventTree_.trainCache(BranchTypeToAuxiliaryBranchName(InEvent).c_str());
0496 
0497     // Update the branch id info. This has to be done before validateFile since
0498     // depending on the file format, the branchIDListHelper_ may have its fixBranchListIndexes call made
0499     if (inputType == InputType::Primary) {
0500       branchListIndexesUnchanged_ = branchIDListHelper_->updateFromInput(*branchIDLists_);
0501     }
0502 
0503     validateFile(inputType, usingGoToEvent);
0504 
0505     // Here, we make the class that will make the ProvenanceReader
0506     // It reads whatever trees it needs.
0507     // propagate_const<T> has no reset() function
0508     provenanceReaderMaker_ = std::unique_ptr<MakeProvenanceReader>(makeProvenanceReaderMaker(inputType).release());
0509 
0510     // Merge into the hashed registries.
0511     if (eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
0512       whyNotFastClonable_ += FileBlock::EventsOrLumisSelectedByID;
0513     }
0514 
0515     initializeDuplicateChecker(indexesIntoFiles, currentIndexIntoFile);
0516     indexIntoFileIter_ = indexIntoFileBegin_ = indexIntoFile_.begin(
0517         noRunLumiSort ? IndexIntoFile::entryOrder
0518                       : (noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder));
0519     indexIntoFileEnd_ = indexIntoFile_.end(
0520         noRunLumiSort ? IndexIntoFile::entryOrder
0521                       : (noEventSort ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder));
0522     runHelper_->setForcedRunOffset(indexIntoFileBegin_ == indexIntoFileEnd_ ? 1 : indexIntoFileBegin_.run());
0523     eventProcessHistoryIter_ = eventProcessHistoryIDs_.begin();
0524 
0525     makeProcessBlockRootTrees(filePtr, treeMaxVirtualSize, enablePrefetching, inputType, storedProcessBlockHelper);
0526 
0527     setPresenceInProductRegistry(inputProdDescReg, storedProcessBlockHelper);
0528 
0529     auto newReg = std::make_unique<ProductRegistry>();
0530 
0531     // Do the translation from the old registry to the new one
0532     {
0533       ProductRegistry::ProductList const& prodList = inputProdDescReg.productList();
0534       for (auto const& product : prodList) {
0535         BranchDescription const& prod = product.second;
0536         std::string newFriendlyName = friendlyname::friendlyName(prod.className());
0537         if (newFriendlyName == prod.friendlyClassName()) {
0538           newReg->copyProduct(prod);
0539         } else {
0540           if (fileFormatVersion().splitProductIDs()) {
0541             throw Exception(errors::UnimplementedFeature)
0542                 << "Cannot change friendly class name algorithm without more development work\n"
0543                 << "to update BranchIDLists and ThinnedAssociationsHelper.  Contact the framework group.\n";
0544           }
0545           BranchDescription newBD(prod);
0546           newBD.updateFriendlyClassName();
0547           newReg->copyProduct(newBD);
0548           newBranchToOldBranch_.insert(std::make_pair(newBD.branchName(), prod.branchName()));
0549         }
0550       }
0551 
0552       dropOnInputAndReorder(
0553           *newReg, productSelectorRules, dropDescendants, inputType, storedProcessBlockHelper, processBlockHelper);
0554 
0555       if (inputType == InputType::SecondaryFile) {
0556         thinnedAssociationsHelper->updateFromSecondaryInput(*fileThinnedAssociationsHelper_,
0557                                                             *associationsFromSecondary);
0558       } else if (inputType == InputType::Primary) {
0559         processBlockHelper->initializeFromPrimaryInput(storedProcessBlockHelper);
0560         thinnedAssociationsHelper->updateFromPrimaryInput(*fileThinnedAssociationsHelper_);
0561       }
0562 
0563       if (inputType == InputType::Primary) {
0564         for (auto& product : newReg->productListUpdator()) {
0565           setIsMergeable(product.second);
0566         }
0567       }
0568       //inform system we want to use DelayedReader
0569       for (auto& product : newReg->productListUpdator()) {
0570         product.second.setOnDemand(true);
0571       }
0572 
0573       for (auto& processBlockTree : processBlockTrees_) {
0574         treePointers_.push_back(processBlockTree.get());
0575       }
0576 
0577       // freeze the product registry
0578       newReg->setFrozen(inputType != InputType::Primary);
0579       productRegistry_.reset(newReg.release());
0580     }
0581 
0582     // Set up information from the product registry.
0583     ProductRegistry::ProductList const& prodList = productRegistry()->productList();
0584 
0585     {
0586       std::vector<size_t> nBranches(treePointers_.size(), 0);
0587       for (auto const& product : prodList) {
0588         if (product.second.branchType() == InProcess) {
0589           std::vector<std::string> const& processes = storedProcessBlockHelper.processesWithProcessBlockProducts();
0590           auto it = std::find(processes.begin(), processes.end(), product.second.processName());
0591           if (it != processes.end()) {
0592             auto index = std::distance(processes.begin(), it);
0593             ++nBranches[numberOfRunLumiEventProductTrees + index];
0594           }
0595         } else {
0596           ++nBranches[product.second.branchType()];
0597         }
0598       }
0599 
0600       int i = 0;
0601       for (auto& t : treePointers_) {
0602         t->numberOfBranchesToAdd(nBranches[i]);
0603         ++i;
0604       }
0605     }
0606     for (auto const& product : prodList) {
0607       BranchDescription const& prod = product.second;
0608       if (prod.branchType() == InProcess) {
0609         std::vector<std::string> const& processes = storedProcessBlockHelper.processesWithProcessBlockProducts();
0610         auto it = std::find(processes.begin(), processes.end(), prod.processName());
0611         if (it != processes.end()) {
0612           auto index = std::distance(processes.begin(), it);
0613           treePointers_[numberOfRunLumiEventProductTrees + index]->addBranch(prod,
0614                                                                              newBranchToOldBranch(prod.branchName()));
0615         }
0616       } else {
0617         treePointers_[prod.branchType()]->addBranch(prod, newBranchToOldBranch(prod.branchName()));
0618       }
0619     }
0620 
0621     // Determine if this file is fast clonable.
0622     setIfFastClonable(remainingEvents, remainingLumis);
0623 
0624     // We are done with our initial reading of EventAuxiliary.
0625     indexIntoFile_.doneFileInitialization();
0626 
0627     // Tell the event tree to begin training at the next read.
0628     eventTree_.resetTraining();
0629 
0630     // Train the run and lumi trees.
0631     runTree_.trainCache("*");
0632     lumiTree_.trainCache("*");
0633     for (auto& processBlockTree : processBlockTrees_) {
0634       processBlockTree->trainCache("*");
0635     }
0636   }
0637 
0638   RootFile::~RootFile() {}
0639 
0640   void RootFile::readEntryDescriptionTree(EntryDescriptionMap& entryDescriptionMap, InputType inputType) {
0641     // Called only for old format files.
0642     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
0643     std::unique_ptr<TTree> entryDescriptionTree(
0644         dynamic_cast<TTree*>(filePtr_->Get(poolNames::entryDescriptionTreeName().c_str())));
0645     if (nullptr == entryDescriptionTree.get()) {
0646       throw Exception(errors::FileReadError)
0647           << "Could not find tree " << poolNames::entryDescriptionTreeName() << " in the input file.\n";
0648     }
0649 
0650     EntryDescriptionID idBuffer;
0651     EntryDescriptionID* pidBuffer = &idBuffer;
0652     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionIDBranchName().c_str(), &pidBuffer);
0653 
0654     EventEntryDescription entryDescriptionBuffer;
0655     EventEntryDescription* pEntryDescriptionBuffer = &entryDescriptionBuffer;
0656     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionBranchName().c_str(), &pEntryDescriptionBuffer);
0657 
0658     // Fill in the parentage registry.
0659     ParentageRegistry& registry = *ParentageRegistry::instance();
0660 
0661     for (Long64_t i = 0, numEntries = entryDescriptionTree->GetEntries(); i < numEntries; ++i) {
0662       roottree::getEntry(entryDescriptionTree.get(), i);
0663       if (idBuffer != entryDescriptionBuffer.id()) {
0664         throw Exception(errors::EventCorruption) << "Corruption of EntryDescription tree detected.\n";
0665       }
0666       entryDescriptionMap.insert(std::make_pair(entryDescriptionBuffer.id(), entryDescriptionBuffer));
0667       Parentage parents;
0668       parents.setParents(entryDescriptionBuffer.parents());
0669       if (daqProvenanceHelper_) {
0670         ParentageID const oldID = parents.id();
0671         daqProvenanceHelper_->fixMetaData(parents.parentsForUpdate());
0672         ParentageID newID = parents.id();
0673         if (newID != oldID) {
0674           daqProvenanceHelper_->setOldParentageIDToNew(oldID, newID);
0675         }
0676       }
0677       // For thread safety, don't update global registries when a secondary source opens a file.
0678       if (inputType != InputType::SecondarySource) {
0679         registry.insertMapped(parents);
0680       }
0681     }
0682     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionIDBranchName().c_str(), nullptr);
0683     entryDescriptionTree->SetBranchAddress(poolNames::entryDescriptionBranchName().c_str(), nullptr);
0684   }
0685 
0686   void RootFile::readParentageTree(InputType inputType) {
0687     // New format file
0688     // We use a smart pointer so the tree will be deleted after use, and not kept for the life of the file.
0689     std::unique_ptr<TTree> parentageTree(dynamic_cast<TTree*>(filePtr_->Get(poolNames::parentageTreeName().c_str())));
0690     if (nullptr == parentageTree.get()) {
0691       throw Exception(errors::FileReadError)
0692           << "Could not find tree " << poolNames::parentageTreeName() << " in the input file.\n";
0693     }
0694 
0695     Parentage parents;
0696     Parentage* pParentageBuffer = &parents;
0697     parentageTree->SetBranchAddress(poolNames::parentageBranchName().c_str(), &pParentageBuffer);
0698 
0699     ParentageRegistry& registry = *ParentageRegistry::instance();
0700 
0701     parentageIDLookup_.reserve(parentageTree->GetEntries());
0702     for (Long64_t i = 0, numEntries = parentageTree->GetEntries(); i < numEntries; ++i) {
0703       roottree::getEntry(parentageTree.get(), i);
0704       if (daqProvenanceHelper_) {
0705         ParentageID const oldID = parents.id();
0706         daqProvenanceHelper_->fixMetaData(parents.parentsForUpdate());
0707         ParentageID newID = parents.id();
0708         if (newID != oldID) {
0709           daqProvenanceHelper_->setOldParentageIDToNew(oldID, newID);
0710         }
0711       }
0712       // For thread safety, don't update global registries when a secondary source opens a file.
0713       if (inputType != InputType::SecondarySource) {
0714         registry.insertMapped(parents);
0715       }
0716       parentageIDLookup_.push_back(parents.id());
0717     }
0718     parentageTree->SetBranchAddress(poolNames::parentageBranchName().c_str(), nullptr);
0719   }
0720 
0721   void RootFile::setIfFastClonable(int remainingEvents, int remainingLumis) {
0722     if (fileFormatVersion().noMetaDataTrees() and !fileFormatVersion().storedProductProvenanceUsed()) {
0723       //we must avoid copying the old branch which stored the per product per event provenance
0724       whyNotFastClonable_ += FileBlock::FileTooOld;
0725       return;
0726     }
0727     if (!fileFormatVersion().splitProductIDs()) {
0728       whyNotFastClonable_ += FileBlock::FileTooOld;
0729       return;
0730     }
0731     if (processingMode_ != InputSource::RunsLumisAndEvents) {
0732       whyNotFastClonable_ += FileBlock::NotProcessingEvents;
0733       return;
0734     }
0735     // Find entry for first event in file
0736     IndexIntoFile::IndexIntoFileItr it = indexIntoFileBegin_;
0737     while (it != indexIntoFileEnd_ && it.getEntryType() != IndexIntoFile::kEvent) {
0738       ++it;
0739     }
0740     if (it == indexIntoFileEnd_) {
0741       whyNotFastClonable_ += FileBlock::NoEventsInFile;
0742       return;
0743     }
0744 
0745     // From here on, record all reasons we can't fast clone.
0746     IndexIntoFile::SortOrder sortOrder =
0747         (noRunLumiSort_ ? IndexIntoFile::entryOrder
0748                         : (noEventSort_ ? IndexIntoFile::firstAppearanceOrder : IndexIntoFile::numericalOrder));
0749     if (!indexIntoFile_.iterationWillBeInEntryOrder(sortOrder)) {
0750       whyNotFastClonable_ += (noEventSort_ ? FileBlock::RunOrLumiNotContiguous : FileBlock::EventsToBeSorted);
0751     }
0752     if (skipAnyEvents_) {
0753       whyNotFastClonable_ += FileBlock::InitialEventsSkipped;
0754     }
0755     if (remainingEvents >= 0 && eventTree_.entries() > remainingEvents) {
0756       whyNotFastClonable_ += FileBlock::MaxEventsTooSmall;
0757     }
0758     if (remainingLumis >= 0 && lumiTree_.entries() > remainingLumis) {
0759       whyNotFastClonable_ += FileBlock::MaxLumisTooSmall;
0760     }
0761     if (duplicateChecker_ && !duplicateChecker_->checkDisabled() && !duplicateChecker_->noDuplicatesInFile()) {
0762       whyNotFastClonable_ += FileBlock::DuplicateEventsRemoved;
0763     }
0764   }
0765 
0766   std::shared_ptr<FileBlock> RootFile::createFileBlock() {
0767     std::vector<TTree*> processBlockTrees;
0768     std::vector<std::string> processesWithProcessBlockTrees;
0769     processBlockTrees.reserve(processBlockTrees_.size());
0770     processesWithProcessBlockTrees.reserve(processBlockTrees_.size());
0771     for (auto& processBlockTree : processBlockTrees_) {
0772       processBlockTrees.push_back(processBlockTree->tree());
0773       processesWithProcessBlockTrees.push_back(processBlockTree->processName());
0774     }
0775     return std::make_shared<FileBlock>(fileFormatVersion(),
0776                                        eventTree_.tree(),
0777                                        eventTree_.metaTree(),
0778                                        lumiTree_.tree(),
0779                                        lumiTree_.metaTree(),
0780                                        runTree_.tree(),
0781                                        runTree_.metaTree(),
0782                                        std::move(processBlockTrees),
0783                                        std::move(processesWithProcessBlockTrees),
0784                                        whyNotFastClonable(),
0785                                        hasNewlyDroppedBranch(),
0786                                        file_,
0787                                        branchListIndexesUnchanged(),
0788                                        modifiedIDs(),
0789                                        branchChildren());
0790   }
0791 
0792   void RootFile::updateFileBlock(FileBlock& fileBlock) {
0793     std::vector<TTree*> processBlockTrees;
0794     std::vector<std::string> processesWithProcessBlockTrees;
0795     processBlockTrees.reserve(processBlockTrees_.size());
0796     processesWithProcessBlockTrees.reserve(processBlockTrees_.size());
0797     for (auto& processBlockTree : processBlockTrees_) {
0798       processBlockTrees.push_back(processBlockTree->tree());
0799       processesWithProcessBlockTrees.push_back(processBlockTree->processName());
0800     }
0801     fileBlock.updateTTreePointers(eventTree_.tree(),
0802                                   eventTree_.metaTree(),
0803                                   lumiTree_.tree(),
0804                                   lumiTree_.metaTree(),
0805                                   runTree_.tree(),
0806                                   runTree_.metaTree(),
0807                                   std::move(processBlockTrees),
0808                                   std::move(processesWithProcessBlockTrees));
0809   }
0810 
0811   std::string const& RootFile::newBranchToOldBranch(std::string const& newBranch) const {
0812     std::map<std::string, std::string>::const_iterator it = newBranchToOldBranch_.find(newBranch);
0813     if (it != newBranchToOldBranch_.end()) {
0814       return it->second;
0815     }
0816     return newBranch;
0817   }
0818 
0819   IndexIntoFile::IndexIntoFileItr RootFile::indexIntoFileIter() const { return indexIntoFileIter_; }
0820 
0821   void RootFile::setPosition(IndexIntoFile::IndexIntoFileItr const& position) {
0822     indexIntoFileIter_.copyPosition(position);
0823   }
0824 
0825   void RootFile::initAssociationsFromSecondary(std::vector<BranchID> const& associationsFromSecondary) {
0826     thinnedAssociationsHelper_->initAssociationsFromSecondary(associationsFromSecondary,
0827                                                               *fileThinnedAssociationsHelper_);
0828   }
0829 
0830   bool RootFile::skipThisEntry() {
0831     if (indexIntoFileIter_ == indexIntoFileEnd_) {
0832       return false;
0833     }
0834 
0835     if (eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
0836       // See first if the entire lumi or run is skipped, so we won't have to read the event Auxiliary in that case.
0837       if (eventSkipperByID_->skipIt(indexIntoFileIter_.run(), indexIntoFileIter_.lumi(), 0U)) {
0838         return true;
0839       }
0840 
0841       // The Lumi is not skipped.  If this is an event, see if the event is skipped.
0842       if (indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent) {
0843         auto eventAux = fillEventAuxiliary(indexIntoFileIter_.entry());
0844         if (eventSkipperByID_->skipIt(indexIntoFileIter_.run(), indexIntoFileIter_.lumi(), eventAux.id().event())) {
0845           return true;
0846         }
0847       }
0848 
0849       // Skip runs with no lumis if either lumisToSkip or lumisToProcess have been set to select lumis
0850       if (indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun && eventSkipperByID_->skippingLumis()) {
0851         // There are no lumis in this run, not even ones we will skip
0852         if (indexIntoFileIter_.peekAheadAtLumi() == IndexIntoFile::invalidLumi) {
0853           return true;
0854         }
0855         // If we get here there are lumis in the run, check to see if we are skipping all of them
0856         do {
0857           if (!eventSkipperByID_->skipIt(indexIntoFileIter_.run(), indexIntoFileIter_.peekAheadAtLumi(), 0U)) {
0858             return false;
0859           }
0860         } while (indexIntoFileIter_.skipLumiInRun());
0861         return true;
0862       }
0863     }
0864     return false;
0865   }
0866 
0867   bool RootFile::isDuplicateEvent() {
0868     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent);
0869     if (duplicateChecker_.get() == nullptr) {
0870       return false;
0871     }
0872     auto const eventAux = fillEventAuxiliary(indexIntoFileIter_.entry());
0873     return duplicateChecker_->isDuplicateAndCheckActive(indexIntoFileIter_.processHistoryIDIndex(),
0874                                                         indexIntoFileIter_.run(),
0875                                                         indexIntoFileIter_.lumi(),
0876                                                         eventAux.id().event(),
0877                                                         file_);
0878   }
0879 
0880   bool RootFile::containsItem(RunNumber_t run, LuminosityBlockNumber_t lumi, EventNumber_t event) const {
0881     return indexIntoFile_.containsItem(run, lumi, event);
0882   }
0883 
0884   IndexIntoFile::EntryType RootFile::getNextItemType(RunNumber_t& run,
0885                                                      LuminosityBlockNumber_t& lumi,
0886                                                      EventNumber_t& event) {
0887     // First, account for consecutive skipped entries.
0888     while (skipThisEntry()) {
0889       if (indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun) {
0890         indexIntoFileIter_.advanceToNextRun();
0891       } else if (indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi) {
0892         indexIntoFileIter_.advanceToNextLumiOrRun();
0893       } else {
0894         ++indexIntoFileIter_;
0895       }
0896     }
0897     // OK, we have an entry that is not skipped.
0898     IndexIntoFile::EntryType entryType = indexIntoFileIter_.getEntryType();
0899     if (entryType == IndexIntoFile::kEnd) {
0900       return IndexIntoFile::kEnd;
0901     }
0902     if (entryType == IndexIntoFile::kRun) {
0903       run = indexIntoFileIter_.run();
0904       runHelper_->checkForNewRun(run, indexIntoFileIter_.peekAheadAtLumi());
0905       return IndexIntoFile::kRun;
0906     } else if (processingMode_ == InputSource::Runs) {
0907       indexIntoFileIter_.advanceToNextRun();
0908       return getNextItemType(run, lumi, event);
0909     }
0910     if (entryType == IndexIntoFile::kLumi) {
0911       run = indexIntoFileIter_.run();
0912       lumi = indexIntoFileIter_.lumi();
0913       return IndexIntoFile::kLumi;
0914     } else if (processingMode_ == InputSource::RunsAndLumis) {
0915       indexIntoFileIter_.advanceToNextLumiOrRun();
0916       return getNextItemType(run, lumi, event);
0917     }
0918     if (isDuplicateEvent()) {
0919       ++indexIntoFileIter_;
0920       return getNextItemType(run, lumi, event);
0921     }
0922     run = indexIntoFileIter_.run();
0923     lumi = indexIntoFileIter_.lumi();
0924     auto eventAux = fillEventAuxiliary(indexIntoFileIter_.entry());
0925     event = eventAux.event();
0926     return IndexIntoFile::kEvent;
0927   }
0928 
0929   bool RootFile::wasLastEventJustRead() const {
0930     IndexIntoFile::IndexIntoFileItr itr(indexIntoFileIter_);
0931     itr.advanceToEvent();
0932     return itr.getEntryType() == IndexIntoFile::kEnd;
0933   }
0934 
0935   bool RootFile::wasFirstEventJustRead() const {
0936     IndexIntoFile::IndexIntoFileItr itr(indexIntoFileIter_);
0937     int phIndex;
0938     RunNumber_t run;
0939     LuminosityBlockNumber_t lumi;
0940     IndexIntoFile::EntryNumber_t eventEntry;
0941     itr.skipEventBackward(phIndex, run, lumi, eventEntry);
0942     itr.skipEventBackward(phIndex, run, lumi, eventEntry);
0943     return eventEntry == IndexIntoFile::invalidEntry;
0944   }
0945 
0946   namespace {
0947     struct RunItem {
0948       RunItem(ProcessHistoryID const& phid, RunNumber_t const& run) : phid_(phid), run_(run) {}
0949       ProcessHistoryID phid_;
0950       RunNumber_t run_;
0951     };
0952     struct RunItemSortByRun {
0953       bool operator()(RunItem const& a, RunItem const& b) const { return a.run_ < b.run_; }
0954     };
0955     struct RunItemSortByRunPhid {
0956       bool operator()(RunItem const& a, RunItem const& b) const {
0957         return a.run_ < b.run_ || (!(b.run_ < a.run_) && a.phid_ < b.phid_);
0958       }
0959     };
0960     struct LumiItem {
0961       LumiItem(ProcessHistoryID const& phid,
0962                RunNumber_t const& run,
0963                LuminosityBlockNumber_t const& lumi,
0964                IndexIntoFile::EntryNumber_t const& entry)
0965           : phid_(phid),
0966             run_(run),
0967             lumi_(lumi),
0968             firstEventEntry_(entry),
0969             lastEventEntry_(entry == IndexIntoFile::invalidEntry ? IndexIntoFile::invalidEntry : entry + 1) {}
0970       ProcessHistoryID phid_;
0971       RunNumber_t run_;
0972       LuminosityBlockNumber_t lumi_;
0973       IndexIntoFile::EntryNumber_t firstEventEntry_;
0974       IndexIntoFile::EntryNumber_t lastEventEntry_;
0975     };
0976     struct LumiItemSortByRunLumi {
0977       bool operator()(LumiItem const& a, LumiItem const& b) const {
0978         return a.run_ < b.run_ || (!(b.run_ < a.run_) && a.lumi_ < b.lumi_);
0979       }
0980     };
0981     struct LumiItemSortByRunLumiPhid {
0982       bool operator()(LumiItem const& a, LumiItem const& b) const {
0983         if (a.run_ < b.run_)
0984           return true;
0985         if (b.run_ < a.run_)
0986           return false;
0987         if (a.lumi_ < b.lumi_)
0988           return true;
0989         if (b.lumi_ < a.lumi_)
0990           return false;
0991         return a.phid_ < b.phid_;
0992       }
0993     };
0994   }  // namespace
0995 
0996   void RootFile::fillIndexIntoFile() {
0997     // This function is for backward compatibility.
0998     // If reading a current format file, indexIntoFile_ is read from the input
0999     // file and should always be there. Note that the algorithm below will work
1000     // sometimes but often fail with the new format introduced in release 3_8_0.
1001     // If it ever becomes necessary to rebuild IndexIntoFile from the new format,
1002     // probably a separate function should be written to deal with the task.
1003     // This is possible just not implemented yet.
1004     assert(!fileFormatVersion().hasIndexIntoFile());
1005 
1006     typedef std::list<LumiItem> LumiList;
1007     LumiList lumis;  // (declare 1)
1008 
1009     typedef std::set<LuminosityBlockID> RunLumiSet;
1010     RunLumiSet runLumiSet;  // (declare 2)
1011 
1012     typedef std::list<RunItem> RunList;
1013     RunList runs;  // (declare 5)
1014 
1015     typedef std::set<RunNumber_t> RunSet;
1016     RunSet runSet;  // (declare 4)
1017 
1018     typedef std::set<RunItem, RunItemSortByRunPhid> RunItemSet;
1019     RunItemSet runItemSet;  // (declare 3)
1020 
1021     typedef std::map<RunNumber_t, ProcessHistoryID> PHIDMap;
1022     PHIDMap phidMap;
1023 
1024     RunNumber_t prevRun = 0;
1025     LuminosityBlockNumber_t prevLumi = 0;
1026     ProcessHistoryID prevPhid;
1027     bool iFirst = true;
1028 
1029     indexIntoFile_.unsortedEventNumbers().clear();  // should already be empty, just being careful
1030     indexIntoFile_.unsortedEventNumbers().reserve(eventTree_.entries());
1031 
1032     // First, loop through the event tree.
1033     EventSelectionIDVector eventSelectionIDs;
1034     BranchListIndexes branchListIndexes;
1035     while (eventTree_.next()) {
1036       bool newRun = false;
1037       bool newLumi = false;
1038       auto evtAux = fillThisEventAuxiliary();
1039       fillEventHistory(evtAux, eventSelectionIDs, branchListIndexes);
1040 
1041       // Save the event numbers as we loop through the event auxiliary to avoid
1042       // having to read through the event auxiliary again later. These event numbers
1043       // are not actually used in this function, but could be needed elsewhere.
1044       indexIntoFile_.unsortedEventNumbers().push_back(evtAux.event());
1045 
1046       ProcessHistoryID reducedPHID = processHistoryRegistry_->reducedProcessHistoryID(evtAux.processHistoryID());
1047 
1048       if (iFirst || prevPhid != reducedPHID || prevRun != evtAux.run()) {
1049         iFirst = false;
1050         newRun = newLumi = true;
1051       } else if (prevLumi != evtAux.luminosityBlock()) {
1052         newLumi = true;
1053       }
1054       prevPhid = reducedPHID;
1055       prevRun = evtAux.run();
1056       prevLumi = evtAux.luminosityBlock();
1057       if (newLumi) {
1058         lumis.emplace_back(
1059             reducedPHID, evtAux.run(), evtAux.luminosityBlock(), eventTree_.entryNumber());  // (insert 1)
1060         runLumiSet.insert(LuminosityBlockID(evtAux.run(), evtAux.luminosityBlock()));        // (insert 2)
1061       } else {
1062         LumiItem& currentLumi = lumis.back();
1063         assert(currentLumi.lastEventEntry_ == eventTree_.entryNumber());
1064         ++currentLumi.lastEventEntry_;
1065       }
1066       if (newRun) {
1067         // Insert run in list if it is not already there.
1068         RunItem item(reducedPHID, evtAux.run());
1069         if (runItemSet.insert(item).second) {  // (check 3, insert 3)
1070           runs.push_back(std::move(item));     // (insert 5)
1071           runSet.insert(evtAux.run());         // (insert 4)
1072           phidMap.insert(std::make_pair(evtAux.run(), reducedPHID));
1073         }
1074       }
1075     }
1076     // now clean up.
1077     eventTree_.setEntryNumber(IndexIntoFile::invalidEntry);
1078     lastEventEntryNumberRead_ = IndexIntoFile::invalidEntry;
1079 
1080     // Loop over run entries and fill information.
1081 
1082     typedef std::map<RunNumber_t, IndexIntoFile::EntryNumber_t> RunMap;
1083     RunMap runMap;  // (declare 11)
1084 
1085     typedef std::vector<RunItem> RunVector;
1086     RunVector emptyRuns;  // (declare 12)
1087 
1088     if (runTree_.isValid()) {
1089       while (runTree_.next()) {
1090         // Note: adjacent duplicates will be skipped without an explicit check.
1091 
1092         std::shared_ptr<RunAuxiliary> runAux = fillRunAuxiliary();
1093         ProcessHistoryID reducedPHID = processHistoryRegistry_->reducedProcessHistoryID(runAux->processHistoryID());
1094 
1095         if (runSet.insert(runAux->run()).second) {  // (check 4, insert 4)
1096           // This run was not associated with any events.
1097           emptyRuns.emplace_back(reducedPHID, runAux->run());  // (insert 12)
1098         }
1099         runMap.insert(std::make_pair(runAux->run(), runTree_.entryNumber()));  // (insert 11)
1100         phidMap.insert(std::make_pair(runAux->run(), reducedPHID));
1101       }
1102       // now clean up.
1103       runTree_.setEntryNumber(IndexIntoFile::invalidEntry);
1104     }
1105 
1106     // Insert the ordered empty runs into the run list.
1107     RunItemSortByRun runItemSortByRun;
1108     stable_sort_all(emptyRuns, runItemSortByRun);
1109 
1110     RunList::iterator itRuns = runs.begin(), endRuns = runs.end();
1111     for (auto const& emptyRun : emptyRuns) {
1112       for (; itRuns != endRuns; ++itRuns) {
1113         if (runItemSortByRun(emptyRun, *itRuns)) {
1114           break;
1115         }
1116       }
1117       runs.insert(itRuns, emptyRun);
1118     }
1119 
1120     // Loop over luminosity block entries and fill information.
1121 
1122     typedef std::vector<LumiItem> LumiVector;
1123     LumiVector emptyLumis;  // (declare 7)
1124 
1125     typedef std::map<LuminosityBlockID, IndexIntoFile::EntryNumber_t> RunLumiMap;
1126     RunLumiMap runLumiMap;  // (declare 6)
1127 
1128     if (lumiTree_.isValid()) {
1129       while (lumiTree_.next()) {
1130         // Note: adjacent duplicates will be skipped without an explicit check.
1131         std::shared_ptr<LuminosityBlockAuxiliary> lumiAux = fillLumiAuxiliary();
1132         LuminosityBlockID lumiID = LuminosityBlockID(lumiAux->run(), lumiAux->luminosityBlock());
1133         if (runLumiSet.insert(lumiID).second) {  // (check 2, insert 2)
1134           // This lumi was not associated with any events.
1135           // Use the process history ID from the corresponding run.  In cases of practical
1136           // importance, this should be the correct process history ID,  but it is possible
1137           // to construct files where this is not the correct process history ID ...
1138           PHIDMap::const_iterator iPhidMap = phidMap.find(lumiAux->run());
1139           assert(iPhidMap != phidMap.end());
1140           emptyLumis.emplace_back(
1141               iPhidMap->second, lumiAux->run(), lumiAux->luminosityBlock(), IndexIntoFile::invalidEntry);  // (insert 7)
1142         }
1143         runLumiMap.insert(std::make_pair(lumiID, lumiTree_.entryNumber()));
1144       }
1145       // now clean up.
1146       lumiTree_.setEntryNumber(IndexIntoFile::invalidEntry);
1147     }
1148 
1149     // Insert the ordered empty lumis into the lumi list.
1150     LumiItemSortByRunLumi lumiItemSortByRunLumi;
1151     stable_sort_all(emptyLumis, lumiItemSortByRunLumi);
1152 
1153     LumiList::iterator itLumis = lumis.begin(), endLumis = lumis.end();
1154     for (auto const& emptyLumi : emptyLumis) {
1155       for (; itLumis != endLumis; ++itLumis) {
1156         if (lumiItemSortByRunLumi(emptyLumi, *itLumis)) {
1157           break;
1158         }
1159       }
1160       lumis.insert(itLumis, emptyLumi);
1161     }
1162 
1163     // Create a map of RunItems that gives the order of first appearance in the list.
1164     // Also fill in the vector of process history IDs
1165     typedef std::map<RunItem, int, RunItemSortByRunPhid> RunCountMap;
1166     RunCountMap runCountMap;  // Declare (17)
1167     std::vector<ProcessHistoryID>& phids = indexIntoFile_.setProcessHistoryIDs();
1168     assert(phids.empty());
1169     std::vector<IndexIntoFile::RunOrLumiEntry>& entries = indexIntoFile_.setRunOrLumiEntries();
1170     assert(entries.empty());
1171     int rcount = 0;
1172     for (auto& run : runs) {
1173       RunCountMap::const_iterator countMapItem = runCountMap.find(run);
1174       if (countMapItem == runCountMap.end()) {
1175         countMapItem = runCountMap.insert(std::make_pair(run, rcount)).first;  // Insert (17)
1176         assert(countMapItem != runCountMap.end());
1177         ++rcount;
1178       }
1179       std::vector<ProcessHistoryID>::const_iterator phidItem = find_in_all(phids, run.phid_);
1180       if (phidItem == phids.end()) {
1181         phids.push_back(run.phid_);
1182         phidItem = phids.end() - 1;
1183       }
1184       entries.emplace_back(countMapItem->second,  // use (17)
1185                            IndexIntoFile::invalidEntry,
1186                            runMap[run.run_],  // use (11)
1187                            phidItem - phids.begin(),
1188                            run.run_,
1189                            0U,
1190                            IndexIntoFile::invalidEntry,
1191                            IndexIntoFile::invalidEntry);
1192     }
1193 
1194     // Create a map of LumiItems that gives the order of first appearance in the list.
1195     typedef std::map<LumiItem, int, LumiItemSortByRunLumiPhid> LumiCountMap;
1196     LumiCountMap lumiCountMap;  // Declare (19)
1197     int lcount = 0;
1198     for (auto& lumi : lumis) {
1199       RunCountMap::const_iterator runCountMapItem = runCountMap.find(RunItem(lumi.phid_, lumi.run_));
1200       assert(runCountMapItem != runCountMap.end());
1201       LumiCountMap::const_iterator countMapItem = lumiCountMap.find(lumi);
1202       if (countMapItem == lumiCountMap.end()) {
1203         countMapItem = lumiCountMap.insert(std::make_pair(lumi, lcount)).first;  // Insert (17)
1204         assert(countMapItem != lumiCountMap.end());
1205         ++lcount;
1206       }
1207       std::vector<ProcessHistoryID>::const_iterator phidItem = find_in_all(phids, lumi.phid_);
1208       assert(phidItem != phids.end());
1209       entries.emplace_back(runCountMapItem->second,
1210                            countMapItem->second,
1211                            runLumiMap[LuminosityBlockID(lumi.run_, lumi.lumi_)],
1212                            phidItem - phids.begin(),
1213                            lumi.run_,
1214                            lumi.lumi_,
1215                            lumi.firstEventEntry_,
1216                            lumi.lastEventEntry_);
1217     }
1218     stable_sort_all(entries);
1219   }
1220 
1221   void RootFile::validateFile(InputType inputType, bool usingGoToEvent) {
1222     if (!fid_.isValid()) {
1223       fid_ = FileID(createGlobalIdentifier());
1224     }
1225     if (!eventTree_.isValid()) {
1226       throw Exception(errors::EventCorruption) << "'Events' tree is corrupted or not present\n"
1227                                                << "in the input file.\n";
1228     }
1229     if (enforceGUIDInFileName_) {
1230       auto guidFromName = stemFromPath(file_);
1231       if (guidFromName != fid_.fid()) {
1232         throw edm::Exception(edm::errors::FileNameInconsistentWithGUID)
1233             << "GUID " << guidFromName << " extracted from file name " << file_
1234             << " is inconsistent with the GUID read from the file " << fid_.fid();
1235       }
1236     }
1237 
1238     if (fileFormatVersion().hasIndexIntoFile()) {
1239       if (runTree().entries() > 0) {
1240         assert(!indexIntoFile_.empty());
1241       }
1242       if (!fileFormatVersion().useReducedProcessHistoryID()) {
1243         if (daqProvenanceHelper_) {
1244           std::vector<ProcessHistoryID>& phidVec = indexIntoFile_.setProcessHistoryIDs();
1245           for (auto& phid : phidVec) {
1246             phid = daqProvenanceHelper_->mapProcessHistoryID(phid);
1247           }
1248         }
1249         indexIntoFile_.reduceProcessHistoryIDs(*processHistoryRegistry_);
1250       }
1251     } else {
1252       assert(indexIntoFile_.empty());
1253       fillIndexIntoFile();
1254     }
1255 
1256     indexIntoFile_.fixIndexes(orderedProcessHistoryIDs_);
1257     indexIntoFile_.setNumberOfEvents(eventTree_.entries());
1258     indexIntoFile_.setEventFinder(
1259         std::shared_ptr<IndexIntoFile::EventFinder>(std::make_shared<RootFileEventFinder>(eventTree_)));
1260     // We fill the event numbers explicitly if we need to find events in closed files,
1261     // such as for secondary files (or secondary sources) or if duplicate checking across files.
1262     bool needEventNumbers = false;
1263     bool needIndexesForDuplicateChecker =
1264         duplicateChecker_ && duplicateChecker_->checkingAllFiles() && !duplicateChecker_->checkDisabled();
1265     if (inputType != InputType::Primary || needIndexesForDuplicateChecker || usingGoToEvent) {
1266       needEventNumbers = true;
1267     }
1268     bool needEventEntries = false;
1269     if (inputType != InputType::Primary || !noEventSort_) {
1270       // We need event entries for sorting or for secondary files or sources.
1271       needEventEntries = true;
1272     }
1273     indexIntoFile_.fillEventNumbersOrEntries(needEventNumbers, needEventEntries);
1274   }
1275 
1276   void RootFile::reportOpened(std::string const& inputType) {
1277     // Report file opened.
1278     std::string const label = "source";
1279     std::string moduleName = "PoolSource";
1280     filePtr_->inputFileOpened(logicalFile_, inputType, moduleName, label, fid_.fid(), eventTree_.branchNames());
1281   }
1282 
1283   void RootFile::close() {
1284     // Just to play it safe, zero all pointers to objects in the InputFile to be closed.
1285     eventHistoryTree_ = nullptr;
1286     for (auto& treePointer : treePointers_) {
1287       treePointer->close();
1288       treePointer = nullptr;
1289     }
1290     filePtr_->Close();
1291     filePtr_ = nullptr;  // propagate_const<T> has no reset() function
1292   }
1293 
1294   EventAuxiliary const& RootFile::fillThisEventAuxiliary() {
1295     if (lastEventEntryNumberRead_ == eventTree_.entryNumber()) {
1296       // Already read.
1297       return eventAuxCache_;
1298     }
1299     if (fileFormatVersion().newAuxiliary()) {
1300       EventAuxiliary* pEvAux = &eventAuxCache_;
1301       eventTree_.fillAux<EventAuxiliary>(pEvAux);
1302     } else {
1303       // for backward compatibility.
1304       EventAux eventAux;
1305       EventAux* pEvAux = &eventAux;
1306       eventTree_.fillAux<EventAux>(pEvAux);
1307       conversion(eventAux, eventAuxCache_);
1308     }
1309     lastEventEntryNumberRead_ = eventTree_.entryNumber();
1310     return eventAuxCache_;
1311   }
1312 
1313   EventAuxiliary RootFile::fillEventAuxiliary(IndexIntoFile::EntryNumber_t entry) {
1314     eventTree_.setEntryNumber(entry);
1315     return fillThisEventAuxiliary();
1316   }
1317 
1318   void RootFile::fillEventToProcessBlockIndexes() {
1319     TBranch* eventToProcessBlockIndexesBranch = get_underlying_safe(eventToProcessBlockIndexesBranch_);
1320     if (eventToProcessBlockIndexesBranch == nullptr) {
1321       if (processBlockHelper_.get() == nullptr) {
1322         eventToProcessBlockIndexes_.setIndex(0);
1323       } else {
1324         eventToProcessBlockIndexes_.setIndex(processBlockHelper_->outerOffset());
1325       }
1326     } else {
1327       if (processBlockHelper_->cacheIndexVectorsPerFile().back() == 1u) {
1328         eventToProcessBlockIndexes_.setIndex(processBlockHelper_->outerOffset());
1329       } else {
1330         EventToProcessBlockIndexes* pEventToProcessBlockIndexes = &eventToProcessBlockIndexes_;
1331         eventTree_.fillBranchEntry(eventToProcessBlockIndexesBranch, pEventToProcessBlockIndexes);
1332         unsigned int updatedIndex = eventToProcessBlockIndexes_.index() + processBlockHelper_->outerOffset();
1333         eventToProcessBlockIndexes_.setIndex(updatedIndex);
1334       }
1335     }
1336   }
1337 
1338   bool RootFile::fillEventHistory(EventAuxiliary& evtAux,
1339                                   EventSelectionIDVector& eventSelectionIDs,
1340                                   BranchListIndexes& branchListIndexes,
1341                                   bool assertOnFailure) {
1342     // We could consider doing delayed reading, but because we have to
1343     // store this History object in a different tree than the event
1344     // data tree, this is too hard to do in this first version.
1345     if (fileFormatVersion().eventHistoryBranch()) {
1346       // Lumi block number was not in EventID for the relevant releases.
1347       EventID id(evtAux.id().run(), 0, evtAux.id().event());
1348       if (eventProcessHistoryIter_->eventID() != id) {
1349         EventProcessHistoryID target(id, ProcessHistoryID());
1350         eventProcessHistoryIter_ = lower_bound_all(eventProcessHistoryIDs_, target);
1351         assert(eventProcessHistoryIter_->eventID() == id);
1352       }
1353       evtAux.setProcessHistoryID(eventProcessHistoryIter_->processHistoryID());
1354       ++eventProcessHistoryIter_;
1355     } else if (fileFormatVersion().eventHistoryTree()) {
1356       // for backward compatibility.
1357       History* pHistory = history_.get();
1358       TBranch* eventHistoryBranch = eventHistoryTree_->GetBranch(poolNames::eventHistoryBranchName().c_str());
1359       if (!eventHistoryBranch) {
1360         throw Exception(errors::EventCorruption) << "Failed to find history branch in event history tree.\n";
1361       }
1362       eventHistoryBranch->SetAddress(&pHistory);
1363       roottree::getEntry(eventHistoryTree_, eventTree_.entryNumber());
1364       evtAux.setProcessHistoryID(history_->processHistoryID());
1365       eventSelectionIDs.swap(history_->eventSelectionIDs());
1366       branchListIndexes.swap(history_->branchListIndexes());
1367     } else if (fileFormatVersion().noMetaDataTrees()) {
1368       // Current format
1369       EventSelectionIDVector* pESV = &eventSelectionIDs;
1370       TBranch* eventSelectionIDBranch = eventTree_.tree()->GetBranch(poolNames::eventSelectionsBranchName().c_str());
1371       assert(eventSelectionIDBranch != nullptr);
1372       eventTree_.fillBranchEntry(eventSelectionIDBranch, pESV);
1373       BranchListIndexes* pBLI = &branchListIndexes;
1374       TBranch* branchListIndexesBranch = eventTree_.tree()->GetBranch(poolNames::branchListIndexesBranchName().c_str());
1375       assert(branchListIndexesBranch != nullptr);
1376       eventTree_.fillBranchEntry(branchListIndexesBranch, pBLI);
1377     }
1378     if (provenanceAdaptor_) {
1379       evtAux.setProcessHistoryID(provenanceAdaptor_->convertID(evtAux.processHistoryID()));
1380       for (auto& esID : eventSelectionIDs) {
1381         esID = provenanceAdaptor_->convertID(esID);
1382       }
1383     }
1384     if (daqProvenanceHelper_) {
1385       evtAux.setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(evtAux.processHistoryID()));
1386     }
1387     if (!fileFormatVersion().splitProductIDs()) {
1388       // old format.  branchListIndexes_ must be filled in from the ProvenanceAdaptor.
1389       provenanceAdaptor_->branchListIndexes(branchListIndexes);
1390     }
1391     if (branchIDListHelper_) {
1392       return branchIDListHelper_->fixBranchListIndexes(branchListIndexes, assertOnFailure);
1393     }
1394     return true;
1395   }
1396 
1397   std::shared_ptr<LuminosityBlockAuxiliary> RootFile::fillLumiAuxiliary() {
1398     auto lumiAuxiliary = std::make_shared<LuminosityBlockAuxiliary>();
1399     if (fileFormatVersion().newAuxiliary()) {
1400       LuminosityBlockAuxiliary* pLumiAux = lumiAuxiliary.get();
1401       lumiTree_.fillAux<LuminosityBlockAuxiliary>(pLumiAux);
1402     } else {
1403       LuminosityBlockAux lumiAux;
1404       LuminosityBlockAux* pLumiAux = &lumiAux;
1405       lumiTree_.fillAux<LuminosityBlockAux>(pLumiAux);
1406       conversion(lumiAux, *lumiAuxiliary);
1407     }
1408     if (provenanceAdaptor_) {
1409       lumiAuxiliary->setProcessHistoryID(provenanceAdaptor_->convertID(lumiAuxiliary->processHistoryID()));
1410     }
1411     if (daqProvenanceHelper_) {
1412       lumiAuxiliary->setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(lumiAuxiliary->processHistoryID()));
1413     }
1414     if (lumiAuxiliary->luminosityBlock() == 0 && !fileFormatVersion().runsAndLumis()) {
1415       lumiAuxiliary->id() = LuminosityBlockID(RunNumber_t(1), LuminosityBlockNumber_t(1));
1416     }
1417     return lumiAuxiliary;
1418   }
1419 
1420   std::shared_ptr<RunAuxiliary> RootFile::fillRunAuxiliary() {
1421     auto runAuxiliary = std::make_shared<RunAuxiliary>();
1422     if (fileFormatVersion().newAuxiliary()) {
1423       RunAuxiliary* pRunAux = runAuxiliary.get();
1424       runTree_.fillAux<RunAuxiliary>(pRunAux);
1425     } else {
1426       RunAux runAux;
1427       RunAux* pRunAux = &runAux;
1428       runTree_.fillAux<RunAux>(pRunAux);
1429       conversion(runAux, *runAuxiliary);
1430     }
1431     if (provenanceAdaptor_) {
1432       runAuxiliary->setProcessHistoryID(provenanceAdaptor_->convertID(runAuxiliary->processHistoryID()));
1433     }
1434     if (daqProvenanceHelper_) {
1435       runAuxiliary->setProcessHistoryID(daqProvenanceHelper_->mapProcessHistoryID(runAuxiliary->processHistoryID()));
1436     }
1437     return runAuxiliary;
1438   }
1439 
1440   bool RootFile::skipEvents(int& offset) {
1441     while (offset > 0 && indexIntoFileIter_ != indexIntoFileEnd_) {
1442       int phIndexOfSkippedEvent = IndexIntoFile::invalidIndex;
1443       RunNumber_t runOfSkippedEvent = IndexIntoFile::invalidRun;
1444       LuminosityBlockNumber_t lumiOfSkippedEvent = IndexIntoFile::invalidLumi;
1445       IndexIntoFile::EntryNumber_t skippedEventEntry = IndexIntoFile::invalidEntry;
1446 
1447       indexIntoFileIter_.skipEventForward(
1448           phIndexOfSkippedEvent, runOfSkippedEvent, lumiOfSkippedEvent, skippedEventEntry);
1449 
1450       // At the end of the file and there were no more events to skip
1451       if (skippedEventEntry == IndexIntoFile::invalidEntry)
1452         break;
1453 
1454       if (eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
1455         auto const evtAux = fillEventAuxiliary(skippedEventEntry);
1456         if (eventSkipperByID_->skipIt(runOfSkippedEvent, lumiOfSkippedEvent, evtAux.id().event())) {
1457           continue;
1458         }
1459       }
1460       if (duplicateChecker_ && !duplicateChecker_->checkDisabled() && !duplicateChecker_->noDuplicatesInFile()) {
1461         auto const evtAux = fillEventAuxiliary(skippedEventEntry);
1462         if (duplicateChecker_->isDuplicateAndCheckActive(
1463                 phIndexOfSkippedEvent, runOfSkippedEvent, lumiOfSkippedEvent, evtAux.id().event(), file_)) {
1464           continue;
1465         }
1466       }
1467       --offset;
1468     }
1469 
1470     while (offset < 0) {
1471       if (duplicateChecker_) {
1472         duplicateChecker_->disable();
1473       }
1474 
1475       int phIndexOfEvent = IndexIntoFile::invalidIndex;
1476       RunNumber_t runOfEvent = IndexIntoFile::invalidRun;
1477       LuminosityBlockNumber_t lumiOfEvent = IndexIntoFile::invalidLumi;
1478       IndexIntoFile::EntryNumber_t eventEntry = IndexIntoFile::invalidEntry;
1479 
1480       indexIntoFileIter_.skipEventBackward(phIndexOfEvent, runOfEvent, lumiOfEvent, eventEntry);
1481 
1482       if (eventEntry == IndexIntoFile::invalidEntry)
1483         break;
1484 
1485       if (eventSkipperByID_ && eventSkipperByID_->somethingToSkip()) {
1486         auto const evtAux = fillEventAuxiliary(eventEntry);
1487         if (eventSkipperByID_->skipIt(runOfEvent, lumiOfEvent, evtAux.id().event())) {
1488           continue;
1489         }
1490       }
1491       ++offset;
1492     }
1493     return (indexIntoFileIter_ == indexIntoFileEnd_);
1494   }
1495 
1496   bool RootFile::goToEvent(EventID const& eventID) {
1497     indexIntoFile_.fillEventNumbers();
1498 
1499     if (duplicateChecker_) {
1500       duplicateChecker_->disable();
1501     }
1502 
1503     IndexIntoFile::SortOrder sortOrder = IndexIntoFile::numericalOrder;
1504     if (noEventSort_)
1505       sortOrder = IndexIntoFile::firstAppearanceOrder;
1506     if (noRunLumiSort_) {
1507       sortOrder = IndexIntoFile::entryOrder;
1508     }
1509 
1510     IndexIntoFile::IndexIntoFileItr iter =
1511         indexIntoFile_.findPosition(sortOrder, eventID.run(), eventID.luminosityBlock(), eventID.event());
1512 
1513     if (iter == indexIntoFile_.end(sortOrder)) {
1514       return false;
1515     }
1516     indexIntoFileIter_ = iter;
1517     return true;
1518   }
1519 
1520   // readEvent() is responsible for creating, and setting up, the
1521   // EventPrincipal.
1522   //
1523   //   1. create an EventPrincipal with a unique EventID
1524   //   2. For each entry in the provenance, put in one ProductResolver,
1525   //      holding the Provenance for the corresponding EDProduct.
1526   //   3. set up the the EventPrincipal to know about this ProductResolver.
1527   //
1528   // We do *not* create the EDProduct instance (the equivalent of reading
1529   // the branch containing this EDProduct. That will be done by the Delayed Reader,
1530   //  when it is asked to do so.
1531   //
1532   bool RootFile::readEvent(EventPrincipal& principal) {
1533     assert(indexIntoFileIter_ != indexIntoFileEnd_);
1534     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent);
1535     // read the event
1536     auto [found, succeeded] = readCurrentEvent(principal, false);
1537     auto const& evtAux = principal.aux();
1538 
1539     runHelper_->checkRunConsistency(evtAux.run(), indexIntoFileIter_.run());
1540     runHelper_->checkLumiConsistency(evtAux.luminosityBlock(), indexIntoFileIter_.lumi());
1541 
1542     ++indexIntoFileIter_;
1543     return succeeded;
1544   }
1545 
1546   // Reads event at the current entry in the event tree
1547   std::tuple<bool, bool> RootFile::readCurrentEvent(EventPrincipal& principal, bool assertOnFailure) {
1548     bool found = true;
1549     bool succeeded = true;
1550     if (!eventTree_.current()) {
1551       found = false;
1552       return {found, succeeded};
1553     }
1554     auto evtAux = fillThisEventAuxiliary();
1555     if (!fileFormatVersion().lumiInEventID()) {
1556       //ugly, but will disappear when the backward compatibility is done with schema evolution.
1557       const_cast<EventID&>(evtAux.id()).setLuminosityBlockNumber(evtAux.oldLuminosityBlock());
1558       evtAux.resetObsoleteInfo();
1559     }
1560     fillEventToProcessBlockIndexes();
1561     EventSelectionIDVector eventSelectionIDs;
1562     BranchListIndexes branchListIndexes;
1563     if (!fillEventHistory(evtAux, eventSelectionIDs, branchListIndexes, assertOnFailure)) {
1564       succeeded = false;
1565     }
1566     runHelper_->overrideRunNumber(evtAux.id(), evtAux.isRealData());
1567 
1568     // We're not done ... so prepare the EventPrincipal
1569     eventTree_.insertEntryForIndex(principal.transitionIndex());
1570     auto history = processHistoryRegistry_->getMapped(evtAux.processHistoryID());
1571     principal.fillEventPrincipal(evtAux,
1572                                  history,
1573                                  std::move(eventSelectionIDs),
1574                                  std::move(branchListIndexes),
1575                                  eventToProcessBlockIndexes_,
1576                                  *(makeProductProvenanceRetriever(principal.streamID().value())),
1577                                  eventTree_.resetAndGetRootDelayedReader());
1578 
1579     // If this next assert shows up in performance profiling or significantly affects memory, then these three lines should be deleted.
1580     // The IndexIntoFile should guarantee that it never fails.
1581     ProcessHistoryID idToCheck = (daqProvenanceHelper_ && fileFormatVersion().useReducedProcessHistoryID()
1582                                       ? *daqProvenanceHelper_->oldProcessHistoryID()
1583                                       : evtAux.processHistoryID());
1584     ProcessHistoryID const& reducedPHID = processHistoryRegistry_->reducedProcessHistoryID(idToCheck);
1585     assert(reducedPHID == indexIntoFile_.processHistoryID(indexIntoFileIter_.processHistoryIDIndex()));
1586 
1587     // report event read from file
1588     filePtr_->eventReadFromFile();
1589     return {found, succeeded};
1590   }
1591 
1592   void RootFile::setAtEventEntry(IndexIntoFile::EntryNumber_t entry) { eventTree_.setEntryNumber(entry); }
1593 
1594   std::shared_ptr<RunAuxiliary> RootFile::readRunAuxiliary_() {
1595     if (runHelper_->fakeNewRun()) {
1596       auto runAuxiliary = std::make_shared<RunAuxiliary>(*savedRunAuxiliary());
1597       runHelper_->overrideRunNumber(runAuxiliary->id());
1598       return runAuxiliary;
1599     }
1600     assert(indexIntoFileIter_ != indexIntoFileEnd_);
1601     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun);
1602 
1603     // Begin code for backward compatibility before the existence of run trees.
1604     if (!runTree_.isValid()) {
1605       // prior to the support of run trees.
1606       // RunAuxiliary did not contain a valid timestamp.  Take it from the next event.
1607       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisRun();
1608       assert(eventEntry != IndexIntoFile::invalidEntry);
1609       assert(eventTree_.current(eventEntry));
1610       auto const evtAux = fillEventAuxiliary(eventEntry);
1611 
1612       RunID run = RunID(indexIntoFileIter_.run());
1613       runHelper_->overrideRunNumber(run);
1614       savedRunAuxiliary_ = std::make_shared<RunAuxiliary>(run.run(), evtAux.time(), Timestamp::invalidTimestamp());
1615       return savedRunAuxiliary();
1616     }
1617     // End code for backward compatibility before the existence of run trees.
1618     runTree_.setEntryNumber(indexIntoFileIter_.entry());
1619     std::shared_ptr<RunAuxiliary> runAuxiliary = fillRunAuxiliary();
1620     assert(runAuxiliary->run() == indexIntoFileIter_.run());
1621     runHelper_->overrideRunNumber(runAuxiliary->id());
1622     filePtr_->reportInputRunNumber(runAuxiliary->run());
1623     // If RunAuxiliary did not contain a valid begin timestamp, invalidate any end timestamp.
1624     if (runAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
1625       runAuxiliary->setEndTime(Timestamp::invalidTimestamp());
1626     }
1627 
1628     // If RunAuxiliary did not contain a valid timestamp, or if this an old format file from
1629     // when the Run's ProcessHistory included only processes where products were added to the Run itself,
1630     // we attempt to read the first event in the run to get appropriate info.
1631     if (runAuxiliary->beginTime() == Timestamp::invalidTimestamp() ||
1632         !fileFormatVersion().processHistorySameWithinRun()) {
1633       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisRun();
1634       // If we have a valid event, use its information.
1635       if (eventEntry != IndexIntoFile::invalidEntry) {
1636         assert(eventTree_.current(eventEntry));
1637         auto evtAux = fillEventAuxiliary(eventEntry);
1638 
1639         // RunAuxiliary did not contain a valid timestamp.  Take it from the next event in this run if there is one.
1640         if (runAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
1641           runAuxiliary->setBeginTime(evtAux.time());
1642         }
1643 
1644         // For backwards compatibility when the Run's ProcessHistory included only processes where products were added to the
1645         // Run, and then the Run and Event auxiliaries could be different.  Use the event ProcessHistoryID if there is one. It should
1646         // almost always be correct by the current definition (processes included if any products are added. This makes the run, lumi,
1647         // and event ProcessHistory's always be the same if no file merging occurs).
1648         if (!fileFormatVersion().processHistorySameWithinRun()) {
1649           EventSelectionIDVector eventSelectionIDs;
1650           BranchListIndexes branchListIndexes;
1651           fillEventHistory(evtAux, eventSelectionIDs, branchListIndexes);
1652           runAuxiliary->setProcessHistoryID(evtAux.processHistoryID());
1653         }
1654       }
1655     }
1656     savedRunAuxiliary_ = runAuxiliary;
1657     return runAuxiliary;
1658   }
1659 
1660   void RootFile::fillProcessBlockHelper_() {
1661     assert(inputType_ == InputType::Primary);
1662     std::vector<unsigned int> nEntries;
1663     nEntries.reserve(processBlockTrees_.size());
1664     for (auto const& processBlockTree : processBlockTrees_) {
1665       nEntries.push_back(processBlockTree->entries());
1666     }
1667     processBlockHelper_->fillFromPrimaryInput(*storedProcessBlockHelper_, nEntries);
1668     storedProcessBlockHelper_ =
1669         std::make_unique<StoredProcessBlockHelper>();  // propagate_const<T> has no reset() function
1670   }
1671 
1672   bool RootFile::initializeFirstProcessBlockEntry() {
1673     if (processBlockTrees_[currentProcessBlockTree_]->entryNumber() == IndexIntoFile::invalidEntry) {
1674       processBlockTrees_[currentProcessBlockTree_]->setEntryNumber(0);
1675       assert(processBlockTrees_[currentProcessBlockTree_]->current());
1676       return true;
1677     }
1678     return false;
1679   }
1680 
1681   bool RootFile::endOfProcessBlocksReached() const { return currentProcessBlockTree_ >= processBlockTrees_.size(); }
1682 
1683   bool RootFile::nextProcessBlock_(ProcessBlockPrincipal&) {
1684     assert(inputType_ == InputType::Primary);
1685     if (endOfProcessBlocksReached()) {
1686       return false;
1687     }
1688     if (initializeFirstProcessBlockEntry()) {
1689       return true;
1690     }
1691     // With the current design, the RootFile should always be
1692     // set to a valid ProcessBlock entry in one of the TTrees
1693     // if it not at the end.
1694     assert(processBlockTrees_[currentProcessBlockTree_]->current());
1695     // Try for next entry in the same TTree
1696     if (processBlockTrees_[currentProcessBlockTree_]->nextWithCache()) {
1697       return true;
1698     }
1699     // Next ProcessBlock TTree
1700     ++currentProcessBlockTree_;
1701     if (endOfProcessBlocksReached()) {
1702       return false;
1703     }
1704     // With current design there should always be at least one entry.
1705     // Initialize for that entry.
1706     processBlockTrees_[currentProcessBlockTree_]->setEntryNumber(0);
1707     assert(processBlockTrees_[currentProcessBlockTree_]->current());
1708     return true;
1709   }
1710 
1711   void RootFile::readProcessBlock_(ProcessBlockPrincipal& processBlockPrincipal) {
1712     assert(inputType_ == InputType::Primary);
1713     RootTree* rootTree = processBlockTrees_[currentProcessBlockTree_].get();
1714     rootTree->insertEntryForIndex(0);
1715     assert(!rootTree->processName().empty());
1716     processBlockPrincipal.fillProcessBlockPrincipal(rootTree->processName(), rootTree->resetAndGetRootDelayedReader());
1717   }
1718 
1719   bool RootFile::readRun_(RunPrincipal& runPrincipal) {
1720     bool shouldProcessRun = indexIntoFileIter_.shouldProcessRun();
1721 
1722     MergeableRunProductMetadata* mergeableRunProductMetadata = nullptr;
1723     if (shouldProcessRun) {
1724       if (inputType_ == InputType::Primary) {
1725         mergeableRunProductMetadata = runPrincipal.mergeableRunProductMetadata();
1726         RootTree::EntryNumber const& entryNumber = runTree_.entryNumber();
1727         assert(entryNumber >= 0);
1728         mergeableRunProductMetadata->readRun(
1729             entryNumber, *storedMergeableRunProductMetadata_, IndexIntoFileItrHolder(indexIntoFileIter_));
1730       }
1731     }
1732 
1733     if (!runHelper_->fakeNewRun()) {
1734       assert(indexIntoFileIter_ != indexIntoFileEnd_);
1735       assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kRun);
1736       ++indexIntoFileIter_;
1737     }
1738     // Begin code for backward compatibility before the existence of run trees.
1739     if (!runTree_.isValid()) {
1740       return shouldProcessRun;
1741     }
1742     // End code for backward compatibility before the existence of run trees.
1743     if (shouldProcessRun) {
1744       // NOTE: we use 0 for the index since do not do delayed reads for RunPrincipals
1745       runTree_.insertEntryForIndex(0);
1746       runPrincipal.fillRunPrincipal(*processHistoryRegistry_, runTree_.resetAndGetRootDelayedReader());
1747       // Read in all the products now.
1748       runPrincipal.readAllFromSourceAndMergeImmediately(mergeableRunProductMetadata);
1749       runPrincipal.setShouldWriteRun(RunPrincipal::kYes);
1750     } else {
1751       runPrincipal.fillRunPrincipal(*processHistoryRegistry_, nullptr);
1752       if (runPrincipal.shouldWriteRun() != RunPrincipal::kYes) {
1753         runPrincipal.setShouldWriteRun(RunPrincipal::kNo);
1754       }
1755     }
1756     return shouldProcessRun;
1757   }
1758 
1759   std::shared_ptr<LuminosityBlockAuxiliary> RootFile::readLuminosityBlockAuxiliary_() {
1760     assert(indexIntoFileIter_ != indexIntoFileEnd_);
1761     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi);
1762     // Begin code for backward compatibility before the existence of lumi trees.
1763     if (!lumiTree_.isValid()) {
1764       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisLumi();
1765       assert(eventEntry != IndexIntoFile::invalidEntry);
1766       assert(eventTree_.current(eventEntry));
1767       auto const evtAux = fillEventAuxiliary(eventEntry);
1768 
1769       LuminosityBlockID lumi = LuminosityBlockID(indexIntoFileIter_.run(), indexIntoFileIter_.lumi());
1770       runHelper_->overrideRunNumber(lumi);
1771       return std::make_shared<LuminosityBlockAuxiliary>(
1772           lumi.run(), lumi.luminosityBlock(), evtAux.time(), Timestamp::invalidTimestamp());
1773     }
1774     // End code for backward compatibility before the existence of lumi trees.
1775     lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
1776     std::shared_ptr<LuminosityBlockAuxiliary> lumiAuxiliary = fillLumiAuxiliary();
1777     assert(lumiAuxiliary->run() == indexIntoFileIter_.run());
1778     assert(lumiAuxiliary->luminosityBlock() == indexIntoFileIter_.lumi());
1779     runHelper_->overrideRunNumber(lumiAuxiliary->id());
1780     filePtr_->reportInputLumiSection(lumiAuxiliary->run(), lumiAuxiliary->luminosityBlock());
1781     if (lumiAuxiliary->beginTime() == Timestamp::invalidTimestamp()) {
1782       IndexIntoFile::EntryNumber_t eventEntry = indexIntoFileIter_.firstEventEntryThisLumi();
1783       if (eventEntry != IndexIntoFile::invalidEntry) {
1784         assert(eventTree_.current(eventEntry));
1785         auto const evtAux = fillEventAuxiliary(eventEntry);
1786 
1787         lumiAuxiliary->setBeginTime(evtAux.time());
1788       }
1789       lumiAuxiliary->setEndTime(Timestamp::invalidTimestamp());
1790     }
1791     if (!fileFormatVersion().processHistorySameWithinRun() && savedRunAuxiliary_) {
1792       lumiAuxiliary->setProcessHistoryID(savedRunAuxiliary_->processHistoryID());
1793     }
1794     return lumiAuxiliary;
1795   }
1796 
1797   bool RootFile::readLuminosityBlock_(LuminosityBlockPrincipal& lumiPrincipal) {
1798     bool shouldProcessLumi = indexIntoFileIter_.shouldProcessLumi();
1799     assert(indexIntoFileIter_ != indexIntoFileEnd_);
1800     assert(indexIntoFileIter_.getEntryType() == IndexIntoFile::kLumi);
1801     // Begin code for backward compatibility before the existence of lumi trees.
1802     if (!lumiTree_.isValid()) {
1803       ++indexIntoFileIter_;
1804       return shouldProcessLumi;
1805     }
1806     // End code for backward compatibility before the existence of lumi trees.
1807     if (shouldProcessLumi) {
1808       lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
1809       // NOTE: we use 0 for the index since do not do delayed reads for LuminosityBlockPrincipals
1810       lumiTree_.insertEntryForIndex(0);
1811       auto history = processHistoryRegistry_->getMapped(lumiPrincipal.aux().processHistoryID());
1812       lumiPrincipal.fillLuminosityBlockPrincipal(history, lumiTree_.resetAndGetRootDelayedReader());
1813       // Read in all the products now.
1814       lumiPrincipal.readAllFromSourceAndMergeImmediately();
1815       lumiPrincipal.setShouldWriteLumi(LuminosityBlockPrincipal::kYes);
1816     } else {
1817       auto history = processHistoryRegistry_->getMapped(lumiPrincipal.aux().processHistoryID());
1818       lumiPrincipal.fillLuminosityBlockPrincipal(history, nullptr);
1819       if (lumiPrincipal.shouldWriteLumi() != LuminosityBlockPrincipal::kYes) {
1820         lumiPrincipal.setShouldWriteLumi(LuminosityBlockPrincipal::kNo);
1821       }
1822     }
1823     ++indexIntoFileIter_;
1824     return shouldProcessLumi;
1825   }
1826 
1827   bool RootFile::setEntryAtEvent(RunNumber_t run, LuminosityBlockNumber_t lumi, EventNumber_t event) {
1828     indexIntoFileIter_ = indexIntoFile_.findEventPosition(run, lumi, event);
1829     if (indexIntoFileIter_ == indexIntoFileEnd_)
1830       return false;
1831     eventTree_.setEntryNumber(indexIntoFileIter_.entry());
1832     return true;
1833   }
1834 
1835   bool RootFile::setEntryAtLumi(RunNumber_t run, LuminosityBlockNumber_t lumi) {
1836     indexIntoFileIter_ = indexIntoFile_.findLumiPosition(run, lumi);
1837     if (indexIntoFileIter_ == indexIntoFileEnd_)
1838       return false;
1839     lumiTree_.setEntryNumber(indexIntoFileIter_.entry());
1840     return true;
1841   }
1842 
1843   bool RootFile::setEntryAtRun(RunNumber_t run) {
1844     indexIntoFileIter_ = indexIntoFile_.findRunPosition(run);
1845     if (indexIntoFileIter_ == indexIntoFileEnd_)
1846       return false;
1847     runTree_.setEntryNumber(indexIntoFileIter_.entry());
1848     return true;
1849   }
1850 
1851   bool RootFile::setEntryAtNextEventInLumi(RunNumber_t run, LuminosityBlockNumber_t lumi) {
1852     if (indexIntoFileIter_.getEntryType() == IndexIntoFile::kEvent) {
1853       ++indexIntoFileIter_;
1854     }
1855     indexIntoFileIter_.advanceToEvent();
1856     if (indexIntoFileIter_.getEntryType() != IndexIntoFile::kEvent)
1857       return false;
1858     if (run != indexIntoFileIter_.run())
1859       return false;
1860     if (lumi != indexIntoFileIter_.lumi())
1861       return false;
1862     //The following is used for its side effect of advancing the
1863     // eventTree entry.
1864     fillEventAuxiliary(indexIntoFileIter_.entry());
1865     return true;
1866   }
1867 
1868   void RootFile::readEventHistoryTree() {
1869     // Read in the event history tree, if we have one...
1870     if (fileFormatVersion().eventHistoryTree()) {
1871       history_ = std::make_unique<History>();  // propagate_const<T> has no reset() function
1872       eventHistoryTree_ = dynamic_cast<TTree*>(filePtr_->Get(poolNames::eventHistoryTreeName().c_str()));
1873       if (!eventHistoryTree_) {
1874         throw Exception(errors::EventCorruption) << "Failed to find the event history tree.\n";
1875       }
1876     }
1877   }
1878 
1879   void RootFile::initializeDuplicateChecker(
1880       std::vector<std::shared_ptr<IndexIntoFile>> const& indexesIntoFiles,
1881       std::vector<std::shared_ptr<IndexIntoFile>>::size_type currentIndexIntoFile) {
1882     if (duplicateChecker_ && !duplicateChecker_->checkDisabled()) {
1883       if (eventTree_.next()) {
1884         auto const evtAux = fillThisEventAuxiliary();
1885 
1886         duplicateChecker_->inputFileOpened(evtAux.isRealData(), indexIntoFile_, indexesIntoFiles, currentIndexIntoFile);
1887       }
1888       eventTree_.setEntryNumber(IndexIntoFile::invalidEntry);
1889     }
1890   }
1891 
1892   void RootFile::setPresenceInProductRegistry(ProductRegistry& inputProdDescReg,
1893                                               StoredProcessBlockHelper const& storedProcessBlockHelper) {
1894     // Set product presence information in the product registry.
1895     // "Presence" is a boolean that is true if and only if the TBranch exists
1896     // in the TTree (except it will be false for ProcessBlock products in non-Primary
1897     // input files).
1898     ProductRegistry::ProductList& pList = inputProdDescReg.productListUpdator();
1899     for (auto& product : pList) {
1900       BranchDescription& prod = product.second;
1901       prod.init();
1902       if (prod.branchType() == InProcess) {
1903         std::vector<std::string> const& processes = storedProcessBlockHelper.processesWithProcessBlockProducts();
1904         auto it = std::find(processes.begin(), processes.end(), prod.processName());
1905         if (it != processes.end()) {
1906           auto index = std::distance(processes.begin(), it);
1907           processBlockTrees_[index]->setPresence(prod, newBranchToOldBranch(prod.branchName()));
1908         } else {
1909           // Given current rules for saving BranchDescriptions, this case should only occur
1910           // in non-Primary sequences.
1911           prod.setDropped(true);
1912         }
1913       } else {
1914         treePointers_[prod.branchType()]->setPresence(prod, newBranchToOldBranch(prod.branchName()));
1915       }
1916     }
1917   }
1918 
1919   void RootFile::markBranchToBeDropped(bool dropDescendants,
1920                                        BranchDescription const& branch,
1921                                        std::set<BranchID>& branchesToDrop,
1922                                        std::map<BranchID, BranchID> const& droppedToKeptAlias) const {
1923     if (dropDescendants) {
1924       branchChildren_->appendToDescendants(branch, branchesToDrop, droppedToKeptAlias);
1925     } else {
1926       branchesToDrop.insert(branch.branchID());
1927     }
1928   }
1929 
1930   void RootFile::dropOnInputAndReorder(ProductRegistry& reg,
1931                                        ProductSelectorRules const& rules,
1932                                        bool dropDescendants,
1933                                        InputType inputType,
1934                                        StoredProcessBlockHelper& storedProcessBlockHelper,
1935                                        ProcessBlockHelper const* processBlockHelper) {
1936     ProductRegistry::ProductList& prodList = reg.productListUpdator();
1937 
1938     // First fill in a map we will need to navigate to descendants
1939     // in the case of EDAliases.
1940     std::map<BranchID, BranchID> droppedToKeptAlias;
1941     for (auto const& product : prodList) {
1942       BranchDescription const& prod = product.second;
1943       if (prod.branchID() != prod.originalBranchID() && prod.present()) {
1944         droppedToKeptAlias[prod.originalBranchID()] = prod.branchID();
1945       }
1946     }
1947 
1948     // This object will select products based on the branchName and the
1949     // keep and drop statements which are in the source configuration.
1950     ProductSelector productSelector;
1951     productSelector.initialize(rules, reg.allBranchDescriptions());
1952 
1953     // In this pass, fill in a set of branches to be dropped.
1954     // Don't drop anything yet.
1955     std::set<BranchID> branchesToDrop;
1956     std::vector<BranchDescription const*> associationDescriptions;
1957     for (auto const& product : prodList) {
1958       BranchDescription const& prod = product.second;
1959       if (inputType != InputType::Primary && prod.branchType() == InProcess) {
1960         markBranchToBeDropped(dropDescendants, prod, branchesToDrop, droppedToKeptAlias);
1961       } else if (prod.unwrappedType() == typeid(ThinnedAssociation) && prod.present()) {
1962         // Special handling for ThinnedAssociations
1963         if (inputType != InputType::SecondarySource) {
1964           associationDescriptions.push_back(&prod);
1965         } else {
1966           markBranchToBeDropped(dropDescendants, prod, branchesToDrop, droppedToKeptAlias);
1967         }
1968       } else if (!productSelector.selected(prod)) {
1969         markBranchToBeDropped(dropDescendants, prod, branchesToDrop, droppedToKeptAlias);
1970       }
1971     }
1972 
1973     if (inputType != InputType::SecondarySource) {
1974       // Decide whether to keep the thinned associations and corresponding
1975       // entries in the helper. For secondary source they are all dropped,
1976       // but in other cases we look for thinned collections the associations
1977       // redirect a Ref or Ptr to when dereferencing them.
1978 
1979       // Need a list of kept products in order to determine which thinned associations
1980       // are kept.
1981       std::set<BranchID> keptProductsInEvent;
1982       for (auto const& product : prodList) {
1983         BranchDescription const& prod = product.second;
1984         if (branchesToDrop.find(prod.branchID()) == branchesToDrop.end() && prod.present() &&
1985             prod.branchType() == InEvent) {
1986           keptProductsInEvent.insert(prod.branchID());
1987         }
1988       }
1989 
1990       // Decide which ThinnedAssociations to keep and store the decision in keepAssociation
1991       std::map<BranchID, bool> keepAssociation;
1992       fileThinnedAssociationsHelper_->selectAssociationProducts(
1993           associationDescriptions, keptProductsInEvent, keepAssociation);
1994 
1995       for (auto association : associationDescriptions) {
1996         if (!keepAssociation[association->branchID()]) {
1997           markBranchToBeDropped(dropDescendants, *association, branchesToDrop, droppedToKeptAlias);
1998         }
1999       }
2000 
2001       // Also delete the dropped associations from the ThinnedAssociationsHelper
2002       auto temp = std::make_unique<ThinnedAssociationsHelper>();
2003       for (auto const& associationBranches : fileThinnedAssociationsHelper_->data()) {
2004         auto iter = keepAssociation.find(associationBranches.association());
2005         if (iter != keepAssociation.end() && iter->second) {
2006           temp->addAssociation(associationBranches);
2007         }
2008       }
2009       // propagate_const<T> has no reset() function
2010       fileThinnedAssociationsHelper_ = std::unique_ptr<ThinnedAssociationsHelper>(temp.release());
2011     }
2012 
2013     // On this pass, actually drop the branches.
2014     std::set<std::string> processesWithKeptProcessBlockProducts;
2015     std::set<BranchID>::const_iterator branchesToDropEnd = branchesToDrop.end();
2016     for (ProductRegistry::ProductList::iterator it = prodList.begin(), itEnd = prodList.end(); it != itEnd;) {
2017       BranchDescription const& prod = it->second;
2018       bool drop = branchesToDrop.find(prod.branchID()) != branchesToDropEnd;
2019       if (drop) {
2020         if (!prod.dropped()) {
2021           if (productSelector.selected(prod) && prod.unwrappedType() != typeid(ThinnedAssociation) &&
2022               prod.branchType() != InProcess) {
2023             LogWarning("RootFile") << "Branch '" << prod.branchName() << "' is being dropped from the input\n"
2024                                    << "of file '" << file_ << "' because it is dependent on a branch\n"
2025                                    << "that was explicitly dropped.\n";
2026           }
2027           if (prod.branchType() == InProcess) {
2028             std::vector<std::string> const& processes = storedProcessBlockHelper.processesWithProcessBlockProducts();
2029             auto it = std::find(processes.begin(), processes.end(), prod.processName());
2030             assert(it != processes.end());
2031             auto index = std::distance(processes.begin(), it);
2032             processBlockTrees_[index]->dropBranch(newBranchToOldBranch(prod.branchName()));
2033           } else {
2034             treePointers_[prod.branchType()]->dropBranch(newBranchToOldBranch(prod.branchName()));
2035           }
2036           hasNewlyDroppedBranch_[prod.branchType()] = true;
2037         }
2038         ProductRegistry::ProductList::iterator icopy = it;
2039         ++it;
2040         prodList.erase(icopy);
2041       } else {
2042         if (prod.branchType() == InProcess && prod.present()) {
2043           processesWithKeptProcessBlockProducts.insert(prod.processName());
2044         }
2045         ++it;
2046       }
2047     }
2048 
2049     dropProcessesAndReorder(storedProcessBlockHelper, processesWithKeptProcessBlockProducts, processBlockHelper);
2050 
2051     // Drop on input mergeable run and lumi products, this needs to be invoked for secondary file input
2052     if (inputType == InputType::SecondaryFile) {
2053       TString tString;
2054       for (ProductRegistry::ProductList::iterator it = prodList.begin(), itEnd = prodList.end(); it != itEnd;) {
2055         BranchDescription const& prod = it->second;
2056         if (prod.branchType() != InEvent && prod.branchType() != InProcess) {
2057           TClass* cp = prod.wrappedType().getClass();
2058           void* p = cp->New();
2059           int offset = cp->GetBaseClassOffset(edProductClass_);
2060           std::unique_ptr<WrapperBase> edp = getWrapperBasePtr(p, offset);
2061           if (edp->isMergeable()) {
2062             treePointers_[prod.branchType()]->dropBranch(newBranchToOldBranch(prod.branchName()));
2063             ProductRegistry::ProductList::iterator icopy = it;
2064             ++it;
2065             prodList.erase(icopy);
2066           } else {
2067             ++it;
2068           }
2069         } else
2070           ++it;
2071       }
2072     }
2073   }
2074 
2075   void RootFile::dropProcessesAndReorder(StoredProcessBlockHelper& storedProcessBlockHelper,
2076                                          std::set<std::string> const& processesWithKeptProcessBlockProducts,
2077                                          ProcessBlockHelper const* processBlockHelper) {
2078     // Modify storedProcessBlockHelper and processBlockTrees_
2079     // This should account for dropOnInput and also make the
2080     // order of process blocks in input files after the first
2081     // be the same as the first. Processes with no ProcessBlock
2082     // products should be removed. After this executes,
2083     // the items in storedProcessBlockHelper
2084     // and processBlockTrees should be in exact one to one
2085     // correspondence and in the same order. For input files
2086     // after the first, these items should be either the same
2087     // as or a subset of the items in processBlockHelper and in
2088     // the same order.
2089 
2090     if (processBlockTrees_.empty()) {
2091       return;
2092     }
2093 
2094     std::vector<unsigned int> nEntries;
2095     nEntries.reserve(processBlockTrees_.size());
2096     for (auto const& processBlockTree : processBlockTrees_) {
2097       nEntries.push_back(processBlockTree->entries());
2098     }
2099 
2100     bool firstInputFile = !processBlockHelper->initializedFromInput();
2101     bool isModified = false;
2102     std::vector<unsigned int> finalIndexToStoredIndex;
2103 
2104     if (firstInputFile) {
2105       isModified = processBlockHelper->firstFileDropProcessesAndReorderStored(
2106           storedProcessBlockHelper, processesWithKeptProcessBlockProducts, nEntries, finalIndexToStoredIndex);
2107     } else {
2108       isModified =
2109           processBlockHelper->dropProcessesAndReorderStored(storedProcessBlockHelper,
2110                                                             processesWithKeptProcessBlockProducts,
2111                                                             nEntries,
2112                                                             finalIndexToStoredIndex,
2113                                                             processBlockHelper->processesWithProcessBlockProducts());
2114     }
2115 
2116     // At this point, any modifications to storedProcessBlockHelper are done.
2117     // Make consistent changes to processBlockTrees_ and this will cause
2118     // unneeded RootTrees to be deleted.
2119     if (isModified) {
2120       std::vector<edm::propagate_const<std::unique_ptr<RootTree>>> newProcessBlockTrees;
2121       unsigned int nFinalProducts = storedProcessBlockHelper.processesWithProcessBlockProducts().size();
2122       for (unsigned int j = 0; j < nFinalProducts; ++j) {
2123         unsigned int iStored = finalIndexToStoredIndex[j];
2124         newProcessBlockTrees.push_back(std::move(processBlockTrees_[iStored]));
2125       }
2126       processBlockTrees_.swap(newProcessBlockTrees);
2127     }
2128   }
2129 
2130   void RootFile::setSignals(
2131       signalslot::Signal<void(StreamContext const&, ModuleCallingContext const&)> const* preEventReadSource,
2132       signalslot::Signal<void(StreamContext const&, ModuleCallingContext const&)> const* postEventReadSource) {
2133     eventTree_.setSignals(preEventReadSource, postEventReadSource);
2134   }
2135 
2136   void RootFile::makeProcessBlockRootTrees(std::shared_ptr<InputFile> filePtr,
2137                                            int treeMaxVirtualSize,
2138                                            bool enablePrefetching,
2139                                            InputType inputType,
2140                                            StoredProcessBlockHelper const& storedProcessBlockHelper) {
2141     // When this functions returns there will be exactly a 1-to-1 correspondence between the
2142     // processes listed in storedProcessBlockHelper and the RootTree objects created. processBlockTrees_
2143     // has pointers to the RootTree's and will be filled in the same order. The RootTree constructor
2144     // will throw an exception if one of these TTree's is not in the file and this should be all of
2145     // the ProcessBlock TTree's in the file. (later in the RootFile constructor, dropOnInput might
2146     // remove some and also reordering may occur).
2147     for (auto const& process : storedProcessBlockHelper.processesWithProcessBlockProducts()) {
2148       processBlockTrees_.emplace_back(std::make_unique<RootTree>(filePtr,
2149                                                                  InProcess,
2150                                                                  process,
2151                                                                  1,
2152                                                                  treeMaxVirtualSize,
2153                                                                  roottree::defaultNonEventCacheSize,
2154                                                                  roottree::defaultNonEventLearningEntries,
2155                                                                  enablePrefetching,
2156                                                                  inputType));
2157     }
2158   }
2159 
2160   std::unique_ptr<MakeProvenanceReader> RootFile::makeProvenanceReaderMaker(InputType inputType) {
2161     if (fileFormatVersion_.storedProductProvenanceUsed()) {
2162       readParentageTree(inputType);
2163       return std::make_unique<MakeReducedProvenanceReader>(parentageIDLookup_);
2164     } else if (fileFormatVersion_.splitProductIDs()) {
2165       readParentageTree(inputType);
2166       return std::make_unique<MakeFullProvenanceReader>();
2167     } else if (fileFormatVersion_.perEventProductIDs()) {
2168       auto entryDescriptionMap = std::make_unique<EntryDescriptionMap>();
2169       readEntryDescriptionTree(*entryDescriptionMap, inputType);
2170       return std::make_unique<MakeOldProvenanceReader>(std::move(entryDescriptionMap));
2171     } else {
2172       return std::make_unique<MakeDummyProvenanceReader>();
2173     }
2174   }
2175 
2176   std::shared_ptr<ProductProvenanceRetriever> RootFile::makeProductProvenanceRetriever(unsigned int iStreamID) {
2177     if (eventProductProvenanceRetrievers_.size() <= iStreamID) {
2178       eventProductProvenanceRetrievers_.resize(iStreamID + 1);
2179     }
2180     if (!eventProductProvenanceRetrievers_[iStreamID]) {
2181       // propagate_const<T> has no reset() function
2182       eventProductProvenanceRetrievers_[iStreamID] = std::make_shared<ProductProvenanceRetriever>(
2183           provenanceReaderMaker_->makeReader(eventTree_, daqProvenanceHelper_.get()));
2184     }
2185     eventProductProvenanceRetrievers_[iStreamID]->reset();
2186     return eventProductProvenanceRetriever(iStreamID);
2187   }
2188 
2189   class ReducedProvenanceReader : public ProvenanceReaderBase {
2190   public:
2191     ReducedProvenanceReader(RootTree* iRootTree,
2192                             std::vector<ParentageID> const& iParentageIDLookup,
2193                             DaqProvenanceHelper const* daqProvenanceHelper);
2194 
2195     std::set<ProductProvenance> readProvenance(unsigned int) const override;
2196 
2197   private:
2198     void readProvenanceAsync(WaitingTaskHolder task,
2199                              ModuleCallingContext const* moduleCallingContext,
2200                              unsigned int transitionIndex,
2201                              std::atomic<const std::set<ProductProvenance>*>& writeTo) const override;
2202 
2203     edm::propagate_const<RootTree*> rootTree_;
2204     edm::propagate_const<TBranch*> provBranch_;
2205     StoredProductProvenanceVector provVector_;
2206     StoredProductProvenanceVector const* pProvVector_;
2207     std::vector<ParentageID> const& parentageIDLookup_;
2208     DaqProvenanceHelper const* daqProvenanceHelper_;
2209     std::shared_ptr<std::recursive_mutex> mutex_;
2210     SharedResourcesAcquirer acquirer_;
2211   };
2212 
2213   ReducedProvenanceReader::ReducedProvenanceReader(RootTree* iRootTree,
2214                                                    std::vector<ParentageID> const& iParentageIDLookup,
2215                                                    DaqProvenanceHelper const* daqProvenanceHelper)
2216       : ProvenanceReaderBase(),
2217         rootTree_(iRootTree),
2218         pProvVector_(&provVector_),
2219         parentageIDLookup_(iParentageIDLookup),
2220         daqProvenanceHelper_(daqProvenanceHelper),
2221         mutex_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().second),
2222         acquirer_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().first) {
2223     provBranch_ =
2224         rootTree_->tree()->GetBranch(BranchTypeToProductProvenanceBranchName(rootTree_->branchType()).c_str());
2225   }
2226 
2227   namespace {
2228     using SignalType = signalslot::Signal<void(StreamContext const&, ModuleCallingContext const&)>;
2229     template <typename R>
2230     void readProvenanceAsyncImpl(R const* iThis,
2231                                  SerialTaskQueueChain& chain,
2232                                  WaitingTaskHolder task,
2233                                  unsigned int transitionIndex,
2234                                  std::atomic<const std::set<ProductProvenance>*>& writeTo,
2235                                  ModuleCallingContext const* iContext,
2236                                  SignalType const* pre,
2237                                  SignalType const* post) {
2238       if (nullptr == writeTo.load()) {
2239         //need to be sure the task isn't run until after the read
2240         WaitingTaskHolder taskHolder{task};
2241         auto pWriteTo = &writeTo;
2242 
2243         auto serviceToken = ServiceRegistry::instance().presentToken();
2244 
2245         chain.push(
2246             *taskHolder.group(),
2247             [holder = std::move(taskHolder),
2248              pWriteTo,
2249              iThis,
2250              transitionIndex,
2251              iContext,
2252              pre,
2253              post,
2254              serviceToken]() mutable {
2255               if (nullptr == pWriteTo->load()) {
2256                 ServiceRegistry::Operate operate(serviceToken);
2257                 std::unique_ptr<const std::set<ProductProvenance>> prov;
2258                 try {
2259                   if (pre) {
2260                     pre->emit(*(iContext->getStreamContext()), *iContext);
2261                   }
2262                   prov = std::make_unique<const std::set<ProductProvenance>>(iThis->readProvenance(transitionIndex));
2263                   if (post) {
2264                     post->emit(*(iContext->getStreamContext()), *iContext);
2265                   }
2266 
2267                 } catch (...) {
2268                   if (post) {
2269                     post->emit(*(iContext->getStreamContext()), *iContext);
2270                   }
2271 
2272                   holder.doneWaiting(std::current_exception());
2273                   return;
2274                 }
2275                 const std::set<ProductProvenance>* expected = nullptr;
2276 
2277                 if (pWriteTo->compare_exchange_strong(expected, prov.get())) {
2278                   prov.release();
2279                 }
2280               }
2281               holder.doneWaiting(std::exception_ptr());
2282             });
2283       }
2284     }
2285   }  // namespace
2286 
2287   void ReducedProvenanceReader::readProvenanceAsync(WaitingTaskHolder task,
2288                                                     ModuleCallingContext const* moduleCallingContext,
2289                                                     unsigned int transitionIndex,
2290                                                     std::atomic<const std::set<ProductProvenance>*>& writeTo) const {
2291     readProvenanceAsyncImpl(this,
2292                             acquirer_.serialQueueChain(),
2293                             task,
2294                             transitionIndex,
2295                             writeTo,
2296                             moduleCallingContext,
2297                             rootTree_->rootDelayedReader()->preEventReadFromSourceSignal(),
2298                             rootTree_->rootDelayedReader()->postEventReadFromSourceSignal());
2299   }
2300 
2301   std::set<ProductProvenance> ReducedProvenanceReader::readProvenance(unsigned int transitionIndex) const {
2302     {
2303       std::lock_guard<std::recursive_mutex> guard(*mutex_);
2304       ReducedProvenanceReader* me = const_cast<ReducedProvenanceReader*>(this);
2305       me->rootTree_->fillBranchEntry(
2306           me->provBranch_, me->rootTree_->entryNumberForIndex(transitionIndex), me->pProvVector_);
2307     }
2308     std::set<ProductProvenance> retValue;
2309     if (daqProvenanceHelper_) {
2310       for (auto const& prov : provVector_) {
2311         BranchID bid(prov.branchID_);
2312         retValue.emplace(daqProvenanceHelper_->mapBranchID(BranchID(prov.branchID_)),
2313                          daqProvenanceHelper_->mapParentageID(parentageIDLookup_[prov.parentageIDIndex_]));
2314       }
2315     } else {
2316       for (auto const& prov : provVector_) {
2317         if (prov.parentageIDIndex_ >= parentageIDLookup_.size()) {
2318           throw edm::Exception(errors::LogicError)
2319               << "ReducedProvenanceReader::ReadProvenance\n"
2320               << "The parentage ID index value " << prov.parentageIDIndex_
2321               << " is out of bounds.  The maximum value is " << parentageIDLookup_.size() - 1 << ".\n"
2322               << "This should never happen.\n"
2323               << "Please report this to the framework hypernews forum 'hn-cms-edmFramework@cern.ch'.\n";
2324         }
2325         retValue.emplace(BranchID(prov.branchID_), parentageIDLookup_[prov.parentageIDIndex_]);
2326       }
2327     }
2328     return retValue;
2329   }
2330 
2331   class FullProvenanceReader : public ProvenanceReaderBase {
2332   public:
2333     explicit FullProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper);
2334     ~FullProvenanceReader() override {}
2335     std::set<ProductProvenance> readProvenance(unsigned int transitionIndex) const override;
2336 
2337   private:
2338     void readProvenanceAsync(WaitingTaskHolder task,
2339                              ModuleCallingContext const* moduleCallingContext,
2340                              unsigned int transitionIndex,
2341                              std::atomic<const std::set<ProductProvenance>*>& writeTo) const override;
2342 
2343     RootTree* rootTree_;
2344     ProductProvenanceVector infoVector_;
2345     //All access to a ROOT file is serialized
2346     CMS_SA_ALLOW mutable ProductProvenanceVector* pInfoVector_;
2347     DaqProvenanceHelper const* daqProvenanceHelper_;
2348     std::shared_ptr<std::recursive_mutex> mutex_;
2349     SharedResourcesAcquirer acquirer_;
2350   };
2351 
2352   FullProvenanceReader::FullProvenanceReader(RootTree* rootTree, DaqProvenanceHelper const* daqProvenanceHelper)
2353       : ProvenanceReaderBase(),
2354         rootTree_(rootTree),
2355         infoVector_(),
2356         pInfoVector_(&infoVector_),
2357         daqProvenanceHelper_(daqProvenanceHelper),
2358         mutex_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().second),
2359         acquirer_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().first) {}
2360 
2361   void FullProvenanceReader::readProvenanceAsync(WaitingTaskHolder task,
2362                                                  ModuleCallingContext const* moduleCallingContext,
2363                                                  unsigned int transitionIndex,
2364                                                  std::atomic<const std::set<ProductProvenance>*>& writeTo) const {
2365     readProvenanceAsyncImpl(this,
2366                             acquirer_.serialQueueChain(),
2367                             task,
2368                             transitionIndex,
2369                             writeTo,
2370                             moduleCallingContext,
2371                             rootTree_->rootDelayedReader()->preEventReadFromSourceSignal(),
2372                             rootTree_->rootDelayedReader()->postEventReadFromSourceSignal());
2373   }
2374 
2375   std::set<ProductProvenance> FullProvenanceReader::readProvenance(unsigned int transitionIndex) const {
2376     {
2377       std::lock_guard<std::recursive_mutex> guard(*mutex_);
2378       rootTree_->fillBranchEntryMeta(
2379           rootTree_->branchEntryInfoBranch(), rootTree_->entryNumberForIndex(transitionIndex), pInfoVector_);
2380     }
2381     std::set<ProductProvenance> retValue;
2382     if (daqProvenanceHelper_) {
2383       for (auto const& info : infoVector_) {
2384         retValue.emplace(daqProvenanceHelper_->mapBranchID(info.branchID()),
2385                          daqProvenanceHelper_->mapParentageID(info.parentageID()));
2386       }
2387     } else {
2388       for (auto const& info : infoVector_) {
2389         retValue.emplace(info);
2390       }
2391     }
2392     return retValue;
2393   }
2394 
2395   class OldProvenanceReader : public ProvenanceReaderBase {
2396   public:
2397     explicit OldProvenanceReader(RootTree* rootTree,
2398                                  EntryDescriptionMap const& theMap,
2399                                  DaqProvenanceHelper const* daqProvenanceHelper);
2400     ~OldProvenanceReader() override {}
2401     std::set<ProductProvenance> readProvenance(unsigned int transitionIndex) const override;
2402 
2403   private:
2404     void readProvenanceAsync(WaitingTaskHolder task,
2405                              ModuleCallingContext const* moduleCallingContext,
2406                              unsigned int transitionIndex,
2407                              std::atomic<const std::set<ProductProvenance>*>& writeTo) const override;
2408 
2409     edm::propagate_const<RootTree*> rootTree_;
2410     std::vector<EventEntryInfo> infoVector_;
2411     //All access to ROOT file are serialized
2412     CMS_SA_ALLOW mutable std::vector<EventEntryInfo>* pInfoVector_;
2413     EntryDescriptionMap const& entryDescriptionMap_;
2414     DaqProvenanceHelper const* daqProvenanceHelper_;
2415     std::shared_ptr<std::recursive_mutex> mutex_;
2416     SharedResourcesAcquirer acquirer_;
2417   };
2418 
2419   OldProvenanceReader::OldProvenanceReader(RootTree* rootTree,
2420                                            EntryDescriptionMap const& theMap,
2421                                            DaqProvenanceHelper const* daqProvenanceHelper)
2422       : ProvenanceReaderBase(),
2423         rootTree_(rootTree),
2424         infoVector_(),
2425         pInfoVector_(&infoVector_),
2426         entryDescriptionMap_(theMap),
2427         daqProvenanceHelper_(daqProvenanceHelper),
2428         mutex_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().second),
2429         acquirer_(SharedResourcesRegistry::instance()->createAcquirerForSourceDelayedReader().first) {}
2430 
2431   void OldProvenanceReader::readProvenanceAsync(WaitingTaskHolder task,
2432                                                 ModuleCallingContext const* moduleCallingContext,
2433                                                 unsigned int transitionIndex,
2434                                                 std::atomic<const std::set<ProductProvenance>*>& writeTo) const {
2435     readProvenanceAsyncImpl(this,
2436                             acquirer_.serialQueueChain(),
2437                             task,
2438                             transitionIndex,
2439                             writeTo,
2440                             moduleCallingContext,
2441                             rootTree_->rootDelayedReader()->preEventReadFromSourceSignal(),
2442                             rootTree_->rootDelayedReader()->postEventReadFromSourceSignal());
2443   }
2444 
2445   std::set<ProductProvenance> OldProvenanceReader::readProvenance(unsigned int transitionIndex) const {
2446     {
2447       std::lock_guard<std::recursive_mutex> guard(*mutex_);
2448       rootTree_->branchEntryInfoBranch()->SetAddress(&pInfoVector_);
2449       roottree::getEntry(rootTree_->branchEntryInfoBranch(), rootTree_->entryNumberForIndex(transitionIndex));
2450     }
2451     std::set<ProductProvenance> retValue;
2452     for (auto const& info : infoVector_) {
2453       EntryDescriptionMap::const_iterator iter = entryDescriptionMap_.find(info.entryDescriptionID());
2454       assert(iter != entryDescriptionMap_.end());
2455       Parentage parentage(iter->second.parents());
2456       if (daqProvenanceHelper_) {
2457         retValue.emplace(daqProvenanceHelper_->mapBranchID(info.branchID()),
2458                          daqProvenanceHelper_->mapParentageID(parentage.id()));
2459       } else {
2460         retValue.emplace(info.branchID(), parentage.id());
2461       }
2462     }
2463     return retValue;
2464   }
2465 
2466   class DummyProvenanceReader : public ProvenanceReaderBase {
2467   public:
2468     DummyProvenanceReader();
2469     ~DummyProvenanceReader() override {}
2470 
2471   private:
2472     std::set<ProductProvenance> readProvenance(unsigned int) const override;
2473     void readProvenanceAsync(WaitingTaskHolder task,
2474                              ModuleCallingContext const* moduleCallingContext,
2475                              unsigned int transitionIndex,
2476                              std::atomic<const std::set<ProductProvenance>*>& writeTo) const override;
2477   };
2478 
2479   DummyProvenanceReader::DummyProvenanceReader() : ProvenanceReaderBase() {}
2480 
2481   std::set<ProductProvenance> DummyProvenanceReader::readProvenance(unsigned int) const {
2482     // Not providing parentage!!!
2483     return std::set<ProductProvenance>{};
2484   }
2485   void DummyProvenanceReader::readProvenanceAsync(WaitingTaskHolder task,
2486                                                   ModuleCallingContext const* moduleCallingContext,
2487                                                   unsigned int transitionIndex,
2488                                                   std::atomic<const std::set<ProductProvenance>*>& writeTo) const {
2489     if (nullptr == writeTo.load()) {
2490       auto emptyProv = std::make_unique<const std::set<ProductProvenance>>();
2491       const std::set<ProductProvenance>* expected = nullptr;
2492       if (writeTo.compare_exchange_strong(expected, emptyProv.get())) {
2493         emptyProv.release();
2494       }
2495     }
2496   }
2497 
2498   std::unique_ptr<ProvenanceReaderBase> MakeDummyProvenanceReader::makeReader(RootTree&,
2499                                                                               DaqProvenanceHelper const*) const {
2500     return std::make_unique<DummyProvenanceReader>();
2501   }
2502 
2503   std::unique_ptr<ProvenanceReaderBase> MakeOldProvenanceReader::makeReader(
2504       RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
2505     return std::make_unique<OldProvenanceReader>(&rootTree, *entryDescriptionMap_, daqProvenanceHelper);
2506   }
2507 
2508   std::unique_ptr<ProvenanceReaderBase> MakeFullProvenanceReader::makeReader(
2509       RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
2510     return std::make_unique<FullProvenanceReader>(&rootTree, daqProvenanceHelper);
2511   }
2512 
2513   std::unique_ptr<ProvenanceReaderBase> MakeReducedProvenanceReader::makeReader(
2514       RootTree& rootTree, DaqProvenanceHelper const* daqProvenanceHelper) const {
2515     return std::make_unique<ReducedProvenanceReader>(&rootTree, parentageIDLookup_, daqProvenanceHelper);
2516   }
2517 }  // namespace edm