1 #include "artdaq/ArtModules/RootDAQOutput-s85/RootDAQOutFile.h"
4 #include "art/Framework/IO/FileStatsCollector.h"
5 #include "art/Framework/IO/Root/DropMetaData.h"
6 #include "art/Framework/IO/Root/GetFileFormatEra.h"
7 #include "art/Framework/IO/Root/GetFileFormatVersion.h"
8 #include "art/Framework/IO/Root/RootDB/SQLErrMsg.h"
9 #include "art/Framework/IO/Root/RootDB/TKeyVFSOpenPolicy.h"
10 #include "art/Framework/IO/Root/RootFileBlock.h"
11 #include "art/Framework/IO/Root/checkDictionaries.h"
12 #include "art/Framework/IO/Root/detail/getObjectRequireDict.h"
13 #include "art/Framework/IO/Root/detail/readFileIndex.h"
14 #include "art/Framework/Principal/EventPrincipal.h"
15 #include "art/Framework/Principal/ResultsPrincipal.h"
16 #include "art/Framework/Principal/RunPrincipal.h"
17 #include "art/Framework/Principal/SubRunPrincipal.h"
18 #include "art/Framework/Services/System/DatabaseConnection.h"
19 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
20 #include "art/Persistency/Provenance/ProductMetaData.h"
21 #include "art/Version/GetReleaseVersion.h"
22 #include "boost/date_time/posix_time/posix_time.hpp"
23 #include "canvas/Persistency/Provenance/BranchChildren.h"
24 #include "canvas/Persistency/Provenance/BranchType.h"
25 #include "canvas/Persistency/Provenance/EventAuxiliary.h"
26 #include "canvas/Persistency/Provenance/EventID.h"
27 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
28 #include "canvas/Persistency/Provenance/History.h"
29 #include "canvas/Persistency/Provenance/ParameterSetBlob.h"
30 #include "canvas/Persistency/Provenance/Parentage.h"
31 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
32 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
33 #include "canvas/Persistency/Provenance/ProductID.h"
34 #include "canvas/Persistency/Provenance/ProductProvenance.h"
35 #include "canvas/Persistency/Provenance/ProductStatus.h"
36 #include "canvas/Persistency/Provenance/ResultsAuxiliary.h"
37 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
38 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
39 #include "canvas/Persistency/Provenance/rootNames.h"
40 #include "canvas/Utilities/Exception.h"
41 #include "canvas_root_io/Utilities/DictionaryChecker.h"
42 #include "cetlib/canonical_string.h"
43 #include "cetlib/container_algorithms.h"
44 #include "cetlib/exempt_ptr.h"
45 #include "cetlib/sqlite/Ntuple.h"
46 #include "cetlib/sqlite/Transaction.h"
47 #include "cetlib/sqlite/create_table.h"
48 #include "cetlib/sqlite/exec.h"
49 #include "cetlib/sqlite/insert.h"
50 #include "fhiclcpp/ParameterSet.h"
51 #include "fhiclcpp/ParameterSetID.h"
52 #include "fhiclcpp/ParameterSetRegistry.h"
56 #include "artdaq/DAQdata/Globals.hh"
58 #define TRACE_NAME (app_name + "_RootDAQOutFile").c_str()
66 #include <sys/sysinfo.h>
70 using art::BranchType;
72 using art::rootNames::metaBranchRootName;
77 create_table(sqlite3*
const db,
78 std::string
const& name,
79 std::vector<std::string>
const& columns,
80 std::string
const& suffix = {})
83 throw art::Exception(art::errors::LogicError)
84 <<
"Number of sqlite columns specified for table: " << name <<
'\n'
87 std::string ddl =
"DROP TABLE IF EXISTS " + name +
90 name +
"(" + columns.front();
91 std::for_each(columns.begin() + 1, columns.end(), [&ddl](
auto const& col) {
97 sqlite::exec(db, ddl);
101 insert_eventRanges_row(sqlite3_stmt* stmt,
102 art::SubRunNumber_t
const sr,
103 art::EventNumber_t
const b,
104 art::EventNumber_t
const e)
106 sqlite3_bind_int64(stmt, 1, sr);
107 sqlite3_bind_int64(stmt, 2, b);
108 sqlite3_bind_int64(stmt, 3, e);
114 insert_rangeSets_eventSets_row(sqlite3_stmt* stmt,
118 sqlite3_bind_int64(stmt, 1, rsid);
119 sqlite3_bind_int64(stmt, 2, esid);
125 getNewRangeSetID(sqlite3* db,
126 art::BranchType
const bt,
127 art::RunNumber_t
const r)
129 sqlite::insert_into(db, art::BranchTypeToString(bt) +
"RangeSets")
131 return sqlite3_last_insert_rowid(db);
135 getExistingRangeSetIDs(sqlite3* db, art::RangeSet
const& rs)
137 vector<unsigned> rangeSetIDs;
139 rs, std::back_inserter(rangeSetIDs), [db](
auto const& range) {
140 sqlite::query_result<unsigned> r;
141 r << sqlite::select(
"ROWID")
142 .from(db,
"EventRanges")
143 .where(
"SubRun=" + std::to_string(range.subRun()) +
146 std::to_string(range.begin()) +
149 std::to_string(range.end()));
150 return unique_value(r);
156 insertIntoEventRanges(sqlite3* db, art::RangeSet
const& rs)
158 sqlite::Transaction txn{db};
159 sqlite3_stmt* stmt{
nullptr};
160 std::string
const ddl{
"INSERT INTO EventRanges(SubRun, begin, end) "
162 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt,
nullptr);
163 for (
auto const& range : rs) {
164 insert_eventRanges_row(stmt, range.subRun(), range.begin(), range.end());
166 sqlite3_finalize(stmt);
171 insertIntoJoinTable(sqlite3* db,
172 art::BranchType
const bt,
174 vector<unsigned>
const& eventRangesIDs)
176 sqlite::Transaction txn{db};
177 sqlite3_stmt* stmt{
nullptr};
178 std::string
const ddl{
179 "INSERT INTO " + art::BranchTypeToString(bt) +
180 "RangeSets_EventRanges(RangeSetsID, EventRangesID) Values(?,?);"};
181 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt,
nullptr);
182 cet::for_all(eventRangesIDs, [stmt, rsID](
auto const eventRangeID) {
183 insert_rangeSets_eventSets_row(stmt, rsID, eventRangeID);
185 sqlite3_finalize(stmt);
190 maybeInvalidateRangeSet(BranchType
const bt,
191 art::RangeSet
const& principalRS,
192 art::RangeSet& productRS)
194 assert(principalRS.is_sorted());
195 assert(productRS.is_sorted());
197 if (!productRS.is_valid()) {
200 if (bt == art::InRun && productRS.is_full_run()) {
203 if (bt == art::InSubRun && productRS.is_full_subRun()) {
206 if (productRS.ranges().empty()) {
209 auto const r = productRS.run();
210 auto const& productFront = productRS.ranges().front();
211 if (!principalRS.contains(r, productFront.subRun(), productFront.begin())) {
212 productRS = art::RangeSet::invalid();
216 using art::detail::RangeSetsSupported;
257 template <BranchType BT>
258 std::enable_if_t<RangeSetsSupported<BT>::value, art::RangeSet>
259 getRangeSet(art::OutputHandle
const& oh,
260 art::RangeSet
const& principalRS,
261 bool const producedInThisProcess)
263 auto rs = oh.isValid() ? oh.rangeOfValidity() : art::RangeSet::invalid();
274 if (!producedInThisProcess) {
275 maybeInvalidateRangeSet(BT, principalRS, rs);
280 template <BranchType BT>
281 std::enable_if_t<!RangeSetsSupported<BT>::value, art::RangeSet>
282 getRangeSet(art::OutputHandle
const&,
283 art::RangeSet
const& ,
286 return art::RangeSet::invalid();
289 template <BranchType BT>
290 std::enable_if_t<!RangeSetsSupported<BT>::value>
291 setProductRangeSetID(art::RangeSet
const& ,
294 std::map<unsigned, unsigned>& )
297 template <BranchType BT>
298 std::enable_if_t<RangeSetsSupported<BT>::value>
299 setProductRangeSetID(art::RangeSet
const& rs,
301 art::EDProduct* product,
302 std::map<unsigned, unsigned>& checksumToIndexLookup)
304 if (!rs.is_valid()) {
309 auto it = checksumToIndexLookup.find(rs.checksum());
310 if (it != checksumToIndexLookup.cend()) {
311 product->setRangeSetID(it->second);
313 unsigned const rsID = getNewRangeSetID(db, BT, rs.run());
314 product->setRangeSetID(rsID);
315 checksumToIndexLookup.emplace(rs.checksum(), rsID);
316 insertIntoEventRanges(db, rs);
317 auto const& eventRangesIDs = getExistingRangeSetIDs(db, rs);
318 insertIntoJoinTable(db, BT, rsID, eventRangesIDs);
324 art::RootDAQOutFile::RootDAQOutFile(OutputModule* om,
325 string const& fileName,
326 ClosingCriteria
const& fileSwitchCriteria,
327 int const compressionLevel,
328 unsigned freePercent,
330 int64_t
const saveMemoryObjectThreshold,
331 int64_t
const treeMaxVirtualSize,
332 int const splitLevel,
333 int const basketSize,
334 DropMetaData dropMetaData,
335 bool const dropMetaDataForDroppedData,
336 bool const fastCloningRequested,
337 bool const parentageEnabled,
338 bool const rangesEnabled,
339 bool const dbEnabled)
342 , fileSwitchCriteria_{fileSwitchCriteria}
343 , compressionLevel_{compressionLevel}
344 , freePercent_{freePercent}
346 , saveMemoryObjectThreshold_{saveMemoryObjectThreshold}
347 , treeMaxVirtualSize_{treeMaxVirtualSize}
348 , splitLevel_{splitLevel}
349 , basketSize_{basketSize}
350 , dropMetaData_{dropMetaData}
351 , dropMetaDataForDroppedData_{dropMetaDataForDroppedData}
352 , fastCloningEnabledAtConstruction_{fastCloningRequested}
353 , filePtr_{TFile::Open(file_.c_str(),
"recreate",
"", compressionLevel)}
355 std::make_unique<RootOutputTree>(
359 pEventProductProvenanceVector_,
363 saveMemoryObjectThreshold),
364 std::make_unique<RootOutputTree>(
368 pSubRunProductProvenanceVector_,
372 saveMemoryObjectThreshold),
373 std::make_unique<RootOutputTree>(
377 pRunProductProvenanceVector_,
381 saveMemoryObjectThreshold),
382 std::make_unique<RootOutputTree>(
386 pResultsProductProvenanceVector_,
390 saveMemoryObjectThreshold)}}
391 , parentageEnabled_{parentageEnabled}
392 , rangesEnabled_{rangesEnabled}
393 , dbEnabled_{dbEnabled}
396 rootFileDB_ = ServiceHandle<DatabaseConnection> {}
397 ->get<TKeyVFSOpenPolicy>(
398 "RootFileDB", filePtr_.get(), SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE);
402 RootOutputTree::makeTTree(filePtr_.get(), rootNames::metaDataTreeName(), 0);
403 fileIndexTree_ = RootOutputTree::makeTTree(
404 filePtr_.get(), rootNames::fileIndexTreeName(), 0);
406 FileIndex::Element elem;
407 auto const* findexElemPtr = &elem;
408 TBranch* b = fileIndexTree_->Branch(
409 metaBranchRootName<FileIndex::Element>(), &findexElemPtr, basketSize_, 0);
413 eventHistoryTree_ = RootOutputTree::makeTTree(
414 filePtr_.get(), rootNames::eventHistoryTreeName(), splitLevel);
415 if (!eventHistoryTree_) {
416 throw art::Exception(art::errors::FatalRootError)
417 <<
"Failed to create the tree for History objects\n";
420 pHistory_ =
new History;
421 TBranch* b = eventHistoryTree_->Branch(
422 rootNames::eventHistoryBranchName().c_str(), &pHistory_, basketSize, 0);
424 throw art::Exception(art::errors::FatalRootError)
425 <<
"Failed to create a branch for History in the output file\n";
431 root::DictionaryChecker checker{};
432 checker.checkDictionaries<EventAuxiliary>();
433 checker.checkDictionaries<SubRunAuxiliary>();
434 checker.checkDictionaries<RunAuxiliary>();
435 checker.checkDictionaries<ResultsAuxiliary>();
436 checker.reportMissingDictionaries();
438 createDatabaseTables();
440 TLOG(3) <<
"RootDAQOutFile ctor complete";
443 art::RootDAQOutFile::~RootDAQOutFile()
446 int sts=sysinfo(&info);
447 unsigned free_percent=(unsigned)(info.freeram*100/info.totalram);
448 unsigned free_MB=(unsigned)(info.freeram*info.mem_unit >> 20);
449 TRACE( 3,
"~RootDAQOutFile free %%%u %.1fMB (%u) buffers=%fGB mem_unit=%u"
451 ,(
float)info.freeram *info.mem_unit/(1024*1024)
453 ,(
float)info.bufferram*info.mem_unit/(1024*1024*1024)
455 if (free_percent < freePercent_ || free_MB < freeMB_ ) {
456 TLOG(3) <<
"RootDAQOutFile Flush/DONTNEED";
458 sts = posix_fadvise( filePtr_->GetFd(), 0,0, POSIX_FADV_DONTNEED );
460 TLOG(3) <<
"~RootDAQOutFile complete sts="<<sts;
464 art::RootDAQOutFile::createDatabaseTables()
470 create_table(rootFileDB_,
475 "UNIQUE (SubRun,begin,end) ON CONFLICT IGNORE"});
477 using namespace cet::sqlite;
478 create_table(rootFileDB_,
"SubRunRangeSets", column<int>{
"Run"});
479 create_table(rootFileDB_,
480 "SubRunRangeSets_EventRanges",
481 {
"RangeSetsID INTEGER",
482 "EventRangesID INTEGER",
483 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
486 create_table(rootFileDB_,
"RunRangeSets", column<int>{
"Run"});
487 create_table(rootFileDB_,
488 "RunRangeSets_EventRanges",
489 {
"RangeSetsID INTEGER",
490 "EventRangesID INTEGER",
491 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
496 art::RootDAQOutFile::selectProducts()
498 for (
int i = InEvent; i < NumBranchTypes; ++i) {
499 auto const bt =
static_cast<BranchType
>(i);
500 auto& items = selectedOutputItemList_[bt];
501 for (
auto const& pd : om_->keptProducts()[bt]) {
504 if (bt == InResults && !pd->produced()) {
507 checkDictionaries(*pd);
512 if (pd->transient()) {
517 for (
auto const& val : items) {
518 treePointers_[bt]->addOutputBranch(*val.branchDescription_, val.product_);
524 art::RootDAQOutFile::beginInputFile(RootFileBlock
const* rfb,
525 bool const fastCloneFromOutputModule)
528 bool shouldFastClone{fastCloningEnabledAtConstruction_ &&
529 fastCloneFromOutputModule && rfb};
533 if (shouldFastClone &&
534 !treePointers_[InEvent]->checkSplitLevelAndBasketSize(rfb->tree())) {
535 mf::LogWarning(
"FastCloning")
536 <<
"Fast cloning deactivated for this input file due to "
537 <<
"splitting level and/or basket size.";
538 shouldFastClone =
false;
539 }
else if (rfb && rfb->tree() &&
540 rfb->tree()->GetCurrentFile()->GetVersion() < 60001) {
541 mf::LogWarning(
"FastCloning")
542 <<
"Fast cloning deactivated for this input file due to "
543 <<
"ROOT version used to write it (< 6.00/01)\n"
544 "having a different splitting policy.";
545 shouldFastClone =
false;
547 if (shouldFastClone && rfb->fileFormatVersion().value_ < 10) {
548 mf::LogWarning(
"FastCloning")
549 <<
"Fast cloning deactivated for this input file due to "
550 <<
"reading in file that has a different ProductID schema.";
551 shouldFastClone =
false;
553 if (shouldFastClone && !fastCloningEnabledAtConstruction_) {
554 mf::LogWarning(
"FastCloning")
555 <<
"Fast cloning reactivated for this input file.";
557 treePointers_[InEvent]->beginInputFile(shouldFastClone);
558 auto tree = (rfb && rfb->tree()) ? rfb->tree() :
nullptr;
559 wasFastCloned_ = treePointers_[InEvent]->fastCloneTree(tree);
563 art::RootDAQOutFile::incrementInputFileNumber()
565 fp_.update<Granularity::InputFile>();
569 art::RootDAQOutFile::respondToCloseInputFile(FileBlock
const&)
571 cet::for_all(treePointers_, [](
auto const& p) { p->setEntries(); });
575 art::RootDAQOutFile::requestsToCloseFile()
577 using namespace std::chrono;
578 unsigned constexpr oneK{1024U};
579 if (fileSwitchCriteria_.fileProperties().size() !=
580 art::Defaults::size_max()) {
583 fp_.updateSize(filePtr_->GetSize() / oneK);
585 fp_.updateAge(duration_cast<seconds>(steady_clock::now() - beginTime_));
586 return fileSwitchCriteria_.should_close(fp_);
590 art::RootDAQOutFile::writeOneEvent_EventPart(EventPrincipal
const& e)
592 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeOne";
596 pEventAux_ = &e.aux();
600 fillBranches<InEvent>(e, pEventProductProvenanceVector_);
604 art::RootDAQOutFile::writeOneEvent_HistoryPart(EventPrincipal
const& e)
607 History historyForOutput{e.history()};
608 historyForOutput.addEventSelectionEntry(om_->selectorConfig());
609 pHistory_ = &historyForOutput;
610 int sz = eventHistoryTree_->Fill();
611 pHistory_ = &e.history();
613 throw art::Exception(art::errors::FatalRootError)
614 <<
"Failed to fill the History tree for event: " << e.id()
615 <<
"\nTTree::Fill() returned " << sz <<
" bytes written." << endl;
620 art::RootDAQOutFile::writeOneEvent_FileIndexPart(EventPrincipal
const& e)
624 FileIndex::Element elem{e.aux().id(), fp_.eventEntryNumber()};
625 auto const* findexElemPtr = &elem;
626 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
628 fileIndexTree_->Fill();
629 fileIndexTree_->ResetBranchAddress(
630 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
635 art::RootDAQOutFile::writeOne(EventPrincipal
const& e)
637 writeOneEvent_EventPart(e);
638 writeOneEvent_HistoryPart(e);
640 if (!dataTypeReported_) {
641 string dataType{
"MC"};
642 if (e.aux().isRealData()) {
645 dataTypeReported_ =
true;
647 writeOneEvent_FileIndexPart(e);
648 fp_.update<Granularity::Event>(status_);
649 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeOne";
653 art::RootDAQOutFile::writeSubRun_FileIndexPart(SubRunPrincipal
const& sr)
656 FileIndex::Element elem{EventID::invalidEvent(sr.aux().id()),
657 fp_.subRunEntryNumber()};
658 auto const* findexElemPtr = &elem;
659 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
661 fileIndexTree_->Fill();
662 fileIndexTree_->ResetBranchAddress(
663 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
668 art::RootDAQOutFile::writeSubRun(SubRunPrincipal
const& sr)
670 pSubRunAux_ = &sr.aux();
671 if (rangesEnabled_) {
672 pSubRunAux_->setRangeSetID(subRunRSID_);
674 fillBranches<InSubRun>(sr, pSubRunProductProvenanceVector_);
675 writeSubRun_FileIndexPart(sr);
676 fp_.update<Granularity::SubRun>(status_);
680 art::RootDAQOutFile::writeRun_FileIndexPart(RunPrincipal
const& r)
683 FileIndex::Element elem{EventID::invalidEvent(r.aux().id()),
684 fp_.runEntryNumber()};
685 auto const* findexElemPtr = &elem;
686 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
688 fileIndexTree_->Fill();
689 fileIndexTree_->ResetBranchAddress(
690 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
695 art::RootDAQOutFile::writeRun(RunPrincipal
const& r)
698 if (rangesEnabled_) {
699 pRunAux_->setRangeSetID(runRSID_);
701 fillBranches<InRun>(r, pRunProductProvenanceVector_);
702 writeRun_FileIndexPart(r);
703 fp_.update<Granularity::Run>(status_);
707 art::RootDAQOutFile::writeParentageRegistry()
709 auto pid = root::getObjectRequireDict<ParentageID>();
710 ParentageID
const* hash = &pid;
711 TBranch* b = parentageTree_->Branch(
712 rootNames::parentageIDBranchName().c_str(), &hash, basketSize_, 0);
714 throw Exception(errors::FatalRootError)
715 <<
"Failed to create a branch for ParentageIDs in the output file";
719 auto par = root::getObjectRequireDict<Parentage>();
720 Parentage
const* desc = ∥
721 b = parentageTree_->Branch(
722 rootNames::parentageBranchName().c_str(), &desc, basketSize_, 0);
724 throw art::Exception(art::errors::FatalRootError)
725 <<
"Failed to create a branch for Parentages in the output file";
728 for (
auto const& pr : ParentageRegistry::get()) {
731 parentageTree_->Fill();
733 parentageTree_->SetBranchAddress(rootNames::parentageIDBranchName().c_str(),
734 reinterpret_cast<void*>(-1L));
735 parentageTree_->SetBranchAddress(rootNames::parentageBranchName().c_str(),
736 reinterpret_cast<void*>(-1L));
740 art::RootDAQOutFile::writeFileFormatVersion()
742 FileFormatVersion
const ver{getFileFormatVersion(), getFileFormatEra()};
743 auto const* pver = &ver;
744 TBranch* b = metaDataTree_->Branch(
745 metaBranchRootName<FileFormatVersion>(), &pver, basketSize_, 0);
751 art::RootDAQOutFile::writeFileIndex()
754 auto findexPtr = &fileIndex_;
755 detail::readFileIndex(filePtr_.get(), fileIndexTree_, findexPtr);
757 fileIndex_.sortBy_Run_SubRun_Event();
759 fileIndexTree_ = RootOutputTree::makeTTree(
760 filePtr_.get(), rootNames::fileIndexTreeName(), 0);
762 FileIndex::Element elem;
763 auto findexElemPtr = &elem;
764 auto b = fileIndexTree_->Branch(
765 metaBranchRootName<FileIndex::Element>(), &findexElemPtr, basketSize_, 0);
767 for (
auto& entry : fileIndex_) {
768 findexElemPtr = &entry;
769 fileIndexTree_->Fill();
775 art::RootDAQOutFile::writeEventHistory()
777 RootOutputTree::writeTTree(eventHistoryTree_);
781 art::RootDAQOutFile::writeProcessConfigurationRegistry()
788 art::RootDAQOutFile::writeProcessHistoryRegistry()
790 ProcessHistoryMap pHistMap;
791 for (
auto const& pr : ProcessHistoryRegistry::get()) {
792 pHistMap.emplace(pr);
794 auto const* p = &pHistMap;
795 TBranch* b = metaDataTree_->Branch(
796 metaBranchRootName<ProcessHistoryMap>(), &p, basketSize_, 0);
798 throw Exception(errors::LogicError)
799 <<
"Unable to locate required ProcessHistoryMap branch in output "
806 art::RootDAQOutFile::writeFileCatalogMetadata(
807 FileStatsCollector
const& stats,
808 FileCatalogMetadata::collection_type
const& md,
809 FileCatalogMetadata::collection_type
const& ssmd)
814 using namespace cet::sqlite;
815 Ntuple<std::string, std::string> fileCatalogMetadata{
816 rootFileDB_,
"FileCatalog_metadata", {{
"Name",
"Value"}},
true};
817 Transaction txn{rootFileDB_};
818 for (
auto const& kv : md) {
819 fileCatalogMetadata.insert(kv.first, kv.second);
822 fileCatalogMetadata.insert(
"file_format",
"\"artroot\"");
823 fileCatalogMetadata.insert(
"file_format_era",
824 cet::canonical_string(getFileFormatEra()));
825 fileCatalogMetadata.insert(
"file_format_version",
826 to_string(getFileFormatVersion()));
828 namespace bpt = boost::posix_time;
829 auto formatted_time = [](
auto const& t) {
830 return cet::canonical_string(bpt::to_iso_extended_string(t));
832 fileCatalogMetadata.insert(
"start_time",
833 formatted_time(stats.outputFileOpenTime()));
835 fileCatalogMetadata.insert(
837 formatted_time(boost::posix_time::second_clock::universal_time()));
839 if (!stats.seenSubRuns().empty()) {
840 auto I = find_if(md.crbegin(), md.crend(), [](
auto const& p) {
841 return p.first ==
"run_type";
843 if (I != md.crend()) {
846 for (
auto const& srid : stats.seenSubRuns()) {
847 buf <<
"[ " << srid.run() <<
", " << srid.subRun() <<
", "
848 << cet::canonical_string(I->second) <<
" ], ";
851 buf.seekp(-2, ios_base::cur);
853 fileCatalogMetadata.insert(
"runs", buf.str());
857 fileCatalogMetadata.insert(
"event_count", to_string(stats.eventsThisFile()));
859 auto eidToTuple = [](EventID
const& eid) ->
string {
860 ostringstream eidStr;
861 eidStr <<
"[ " << eid.run() <<
", " << eid.subRun() <<
", " << eid.event()
865 fileCatalogMetadata.insert(
"first_event", eidToTuple(stats.lowestEventID()));
866 fileCatalogMetadata.insert(
"last_event", eidToTuple(stats.highestEventID()));
868 if (!stats.parents().empty()) {
869 ostringstream pstring;
871 for (
auto const& parent : stats.parents()) {
872 pstring << cet::canonical_string(parent) <<
", ";
875 pstring.seekp(-2, ios_base::cur);
877 fileCatalogMetadata.insert(
"parents", pstring.str());
880 for (
auto const& kv : ssmd) {
881 fileCatalogMetadata.insert(kv.first, kv.second);
887 art::RootDAQOutFile::writeParameterSetRegistry()
892 fhicl::ParameterSetRegistry::exportTo(rootFileDB_);
896 art::RootDAQOutFile::writeProductDescriptionRegistry()
900 auto end = branchesWithStoredHistory_.end();
902 for (
auto const& pr : ProductMetaData::instance().productList()) {
903 if (branchesWithStoredHistory_.find(pr.second.productID()) == end) {
906 reg.productList_.emplace_hint(reg.productList_.end(), pr);
908 ProductRegistry
const* regp = ®
909 TBranch* b = metaDataTree_->Branch(
910 metaBranchRootName<ProductRegistry>(), ®p, basketSize_, 0);
915 art::RootDAQOutFile::writeProductDependencies()
917 BranchChildren
const* ppDeps = &om_->branchChildren();
918 TBranch* b = metaDataTree_->Branch(
919 metaBranchRootName<BranchChildren>(), &ppDeps, basketSize_, 0);
924 art::RootDAQOutFile::writeResults(ResultsPrincipal& resp)
926 pResultsAux_ = &resp.aux();
927 fillBranches<InResults>(resp, pResultsProductProvenanceVector_);
931 art::RootDAQOutFile::writeTTrees()
933 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeTTrees";
934 RootOutputTree::writeTTree(metaDataTree_);
935 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing metaDataTree_";
936 RootOutputTree::writeTTree(fileIndexTree_);
937 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing fileIndexTree_";
938 RootOutputTree::writeTTree(parentageTree_);
939 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing parentageTree_";
941 for (
int i = InEvent; i < NumBranchTypes; ++i) {
942 auto const branchType =
static_cast<BranchType
>(i);
943 treePointers_[branchType]->writeTree();
945 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeTTrees";
949 art::RootDAQOutFile::insertParents(std::set<ProductProvenance>& keptProvenance,
950 Principal
const& principal,
951 vector<ProductID>
const& parents)
953 for (
auto const pid : parents) {
954 auto pp = principal.branchMapper().branchToProductProvenance(pid);
958 branchesWithStoredHistory_.insert(pid);
959 keptProvenance.insert(*pp);
960 if ((dropMetaData_ == DropMetaData::DropPrior) ||
961 (dropMetaData_ == DropMetaData::DropAll) ||
962 dropMetaDataForDroppedData_) {
965 auto const* pd = principal.getForOutput(pp->productID(),
false).desc();
966 if (pd && pd->produced()) {
967 insertParents(keptProvenance, principal, pp->parentage().parents());
972 template <art::BranchType BT>
974 art::RootDAQOutFile::fillBranches(Principal
const& principal,
975 vector<ProductProvenance>* vpp)
977 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::fillBranches";
978 set<ProductProvenance> keptProvenance;
979 map<unsigned, unsigned> checksumToIndex;
980 for (
auto const& val : selectedOutputItemList_[BT]) {
981 auto const* pd = val.branchDescription_;
982 branchesWithStoredHistory_.insert(pd->productID());
983 bool const readProductNow =
984 (pd->produced() || ((BT != InEvent) || !wasFastCloned_) ||
985 treePointers_[BT]->uncloned(pd->branchName()));
986 auto const& oh = principal.getForOutput(pd->productID(), readProductNow);
987 unique_ptr<ProductProvenance> prov;
988 if ((dropMetaData_ == DropMetaData::DropNone) ||
989 (pd->produced() && (dropMetaData_ == DropMetaData::DropPrior))) {
991 if (oh.productProvenance()) {
992 prov = std::make_unique<ProductProvenance>(
993 *keptProvenance.insert(*oh.productProvenance()).first);
994 if (parentageEnabled_ && (dropMetaData_ == DropMetaData::DropNone) &&
995 !dropMetaDataForDroppedData_) {
997 insertParents(keptProvenance,
999 oh.productProvenance()->parentage().parents());
1004 prov = std::make_unique<ProductProvenance>(
1006 .emplace(pd->productID(),
1007 pd->produced() ? productstatus::neverCreated() :
1008 productstatus::dropped())
1012 if (readProductNow) {
1013 art::EDProduct
const* product{
nullptr};
1014 if (rangesEnabled_) {
1016 getRangeSet<BT>(oh, principal.seenRanges(), pd->produced());
1017 if (RangeSetsSupported<BT>::value && !rs.is_valid()) {
1023 if (keptProvenance.erase(*prov) != 1ULL) {
1024 throw Exception(errors::LogicError,
1025 "art::RootDAQOutFile::fillBranches")
1026 <<
"Attempt to set product status for product whose provenance "
1027 "is not being recorded.";
1029 keptProvenance.emplace(prov->productID(), productstatus::unknown());
1032 product = getProduct<BT>(oh, rs, pd->wrappedName());
1034 setProductRangeSetID<BT>(
1035 rs, rootFileDB_,
const_cast<EDProduct*
>(product), checksumToIndex);
1039 getProduct<BT>(oh, art::RangeSet::invalid(), pd->wrappedName());
1041 val.product_ = product;
1044 vpp->assign(keptProvenance.begin(), keptProvenance.end());
1045 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches before fillTree call";
1046 treePointers_[BT]->fillTree();
1047 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches after fillTree call";
1049 vpp->shrink_to_fit();
1050 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::fillBranches";
1054 art::RootDAQOutFile::setSubRunAuxiliaryRangeSetID(RangeSet
const& ranges)
1056 if (!rangesEnabled_) {
1062 subRunRSID_ = getNewRangeSetID(rootFileDB_, InSubRun, ranges.run());
1063 insertIntoEventRanges(rootFileDB_, ranges);
1064 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
1065 insertIntoJoinTable(rootFileDB_, InSubRun, subRunRSID_, eventRangesIDs);
1069 art::RootDAQOutFile::setRunAuxiliaryRangeSetID(RangeSet
const& ranges)
1071 if (!rangesEnabled_) {
1077 runRSID_ = getNewRangeSetID(rootFileDB_, InRun, ranges.run());
1078 insertIntoEventRanges(rootFileDB_, ranges);
1079 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
1080 insertIntoJoinTable(rootFileDB_, InRun, runRSID_, eventRangesIDs);
1083 template <BranchType BT>
1084 std::enable_if_t<!RangeSetsSupported<BT>::value, art::EDProduct
const*>
1085 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
1086 art::RangeSet
const& ,
1087 std::string
const& wrappedName)
1090 return oh.wrapper();
1092 return dummyProductCache_.product(wrappedName);
1095 template <BranchType BT>
1096 std::enable_if_t<RangeSetsSupported<BT>::value, art::EDProduct
const*>
1097 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
1098 art::RangeSet
const& prunedProductRS,
1099 std::string
const& wrappedName)
1101 if (rangesEnabled_) {
1102 if (oh.isValid() && prunedProductRS.is_valid()) {
1103 return oh.wrapper();
1105 return dummyProductCache_.product(wrappedName);
1108 return oh.wrapper();
1110 return dummyProductCache_.product(wrappedName);