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()
61 #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())
197 if (bt == art::InRun && productRS.is_full_run())
201 if (bt == art::InSubRun && productRS.is_full_subRun())
205 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()))
213 productRS = art::RangeSet::invalid();
217 using art::detail::RangeSetsSupported;
258 template<BranchType BT>
259 std::enable_if_t<RangeSetsSupported<BT>::value, art::RangeSet>
260 getRangeSet(art::OutputHandle
const& oh,
261 art::RangeSet
const& principalRS,
262 bool const producedInThisProcess)
264 auto rs = oh.isValid() ? oh.rangeOfValidity() : art::RangeSet::invalid();
275 if (!producedInThisProcess)
277 maybeInvalidateRangeSet(BT, principalRS, rs);
282 template<BranchType BT>
283 std::enable_if_t<!RangeSetsSupported<BT>::value, art::RangeSet>
284 getRangeSet(art::OutputHandle
const&,
285 art::RangeSet
const& ,
288 return art::RangeSet::invalid();
291 template<BranchType BT>
292 std::enable_if_t<!RangeSetsSupported<BT>::value>
293 setProductRangeSetID(art::RangeSet
const& ,
296 std::map<unsigned, unsigned>& )
299 template<BranchType BT>
300 std::enable_if_t<RangeSetsSupported<BT>::value>
301 setProductRangeSetID(art::RangeSet
const& rs,
303 art::EDProduct* product,
304 std::map<unsigned, unsigned>& checksumToIndexLookup)
312 auto it = checksumToIndexLookup.find(rs.checksum());
313 if (it != checksumToIndexLookup.cend())
315 product->setRangeSetID(it->second);
319 unsigned const rsID = getNewRangeSetID(db, BT, rs.run());
320 product->setRangeSetID(rsID);
321 checksumToIndexLookup.emplace(rs.checksum(), rsID);
322 insertIntoEventRanges(db, rs);
323 auto const& eventRangesIDs = getExistingRangeSetIDs(db, rs);
324 insertIntoJoinTable(db, BT, rsID, eventRangesIDs);
330 art::RootDAQOutFile::RootDAQOutFile(OutputModule* om,
331 string const& fileName,
332 ClosingCriteria
const& fileSwitchCriteria,
333 int const compressionLevel,
334 unsigned freePercent,
336 int64_t
const saveMemoryObjectThreshold,
337 int64_t
const treeMaxVirtualSize,
338 int const splitLevel,
339 int const basketSize,
340 DropMetaData dropMetaData,
341 bool const dropMetaDataForDroppedData,
342 bool const fastCloningRequested,
343 bool const parentageEnabled,
344 bool const rangesEnabled,
345 bool const dbEnabled)
348 , fileSwitchCriteria_{fileSwitchCriteria}
349 , compressionLevel_{compressionLevel}
350 , freePercent_{freePercent}
352 , saveMemoryObjectThreshold_{saveMemoryObjectThreshold}
353 , treeMaxVirtualSize_{treeMaxVirtualSize}
354 , splitLevel_{splitLevel}
355 , basketSize_{basketSize}
356 , dropMetaData_{dropMetaData}
357 , dropMetaDataForDroppedData_{dropMetaDataForDroppedData}
358 , fastCloningEnabledAtConstruction_{fastCloningRequested}
359 , filePtr_{TFile::Open(file_.c_str(),
"recreate",
"", compressionLevel)}
361 std::make_unique<RootOutputTree>(
365 pEventProductProvenanceVector_,
369 saveMemoryObjectThreshold),
370 std::make_unique<RootOutputTree>(
374 pSubRunProductProvenanceVector_,
378 saveMemoryObjectThreshold),
379 std::make_unique<RootOutputTree>(
383 pRunProductProvenanceVector_,
387 saveMemoryObjectThreshold),
388 std::make_unique<RootOutputTree>(
392 pResultsProductProvenanceVector_,
396 saveMemoryObjectThreshold)}}
397 , parentageEnabled_{parentageEnabled}
398 , rangesEnabled_{rangesEnabled}
399 , dbEnabled_{dbEnabled}
403 rootFileDB_ = ServiceHandle<DatabaseConnection> {}
404 ->get<TKeyVFSOpenPolicy>(
405 "RootFileDB", filePtr_.get(), SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE);
409 RootOutputTree::makeTTree(filePtr_.get(), rootNames::metaDataTreeName(), 0);
410 fileIndexTree_ = RootOutputTree::makeTTree(
411 filePtr_.get(), rootNames::fileIndexTreeName(), 0);
413 FileIndex::Element elem;
414 auto const* findexElemPtr = &elem;
415 TBranch* b = fileIndexTree_->Branch(
416 metaBranchRootName<FileIndex::Element>(), &findexElemPtr, basketSize_, 0);
420 eventHistoryTree_ = RootOutputTree::makeTTree(
421 filePtr_.get(), rootNames::eventHistoryTreeName(), splitLevel);
422 if (!eventHistoryTree_)
424 throw art::Exception(art::errors::FatalRootError)
425 <<
"Failed to create the tree for History objects\n";
428 pHistory_ =
new History;
429 TBranch* b = eventHistoryTree_->Branch(
430 rootNames::eventHistoryBranchName().c_str(), &pHistory_, basketSize, 0);
433 throw art::Exception(art::errors::FatalRootError)
434 <<
"Failed to create a branch for History in the output file\n";
440 root::DictionaryChecker checker{};
441 checker.checkDictionaries<EventAuxiliary>();
442 checker.checkDictionaries<SubRunAuxiliary>();
443 checker.checkDictionaries<RunAuxiliary>();
444 checker.checkDictionaries<ResultsAuxiliary>();
445 checker.reportMissingDictionaries();
448 createDatabaseTables();
450 TLOG(3) <<
"RootDAQOutFile ctor complete";
453 art::RootDAQOutFile::~RootDAQOutFile()
456 int sts = sysinfo(&info);
457 unsigned free_percent = (unsigned)(info.freeram * 100 / info.totalram);
458 unsigned free_MB = (unsigned)(info.freeram * info.mem_unit >> 20);
459 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);
460 if (free_percent < freePercent_ || free_MB < freeMB_)
462 TLOG(3) <<
"RootDAQOutFile Flush/DONTNEED";
464 sts = posix_fadvise(filePtr_->GetFd(), 0, 0 , POSIX_FADV_DONTNEED);
466 TLOG(3) <<
"~RootDAQOutFile complete sts=" << sts;
469 void art::RootDAQOutFile::createDatabaseTables()
476 create_table(rootFileDB_,
481 "UNIQUE (SubRun,begin,end) ON CONFLICT IGNORE"});
483 using namespace cet::sqlite;
484 create_table(rootFileDB_,
"SubRunRangeSets", column<int>{
"Run"});
485 create_table(rootFileDB_,
486 "SubRunRangeSets_EventRanges",
487 {
"RangeSetsID INTEGER",
488 "EventRangesID INTEGER",
489 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
492 create_table(rootFileDB_,
"RunRangeSets", column<int>{
"Run"});
493 create_table(rootFileDB_,
494 "RunRangeSets_EventRanges",
495 {
"RangeSetsID INTEGER",
496 "EventRangesID INTEGER",
497 "PRIMARY KEY(RangeSetsID,EventRangesID)"},
501 void art::RootDAQOutFile::selectProducts()
503 for (
int i = InEvent; i < NumBranchTypes; ++i)
505 auto const bt =
static_cast<BranchType
>(i);
506 auto& items = selectedOutputItemList_[bt];
507 for (
auto const& pd : om_->keptProducts()[bt])
511 if (bt == InResults && !pd->produced())
515 checkDictionaries(*pd);
526 for (
auto const& val : items)
528 treePointers_[bt]->addOutputBranch(*val.branchDescription_, val.product_);
533 void art::RootDAQOutFile::beginInputFile(RootFileBlock
const* rfb,
534 bool const fastCloneFromOutputModule)
537 bool shouldFastClone{fastCloningEnabledAtConstruction_ &&
538 fastCloneFromOutputModule && rfb};
542 if (shouldFastClone &&
543 !treePointers_[InEvent]->checkSplitLevelAndBasketSize(rfb->tree()))
545 mf::LogWarning(
"FastCloning")
546 <<
"Fast cloning deactivated for this input file due to "
547 <<
"splitting level and/or basket size.";
548 shouldFastClone =
false;
550 else if (rfb && rfb->tree() &&
551 rfb->tree()->GetCurrentFile()->GetVersion() < 60001)
553 mf::LogWarning(
"FastCloning")
554 <<
"Fast cloning deactivated for this input file due to "
555 <<
"ROOT version used to write it (< 6.00/01)\n"
556 "having a different splitting policy.";
557 shouldFastClone =
false;
559 if (shouldFastClone && rfb->fileFormatVersion().value_ < 10)
561 mf::LogWarning(
"FastCloning")
562 <<
"Fast cloning deactivated for this input file due to "
563 <<
"reading in file that has a different ProductID schema.";
564 shouldFastClone =
false;
566 if (shouldFastClone && !fastCloningEnabledAtConstruction_)
568 mf::LogWarning(
"FastCloning")
569 <<
"Fast cloning reactivated for this input file.";
571 treePointers_[InEvent]->beginInputFile(shouldFastClone);
572 auto tree = (rfb && rfb->tree()) ? rfb->tree() :
nullptr;
573 wasFastCloned_ = treePointers_[InEvent]->fastCloneTree(tree);
576 void art::RootDAQOutFile::incrementInputFileNumber()
578 fp_.update<Granularity::InputFile>();
581 void art::RootDAQOutFile::respondToCloseInputFile(FileBlock
const&)
583 cet::for_all(treePointers_, [](
auto const& p) { p->setEntries(); });
586 bool art::RootDAQOutFile::requestsToCloseFile()
588 using namespace std::chrono;
589 unsigned constexpr oneK{1024U};
590 if (fileSwitchCriteria_.fileProperties().size() !=
591 art::Defaults::size_max())
595 fp_.updateSize(filePtr_->GetSize() / oneK);
597 fp_.updateAge(duration_cast<seconds>(steady_clock::now() - beginTime_));
598 return fileSwitchCriteria_.should_close(fp_);
601 void art::RootDAQOutFile::writeOneEvent_EventPart(EventPrincipal
const& e)
603 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeOne";
607 pEventAux_ = &e.aux();
611 fillBranches<InEvent>(e, pEventProductProvenanceVector_);
614 void art::RootDAQOutFile::writeOneEvent_HistoryPart(EventPrincipal
const& e)
617 History historyForOutput{e.history()};
618 historyForOutput.addEventSelectionEntry(om_->selectorConfig());
619 pHistory_ = &historyForOutput;
620 int sz = eventHistoryTree_->Fill();
621 pHistory_ = &e.history();
624 throw art::Exception(art::errors::FatalRootError)
625 <<
"Failed to fill the History tree for event: " << e.id()
626 <<
"\nTTree::Fill() returned " << sz <<
" bytes written." << endl;
630 void art::RootDAQOutFile::writeOneEvent_FileIndexPart(EventPrincipal
const& e)
634 FileIndex::Element elem{e.aux().id(), fp_.eventEntryNumber()};
635 auto const* findexElemPtr = &elem;
636 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
638 fileIndexTree_->Fill();
639 fileIndexTree_->ResetBranchAddress(
640 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
644 void art::RootDAQOutFile::writeOne(EventPrincipal
const& e)
646 writeOneEvent_EventPart(e);
647 writeOneEvent_HistoryPart(e);
649 if (!dataTypeReported_)
651 string dataType{
"MC"};
652 if (e.aux().isRealData())
656 dataTypeReported_ =
true;
658 writeOneEvent_FileIndexPart(e);
659 fp_.update<Granularity::Event>(status_);
660 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeOne";
663 void art::RootDAQOutFile::writeSubRun_FileIndexPart(SubRunPrincipal
const& sr)
666 FileIndex::Element elem{EventID::invalidEvent(sr.aux().id()),
667 fp_.subRunEntryNumber()};
668 auto const* findexElemPtr = &elem;
669 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
671 fileIndexTree_->Fill();
672 fileIndexTree_->ResetBranchAddress(
673 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
677 void art::RootDAQOutFile::writeSubRun(SubRunPrincipal
const& sr)
679 pSubRunAux_ = &sr.aux();
682 pSubRunAux_->setRangeSetID(subRunRSID_);
684 fillBranches<InSubRun>(sr, pSubRunProductProvenanceVector_);
685 writeSubRun_FileIndexPart(sr);
686 fp_.update<Granularity::SubRun>(status_);
689 void art::RootDAQOutFile::writeRun_FileIndexPart(RunPrincipal
const& r)
692 FileIndex::Element elem{EventID::invalidEvent(r.aux().id()),
693 fp_.runEntryNumber()};
694 auto const* findexElemPtr = &elem;
695 fileIndexTree_->SetBranchAddress(metaBranchRootName<FileIndex::Element>(),
697 fileIndexTree_->Fill();
698 fileIndexTree_->ResetBranchAddress(
699 fileIndexTree_->GetBranch(metaBranchRootName<FileIndex::Element>()));
703 void art::RootDAQOutFile::writeRun(RunPrincipal
const& r)
708 pRunAux_->setRangeSetID(runRSID_);
710 fillBranches<InRun>(r, pRunProductProvenanceVector_);
711 writeRun_FileIndexPart(r);
712 fp_.update<Granularity::Run>(status_);
715 void art::RootDAQOutFile::writeParentageRegistry()
717 auto pid = root::getObjectRequireDict<ParentageID>();
718 ParentageID
const* hash = &pid;
719 TBranch* b = parentageTree_->Branch(
720 rootNames::parentageIDBranchName().c_str(), &hash, basketSize_, 0);
723 throw Exception(errors::FatalRootError)
724 <<
"Failed to create a branch for ParentageIDs in the output file";
728 auto par = root::getObjectRequireDict<Parentage>();
729 Parentage
const* desc = ∥
730 b = parentageTree_->Branch(
731 rootNames::parentageBranchName().c_str(), &desc, basketSize_, 0);
734 throw art::Exception(art::errors::FatalRootError)
735 <<
"Failed to create a branch for Parentages in the output file";
738 for (
auto const& pr : ParentageRegistry::get())
742 parentageTree_->Fill();
744 parentageTree_->SetBranchAddress(rootNames::parentageIDBranchName().c_str(),
745 reinterpret_cast<void*>(-1L));
746 parentageTree_->SetBranchAddress(rootNames::parentageBranchName().c_str(),
747 reinterpret_cast<void*>(-1L));
750 void art::RootDAQOutFile::writeFileFormatVersion()
752 FileFormatVersion
const ver{getFileFormatVersion(), getFileFormatEra()};
753 auto const* pver = &ver;
754 TBranch* b = metaDataTree_->Branch(
755 metaBranchRootName<FileFormatVersion>(), &pver, basketSize_, 0);
760 void art::RootDAQOutFile::writeFileIndex()
763 auto findexPtr = &fileIndex_;
764 detail::readFileIndex(filePtr_.get(), fileIndexTree_, findexPtr);
766 fileIndex_.sortBy_Run_SubRun_Event();
768 fileIndexTree_ = RootOutputTree::makeTTree(
769 filePtr_.get(), rootNames::fileIndexTreeName(), 0);
771 FileIndex::Element elem;
772 auto findexElemPtr = &elem;
773 auto b = fileIndexTree_->Branch(
774 metaBranchRootName<FileIndex::Element>(), &findexElemPtr, basketSize_, 0);
776 for (
auto& entry : fileIndex_)
778 findexElemPtr = &entry;
779 fileIndexTree_->Fill();
784 void art::RootDAQOutFile::writeEventHistory()
786 RootOutputTree::writeTTree(eventHistoryTree_);
789 void art::RootDAQOutFile::writeProcessConfigurationRegistry()
795 void art::RootDAQOutFile::writeProcessHistoryRegistry()
797 ProcessHistoryMap pHistMap;
798 for (
auto const& pr : ProcessHistoryRegistry::get())
800 pHistMap.emplace(pr);
802 auto const* p = &pHistMap;
803 TBranch* b = metaDataTree_->Branch(
804 metaBranchRootName<ProcessHistoryMap>(), &p, basketSize_, 0);
807 throw Exception(errors::LogicError)
808 <<
"Unable to locate required ProcessHistoryMap branch in output "
814 void art::RootDAQOutFile::writeFileCatalogMetadata(
815 FileStatsCollector
const& stats,
816 FileCatalogMetadata::collection_type
const& md,
817 FileCatalogMetadata::collection_type
const& ssmd)
823 using namespace cet::sqlite;
824 Ntuple<std::string, std::string> fileCatalogMetadata{
825 rootFileDB_,
"FileCatalog_metadata", {{
"Name",
"Value"}},
true};
826 Transaction txn{rootFileDB_};
827 for (
auto const& kv : md)
829 fileCatalogMetadata.insert(kv.first, kv.second);
832 fileCatalogMetadata.insert(
"file_format",
"\"artroot\"");
833 fileCatalogMetadata.insert(
"file_format_era",
834 cet::canonical_string(getFileFormatEra()));
835 fileCatalogMetadata.insert(
"file_format_version",
836 to_string(getFileFormatVersion()));
838 namespace bpt = boost::posix_time;
839 auto formatted_time = [](
auto const& t) {
840 return cet::canonical_string(bpt::to_iso_extended_string(t));
842 fileCatalogMetadata.insert(
"start_time",
843 formatted_time(stats.outputFileOpenTime()));
845 fileCatalogMetadata.insert(
847 formatted_time(boost::posix_time::second_clock::universal_time()));
849 if (!stats.seenSubRuns().empty())
851 auto I = find_if(md.crbegin(), md.crend(), [](
auto const& p) {
852 return p.first ==
"run_type";
858 for (
auto const& srid : stats.seenSubRuns())
860 buf <<
"[ " << srid.run() <<
", " << srid.subRun() <<
", "
861 << cet::canonical_string(I->second) <<
" ], ";
864 buf.seekp(-2, ios_base::cur);
866 fileCatalogMetadata.insert(
"runs", buf.str());
870 fileCatalogMetadata.insert(
"event_count", to_string(stats.eventsThisFile()));
872 auto eidToTuple = [](EventID
const& eid) ->
string {
873 ostringstream eidStr;
874 eidStr <<
"[ " << eid.run() <<
", " << eid.subRun() <<
", " << eid.event()
878 fileCatalogMetadata.insert(
"first_event", eidToTuple(stats.lowestEventID()));
879 fileCatalogMetadata.insert(
"last_event", eidToTuple(stats.highestEventID()));
881 if (!stats.parents().empty())
883 ostringstream pstring;
885 for (
auto const& parent : stats.parents())
887 pstring << cet::canonical_string(parent) <<
", ";
890 pstring.seekp(-2, ios_base::cur);
892 fileCatalogMetadata.insert(
"parents", pstring.str());
895 for (
auto const& kv : ssmd)
897 fileCatalogMetadata.insert(kv.first, kv.second);
902 void art::RootDAQOutFile::writeParameterSetRegistry()
908 fhicl::ParameterSetRegistry::exportTo(rootFileDB_);
911 void art::RootDAQOutFile::writeProductDescriptionRegistry()
915 auto end = branchesWithStoredHistory_.end();
917 for (
auto const& pr : ProductMetaData::instance().productList())
919 if (branchesWithStoredHistory_.find(pr.second.productID()) == end)
923 reg.productList_.emplace_hint(reg.productList_.end(), pr);
925 ProductRegistry
const* regp = ®
926 TBranch* b = metaDataTree_->Branch(
927 metaBranchRootName<ProductRegistry>(), ®p, basketSize_, 0);
931 void art::RootDAQOutFile::writeProductDependencies()
933 BranchChildren
const* ppDeps = &om_->branchChildren();
934 TBranch* b = metaDataTree_->Branch(
935 metaBranchRootName<BranchChildren>(), &ppDeps, basketSize_, 0);
939 void art::RootDAQOutFile::writeResults(ResultsPrincipal& resp)
941 pResultsAux_ = &resp.aux();
942 fillBranches<InResults>(resp, pResultsProductProvenanceVector_);
945 void art::RootDAQOutFile::writeTTrees()
947 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::writeTTrees";
948 RootOutputTree::writeTTree(metaDataTree_);
949 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing metaDataTree_";
950 RootOutputTree::writeTTree(fileIndexTree_);
951 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing fileIndexTree_";
952 RootOutputTree::writeTTree(parentageTree_);
953 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::writeTTrees after writing parentageTree_";
955 for (
int i = InEvent; i < NumBranchTypes; ++i)
957 auto const branchType =
static_cast<BranchType
>(i);
958 treePointers_[branchType]->writeTree();
960 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::writeTTrees";
963 void art::RootDAQOutFile::insertParents(std::set<ProductProvenance>& keptProvenance,
964 Principal
const& principal,
965 vector<ProductID>
const& parents)
967 for (
auto const pid : parents)
969 auto pp = principal.branchMapper().branchToProductProvenance(pid);
974 branchesWithStoredHistory_.insert(pid);
975 keptProvenance.insert(*pp);
976 if ((dropMetaData_ == DropMetaData::DropPrior) ||
977 (dropMetaData_ == DropMetaData::DropAll) ||
978 dropMetaDataForDroppedData_)
982 auto const* pd = principal.getForOutput(pp->productID(),
false).desc();
983 if (pd && pd->produced())
985 insertParents(keptProvenance, principal, pp->parentage().parents());
990 template<art::BranchType BT>
991 void art::RootDAQOutFile::fillBranches(Principal
const& principal,
992 vector<ProductProvenance>* vpp)
994 TLOG(TLVL_TRACE) <<
"Start of RootDAQOutFile::fillBranches";
995 set<ProductProvenance> keptProvenance;
996 map<unsigned, unsigned> checksumToIndex;
997 for (
auto const& val : selectedOutputItemList_[BT])
999 auto const* pd = val.branchDescription_;
1000 branchesWithStoredHistory_.insert(pd->productID());
1001 bool const readProductNow =
1002 (pd->produced() || ((BT != InEvent) || !wasFastCloned_) ||
1003 treePointers_[BT]->uncloned(pd->branchName()));
1004 auto const& oh = principal.getForOutput(pd->productID(), readProductNow);
1005 unique_ptr<ProductProvenance> prov;
1006 if ((dropMetaData_ == DropMetaData::DropNone) ||
1007 (pd->produced() && (dropMetaData_ == DropMetaData::DropPrior)))
1010 if (oh.productProvenance())
1012 prov = std::make_unique<ProductProvenance>(
1013 *keptProvenance.insert(*oh.productProvenance()).first);
1014 if (parentageEnabled_ && (dropMetaData_ == DropMetaData::DropNone) &&
1015 !dropMetaDataForDroppedData_)
1018 insertParents(keptProvenance,
1020 oh.productProvenance()->parentage().parents());
1027 prov = std::make_unique<ProductProvenance>(
1029 .emplace(pd->productID(),
1030 pd->produced() ? productstatus::neverCreated() : productstatus::dropped())
1036 art::EDProduct
const* product{
nullptr};
1040 getRangeSet<BT>(oh, principal.seenRanges(), pd->produced());
1041 if (RangeSetsSupported<BT>::value && !rs.is_valid())
1048 if (keptProvenance.erase(*prov) != 1ULL)
1050 throw Exception(errors::LogicError,
1051 "art::RootDAQOutFile::fillBranches")
1052 <<
"Attempt to set product status for product whose provenance "
1053 "is not being recorded.";
1055 keptProvenance.emplace(prov->productID(), productstatus::unknown());
1058 product = getProduct<BT>(oh, rs, pd->wrappedName());
1061 setProductRangeSetID<BT>(
1062 rs, rootFileDB_,
const_cast<EDProduct*
>(product), checksumToIndex);
1068 getProduct<BT>(oh, art::RangeSet::invalid(), pd->wrappedName());
1070 val.product_ = product;
1073 vpp->assign(keptProvenance.begin(), keptProvenance.end());
1074 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches before fillTree call";
1075 treePointers_[BT]->fillTree();
1076 TLOG(TLVL_TRACE) <<
"RootDAQOutFile::fillBranches after fillTree call";
1078 vpp->shrink_to_fit();
1079 TLOG(TLVL_TRACE) <<
"End of RootDAQOutFile::fillBranches";
1082 void art::RootDAQOutFile::setSubRunAuxiliaryRangeSetID(RangeSet
const& ranges)
1084 if (!rangesEnabled_)
1092 subRunRSID_ = getNewRangeSetID(rootFileDB_, InSubRun, ranges.run());
1093 insertIntoEventRanges(rootFileDB_, ranges);
1094 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
1095 insertIntoJoinTable(rootFileDB_, InSubRun, subRunRSID_, eventRangesIDs);
1098 void art::RootDAQOutFile::setRunAuxiliaryRangeSetID(RangeSet
const& ranges)
1100 if (!rangesEnabled_)
1108 runRSID_ = getNewRangeSetID(rootFileDB_, InRun, ranges.run());
1109 insertIntoEventRanges(rootFileDB_, ranges);
1110 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
1111 insertIntoJoinTable(rootFileDB_, InRun, runRSID_, eventRangesIDs);
1114 template<BranchType BT>
1115 std::enable_if_t<!RangeSetsSupported<BT>::value, art::EDProduct
const*>
1116 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
1117 art::RangeSet
const& ,
1118 std::string
const& wrappedName)
1122 return oh.wrapper();
1124 return dummyProductCache_.product(wrappedName);
1127 template<BranchType BT>
1128 std::enable_if_t<RangeSetsSupported<BT>::value, art::EDProduct
const*>
1129 art::RootDAQOutFile::getProduct(art::OutputHandle
const& oh,
1130 art::RangeSet
const& prunedProductRS,
1131 std::string
const& wrappedName)
1135 if (oh.isValid() && prunedProductRS.is_valid())
1137 return oh.wrapper();
1139 return dummyProductCache_.product(wrappedName);
1143 return oh.wrapper();
1145 return dummyProductCache_.product(wrappedName);