1 #include "artdaq/ArtModules/RootDAQOutput/RootDAQOutFile.h"
5 #include "TBranchElement.h"
9 #include "art/Framework/IO/FileStatsCollector.h"
10 #include "art/Framework/IO/Root/DropMetaData.h"
11 #include "art/Framework/IO/Root/GetFileFormatEra.h"
12 #include "art/Framework/IO/Root/GetFileFormatVersion.h"
13 #include "art/Framework/IO/Root/RootDB/SQLErrMsg.h"
14 #include "art/Framework/IO/Root/RootDB/TKeyVFSOpenPolicy.h"
15 #include "art/Framework/IO/Root/RootFileBlock.h"
16 #include "art/Framework/IO/Root/checkDictionaries.h"
17 #include "art/Framework/IO/Root/detail/KeptProvenance.h"
18 #include "art/Framework/IO/Root/detail/getObjectRequireDict.h"
19 #include "art/Framework/Principal/EventPrincipal.h"
20 #include "art/Framework/Principal/ResultsPrincipal.h"
21 #include "art/Framework/Principal/RunPrincipal.h"
22 #include "art/Framework/Principal/SubRunPrincipal.h"
23 #include "art/Framework/Services/System/DatabaseConnection.h"
24 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
25 #if ART_HEX_VERSION < 0x30000
26 #include "art/Persistency/Provenance/ProductMetaData.h"
28 #include "art/Version/GetReleaseVersion.h"
29 #include "artdaq/DAQdata/Globals.hh"
30 #include "boost/date_time/posix_time/posix_time.hpp"
31 #include "canvas/Persistency/Provenance/BranchChildren.h"
32 #include "canvas/Persistency/Provenance/BranchType.h"
33 #include "canvas/Persistency/Provenance/EventAuxiliary.h"
34 #include "canvas/Persistency/Provenance/EventID.h"
35 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
36 #include "canvas/Persistency/Provenance/History.h"
37 #include "canvas/Persistency/Provenance/ParameterSetBlob.h"
38 #include "canvas/Persistency/Provenance/Parentage.h"
39 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
40 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
41 #include "canvas/Persistency/Provenance/ProductStatus.h"
42 #include "canvas/Persistency/Provenance/ResultsAuxiliary.h"
43 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
44 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
45 #include "canvas/Persistency/Provenance/rootNames.h"
46 #include "canvas/Utilities/Exception.h"
47 #include "canvas_root_io/Utilities/DictionaryChecker.h"
48 #include "cetlib/canonical_string.h"
49 #include "cetlib/container_algorithms.h"
50 #include "cetlib/exempt_ptr.h"
51 #include "cetlib/sqlite/Ntuple.h"
52 #include "cetlib/sqlite/Transaction.h"
53 #include "cetlib/sqlite/create_table.h"
54 #include "cetlib/sqlite/exec.h"
55 #include "cetlib/sqlite/insert.h"
56 #include "fhiclcpp/ParameterSet.h"
57 #include "fhiclcpp/ParameterSetID.h"
58 #include "fhiclcpp/ParameterSetRegistry.h"
60 #define TRACE_NAME (app_name + "_RootDAQOutFile").c_str()
63 #include <sys/sysinfo.h>
70 using art::BranchType;
72 using art::rootNames::metaBranchRootName;
76 void create_table(sqlite3*
const db,
77 std::string
const& name,
78 std::vector<std::string>
const& columns,
79 std::string
const& suffix = {})
82 throw art::Exception(art::errors::LogicError)
83 <<
"Number of sqlite columns specified for table: " << name <<
'\n'
86 std::string ddl =
"DROP TABLE IF EXISTS " + name +
89 name +
"(" + columns.front();
90 std::for_each(columns.begin() + 1, columns.end(), [&ddl](
auto const& col) {
96 sqlite::exec(db, ddl);
99 void insert_eventRanges_row(sqlite3_stmt* stmt,
100 art::SubRunNumber_t
const sr,
101 art::EventNumber_t
const b,
102 art::EventNumber_t
const e)
104 sqlite3_bind_int64(stmt, 1, sr);
105 sqlite3_bind_int64(stmt, 2, b);
106 sqlite3_bind_int64(stmt, 3, e);
111 void insert_rangeSets_eventSets_row(sqlite3_stmt* stmt,
115 sqlite3_bind_int64(stmt, 1, rsid);
116 sqlite3_bind_int64(stmt, 2, esid);
122 getNewRangeSetID(sqlite3* db,
123 art::BranchType
const bt,
124 art::RunNumber_t
const r)
126 sqlite::insert_into(db, art::BranchTypeToString(bt) +
"RangeSets")
128 return sqlite3_last_insert_rowid(db);
132 getExistingRangeSetIDs(sqlite3* db, art::RangeSet
const& rs)
134 vector<unsigned> rangeSetIDs;
136 rs, std::back_inserter(rangeSetIDs), [db](
auto const& range) {
137 sqlite::query_result<unsigned> r;
138 r << sqlite::select(
"ROWID")
139 .from(db,
"EventRanges")
140 .where(
"SubRun=" + std::to_string(range.subRun()) +
143 std::to_string(range.begin()) +
146 std::to_string(range.end()));
147 return unique_value(r);
152 void insertIntoEventRanges(sqlite3* db, art::RangeSet
const& rs)
154 sqlite::Transaction txn{db};
155 sqlite3_stmt* stmt{
nullptr};
156 std::string
const ddl{
157 "INSERT INTO EventRanges(SubRun, begin, end) "
159 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt,
nullptr);
160 for (
auto const& range : rs)
162 insert_eventRanges_row(stmt, range.subRun(), range.begin(), range.end());
164 sqlite3_finalize(stmt);
168 void insertIntoJoinTable(sqlite3* db,
169 art::BranchType
const bt,
171 vector<unsigned>
const& eventRangesIDs)
173 sqlite::Transaction txn{db};
174 sqlite3_stmt* stmt{
nullptr};
175 std::string
const ddl{
176 "INSERT INTO " + art::BranchTypeToString(bt) +
177 "RangeSets_EventRanges(RangeSetsID, EventRangesID) Values(?,?);"};
178 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt,
nullptr);
179 cet::for_all(eventRangesIDs, [stmt, rsID](
auto const eventRangeID) {
180 insert_rangeSets_eventSets_row(stmt, rsID, eventRangeID);
182 sqlite3_finalize(stmt);
186 void maybeInvalidateRangeSet(BranchType
const bt,
187 art::RangeSet
const& principalRS,
188 art::RangeSet& productRS)
190 assert(principalRS.is_sorted());
191 assert(productRS.is_sorted());
193 if (!productRS.is_valid())
195 if (bt == art::InRun && productRS.is_full_run())
197 if (bt == art::InSubRun && productRS.is_full_subRun())
199 if (productRS.ranges().empty())
202 auto const r = productRS.run();
203 auto const& productFront = productRS.ranges().front();
204 if (!principalRS.contains(r, productFront.subRun(), productFront.begin()))
205 productRS = art::RangeSet::invalid();
208 using art::detail::RangeSetsSupported;
249 template<BranchType BT>
250 std::enable_if_t<RangeSetsSupported<BT>::value, art::RangeSet>
251 getRangeSet(art::OutputHandle
const& oh,
252 art::RangeSet
const& principalRS,
253 bool const producedInThisProcess)
255 auto rs = oh.isValid() ? oh.rangeOfValidity() : art::RangeSet::invalid();
266 if (!producedInThisProcess)
268 maybeInvalidateRangeSet(BT, principalRS, rs);
273 template<BranchType BT>
274 std::enable_if_t<!RangeSetsSupported<BT>::value, art::RangeSet>
275 getRangeSet(art::OutputHandle
const&,
276 art::RangeSet
const& ,
279 return art::RangeSet::invalid();
282 template<BranchType BT>
283 std::enable_if_t<!RangeSetsSupported<BT>::value>
284 setProductRangeSetID(art::RangeSet
const& ,
287 std::map<unsigned, unsigned>& )
290 template<BranchType BT>
291 std::enable_if_t<RangeSetsSupported<BT>::value>
292 setProductRangeSetID(art::RangeSet
const& rs,
294 art::EDProduct* product,
295 std::map<unsigned, unsigned>& checksumToIndexLookup)
301 auto it = checksumToIndexLookup.find(rs.checksum());
302 if (it != checksumToIndexLookup.cend())
304 product->setRangeSetID(it->second);
308 unsigned const rsID = getNewRangeSetID(db, BT, rs.run());
309 product->setRangeSetID(rsID);
310 checksumToIndexLookup.emplace(rs.checksum(), rsID);
311 insertIntoEventRanges(db, rs);
312 auto const& eventRangesIDs = getExistingRangeSetIDs(db, rs);
313 insertIntoJoinTable(db, BT, rsID, eventRangesIDs);
319 art::RootDAQOutFile::RootDAQOutFile(OutputModule* om,
320 string const& fileName,
321 ClosingCriteria
const& fileSwitchCriteria,
322 int const compressionLevel,
323 unsigned freePercent,
325 int64_t
const saveMemoryObjectThreshold,
326 int64_t
const treeMaxVirtualSize,
327 int const splitLevel,
328 int const basketSize,
329 DropMetaData dropMetaData,
330 bool const dropMetaDataForDroppedData,
331 bool const fastCloningRequested)
334 , fileSwitchCriteria_{fileSwitchCriteria}
335 , compressionLevel_{compressionLevel}
336 , freePercent_{freePercent}
338 , saveMemoryObjectThreshold_{saveMemoryObjectThreshold}
339 , treeMaxVirtualSize_{treeMaxVirtualSize}
340 , splitLevel_{splitLevel}
341 , basketSize_{basketSize}
342 , dropMetaData_{dropMetaData}
343 , dropMetaDataForDroppedData_{dropMetaDataForDroppedData}
344 , fastCloningEnabledAtConstruction_{fastCloningRequested}
345 , filePtr_{TFile::Open(file_.c_str(),
"recreate",
"", compressionLevel)}
347 std::make_unique<RootOutputTree>(
351 pEventProductProvenanceVector_,
355 saveMemoryObjectThreshold),
356 std::make_unique<RootOutputTree>(
360 pSubRunProductProvenanceVector_,
364 saveMemoryObjectThreshold),
365 std::make_unique<RootOutputTree>(
369 pRunProductProvenanceVector_,
373 saveMemoryObjectThreshold),
374 std::make_unique<RootOutputTree>(
378 pResultsProductProvenanceVector_,
382 saveMemoryObjectThreshold)}}
383 , rootFileDB_{ServiceHandle<DatabaseConnection>{}->get<TKeyVFSOpenPolicy>(
386 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE)}
390 RootOutputTree::makeTTree(filePtr_.get(), rootNames::metaDataTreeName(), 0);
391 fileIndexTree_ = RootOutputTree::makeTTree(
392 filePtr_.get(), rootNames::fileIndexTreeName(), 0);
393 parentageTree_ = RootOutputTree::makeTTree(
394 filePtr_.get(), rootNames::parentageTreeName(), 0);
396 eventHistoryTree_ = RootOutputTree::makeTTree(
397 filePtr_.get(), rootNames::eventHistoryTreeName(), splitLevel);
398 if (!eventHistoryTree_)
400 throw art::Exception(art::errors::FatalRootError)
401 <<
"Failed to create the tree for History objects\n";
404 pHistory_ =
new History;
405 if (!eventHistoryTree_->Branch(rootNames::eventHistoryBranchName().c_str(),
410 throw art::Exception(art::errors::FatalRootError)
411 <<
"Failed to create a branch for History in the output file\n";
417 root::DictionaryChecker checker{};
418 checker.checkDictionaries<EventAuxiliary>();
419 checker.checkDictionaries<SubRunAuxiliary>();
420 checker.checkDictionaries<RunAuxiliary>();
421 checker.checkDictionaries<ResultsAuxiliary>();
422 checker.reportMissingDictionaries();
424 createDatabaseTables();
425 TLOG(3) <<
"RootDAQOutFile ctor complete";
428 art::RootDAQOutFile::~RootDAQOutFile()
431 int sts = sysinfo(&info);
432 unsigned free_percent = (unsigned)(info.freeram * 100 / info.totalram);
433 unsigned free_MB = (unsigned)(info.freeram * info.mem_unit >> 20);
434 TRACE(3,
"~RootDAQOutFile free %%%u %.1fMB (%u) buffers=%fGB mem_unit=%u", free_percent, (
float)info.freeram * info.mem_unit / (1024 * 1024), free_MB, (
float)info.bufferram * info.mem_unit / (1024 * 1024 * 1024), info.mem_unit);
435 if (free_percent < freePercent_ || free_MB < freeMB_)
437 TLOG(3) <<
"RootDAQOutFile Flush/DONTNEED";
439 sts = posix_fadvise(filePtr_->GetFd(), 0, 0 , POSIX_FADV_DONTNEED);
441 TLOG(3) <<
"~RootDAQOutFile complete sts=" << sts;
444 void art::RootDAQOutFile::createDatabaseTables()
447 create_table(rootFileDB_,
452 "UNIQUE (SubRun,begin,end) ON CONFLICT IGNORE"});
455 using namespace cet::sqlite;
456 create_table(rootFileDB_,
"SubRunRangeSets", column<int>{
"Run"});
457 create_table(rootFileDB_,
458 "SubRunRangeSets_EventRanges",
459 {
"RangeSetsID INTEGER",
460 "EventRangesID INTEGER",
461 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
465 create_table(rootFileDB_,
"RunRangeSets", column<int>{
"Run"});
466 create_table(rootFileDB_,
467 "RunRangeSets_EventRanges",
468 {
"RangeSetsID INTEGER",
469 "EventRangesID INTEGER",
470 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
474 void art::RootDAQOutFile::selectProducts()
476 for (
int i = InEvent; i < NumBranchTypes; ++i)
478 auto const bt =
static_cast<BranchType
>(i);
479 auto& items = selectedOutputItemList_[bt];
481 for (
auto const& pd : om_->keptProducts()[bt])
485 if (bt == InResults && !pd->produced())
487 checkDictionaries(*pd);
501 for (
auto const& val : items)
503 treePointers_[bt]->addOutputBranch(*val.branchDescription_, val.product_);
508 void art::RootDAQOutFile::beginInputFile(RootFileBlock
const* rfb,
509 bool const fastCloneFromOutputModule)
512 bool shouldFastClone{fastCloningEnabledAtConstruction_ &&
513 fastCloneFromOutputModule && rfb};
517 if (shouldFastClone &&
518 !treePointers_[InEvent]->checkSplitLevelAndBasketSize(rfb->tree()))
520 mf::LogWarning(
"FastCloning")
521 <<
"Fast cloning deactivated for this input file due to "
522 <<
"splitting level and/or basket size.";
523 shouldFastClone =
false;
525 else if (rfb && rfb->tree() &&
526 rfb->tree()->GetCurrentFile()->GetVersion() < 60001)
528 mf::LogWarning(
"FastCloning")
529 <<
"Fast cloning deactivated for this input file due to "
530 <<
"ROOT version used to write it (< 6.00/01)\n"
531 "having a different splitting policy.";
532 shouldFastClone =
false;
535 if (shouldFastClone && rfb->fileFormatVersion().value_ < 10)
537 mf::LogWarning(
"FastCloning")
538 <<
"Fast cloning deactivated for this input file due to "
539 <<
"reading in file that has a different ProductID schema.";
540 shouldFastClone =
false;
543 if (shouldFastClone && !fastCloningEnabledAtConstruction_)
545 mf::LogWarning(
"FastCloning")
546 <<
"Fast cloning reactivated for this input file.";
548 treePointers_[InEvent]->beginInputFile(shouldFastClone);
549 auto tree = (rfb && rfb->tree()) ? rfb->tree() :
nullptr;
550 wasFastCloned_ = treePointers_[InEvent]->fastCloneTree(tree);
553 void art::RootDAQOutFile::incrementInputFileNumber()
555 fp_.update<Granularity::InputFile>();
558 void art::RootDAQOutFile::respondToCloseInputFile(FileBlock
const&)
560 cet::for_all(treePointers_, [](
auto const& p) { p->setEntries(); });
563 bool art::RootDAQOutFile::requestsToCloseFile()
565 using namespace std::chrono;
566 unsigned int constexpr oneK{1024u};
567 fp_.updateSize(filePtr_->GetSize() / oneK);
568 fp_.updateAge(duration_cast<seconds>(steady_clock::now() - beginTime_));
569 return fileSwitchCriteria_.should_close(fp_);
572 void art::RootDAQOutFile::writeOne(EventPrincipal
const& e)
574 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeOne";
578 pEventAux_ = &e.aux();
582 fillBranches<InEvent>(e, pEventProductProvenanceVector_);
584 History historyForOutput{e.history()};
585 historyForOutput.addEventSelectionEntry(om_->selectorConfig());
586 pHistory_ = &historyForOutput;
587 int sz = eventHistoryTree_->Fill();
590 throw art::Exception(art::errors::FatalRootError)
591 <<
"Failed to fill the History tree for event: " << e.id()
592 <<
"\nTTree::Fill() returned " << sz <<
" bytes written." << endl;
595 if (!dataTypeReported_)
597 string dataType{
"MC"};
598 if (pEventAux_->isRealData())
602 dataTypeReported_ =
true;
604 pHistory_ = &e.history();
606 fileIndex_.addEntry(pEventAux_->id(), fp_.eventEntryNumber());
607 fp_.update<Granularity::Event>(status_);
608 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeOne";
611 void art::RootDAQOutFile::writeSubRun(SubRunPrincipal
const& sr)
613 pSubRunAux_ = &sr.aux();
614 pSubRunAux_->setRangeSetID(subRunRSID_);
615 fillBranches<InSubRun>(sr, pSubRunProductProvenanceVector_);
616 fileIndex_.addEntry(EventID::invalidEvent(pSubRunAux_->id()),
617 fp_.subRunEntryNumber());
618 fp_.update<Granularity::SubRun>(status_);
621 void art::RootDAQOutFile::writeRun(RunPrincipal
const& r)
624 pRunAux_->setRangeSetID(runRSID_);
625 fillBranches<InRun>(r, pRunProductProvenanceVector_);
626 fileIndex_.addEntry(EventID::invalidEvent(pRunAux_->id()),
627 fp_.runEntryNumber());
628 fp_.update<Granularity::Run>(status_);
631 void art::RootDAQOutFile::writeParentageRegistry()
633 auto pid = root::getObjectRequireDict<ParentageID>();
634 ParentageID
const* hash = &pid;
635 if (!parentageTree_->Branch(
636 rootNames::parentageIDBranchName().c_str(), &hash, basketSize_, 0))
638 throw Exception(errors::FatalRootError)
639 <<
"Failed to create a branch for ParentageIDs in the output file";
643 auto par = root::getObjectRequireDict<Parentage>();
644 Parentage
const* desc = ∥
645 if (!parentageTree_->Branch(
646 rootNames::parentageBranchName().c_str(), &desc, basketSize_, 0))
648 throw art::Exception(art::errors::FatalRootError)
649 <<
"Failed to create a branch for Parentages in the output file";
653 for (
auto const& pr : ParentageRegistry::get())
657 parentageTree_->Fill();
659 parentageTree_->SetBranchAddress(rootNames::parentageIDBranchName().c_str(),
661 parentageTree_->SetBranchAddress(rootNames::parentageBranchName().c_str(),
665 void art::RootDAQOutFile::writeFileFormatVersion()
667 FileFormatVersion
const ver{getFileFormatVersion(), getFileFormatEra()};
668 auto const* pver = &ver;
669 TBranch* b = metaDataTree_->Branch(
670 metaBranchRootName<FileFormatVersion>(), &pver, basketSize_, 0);
676 void art::RootDAQOutFile::writeFileIndex()
678 fileIndex_.sortBy_Run_SubRun_Event();
679 FileIndex::Element elem{};
680 auto const* findexElemPtr = &elem;
681 TBranch* b = fileIndexTree_->Branch(
682 metaBranchRootName<FileIndex::Element>(), &findexElemPtr, basketSize_, 0);
685 for (
auto& entry : fileIndex_)
687 findexElemPtr = &entry;
693 void art::RootDAQOutFile::writeEventHistory()
695 RootOutputTree::writeTTree(eventHistoryTree_);
698 void art::RootDAQOutFile::writeProcessConfigurationRegistry()
704 void art::RootDAQOutFile::writeProcessHistoryRegistry()
706 ProcessHistoryMap pHistMap;
707 for (
auto const& pr : ProcessHistoryRegistry::get())
709 pHistMap.emplace(pr);
711 auto const* p = &pHistMap;
712 TBranch* b = metaDataTree_->Branch(
713 metaBranchRootName<ProcessHistoryMap>(), &p, basketSize_, 0);
720 throw Exception(errors::LogicError) <<
"Unable to locate required "
721 "ProcessHistoryMap branch in output "
726 void art::RootDAQOutFile::writeFileCatalogMetadata(
727 FileStatsCollector
const& stats,
728 FileCatalogMetadata::collection_type
const& md,
729 FileCatalogMetadata::collection_type
const& ssmd)
731 using namespace cet::sqlite;
732 Ntuple<std::string, std::string> fileCatalogMetadata{
733 rootFileDB_,
"FileCatalog_metadata", {{
"Name",
"Value"}},
true};
734 Transaction txn{rootFileDB_};
735 for (
auto const& kv : md)
737 fileCatalogMetadata.insert(kv.first, kv.second);
740 fileCatalogMetadata.insert(
"file_format",
"\"artroot\"");
741 fileCatalogMetadata.insert(
"file_format_era",
742 cet::canonical_string(getFileFormatEra()));
743 fileCatalogMetadata.insert(
"file_format_version",
744 to_string(getFileFormatVersion()));
747 namespace bpt = boost::posix_time;
748 auto formatted_time = [](
auto const& t) {
749 return cet::canonical_string(bpt::to_iso_extended_string(t));
751 fileCatalogMetadata.insert(
"start_time",
752 formatted_time(stats.outputFileOpenTime()));
754 fileCatalogMetadata.insert(
756 formatted_time(boost::posix_time::second_clock::universal_time()));
759 if (!stats.seenSubRuns().empty())
761 auto I = find_if(md.crbegin(), md.crend(), [](
auto const& p) {
762 return p.first ==
"run_type";
769 for (
auto const& srid : stats.seenSubRuns())
771 buf <<
"[ " << srid.run() <<
", " << srid.subRun() <<
", "
772 << cet::canonical_string(I->second) <<
" ], ";
775 buf.seekp(-2, ios_base::cur);
777 fileCatalogMetadata.insert(
"runs", buf.str());
781 fileCatalogMetadata.insert(
"event_count", to_string(stats.eventsThisFile()));
783 auto eidToTuple = [](EventID
const& eid) ->
string {
784 ostringstream eidStr;
785 eidStr <<
"[ " << eid.run() <<
", " << eid.subRun() <<
", " << eid.event()
789 fileCatalogMetadata.insert(
"first_event", eidToTuple(stats.lowestEventID()));
790 fileCatalogMetadata.insert(
"last_event", eidToTuple(stats.highestEventID()));
792 if (!stats.parents().empty())
794 ostringstream pstring;
796 for (
auto const& parent : stats.parents())
798 pstring << cet::canonical_string(parent) <<
", ";
801 pstring.seekp(-2, ios_base::cur);
803 fileCatalogMetadata.insert(
"parents", pstring.str());
806 for (
auto const& kv : ssmd)
808 fileCatalogMetadata.insert(kv.first, kv.second);
813 void art::RootDAQOutFile::writeParameterSetRegistry()
815 fhicl::ParameterSetRegistry::exportTo(rootFileDB_);
818 void art::RootDAQOutFile::writeProductDescriptionRegistry()
822 auto end = branchesWithStoredHistory_.end();
825 for (
auto const& pr : ProductMetaData::instance().productList())
827 if (branchesWithStoredHistory_.find(pr.second.productID()) == end)
831 reg.productList_.emplace_hint(reg.productList_.end(), pr);
834 ProductRegistry
const* regp = ®
835 TBranch* b = metaDataTree_->Branch(
836 metaBranchRootName<ProductRegistry>(), ®p, basketSize_, 0);
842 void art::RootDAQOutFile::writeProductDependencies()
844 BranchChildren
const* ppDeps = &om_->branchChildren();
845 TBranch* b = metaDataTree_->Branch(
846 metaBranchRootName<BranchChildren>(), &ppDeps, basketSize_, 0);
852 void art::RootDAQOutFile::writeResults(ResultsPrincipal& resp)
854 pResultsAux_ = &resp.aux();
855 fillBranches<InResults>(resp, pResultsProductProvenanceVector_);
858 void art::RootDAQOutFile::writeTTrees()
860 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeTTrees";
861 RootOutputTree::writeTTree(metaDataTree_);
862 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing metaDataTree_";
863 RootOutputTree::writeTTree(fileIndexTree_);
864 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing fileIndexTree_";
865 RootOutputTree::writeTTree(parentageTree_);
866 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing parentageTree_";
868 for (
int i = InEvent; i < NumBranchTypes; ++i)
870 auto const branchType =
static_cast<BranchType
>(i);
871 treePointers_[branchType]->writeTree();
873 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeTTrees";
876 template<art::BranchType BT>
877 void art::RootDAQOutFile::fillBranches(Principal
const& principal,
878 vector<ProductProvenance>* vpp)
880 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::fillBranches";
881 bool const fastCloning = (BT == InEvent) && wasFastCloned_;
882 detail::KeptProvenance keptProvenance{
883 dropMetaData_, dropMetaDataForDroppedData_, branchesWithStoredHistory_};
884 map<unsigned, unsigned> checksumToIndex;
886 auto const& principalRS = principal.seenRanges();
888 for (
auto const& val : selectedOutputItemList_[BT])
890 auto const* pd = val.branchDescription_;
891 auto const pid = pd->productID();
892 branchesWithStoredHistory_.insert(pid);
893 bool const produced{pd->produced()};
894 bool const resolveProd = (produced || !fastCloning ||
895 treePointers_[BT]->uncloned(pd->branchName()));
898 bool const keepProvenance =
899 (dropMetaData_ == DropMetaData::DropNone ||
900 (dropMetaData_ == DropMetaData::DropPrior && produced));
901 auto const& oh = principal.getForOutput(pid, resolveProd);
903 unique_ptr<ProductProvenance> prov{
nullptr};
906 if (oh.productProvenance())
908 prov = std::make_unique<ProductProvenance>(
909 keptProvenance.insert(*oh.productProvenance()));
910 keptProvenance.insertAncestors(*oh.productProvenance(), principal);
917 produced ? productstatus::neverCreated() : productstatus::dropped();
918 prov = std::make_unique<ProductProvenance>(
919 keptProvenance.emplace(pid, status));
926 auto const& rs = getRangeSet<BT>(oh, principalRS, produced);
927 if (RangeSetsSupported<BT>::value && !rs.is_valid())
933 keptProvenance.setStatus(*prov, productstatus::unknown());
936 auto const* product = getProduct<BT>(oh, rs, pd->wrappedName());
937 setProductRangeSetID<BT>(
938 rs, rootFileDB_,
const_cast<EDProduct*
>(product), checksumToIndex);
939 val.product_ = product;
942 vpp->assign(keptProvenance.begin(), keptProvenance.end());
943 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches before fillTree call";
944 treePointers_[BT]->fillTree();
945 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches after fillTree call";
947 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::fillBranches";
950 void art::RootDAQOutFile::setSubRunAuxiliaryRangeSetID(RangeSet
const& ranges)
952 subRunRSID_ = getNewRangeSetID(rootFileDB_, InSubRun, ranges.run());
953 insertIntoEventRanges(rootFileDB_, ranges);
954 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
955 insertIntoJoinTable(rootFileDB_, InSubRun, subRunRSID_, eventRangesIDs);
958 void art::RootDAQOutFile::setRunAuxiliaryRangeSetID(RangeSet
const& ranges)
960 runRSID_ = getNewRangeSetID(rootFileDB_, InRun, ranges.run());
961 insertIntoEventRanges(rootFileDB_, ranges);
962 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
963 insertIntoJoinTable(rootFileDB_, InRun, runRSID_, eventRangesIDs);
966 template<BranchType BT>
967 std::enable_if_t<!RangeSetsSupported<BT>::value, art::EDProduct
const*>
968 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
969 art::RangeSet
const& ,
970 std::string
const& wrappedName)
972 return oh.isValid() ? oh.wrapper() : dummyProductCache_.product(wrappedName);
975 template<BranchType BT>
976 std::enable_if_t<RangeSetsSupported<BT>::value, art::EDProduct
const*>
977 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
978 art::RangeSet
const& prunedProductRS,
979 std::string
const& wrappedName)
981 return (oh.isValid() && prunedProductRS.is_valid()) ? oh.wrapper() : dummyProductCache_.product(wrappedName);