File indexing completed on 2024-06-07 02:29:43
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/BranchDescription.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/BranchChildren.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 "FWCore/Framework/interface/ConstProductRegistry.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(BranchDescription const* lh, BranchDescription 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::kZLIB);
0129 } else if (om_->compressionAlgorithm() == std::string("LZMA")) {
0130 filePtr_->SetCompressionAlgorithm(ROOT::kLZMA);
0131 } else if (om_->compressionAlgorithm() == std::string("ZSTD")) {
0132 filePtr_->SetCompressionAlgorithm(ROOT::kZSTD);
0133 } else if (om_->compressionAlgorithm() == std::string("LZ4")) {
0134 filePtr_->SetCompressionAlgorithm(ROOT::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 BranchDescription const& desc = *item.branchDescription();
0185 theTree->addBranch(desc.branchName(),
0186 desc.wrappedName(),
0187 item.product(),
0188 item.splitLevel(),
0189 item.basketSize(),
0190 item.branchDescription()->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<BranchDescription 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.branchDescription()->branchName());
0221 branches.push_back(item.branchDescription());
0222 }
0223
0224 sort_all(branches, sorterForJobReportHash);
0225
0226 std::ostringstream oss;
0227 char const underscore = '_';
0228 for (auto const& branch : branches) {
0229 BranchDescription 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
0430 Service<JobReport> reportSvc;
0431 reportSvc->reportFastCopyingStatus(reportToken_, fb.fileName(), whyNotFastClonable_ == FileBlock::CanFastClone);
0432 } else {
0433 whyNotFastClonable_ |= FileBlock::NoRootInputSource;
0434 }
0435
0436 eventTree_.maybeFastCloneTree(
0437 whyNotFastClonable_ == FileBlock::CanFastClone, canFastCloneAux_, fb.tree(), om_->basketOrder());
0438
0439
0440 if (fb.tree() != nullptr && whyNotFastClonable_ != FileBlock::CanFastClone) {
0441 maybeIssueWarning(whyNotFastClonable_, fb.fileName(), file_);
0442 }
0443
0444 if (om_->compactEventAuxiliary() &&
0445 (whyNotFastClonable_ & (FileBlock::EventsOrLumisSelectedByID | FileBlock::InitialEventsSkipped |
0446 FileBlock::EventSelectionUsed)) == 0) {
0447 long long int reserve = remainingEvents;
0448 if (fb.tree() != nullptr) {
0449 reserve = reserve > 0 ? std::min(fb.tree()->GetEntries(), reserve) : fb.tree()->GetEntries();
0450 }
0451 if (reserve > 0) {
0452 compactEventAuxiliary_.reserve(compactEventAuxiliary_.size() + reserve);
0453 }
0454 }
0455 }
0456
0457 void RootOutputFile::respondToCloseInputFile(FileBlock const&) {
0458
0459 if (not om_->compactEventAuxiliary()) {
0460 eventTree_.setEntries();
0461 }
0462 lumiTree_.setEntries();
0463 runTree_.setEntries();
0464 }
0465
0466 bool RootOutputFile::shouldWeCloseFile() const {
0467 unsigned int const oneK = 1024;
0468 Long64_t size = filePtr_->GetSize() / oneK;
0469 return (size >= om_->maxFileSize());
0470 }
0471
0472 void RootOutputFile::writeOne(EventForOutput const& e) {
0473
0474 pEventAux_ = &e.eventAuxiliary();
0475
0476
0477
0478
0479
0480 assert(pEventAux_->processHistoryID() == e.processHistoryID());
0481 pBranchListIndexes_ = &e.branchListIndexes();
0482 pEventToProcessBlockIndexes_ = &e.eventToProcessBlockIndexes();
0483
0484
0485
0486
0487 Service<ConstProductRegistry> reg;
0488 EventSelectionIDVector esids = e.eventSelectionIDs();
0489 if (reg->anyProductProduced() || !om_->wantAllEvents()) {
0490 esids.push_back(om_->selectorConfig());
0491 }
0492 pEventSelectionIDs_ = &esids;
0493 ProductProvenanceRetriever const* provRetriever = e.productProvenanceRetrieverPtr();
0494 assert(provRetriever);
0495 unsigned int ttreeIndex = InEvent;
0496 fillBranches(InEvent, e, ttreeIndex, pEventEntryInfoVector_, provRetriever);
0497
0498
0499 if (!dataTypeReported_) {
0500 Service<JobReport> reportSvc;
0501 std::string dataType("MC");
0502 if (pEventAux_->isRealData())
0503 dataType = "Data";
0504 reportSvc->reportDataType(reportToken_, dataType);
0505 dataTypeReported_ = true;
0506 }
0507
0508
0509 processHistoryRegistry_.registerProcessHistory(e.processHistory());
0510
0511 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(e.processHistoryID());
0512
0513 indexIntoFile_.addEntry(
0514 reducedPHID, pEventAux_->run(), pEventAux_->luminosityBlock(), pEventAux_->event(), eventEntryNumber_);
0515 ++eventEntryNumber_;
0516
0517 if (om_->compactEventAuxiliary()) {
0518 compactEventAuxiliary_.push_back(*pEventAux_);
0519 }
0520
0521
0522 Service<JobReport> reportSvc;
0523 reportSvc->eventWrittenToFile(reportToken_, e.id().run(), e.id().event());
0524 ++nEventsInLumi_;
0525 }
0526
0527 void RootOutputFile::writeLuminosityBlock(LuminosityBlockForOutput const& lb) {
0528
0529
0530 lumiAux_ = lb.luminosityBlockAuxiliary();
0531
0532 lumiAux_.setProcessHistoryID(lb.processHistoryID());
0533
0534 processHistoryRegistry_.registerProcessHistory(lb.processHistory());
0535
0536 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(lb.processHistoryID());
0537
0538 indexIntoFile_.addEntry(reducedPHID, lumiAux_.run(), lumiAux_.luminosityBlock(), 0U, lumiEntryNumber_);
0539 ++lumiEntryNumber_;
0540 unsigned int ttreeIndex = InLumi;
0541 fillBranches(InLumi, lb, ttreeIndex);
0542 lumiTree_.optimizeBaskets(10ULL * 1024 * 1024);
0543
0544 Service<JobReport> reportSvc;
0545 reportSvc->reportLumiSection(reportToken_, lb.id().run(), lb.id().luminosityBlock(), nEventsInLumi_);
0546 nEventsInLumi_ = 0;
0547 }
0548
0549 void RootOutputFile::writeRun(RunForOutput const& r) {
0550
0551
0552 runAux_ = r.runAuxiliary();
0553
0554 runAux_.setProcessHistoryID(r.processHistoryID());
0555
0556 processHistoryRegistry_.registerProcessHistory(r.processHistory());
0557
0558 ProcessHistoryID reducedPHID = processHistoryRegistry_.reducedProcessHistoryID(r.processHistoryID());
0559
0560 indexIntoFile_.addEntry(reducedPHID, runAux_.run(), 0U, 0U, runEntryNumber_);
0561 r.mergeableRunProductMetadata()->addEntryToStoredMetadata(storedMergeableRunProductMetadata_);
0562 ++runEntryNumber_;
0563 unsigned int ttreeIndex = InRun;
0564 fillBranches(InRun, r, ttreeIndex);
0565 runTree_.optimizeBaskets(10ULL * 1024 * 1024);
0566
0567 Service<JobReport> reportSvc;
0568 reportSvc->reportRunNumber(reportToken_, r.run());
0569 }
0570
0571 void RootOutputFile::writeProcessBlock(ProcessBlockForOutput const& pb) {
0572 std::string const& processName = pb.processName();
0573 std::vector<std::string> const& processesWithProcessBlockProducts =
0574 om_->outputProcessBlockHelper().processesWithProcessBlockProducts();
0575 std::vector<std::string>::const_iterator it =
0576 std::find(processesWithProcessBlockProducts.cbegin(), processesWithProcessBlockProducts.cend(), processName);
0577 if (it == processesWithProcessBlockProducts.cend()) {
0578 return;
0579 }
0580 unsigned int ttreeIndex = InProcess + std::distance(processesWithProcessBlockProducts.cbegin(), it);
0581 fillBranches(InProcess, pb, ttreeIndex);
0582 treePointers_[ttreeIndex]->optimizeBaskets(10ULL * 1024 * 1024);
0583 }
0584
0585 void RootOutputFile::writeParentageRegistry() {
0586 Parentage const* desc(nullptr);
0587
0588 if (!parentageTree_->Branch(poolNames::parentageBranchName().c_str(), &desc, om_->basketSize(), 0))
0589 throw Exception(errors::FatalRootError) << "Failed to create a branch for Parentages in the output file";
0590
0591 ParentageRegistry& ptReg = *ParentageRegistry::instance();
0592
0593 std::vector<ParentageID> orderedIDs(parentageIDs_.size());
0594 for (auto const& parentageID : parentageIDs_) {
0595 orderedIDs[parentageID.second] = parentageID.first;
0596 }
0597
0598 for (auto const& orderedID : orderedIDs) {
0599 desc = ptReg.getMapped(orderedID);
0600
0601
0602
0603 parentageTree_->Fill();
0604 }
0605 }
0606
0607 void RootOutputFile::writeFileFormatVersion() {
0608 FileFormatVersion fileFormatVersion(getFileFormatVersion());
0609 FileFormatVersion* pFileFmtVsn = &fileFormatVersion;
0610 TBranch* b =
0611 metaDataTree_->Branch(poolNames::fileFormatVersionBranchName().c_str(), &pFileFmtVsn, om_->basketSize(), 0);
0612 assert(b);
0613 b->Fill();
0614 }
0615
0616 void RootOutputFile::writeFileIdentifier() {
0617 FileID* fidPtr = &fid_;
0618 TBranch* b = metaDataTree_->Branch(poolNames::fileIdentifierBranchName().c_str(), &fidPtr, om_->basketSize(), 0);
0619 assert(b);
0620 b->Fill();
0621 }
0622
0623 void RootOutputFile::writeIndexIntoFile() {
0624 if (eventTree_.checkEntriesInReadBranches(eventEntryNumber_) == false) {
0625 Exception ex(errors::OtherCMS);
0626 ex << "The number of entries in at least one output TBranch whose entries\n"
0627 "were copied from the input does not match the number of events\n"
0628 "recorded in IndexIntoFile. This might (or might not) indicate a\n"
0629 "problem related to fast copy.";
0630 ex.addContext("Calling RootOutputFile::writeIndexIntoFile");
0631 throw ex;
0632 }
0633 indexIntoFile_.sortVector_Run_Or_Lumi_Entries();
0634 IndexIntoFile* iifPtr = &indexIntoFile_;
0635 TBranch* b = metaDataTree_->Branch(poolNames::indexIntoFileBranchName().c_str(), &iifPtr, om_->basketSize(), 0);
0636 assert(b);
0637 b->Fill();
0638 }
0639
0640 void RootOutputFile::writeStoredMergeableRunProductMetadata() {
0641 storedMergeableRunProductMetadata_.optimizeBeforeWrite();
0642 StoredMergeableRunProductMetadata* ptr = &storedMergeableRunProductMetadata_;
0643 TBranch* b =
0644 metaDataTree_->Branch(poolNames::mergeableRunProductMetadataBranchName().c_str(), &ptr, om_->basketSize(), 0);
0645 assert(b);
0646 b->Fill();
0647 }
0648
0649 void RootOutputFile::writeProcessHistoryRegistry() {
0650 fillProcessHistoryBranch(metaDataTree_.get(), om_->basketSize(), processHistoryRegistry_);
0651 }
0652
0653 void RootOutputFile::writeBranchIDListRegistry() {
0654 BranchIDLists const* p = om_->branchIDLists();
0655 TBranch* b = metaDataTree_->Branch(poolNames::branchIDListBranchName().c_str(), &p, om_->basketSize(), 0);
0656 assert(b);
0657 b->Fill();
0658 }
0659
0660 void RootOutputFile::writeThinnedAssociationsHelper() {
0661 ThinnedAssociationsHelper const* p = om_->thinnedAssociationsHelper();
0662 TBranch* b =
0663 metaDataTree_->Branch(poolNames::thinnedAssociationsHelperBranchName().c_str(), &p, om_->basketSize(), 0);
0664 assert(b);
0665 b->Fill();
0666 }
0667
0668 void RootOutputFile::writeParameterSetRegistry() {
0669 fillParameterSetBranch(parameterSetsTree_.get(), om_->basketSize());
0670 }
0671
0672 void RootOutputFile::writeProductDescriptionRegistry() {
0673
0674 using ProductList = ProductRegistry::ProductList;
0675 Service<ConstProductRegistry> reg;
0676 ProductRegistry pReg(reg->productList());
0677 ProductList& pList = const_cast<ProductList&>(pReg.productList());
0678 for (auto const& prod : pList) {
0679 if (prod.second.branchID() != prod.second.originalBranchID()) {
0680 if (branchesWithStoredHistory_.find(prod.second.branchID()) != branchesWithStoredHistory_.end()) {
0681 branchesWithStoredHistory_.insert(prod.second.originalBranchID());
0682 }
0683 }
0684 }
0685 std::set<BranchID>::iterator end = branchesWithStoredHistory_.end();
0686 for (ProductList::iterator it = pList.begin(); it != pList.end();) {
0687 if (branchesWithStoredHistory_.find(it->second.branchID()) == end) {
0688
0689 ProductList::iterator itCopy = it;
0690 ++it;
0691 pList.erase(itCopy);
0692
0693 } else {
0694 ++it;
0695 }
0696 }
0697
0698 ProductRegistry* ppReg = &pReg;
0699 TBranch* b = metaDataTree_->Branch(poolNames::productDescriptionBranchName().c_str(), &ppReg, om_->basketSize(), 0);
0700 assert(b);
0701 b->Fill();
0702 }
0703 void RootOutputFile::writeProductDependencies() {
0704 BranchChildren& pDeps = const_cast<BranchChildren&>(om_->branchChildren());
0705 BranchChildren* ppDeps = &pDeps;
0706 TBranch* b =
0707 metaDataTree_->Branch(poolNames::productDependenciesBranchName().c_str(), &ppDeps, om_->basketSize(), 0);
0708 assert(b);
0709 b->Fill();
0710 }
0711
0712
0713
0714
0715
0716
0717
0718
0719 void RootOutputFile::writeEventAuxiliary() {
0720 constexpr std::size_t maxEaBasketSize = 4 * 1024 * 1024;
0721
0722 if (om_->compactEventAuxiliary()) {
0723 auto tree = eventTree_.tree();
0724 auto const& bname = BranchTypeToAuxiliaryBranchName(InEvent).c_str();
0725
0726 tree->SetBranchStatus(bname, true);
0727 auto basketsize =
0728 std::min(maxEaBasketSize,
0729 compactEventAuxiliary_.size() * (sizeof(EventAuxiliary) + 26));
0730 tree->SetBasketSize(bname, basketsize);
0731 auto b = tree->GetBranch(bname);
0732
0733 assert(b);
0734
0735 LogDebug("writeEventAuxiliary") << "EventAuxiliary ratio extras/GUIDs/all = "
0736 << compactEventAuxiliary_.extrasSize() << "/"
0737 << compactEventAuxiliary_.guidsSize() << "/" << compactEventAuxiliary_.size();
0738
0739 for (auto const& aux : compactEventAuxiliary_) {
0740 const auto ea = aux.eventAuxiliary();
0741 pEventAux_ = &ea;
0742
0743 b->Fill();
0744 }
0745 eventTree_.setEntries();
0746 }
0747 }
0748
0749 void RootOutputFile::writeProcessBlockHelper() {
0750 if (!om_->outputProcessBlockHelper().processesWithProcessBlockProducts().empty()) {
0751 StoredProcessBlockHelper storedProcessBlockHelper(
0752 om_->outputProcessBlockHelper().processesWithProcessBlockProducts());
0753 om_->outputProcessBlockHelper().fillCacheIndices(storedProcessBlockHelper);
0754
0755 StoredProcessBlockHelper* pStoredProcessBlockHelper = &storedProcessBlockHelper;
0756 TBranch* b = metaDataTree_->Branch(
0757 poolNames::processBlockHelperBranchName().c_str(), &pStoredProcessBlockHelper, om_->basketSize(), 0);
0758 assert(b);
0759 b->Fill();
0760 }
0761 }
0762
0763 void RootOutputFile::finishEndFile() {
0764 std::string_view status = "beginning";
0765 std::string_view value = "";
0766 try {
0767 metaDataTree_->SetEntries(-1);
0768 status = "writeTTree() for metadata";
0769 RootOutputTree::writeTTree(metaDataTree_);
0770 status = "writeTTree() for ParameterSets";
0771 RootOutputTree::writeTTree(parameterSetsTree_);
0772
0773 status = "writeTTree() for parentage";
0774 RootOutputTree::writeTTree(parentageTree_);
0775
0776
0777
0778
0779 status = "writeTree() for ";
0780 for (unsigned int i = 0; i < treePointers_.size(); ++i) {
0781 std::string processName;
0782 BranchType branchType = InProcess;
0783 if (i < InProcess) {
0784 branchType = static_cast<BranchType>(i);
0785 } else {
0786 processName = om_->outputProcessBlockHelper().processesWithProcessBlockProducts()[i - InProcess];
0787 }
0788 setBranchAliases(treePointers_[i]->tree(), om_->keptProducts()[branchType], processName);
0789 value = treePointers_[i]->tree()->GetName();
0790 treePointers_[i]->writeTree();
0791 }
0792
0793
0794
0795 status = "closing TTrees";
0796 value = "";
0797 metaDataTree_ = parentageTree_ = nullptr;
0798 for (auto& treePointer : treePointers_) {
0799 treePointer->close();
0800 treePointer = nullptr;
0801 }
0802 status = "closing TFile";
0803 filePtr_->Close();
0804 filePtr_ = nullptr;
0805
0806
0807 status = "reporting to JobReport";
0808 Service<JobReport> reportSvc;
0809 reportSvc->outputFileClosed(reportToken_);
0810 } catch (cms::Exception& e) {
0811 e.addContext("Calling RootOutputFile::finishEndFile() while closing " + file_);
0812 e.addAdditionalInfo("While calling " + std::string(status) + std::string(value));
0813 throw;
0814 }
0815 }
0816
0817 void RootOutputFile::setBranchAliases(TTree* tree,
0818 SelectedProducts const& branches,
0819 std::string const& processName) const {
0820 if (tree && tree->GetNbranches() != 0) {
0821 for (auto const& selection : branches) {
0822 BranchDescription const& pd = *selection.first;
0823 if (pd.branchType() == InProcess && processName != pd.processName()) {
0824 continue;
0825 }
0826 std::string const& full = pd.branchName() + "obj";
0827 if (pd.branchAliases().empty()) {
0828 std::string const& alias = (pd.productInstanceName().empty() ? pd.moduleLabel() : pd.productInstanceName());
0829 tree->SetAlias(alias.c_str(), full.c_str());
0830 } else {
0831 for (auto const& alias : pd.branchAliases()) {
0832 tree->SetAlias(alias.c_str(), full.c_str());
0833 }
0834 }
0835 }
0836 }
0837 }
0838
0839 void RootOutputFile::insertAncestors(ProductProvenance const& iGetParents,
0840 ProductProvenanceRetriever const* iMapper,
0841 bool produced,
0842 std::set<BranchID> const& iProducedIDs,
0843 std::set<StoredProductProvenance>& oToFill) {
0844 assert(om_->dropMetaData() != PoolOutputModule::DropAll);
0845 assert(produced || om_->dropMetaData() != PoolOutputModule::DropPrior);
0846 if (om_->dropMetaData() == PoolOutputModule::DropDroppedPrior && !produced)
0847 return;
0848 std::vector<BranchID> const& parentIDs = iGetParents.parentage().parents();
0849 for (auto const& parentID : parentIDs) {
0850 branchesWithStoredHistory_.insert(parentID);
0851 ProductProvenance const* info = iMapper->branchIDToProvenance(parentID);
0852 if (info) {
0853 if (om_->dropMetaData() == PoolOutputModule::DropNone ||
0854 (iProducedIDs.end() != iProducedIDs.find(info->branchID()))) {
0855 if (insertProductProvenance(*info, oToFill)) {
0856
0857 insertAncestors(*info, iMapper, produced, iProducedIDs, oToFill);
0858 }
0859 }
0860 }
0861 }
0862 }
0863
0864 void RootOutputFile::fillBranches(BranchType const& branchType,
0865 OccurrenceForOutput const& occurrence,
0866 unsigned int ttreeIndex,
0867 StoredProductProvenanceVector* productProvenanceVecPtr,
0868 ProductProvenanceRetriever const* provRetriever) {
0869 std::vector<std::unique_ptr<WrapperBase> > dummies;
0870
0871 OutputItemList& items = om_->selectedOutputItemList()[ttreeIndex];
0872
0873 bool const doProvenance =
0874 (productProvenanceVecPtr != nullptr) && (om_->dropMetaData() != PoolOutputModule::DropAll);
0875 bool const keepProvenanceForPrior = doProvenance && om_->dropMetaData() != PoolOutputModule::DropPrior;
0876
0877 bool const fastCloning = (branchType == InEvent) && (whyNotFastClonable_ == FileBlock::CanFastClone);
0878 std::set<StoredProductProvenance> provenanceToKeep;
0879
0880
0881
0882
0883
0884 std::set<BranchID> producedBranches;
0885 if (doProvenance && branchType == InEvent && om_->dropMetaData() != PoolOutputModule::DropNone) {
0886 Service<ConstProductRegistry> preg;
0887 for (auto bd : preg->allBranchDescriptions()) {
0888 if (bd->produced() && bd->branchType() == InEvent) {
0889 producedBranches.insert(bd->branchID());
0890 }
0891 }
0892 }
0893
0894
0895 for (auto& item : items) {
0896 BranchID const& id = item.branchDescription()->branchID();
0897 branchesWithStoredHistory_.insert(id);
0898
0899 bool produced = item.branchDescription()->produced();
0900 bool getProd =
0901 (produced || !fastCloning || treePointers_[ttreeIndex]->uncloned(item.branchDescription()->branchName()));
0902 bool keepProvenance = doProvenance && (produced || keepProvenanceForPrior);
0903
0904 WrapperBase const* product = nullptr;
0905 ProductProvenance const* productProvenance = nullptr;
0906 if (getProd) {
0907 BasicHandle result = occurrence.getByToken(item.token(), item.branchDescription()->unwrappedTypeID());
0908 product = result.wrapper();
0909 if (result.isValid() && keepProvenance) {
0910 productProvenance = result.provenance()->productProvenance();
0911 }
0912 if (product == nullptr) {
0913
0914
0915 TClass* cp = item.branchDescription()->wrappedType().getClass();
0916 assert(cp != nullptr);
0917 int offset = cp->GetBaseClassOffset(wrapperBaseTClass_);
0918 void* p = cp->New();
0919 std::unique_ptr<WrapperBase> dummy = getWrapperBasePtr(p, offset);
0920 product = dummy.get();
0921 dummies.emplace_back(std::move(dummy));
0922 }
0923 item.setProduct(product);
0924 }
0925 if (keepProvenance && productProvenance == nullptr) {
0926 productProvenance = provRetriever->branchIDToProvenance(item.branchDescription()->originalBranchID());
0927 }
0928 if (productProvenance) {
0929 insertProductProvenance(*productProvenance, provenanceToKeep);
0930 insertAncestors(*productProvenance, provRetriever, produced, producedBranches, provenanceToKeep);
0931 }
0932 }
0933
0934 if (doProvenance)
0935 productProvenanceVecPtr->assign(provenanceToKeep.begin(), provenanceToKeep.end());
0936 treePointers_[ttreeIndex]->fillTree();
0937 if (doProvenance)
0938 productProvenanceVecPtr->clear();
0939 }
0940
0941 bool RootOutputFile::insertProductProvenance(const edm::ProductProvenance& iProv,
0942 std::set<edm::StoredProductProvenance>& oToInsert) {
0943 StoredProductProvenance toStore;
0944 toStore.branchID_ = iProv.branchID().id();
0945 std::set<edm::StoredProductProvenance>::iterator itFound = oToInsert.find(toStore);
0946 if (itFound == oToInsert.end()) {
0947
0948 std::pair<std::map<edm::ParentageID, unsigned int>::iterator, bool> i =
0949 parentageIDs_.insert(std::make_pair(iProv.parentageID(), static_cast<unsigned int>(parentageIDs_.size())));
0950 toStore.parentageIDIndex_ = i.first->second;
0951 if (toStore.parentageIDIndex_ >= parentageIDs_.size()) {
0952 throw edm::Exception(errors::LogicError)
0953 << "RootOutputFile::insertProductProvenance\n"
0954 << "The parentage ID index value " << toStore.parentageIDIndex_
0955 << " is out of bounds. The maximum value is currently " << parentageIDs_.size() - 1 << ".\n"
0956 << "This should never happen.\n"
0957 << "Please report this to the framework developers.";
0958 }
0959
0960 oToInsert.insert(toStore);
0961 return true;
0962 }
0963 return false;
0964 }
0965 }