File indexing completed on 2025-02-14 03:16:47
0001
0002 #include "IOPool/Output/src/RootOutputFile.h"
0003
0004 #include "FWCore/Utilities/interface/GlobalIdentifier.h"
0005
0006 #include "DataFormats/Provenance/interface/EventAuxiliary.h"
0007 #include "DataFormats/Provenance/interface/ProductDescription.h"
0008 #include "FWCore/Version/interface/GetFileFormatVersion.h"
0009 #include "DataFormats/Provenance/interface/FileFormatVersion.h"
0010 #include "FWCore/Utilities/interface/EDMException.h"
0011 #include "FWCore/Utilities/interface/Algorithms.h"
0012 #include "FWCore/Utilities/interface/Digest.h"
0013 #include "FWCore/Common/interface/OutputProcessBlockHelper.h"
0014 #include "FWCore/Framework/interface/FileBlock.h"
0015 #include "FWCore/Framework/interface/EventForOutput.h"
0016 #include "FWCore/Framework/interface/LuminosityBlockForOutput.h"
0017 #include "FWCore/Framework/interface/MergeableRunProductMetadata.h"
0018 #include "FWCore/Framework/interface/OccurrenceForOutput.h"
0019 #include "FWCore/Framework/interface/ProcessBlockForOutput.h"
0020 #include "FWCore/Framework/interface/RunForOutput.h"
0021 #include "FWCore/MessageLogger/interface/JobReport.h"
0022 #include "FWCore/MessageLogger/interface/MessageLogger.h"
0023 #include "DataFormats/Common/interface/BasicHandle.h"
0024 #include "DataFormats/Provenance/interface/ProductDependencies.h"
0025 #include "DataFormats/Provenance/interface/BranchIDList.h"
0026 #include "DataFormats/Provenance/interface/Parentage.h"
0027 #include "DataFormats/Provenance/interface/ParentageRegistry.h"
0028 #include "DataFormats/Provenance/interface/EventID.h"
0029 #include "DataFormats/Provenance/interface/EventToProcessBlockIndexes.h"
0030 #include "DataFormats/Provenance/interface/ParameterSetBlob.h"
0031 #include "DataFormats/Provenance/interface/ParameterSetID.h"
0032 #include "DataFormats/Provenance/interface/ProcessHistoryID.h"
0033 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0034 #include "DataFormats/Provenance/interface/StoredProcessBlockHelper.h"
0035 #include "DataFormats/Provenance/interface/ThinnedAssociationsHelper.h"
0036 #include "DataFormats/Provenance/interface/ProductRegistry.h"
0037 #include "FWCore/ParameterSet/interface/ParameterSet.h"
0038 #include "FWCore/ParameterSet/interface/Registry.h"
0039 #include "FWCore/ServiceRegistry/interface/Service.h"
0040 #include "FWCore/Utilities/interface/ExceptionPropagate.h"
0041 #include "IOPool/Common/interface/getWrapperBasePtr.h"
0042 #include "IOPool/Provenance/interface/CommonProvenanceFiller.h"
0043
0044 #include "TTree.h"
0045 #include "TFile.h"
0046 #include "TClass.h"
0047 #include "Rtypes.h"
0048 #include "RVersion.h"
0049
0050 #include "Compression.h"
0051
0052 #include <algorithm>
0053 #include <iomanip>
0054 #include <sstream>
0055
0056 namespace edm {
0057
0058 namespace {
0059 bool sorterForJobReportHash(ProductDescription const* lh, ProductDescription const* rh) {
0060 return lh->fullClassName() < rh->fullClassName() ? true
0061 : lh->fullClassName() > rh->fullClassName() ? false
0062 : lh->moduleLabel() < rh->moduleLabel() ? true
0063 : lh->moduleLabel() > rh->moduleLabel() ? false
0064 : lh->productInstanceName() < rh->productInstanceName() ? true
0065 : lh->productInstanceName() > rh->productInstanceName() ? false
0066 : lh->processName() < rh->processName() ? true
0067 : false;
0068 }
0069
0070 TFile* openTFile(char const* name, int compressionLevel) {
0071 TFile* file = TFile::Open(name, "recreate", "", compressionLevel);
0072 std::exception_ptr e = edm::threadLocalException::getException();
0073 if (e != std::exception_ptr()) {
0074 edm::threadLocalException::setException(std::exception_ptr());
0075 std::rethrow_exception(e);
0076 }
0077 return file;
0078 }
0079 }
0080
0081 RootOutputFile::RootOutputFile(PoolOutputModule* om,
0082 std::string const& fileName,
0083 std::string const& logicalFileName,
0084 std::vector<std::string> const& processesWithSelectedMergeableRunProducts,
0085 std::string const& overrideGUID)
0086 : file_(fileName),
0087 logicalFile_(logicalFileName),
0088 reportToken_(0),
0089 om_(om),
0090 whyNotFastClonable_(om_->whyNotFastClonable()),
0091 canFastCloneAux_(false),
0092 filePtr_(openTFile(file_.c_str(), om_->compressionLevel())),
0093 fid_(),
0094 eventEntryNumber_(0LL),
0095 lumiEntryNumber_(0LL),
0096 runEntryNumber_(0LL),
0097 indexIntoFile_(),
0098 storedMergeableRunProductMetadata_(processesWithSelectedMergeableRunProducts),
0099 nEventsInLumi_(0),
0100 metaDataTree_(nullptr),
0101 parameterSetsTree_(nullptr),
0102 parentageTree_(nullptr),
0103 lumiAux_(),
0104 runAux_(),
0105 pEventAux_(nullptr),
0106 pLumiAux_(&lumiAux_),
0107 pRunAux_(&runAux_),
0108 eventEntryInfoVector_(),
0109 pEventEntryInfoVector_(&eventEntryInfoVector_),
0110 pBranchListIndexes_(nullptr),
0111 pEventSelectionIDs_(nullptr),
0112 eventTree_(filePtr(), InEvent, om_->splitLevel(), om_->treeMaxVirtualSize()),
0113 lumiTree_(filePtr(), InLumi, om_->splitLevel(), om_->treeMaxVirtualSize()),
0114 runTree_(filePtr(), InRun, om_->splitLevel(), om_->treeMaxVirtualSize()),
0115 dataTypeReported_(false),
0116 processHistoryRegistry_(),
0117 parentageIDs_(),
0118 branchesWithStoredHistory_(),
0119 wrapperBaseTClass_(TClass::GetClass("edm::WrapperBase")) {
0120 std::vector<std::string> const& processesWithProcessBlockProducts =
0121 om_->outputProcessBlockHelper().processesWithProcessBlockProducts();
0122 for (auto const& processName : processesWithProcessBlockProducts) {
0123 processBlockTrees_.emplace_back(std::make_unique<RootOutputTree>(
0124 filePtr(), InProcess, om_->splitLevel(), om_->treeMaxVirtualSize(), processName));
0125 }
0126
0127 if (om_->compressionAlgorithm() == std::string("ZLIB")) {
0128 filePtr_->SetCompressionAlgorithm(ROOT::RCompressionSetting::EAlgorithm::kZLIB);
0129 } else if (om_->compressionAlgorithm() == std::string("LZMA")) {
0130 filePtr_->SetCompressionAlgorithm(ROOT::RCompressionSetting::EAlgorithm::kLZMA);
0131 } else if (om_->compressionAlgorithm() == std::string("ZSTD")) {
0132 filePtr_->SetCompressionAlgorithm(ROOT::RCompressionSetting::EAlgorithm::kZSTD);
0133 } else if (om_->compressionAlgorithm() == std::string("LZ4")) {
0134 filePtr_->SetCompressionAlgorithm(ROOT::RCompressionSetting::EAlgorithm::kLZ4);
0135 } else {
0136 throw Exception(errors::Configuration)
0137 << "PoolOutputModule configured with unknown compression algorithm '" << om_->compressionAlgorithm() << "'\n"
0138 << "Allowed compression algorithms are ZLIB, LZMA, LZ4, and ZSTD\n";
0139 }
0140 if (-1 != om->eventAutoFlushSize()) {
0141 eventTree_.setAutoFlush(-1 * om->eventAutoFlushSize());
0142 }
0143 if (om_->compactEventAuxiliary()) {
0144 eventTree_.addAuxiliary<EventAuxiliary>(
0145 BranchTypeToAuxiliaryBranchName(InEvent), pEventAux_, om_->auxItems()[InEvent].basketSize_, false);
0146 eventTree_.tree()->SetBranchStatus(BranchTypeToAuxiliaryBranchName(InEvent).c_str(),
0147 false);
0148 } else {
0149 eventTree_.addAuxiliary<EventAuxiliary>(
0150 BranchTypeToAuxiliaryBranchName(InEvent), pEventAux_, om_->auxItems()[InEvent].basketSize_);
0151 }
0152
0153 eventTree_.addAuxiliary<StoredProductProvenanceVector>(BranchTypeToProductProvenanceBranchName(InEvent),
0154 pEventEntryInfoVector(),
0155 om_->auxItems()[InEvent].basketSize_);
0156 eventTree_.addAuxiliary<EventSelectionIDVector>(
0157 poolNames::eventSelectionsBranchName(), pEventSelectionIDs_, om_->auxItems()[InEvent].basketSize_, false);
0158 eventTree_.addAuxiliary<BranchListIndexes>(
0159 poolNames::branchListIndexesBranchName(), pBranchListIndexes_, om_->auxItems()[InEvent].basketSize_);
0160
0161 if (om_->outputProcessBlockHelper().productsFromInputKept()) {
0162 eventTree_.addAuxiliary<EventToProcessBlockIndexes>(poolNames::eventToProcessBlockIndexesBranchName(),
0163 pEventToProcessBlockIndexes_,
0164 om_->auxItems()[InEvent].basketSize_);
0165 }
0166
0167 lumiTree_.addAuxiliary<LuminosityBlockAuxiliary>(
0168 BranchTypeToAuxiliaryBranchName(InLumi), pLumiAux_, om_->auxItems()[InLumi].basketSize_);
0169
0170 runTree_.addAuxiliary<RunAuxiliary>(
0171 BranchTypeToAuxiliaryBranchName(InRun), pRunAux_, om_->auxItems()[InRun].basketSize_);
0172
0173 treePointers_.emplace_back(&eventTree_);
0174 treePointers_.emplace_back(&lumiTree_);
0175 treePointers_.emplace_back(&runTree_);
0176 for (auto& processBlockTree : processBlockTrees_) {
0177 treePointers_.emplace_back(processBlockTree.get());
0178 }
0179
0180 for (unsigned int i = 0; i < treePointers_.size(); ++i) {
0181 RootOutputTree* theTree = treePointers_[i];
0182 for (auto& item : om_->selectedOutputItemList()[i]) {
0183 item.setProduct(nullptr);
0184 ProductDescription const& desc = *item.productDescription();
0185 theTree->addBranch(desc.branchName(),
0186 desc.wrappedName(),
0187 item.product(),
0188 item.splitLevel(),
0189 item.basketSize(),
0190 item.productDescription()->produced());
0191
0192 branchesWithStoredHistory_.insert(item.branchID());
0193 }
0194 }
0195
0196 metaDataTree_ = RootOutputTree::makeTTree(filePtr_.get(), poolNames::metaDataTreeName(), 0);
0197 parentageTree_ = RootOutputTree::makeTTree(filePtr_.get(), poolNames::parentageTreeName(), 0);
0198 parameterSetsTree_ = RootOutputTree::makeTTree(filePtr_.get(), poolNames::parameterSetsTreeName(), 0);
0199
0200 if (overrideGUID.empty()) {
0201 fid_ = FileID(createGlobalIdentifier());
0202 } else {
0203 if (not isValidGlobalIdentifier(overrideGUID)) {
0204 throw edm::Exception(errors::Configuration)
0205 << "GUID to be used for output file is not valid (is '" << overrideGUID << "')";
0206 }
0207 fid_ = FileID(overrideGUID);
0208 }
0209
0210
0211
0212
0213
0214
0215 std::vector<std::string> branchNames;
0216 std::vector<ProductDescription const*> branches;
0217 branchNames.reserve(om_->selectedOutputItemList()[InEvent].size());
0218 branches.reserve(om->selectedOutputItemList()[InEvent].size());
0219 for (auto const& item : om_->selectedOutputItemList()[InEvent]) {
0220 branchNames.push_back(item.productDescription()->branchName());
0221 branches.push_back(item.productDescription());
0222 }
0223
0224 sort_all(branches, sorterForJobReportHash);
0225
0226 std::ostringstream oss;
0227 char const underscore = '_';
0228 for (auto const& branch : branches) {
0229 ProductDescription const& bd = *branch;
0230 oss << bd.fullClassName() << underscore << bd.moduleLabel() << underscore << bd.productInstanceName()
0231 << underscore << bd.processName() << underscore;
0232 }
0233 std::string stringrep = oss.str();
0234 cms::Digest md5alg(stringrep);
0235
0236
0237
0238 std::string moduleName = "PoolOutputModule";
0239 Service<JobReport> reportSvc;
0240 reportToken_ = reportSvc->outputFileOpened(file_,
0241 logicalFile_,
0242 om_->catalog(),
0243 moduleName,
0244 om_->moduleLabel(),
0245 fid_.fid(),
0246 std::string(),
0247 md5alg.digest().toString(),
0248 branchNames);
0249 }
0250
0251 namespace {
0252 void maybeIssueWarning(int whyNotFastClonable, std::string const& ifileName, std::string const& ofileName) {
0253
0254 if ((whyNotFastClonable & (FileBlock::DisabledInConfigFile | FileBlock::NoRootInputSource |
0255 FileBlock::NotProcessingEvents | FileBlock::NoEventsInFile)) != 0) {
0256 return;
0257 }
0258
0259
0260
0261
0262 bool isWarning = true;
0263 std::ostringstream message;
0264 message << "Fast copying of file " << ifileName << " to file " << ofileName << " is disabled because:\n";
0265 if ((whyNotFastClonable & FileBlock::HasSecondaryFileSequence) != 0) {
0266 message << "a SecondaryFileSequence was specified.\n";
0267 whyNotFastClonable &= ~(FileBlock::HasSecondaryFileSequence);
0268 isWarning = false;
0269 }
0270 if ((whyNotFastClonable & FileBlock::FileTooOld) != 0) {
0271 message << "the input file is in an old format.\n";
0272 whyNotFastClonable &= ~(FileBlock::FileTooOld);
0273 isWarning = false;
0274 }
0275 if ((whyNotFastClonable & FileBlock::EventsToBeSorted) != 0) {
0276 message << "events need to be sorted.\n";
0277 whyNotFastClonable &= ~(FileBlock::EventsToBeSorted);
0278 }
0279 if ((whyNotFastClonable & FileBlock::RunOrLumiNotContiguous) != 0) {
0280 message << "a run or a lumi is not contiguous in the input file.\n";
0281 whyNotFastClonable &= ~(FileBlock::RunOrLumiNotContiguous);
0282 }
0283 if ((whyNotFastClonable & FileBlock::EventsOrLumisSelectedByID) != 0) {
0284 message << "events or lumis were selected or skipped by ID.\n";
0285 whyNotFastClonable &= ~(FileBlock::EventsOrLumisSelectedByID);
0286 isWarning = false;
0287 }
0288 if ((whyNotFastClonable & FileBlock::InitialEventsSkipped) != 0) {
0289 message << "initial events, lumis or runs were skipped.\n";
0290 whyNotFastClonable &= ~(FileBlock::InitialEventsSkipped);
0291 isWarning = false;
0292 }
0293 if ((whyNotFastClonable & FileBlock::DuplicateEventsRemoved) != 0) {
0294 message << "some events were skipped because of duplicate checking.\n";
0295 whyNotFastClonable &= ~(FileBlock::DuplicateEventsRemoved);
0296 }
0297 if ((whyNotFastClonable & FileBlock::MaxEventsTooSmall) != 0) {
0298 message << "some events were not copied because of maxEvents limit.\n";
0299 whyNotFastClonable &= ~(FileBlock::MaxEventsTooSmall);
0300 isWarning = false;
0301 }
0302 if ((whyNotFastClonable & FileBlock::MaxLumisTooSmall) != 0) {
0303 message << "some events were not copied because of maxLumis limit.\n";
0304 whyNotFastClonable &= ~(FileBlock::MaxLumisTooSmall);
0305 isWarning = false;
0306 }
0307 if ((whyNotFastClonable & FileBlock::ParallelProcesses) != 0) {
0308 message << "parallel processing was specified.\n";
0309 whyNotFastClonable &= ~(FileBlock::ParallelProcesses);
0310 isWarning = false;
0311 }
0312 if ((whyNotFastClonable & FileBlock::EventSelectionUsed) != 0) {
0313 message << "an EventSelector was specified.\n";
0314 whyNotFastClonable &= ~(FileBlock::EventSelectionUsed);
0315 isWarning = false;
0316 }
0317 if ((whyNotFastClonable & FileBlock::OutputMaxEventsTooSmall) != 0) {
0318 message << "some events were not copied because of maxEvents output limit.\n";
0319 whyNotFastClonable &= ~(FileBlock::OutputMaxEventsTooSmall);
0320 isWarning = false;
0321 }
0322 if ((whyNotFastClonable & FileBlock::SplitLevelMismatch) != 0) {
0323 message << "the split level or basket size of a branch or branches was modified.\n";
0324 whyNotFastClonable &= ~(FileBlock::SplitLevelMismatch);
0325 }
0326 if ((whyNotFastClonable & FileBlock::BranchMismatch) != 0) {
0327 message << "The format of a data product has changed.\n";
0328 whyNotFastClonable &= ~(FileBlock::BranchMismatch);
0329 }
0330 assert(whyNotFastClonable == FileBlock::CanFastClone);
0331 if (isWarning) {
0332 LogWarning("FastCloningDisabled") << message.str();
0333 } else {
0334 LogInfo("FastCloningDisabled") << message.str();
0335 }
0336 }
0337 }
0338
0339 void RootOutputFile::beginInputFile(FileBlock const& fb, int remainingEvents) {
0340
0341 whyNotFastClonable_ = om_->whyNotFastClonable();
0342 canFastCloneAux_ = false;
0343
0344 if (fb.tree() != nullptr) {
0345 whyNotFastClonable_ |= fb.whyNotFastClonable();
0346
0347 if (remainingEvents >= 0 && remainingEvents < fb.tree()->GetEntries()) {
0348 whyNotFastClonable_ |= FileBlock::OutputMaxEventsTooSmall;
0349 }
0350
0351 bool match = eventTree_.checkSplitLevelsAndBasketSizes(fb.tree());
0352 if (!match) {
0353 if (om_->overrideInputFileSplitLevels()) {
0354
0355
0356 whyNotFastClonable_ |= FileBlock::SplitLevelMismatch;
0357 } else {
0358
0359
0360
0361
0362 assert(om_->inputFileCount() > 1);
0363 throw Exception(errors::MismatchedInputFiles, "RootOutputFile::beginInputFile()")
0364 << "Merge failure because input file " << file_ << " has different ROOT split levels or basket sizes\n"
0365 << "than previous files. To allow merging in spite of this, use the configuration parameter\n"
0366 << "overrideInputFileSplitLevels=cms.untracked.bool(True)\n"
0367 << "in every PoolOutputModule.\n";
0368 }
0369 }
0370
0371
0372 if (whyNotFastClonable_ == FileBlock::CanFastClone) {
0373 if (!eventTree_.checkIfFastClonable(fb.tree())) {
0374 whyNotFastClonable_ |= FileBlock::BranchMismatch;
0375 }
0376 }
0377
0378
0379 constexpr auto setSubBranchBasketConditions =
0380 FileBlock::EventsOrLumisSelectedByID | FileBlock::InitialEventsSkipped | FileBlock::MaxEventsTooSmall |
0381 FileBlock::MaxLumisTooSmall | FileBlock::EventSelectionUsed | FileBlock::OutputMaxEventsTooSmall |
0382 FileBlock::SplitLevelMismatch | FileBlock::BranchMismatch;
0383
0384 if (om_->inputFileCount() == 1) {
0385 if (om_->mergeJob()) {
0386
0387 auto infile = fb.tree()->GetCurrentFile();
0388 if (infile != nullptr) {
0389 filePtr_->SetCompressionSettings(infile->GetCompressionSettings());
0390 }
0391 }
0392
0393
0394
0395
0396 if (whyNotFastClonable_ != FileBlock::CanFastClone &&
0397 ((om_->mergeJob() && (whyNotFastClonable_ & setSubBranchBasketConditions) == 0) ||
0398 (whyNotFastClonable_ == FileBlock::ParallelProcesses))) {
0399 eventTree_.setSubBranchBasketSizes(fb.tree());
0400 }
0401 }
0402
0403
0404
0405
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429 Service<JobReport> reportSvc;
0430 reportSvc->reportFastCopyingStatus(reportToken_, fb.fileName(), whyNotFastClonable_ == FileBlock::CanFastClone);
0431 } else {
0432 whyNotFastClonable_ |= FileBlock::NoRootInputSource;
0433 }
0434
0435 eventTree_.maybeFastCloneTree(
0436 whyNotFastClonable_ == FileBlock::CanFastClone, canFastCloneAux_, fb.tree(), om_->basketOrder());
0437
0438
0439 if (fb.tree() != nullptr && whyNotFastClonable_ != FileBlock::CanFastClone) {
0440 maybeIssueWarning(whyNotFastClonable_, fb.fileName(), file_);
0441 }
0442
0443 if (om_->compactEventAuxiliary() &&
0444 (whyNotFastClonable_ & (FileBlock::EventsOrLumisSelectedByID | FileBlock::InitialEventsSkipped |
0445 FileBlock::EventSelectionUsed)) == 0) {
0446 long long int reserve = remainingEvents;
0447 if (fb.tree() != nullptr) {
0448 reserve = reserve > 0 ? std::min(fb.tree()->GetEntries(), reserve) : fb.tree()->GetEntries();
0449 }
0450 if (reserve > 0) {
0451 compactEventAuxiliary_.reserve(compactEventAuxiliary_.size() + reserve);
0452 }
0453 }
0454 }
0455
0456 void RootOutputFile::respondToCloseInputFile(FileBlock const&) {
0457
0458 if (not om_->compactEventAuxiliary()) {
0459 eventTree_.setEntries();
0460 }
0461 lumiTree_.setEntries();
0462 runTree_.setEntries();
0463 }
0464
0465 bool RootOutputFile::shouldWeCloseFile() const {
0466 unsigned int const oneK = 1024;
0467 Long64_t size = filePtr_->GetSize() / oneK;
0468 return (size >= om_->maxFileSize());
0469 }
0470
0471 void RootOutputFile::writeOne(EventForOutput const& e) {
0472
0473 pEventAux_ = &e.eventAuxiliary();
0474
0475
0476
0477
0478
0479 assert(pEventAux_->processHistoryID() == e.processHistoryID());
0480 pBranchListIndexes_ = &e.branchListIndexes();
0481 pEventToProcessBlockIndexes_ = &e.eventToProcessBlockIndexes();
0482
0483
0484
0485
0486 EventSelectionIDVector esids = e.eventSelectionIDs();
0487 if (e.productRegistry().anyProductProduced() || !om_->wantAllEvents()) {
0488 esids.push_back(om_->selectorConfig());
0489 }
0490 pEventSelectionIDs_ = &esids;
0491 ProductProvenanceRetriever const* provRetriever = e.productProvenanceRetrieverPtr();
0492 assert(provRetriever);
0493 unsigned int ttreeIndex = InEvent;
0494 fillBranches(InEvent, e, ttreeIndex, pEventEntryInfoVector_, provRetriever);
0495
0496
0497 if (!dataTypeReported_) {
0498 Service<JobReport> reportSvc;
0499 std::string dataType("MC");
0500 if (pEventAux_->isRealData())
0501 dataType = "Data";
0502 reportSvc->reportDataType(reportToken_, dataType);
0503 dataTypeReported_ = true;
0504 }
0505
0506
0507 processHistoryRegistry_.registerProcessHistory(e.processHistory());
0508
0509 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(e.processHistoryID());
0510
0511 indexIntoFile_.addEntry(
0512 reducedPHID, pEventAux_->run(), pEventAux_->luminosityBlock(), pEventAux_->event(), eventEntryNumber_);
0513 ++eventEntryNumber_;
0514
0515 if (om_->compactEventAuxiliary()) {
0516 compactEventAuxiliary_.push_back(*pEventAux_);
0517 }
0518
0519
0520 Service<JobReport> reportSvc;
0521 reportSvc->eventWrittenToFile(reportToken_, e.id().run(), e.id().event());
0522 ++nEventsInLumi_;
0523 }
0524
0525 void RootOutputFile::writeLuminosityBlock(LuminosityBlockForOutput const& lb) {
0526
0527
0528 lumiAux_ = lb.luminosityBlockAuxiliary();
0529
0530 lumiAux_.setProcessHistoryID(lb.processHistoryID());
0531
0532 processHistoryRegistry_.registerProcessHistory(lb.processHistory());
0533
0534 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(lb.processHistoryID());
0535
0536 indexIntoFile_.addEntry(reducedPHID, lumiAux_.run(), lumiAux_.luminosityBlock(), 0U, lumiEntryNumber_);
0537 ++lumiEntryNumber_;
0538 unsigned int ttreeIndex = InLumi;
0539 fillBranches(InLumi, lb, ttreeIndex);
0540 lumiTree_.optimizeBaskets(10ULL * 1024 * 1024);
0541
0542 Service<JobReport> reportSvc;
0543 reportSvc->reportLumiSection(reportToken_, lb.id().run(), lb.id().luminosityBlock(), nEventsInLumi_);
0544 nEventsInLumi_ = 0;
0545 }
0546
0547 void RootOutputFile::writeRun(RunForOutput const& r) {
0548
0549
0550 runAux_ = r.runAuxiliary();
0551
0552 runAux_.setProcessHistoryID(r.processHistoryID());
0553
0554 processHistoryRegistry_.registerProcessHistory(r.processHistory());
0555
0556 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(r.processHistoryID());
0557
0558 indexIntoFile_.addEntry(reducedPHID, runAux_.run(), 0U, 0U, runEntryNumber_);
0559 r.mergeableRunProductMetadata()->addEntryToStoredMetadata(storedMergeableRunProductMetadata_);
0560 ++runEntryNumber_;
0561 unsigned int ttreeIndex = InRun;
0562 fillBranches(InRun, r, ttreeIndex);
0563 runTree_.optimizeBaskets(10ULL * 1024 * 1024);
0564
0565 Service<JobReport> reportSvc;
0566 reportSvc->reportRunNumber(reportToken_, r.run());
0567 }
0568
0569 void RootOutputFile::writeProcessBlock(ProcessBlockForOutput const& pb) {
0570 std::string const& processName = pb.processName();
0571 std::vector<std::string> const& processesWithProcessBlockProducts =
0572 om_->outputProcessBlockHelper().processesWithProcessBlockProducts();
0573 std::vector<std::string>::const_iterator it =
0574 std::find(processesWithProcessBlockProducts.cbegin(), processesWithProcessBlockProducts.cend(), processName);
0575 if (it == processesWithProcessBlockProducts.cend()) {
0576 return;
0577 }
0578 unsigned int ttreeIndex = InProcess + std::distance(processesWithProcessBlockProducts.cbegin(), it);
0579 fillBranches(InProcess, pb, ttreeIndex);
0580 treePointers_[ttreeIndex]->optimizeBaskets(10ULL * 1024 * 1024);
0581 }
0582
0583 void RootOutputFile::writeParentageRegistry() {
0584 Parentage const* desc(nullptr);
0585
0586 if (!parentageTree_->Branch(poolNames::parentageBranchName().c_str(), &desc, om_->basketSize(), 0))
0587 throw Exception(errors::FatalRootError) << "Failed to create a branch for Parentages in the output file";
0588
0589 ParentageRegistry& ptReg = *ParentageRegistry::instance();
0590
0591 std::vector<ParentageID> orderedIDs(parentageIDs_.size());
0592 for (auto const& parentageID : parentageIDs_) {
0593 orderedIDs[parentageID.second] = parentageID.first;
0594 }
0595
0596 for (auto const& orderedID : orderedIDs) {
0597 desc = ptReg.getMapped(orderedID);
0598
0599
0600
0601 parentageTree_->Fill();
0602 }
0603 }
0604
0605 void RootOutputFile::writeFileFormatVersion() {
0606 FileFormatVersion fileFormatVersion(getFileFormatVersion());
0607 FileFormatVersion* pFileFmtVsn = &fileFormatVersion;
0608 TBranch* b =
0609 metaDataTree_->Branch(poolNames::fileFormatVersionBranchName().c_str(), &pFileFmtVsn, om_->basketSize(), 0);
0610 assert(b);
0611 b->Fill();
0612 }
0613
0614 void RootOutputFile::writeFileIdentifier() {
0615 FileID* fidPtr = &fid_;
0616 TBranch* b = metaDataTree_->Branch(poolNames::fileIdentifierBranchName().c_str(), &fidPtr, om_->basketSize(), 0);
0617 assert(b);
0618 b->Fill();
0619 }
0620
0621 void RootOutputFile::writeIndexIntoFile() {
0622 if (eventTree_.checkEntriesInReadBranches(eventEntryNumber_) == false) {
0623 Exception ex(errors::OtherCMS);
0624 ex << "The number of entries in at least one output TBranch whose entries\n"
0625 "were copied from the input does not match the number of events\n"
0626 "recorded in IndexIntoFile. This might (or might not) indicate a\n"
0627 "problem related to fast copy.";
0628 ex.addContext("Calling RootOutputFile::writeIndexIntoFile");
0629 throw ex;
0630 }
0631 indexIntoFile_.sortVector_Run_Or_Lumi_Entries();
0632 IndexIntoFile* iifPtr = &indexIntoFile_;
0633 TBranch* b = metaDataTree_->Branch(poolNames::indexIntoFileBranchName().c_str(), &iifPtr, om_->basketSize(), 0);
0634 assert(b);
0635 b->Fill();
0636 }
0637
0638 void RootOutputFile::writeStoredMergeableRunProductMetadata() {
0639 storedMergeableRunProductMetadata_.optimizeBeforeWrite();
0640 StoredMergeableRunProductMetadata* ptr = &storedMergeableRunProductMetadata_;
0641 TBranch* b =
0642 metaDataTree_->Branch(poolNames::mergeableRunProductMetadataBranchName().c_str(), &ptr, om_->basketSize(), 0);
0643 assert(b);
0644 b->Fill();
0645 }
0646
0647 void RootOutputFile::writeProcessHistoryRegistry() {
0648 fillProcessHistoryBranch(metaDataTree_.get(), om_->basketSize(), processHistoryRegistry_);
0649 }
0650
0651 void RootOutputFile::writeBranchIDListRegistry() {
0652 BranchIDLists const* p = om_->branchIDLists();
0653 TBranch* b = metaDataTree_->Branch(poolNames::branchIDListBranchName().c_str(), &p, om_->basketSize(), 0);
0654 assert(b);
0655 b->Fill();
0656 }
0657
0658 void RootOutputFile::writeThinnedAssociationsHelper() {
0659 ThinnedAssociationsHelper const* p = om_->thinnedAssociationsHelper();
0660 TBranch* b =
0661 metaDataTree_->Branch(poolNames::thinnedAssociationsHelperBranchName().c_str(), &p, om_->basketSize(), 0);
0662 assert(b);
0663 b->Fill();
0664 }
0665
0666 void RootOutputFile::writeParameterSetRegistry() {
0667 fillParameterSetBranch(parameterSetsTree_.get(), om_->basketSize());
0668 }
0669
0670 void RootOutputFile::writeProductDescriptionRegistry(ProductRegistry const& iReg) {
0671
0672 using ProductList = ProductRegistry::ProductList;
0673 ProductRegistry pReg(iReg.productList());
0674 ProductList& pList = const_cast<ProductList&>(pReg.productList());
0675 for (auto const& prod : pList) {
0676 if (prod.second.branchID() != prod.second.originalBranchID()) {
0677 if (branchesWithStoredHistory_.find(prod.second.branchID()) != branchesWithStoredHistory_.end()) {
0678 branchesWithStoredHistory_.insert(prod.second.originalBranchID());
0679 }
0680 }
0681 }
0682 std::set<BranchID>::iterator end = branchesWithStoredHistory_.end();
0683 for (ProductList::iterator it = pList.begin(); it != pList.end();) {
0684 if (branchesWithStoredHistory_.find(it->second.branchID()) == end) {
0685
0686 ProductList::iterator itCopy = it;
0687 ++it;
0688 pList.erase(itCopy);
0689
0690 } else {
0691 ++it;
0692 }
0693 }
0694
0695 ProductRegistry* ppReg = &pReg;
0696 TBranch* b = metaDataTree_->Branch(poolNames::productDescriptionBranchName().c_str(), &ppReg, om_->basketSize(), 0);
0697 assert(b);
0698 b->Fill();
0699 }
0700 void RootOutputFile::writeProductDependencies() {
0701 ProductDependencies& pDeps = const_cast<ProductDependencies&>(om_->productDependencies());
0702 ProductDependencies* ppDeps = &pDeps;
0703 TBranch* b =
0704 metaDataTree_->Branch(poolNames::productDependenciesBranchName().c_str(), &ppDeps, om_->basketSize(), 0);
0705 assert(b);
0706 b->Fill();
0707 }
0708
0709
0710
0711
0712
0713
0714
0715
0716 void RootOutputFile::writeEventAuxiliary() {
0717 constexpr std::size_t maxEaBasketSize = 4 * 1024 * 1024;
0718
0719 if (om_->compactEventAuxiliary()) {
0720 auto tree = eventTree_.tree();
0721 auto const& bname = BranchTypeToAuxiliaryBranchName(InEvent).c_str();
0722
0723 tree->SetBranchStatus(bname, true);
0724 auto basketsize =
0725 std::min(maxEaBasketSize,
0726 compactEventAuxiliary_.size() * (sizeof(EventAuxiliary) + 26));
0727 tree->SetBasketSize(bname, basketsize);
0728 auto b = tree->GetBranch(bname);
0729
0730 assert(b);
0731
0732 LogDebug("writeEventAuxiliary") << "EventAuxiliary ratio extras/GUIDs/all = "
0733 << compactEventAuxiliary_.extrasSize() << "/"
0734 << compactEventAuxiliary_.guidsSize() << "/" << compactEventAuxiliary_.size();
0735
0736 for (auto const& aux : compactEventAuxiliary_) {
0737 const auto ea = aux.eventAuxiliary();
0738 pEventAux_ = &ea;
0739
0740 b->Fill();
0741 }
0742 eventTree_.setEntries();
0743 }
0744 }
0745
0746 void RootOutputFile::writeProcessBlockHelper() {
0747 if (!om_->outputProcessBlockHelper().processesWithProcessBlockProducts().empty()) {
0748 StoredProcessBlockHelper storedProcessBlockHelper(
0749 om_->outputProcessBlockHelper().processesWithProcessBlockProducts());
0750 om_->outputProcessBlockHelper().fillCacheIndices(storedProcessBlockHelper);
0751
0752 StoredProcessBlockHelper* pStoredProcessBlockHelper = &storedProcessBlockHelper;
0753 TBranch* b = metaDataTree_->Branch(
0754 poolNames::processBlockHelperBranchName().c_str(), &pStoredProcessBlockHelper, om_->basketSize(), 0);
0755 assert(b);
0756 b->Fill();
0757 }
0758 }
0759
0760 void RootOutputFile::finishEndFile() {
0761 std::string_view status = "beginning";
0762 std::string_view value = "";
0763 try {
0764 metaDataTree_->SetEntries(-1);
0765 status = "writeTTree() for metadata";
0766 RootOutputTree::writeTTree(metaDataTree_);
0767 status = "writeTTree() for ParameterSets";
0768 RootOutputTree::writeTTree(parameterSetsTree_);
0769
0770 status = "writeTTree() for parentage";
0771 RootOutputTree::writeTTree(parentageTree_);
0772
0773
0774
0775
0776 status = "writeTree() for ";
0777 for (unsigned int i = 0; i < treePointers_.size(); ++i) {
0778 std::string processName;
0779 BranchType branchType = InProcess;
0780 if (i < InProcess) {
0781 branchType = static_cast<BranchType>(i);
0782 } else {
0783 processName = om_->outputProcessBlockHelper().processesWithProcessBlockProducts()[i - InProcess];
0784 }
0785 setBranchAliases(treePointers_[i]->tree(), om_->keptProducts()[branchType], processName);
0786 value = treePointers_[i]->tree()->GetName();
0787 treePointers_[i]->writeTree();
0788 }
0789
0790
0791
0792 status = "closing TTrees";
0793 value = "";
0794 metaDataTree_ = parentageTree_ = nullptr;
0795 for (auto& treePointer : treePointers_) {
0796 treePointer->close();
0797 treePointer = nullptr;
0798 }
0799 status = "closing TFile";
0800 filePtr_->Close();
0801 filePtr_ = nullptr;
0802
0803
0804 status = "reporting to JobReport";
0805 Service<JobReport> reportSvc;
0806 reportSvc->outputFileClosed(reportToken_);
0807 } catch (cms::Exception& e) {
0808 e.addContext("Calling RootOutputFile::finishEndFile() while closing " + file_);
0809 e.addAdditionalInfo("While calling " + std::string(status) + std::string(value));
0810 throw;
0811 }
0812 }
0813
0814 void RootOutputFile::setBranchAliases(TTree* tree,
0815 SelectedProducts const& branches,
0816 std::string const& processName) const {
0817 if (tree && tree->GetNbranches() != 0) {
0818 auto const& aliasForBranches = om_->aliasForBranches();
0819 for (auto const& selection : branches) {
0820 ProductDescription const& pd = *selection.first;
0821 if (pd.branchType() == InProcess && processName != pd.processName()) {
0822 continue;
0823 }
0824 std::string const& full = pd.branchName() + "obj";
0825 bool matched = false;
0826 for (auto const& matcher : aliasForBranches) {
0827 if (matcher.match(pd.branchName())) {
0828 tree->SetAlias(matcher.alias_.c_str(), full.c_str());
0829 matched = true;
0830 }
0831 }
0832 if (not matched and pd.branchAliases().empty()) {
0833 std::string const& alias = (pd.productInstanceName().empty() ? pd.moduleLabel() : pd.productInstanceName());
0834 tree->SetAlias(alias.c_str(), full.c_str());
0835 } else {
0836 for (auto const& alias : pd.branchAliases()) {
0837 tree->SetAlias(alias.c_str(), full.c_str());
0838 }
0839 }
0840 }
0841 }
0842 }
0843
0844 void RootOutputFile::insertAncestors(ProductProvenance const& iGetParents,
0845 ProductProvenanceRetriever const* iMapper,
0846 bool produced,
0847 std::set<BranchID> const& iProducedIDs,
0848 std::set<StoredProductProvenance>& oToFill) {
0849 assert(om_->dropMetaData() != PoolOutputModule::DropAll);
0850 assert(produced || om_->dropMetaData() != PoolOutputModule::DropPrior);
0851 if (om_->dropMetaData() == PoolOutputModule::DropDroppedPrior && !produced)
0852 return;
0853 std::vector<BranchID> const& parentIDs = iGetParents.parentage().parents();
0854 for (auto const& parentID : parentIDs) {
0855 branchesWithStoredHistory_.insert(parentID);
0856 ProductProvenance const* info = iMapper->branchIDToProvenance(parentID);
0857 if (info) {
0858 if (om_->dropMetaData() == PoolOutputModule::DropNone ||
0859 (iProducedIDs.end() != iProducedIDs.find(info->branchID()))) {
0860 if (insertProductProvenance(*info, oToFill)) {
0861
0862 insertAncestors(*info, iMapper, produced, iProducedIDs, oToFill);
0863 }
0864 }
0865 }
0866 }
0867 }
0868
0869 void RootOutputFile::fillBranches(BranchType const& branchType,
0870 OccurrenceForOutput const& occurrence,
0871 unsigned int ttreeIndex,
0872 StoredProductProvenanceVector* productProvenanceVecPtr,
0873 ProductProvenanceRetriever const* provRetriever) {
0874 std::vector<std::unique_ptr<WrapperBase> > dummies;
0875
0876 OutputItemList& items = om_->selectedOutputItemList()[ttreeIndex];
0877
0878 bool const doProvenance =
0879 (productProvenanceVecPtr != nullptr) && (om_->dropMetaData() != PoolOutputModule::DropAll);
0880 bool const keepProvenanceForPrior = doProvenance && om_->dropMetaData() != PoolOutputModule::DropPrior;
0881
0882 bool const fastCloning = (branchType == InEvent) && (whyNotFastClonable_ == FileBlock::CanFastClone);
0883 std::set<StoredProductProvenance> provenanceToKeep;
0884
0885
0886
0887
0888
0889 std::set<BranchID> producedBranches;
0890 if (doProvenance && branchType == InEvent && om_->dropMetaData() != PoolOutputModule::DropNone) {
0891 for (auto bd : occurrence.productRegistry().allProductDescriptions()) {
0892 if (bd->produced() && bd->branchType() == InEvent) {
0893 producedBranches.insert(bd->branchID());
0894 }
0895 }
0896 }
0897
0898
0899 for (auto& item : items) {
0900 BranchID const& id = item.productDescription()->branchID();
0901 branchesWithStoredHistory_.insert(id);
0902
0903 bool produced = item.productDescription()->produced();
0904 bool getProd =
0905 (produced || !fastCloning || treePointers_[ttreeIndex]->uncloned(item.productDescription()->branchName()));
0906 bool keepProvenance = doProvenance && (produced || keepProvenanceForPrior);
0907
0908 WrapperBase const* product = nullptr;
0909 ProductProvenance const* productProvenance = nullptr;
0910 if (getProd) {
0911 BasicHandle result = occurrence.getByToken(item.token(), item.productDescription()->unwrappedTypeID());
0912 product = result.wrapper();
0913 if (result.isValid() && keepProvenance) {
0914 productProvenance = result.provenance()->productProvenance();
0915 }
0916 if (product == nullptr) {
0917
0918
0919 TClass* cp = item.productDescription()->wrappedType().getClass();
0920 assert(cp != nullptr);
0921 int offset = cp->GetBaseClassOffset(wrapperBaseTClass_);
0922 void* p = cp->New();
0923 std::unique_ptr<WrapperBase> dummy = getWrapperBasePtr(p, offset);
0924 product = dummy.get();
0925 dummies.emplace_back(std::move(dummy));
0926 }
0927 item.setProduct(product);
0928 }
0929 if (keepProvenance && productProvenance == nullptr) {
0930 productProvenance = provRetriever->branchIDToProvenance(item.productDescription()->originalBranchID());
0931 }
0932 if (productProvenance) {
0933 insertProductProvenance(*productProvenance, provenanceToKeep);
0934 insertAncestors(*productProvenance, provRetriever, produced, producedBranches, provenanceToKeep);
0935 }
0936 }
0937
0938 if (doProvenance)
0939 productProvenanceVecPtr->assign(provenanceToKeep.begin(), provenanceToKeep.end());
0940 treePointers_[ttreeIndex]->fillTree();
0941 if (doProvenance)
0942 productProvenanceVecPtr->clear();
0943 }
0944
0945 bool RootOutputFile::insertProductProvenance(const edm::ProductProvenance& iProv,
0946 std::set<edm::StoredProductProvenance>& oToInsert) {
0947 StoredProductProvenance toStore;
0948 toStore.branchID_ = iProv.branchID().id();
0949 std::set<edm::StoredProductProvenance>::iterator itFound = oToInsert.find(toStore);
0950 if (itFound == oToInsert.end()) {
0951
0952 std::pair<std::map<edm::ParentageID, unsigned int>::iterator, bool> i =
0953 parentageIDs_.insert(std::make_pair(iProv.parentageID(), static_cast<unsigned int>(parentageIDs_.size())));
0954 toStore.parentageIDIndex_ = i.first->second;
0955 if (toStore.parentageIDIndex_ >= parentageIDs_.size()) {
0956 throw edm::Exception(errors::LogicError)
0957 << "RootOutputFile::insertProductProvenance\n"
0958 << "The parentage ID index value " << toStore.parentageIDIndex_
0959 << " is out of bounds. The maximum value is currently " << parentageIDs_.size() - 1 << ".\n"
0960 << "This should never happen.\n"
0961 << "Please report this to the framework developers.";
0962 }
0963
0964 oToInsert.insert(toStore);
0965 return true;
0966 }
0967 return false;
0968 }
0969 }