Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-05-11 03:34:24

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