00001 #include "artdaq/ArtModules/RootDAQOutput/RootDAQOutFile.h"
00002
00003
00004 #include "Rtypes.h"
00005 #include "TBranchElement.h"
00006 #include "TClass.h"
00007 #include "TFile.h"
00008 #include "TTree.h"
00009 #include "art/Framework/Core/FileBlock.h"
00010 # include "art/Framework/Core/OutputFileGranularity.h"
00011 # include "art/Framework/Services/System/DatabaseConnection.h"
00012 # include "art/Persistency/RootDB/TKeyVFSOpenPolicy.h"
00013 # include "cetlib/sqlite/Ntuple.h"
00014 # include "cetlib/sqlite/Transaction.h"
00015 # include "cetlib/sqlite/create_table.h"
00016 # include "cetlib/sqlite/exec.h"
00017 # include "cetlib/sqlite/insert.h"
00018 #include "art/Framework/IO/FileStatsCollector.h"
00019 #include "art/Framework/IO/Root/DropMetaData.h"
00020 #include "art/Framework/IO/Root/GetFileFormatEra.h"
00021 #include "art/Framework/IO/Root/GetFileFormatVersion.h"
00022 #include "artdaq/ArtModules/RootDAQOutput/detail/KeptProvenance.h"
00023 #include "artdaq/ArtModules/RootDAQOutput/RootDAQOutFile.h"
00024 #include "art/Framework/Principal/EventPrincipal.h"
00025 #include "art/Framework/Principal/ResultsPrincipal.h"
00026 #include "art/Framework/Principal/RunPrincipal.h"
00027 #include "art/Framework/Principal/SubRunPrincipal.h"
00028 #include "art/Persistency/Provenance/BranchIDListRegistry.h"
00029 #include "art/Persistency/Provenance/ProcessHistoryRegistry.h"
00030 #include "art/Persistency/Provenance/ProductMetaData.h"
00031 #include "art/Persistency/RootDB/SQLErrMsg.h"
00032 #include "art/Version/GetReleaseVersion.h"
00033 #include "boost/date_time/posix_time/posix_time.hpp"
00034 #include "canvas/Persistency/Provenance/rootNames.h"
00035 #include "canvas/Persistency/Provenance/BranchChildren.h"
00036 #include "canvas/Persistency/Provenance/BranchID.h"
00037 #include "canvas/Persistency/Provenance/BranchIDList.h"
00038 #include "canvas/Persistency/Provenance/BranchType.h"
00039 #include "canvas/Persistency/Provenance/EventAuxiliary.h"
00040 #include "canvas/Persistency/Provenance/EventID.h"
00041 #include "canvas/Persistency/Provenance/FileFormatVersion.h"
00042 #include "canvas/Persistency/Provenance/History.h"
00043 #include "canvas/Persistency/Provenance/ParameterSetBlob.h"
00044 #include "canvas/Persistency/Provenance/Parentage.h"
00045 #include "canvas/Persistency/Provenance/ParentageRegistry.h"
00046 #include "canvas/Persistency/Provenance/ProcessHistoryID.h"
00047 #include "canvas/Persistency/Provenance/ProductStatus.h"
00048 #include "canvas/Persistency/Provenance/ResultsAuxiliary.h"
00049 #include "canvas/Persistency/Provenance/RunAuxiliary.h"
00050 #include "canvas/Persistency/Provenance/SubRunAuxiliary.h"
00051 #include "canvas/Utilities/Exception.h"
00052 #include "cetlib/canonical_string.h"
00053 #include "cetlib/container_algorithms.h"
00054 #include "cetlib/exempt_ptr.h"
00055 #include "fhiclcpp/ParameterSet.h"
00056 #include "fhiclcpp/ParameterSetID.h"
00057 #include "fhiclcpp/ParameterSetRegistry.h"
00058 #define TRACE_NAME "RootDAQOutFile"
00059 #include "trace.h"
00060
00061 #include <algorithm>
00062 #include <iomanip>
00063 #include <sstream>
00064 #include <utility>
00065 #include <utility>
00066 #include <vector>
00067
00068 using namespace cet;
00069 using namespace std;
00070 using art::BranchType;
00071 using art::RootDAQOutFile;
00072 using art::rootNames::metaBranchRootName;
00073
00074 namespace {
00075
00076 void create_table(sqlite3* const db,
00077 std::string const& name,
00078 std::vector<std::string> const& columns,
00079 std::string const& suffix = {})
00080 {
00081 if (columns.empty())
00082 throw art::Exception(art::errors::LogicError)
00083 << "Number of sqlite columns specified for table: "
00084 << name << '\n'
00085 << "is zero.\n";
00086
00087 sqlite::Transaction txn{ db };
00088 art::SQLErrMsg errMsg;
00089 std::string ddl =
00090 "DROP TABLE IF EXISTS " + name + "; "
00091 "CREATE TABLE " + name +
00092 "(" + columns.front();
00093 std::for_each(columns.begin() + 1, columns.end(),
00094 [&ddl](auto const& col)
00095 {
00096 ddl += "," + col;
00097 });
00098 ddl += ") ";
00099 ddl += suffix;
00100 ddl += ";";
00101 sqlite3_exec(db, ddl.c_str(), nullptr, nullptr, errMsg);
00102 errMsg.throwIfError();
00103 txn.commit();
00104 }
00105
00106 void
00107 insert_eventRanges_row(sqlite3_stmt* stmt,
00108 art::SubRunNumber_t const sr,
00109 art::EventNumber_t const b,
00110 art::EventNumber_t const e)
00111 {
00112 sqlite3_bind_int64(stmt, 1, sr);
00113 sqlite3_bind_int64(stmt, 2, b);
00114 sqlite3_bind_int64(stmt, 3, e);
00115 sqlite3_step(stmt);
00116 sqlite3_reset(stmt);
00117 }
00118
00119 void
00120 insert_rangeSets_row(sqlite3_stmt* stmt,
00121 art::RunNumber_t const r)
00122 {
00123 sqlite3_bind_int64(stmt, 1, r);
00124 sqlite3_step(stmt);
00125 sqlite3_reset(stmt);
00126 }
00127
00128 void
00129 insert_rangeSets_eventSets_row(sqlite3_stmt* stmt,
00130 unsigned const rsid,
00131 unsigned const esid)
00132 {
00133 sqlite3_bind_int64(stmt, 1, rsid);
00134 sqlite3_bind_int64(stmt, 2, esid);
00135 sqlite3_step(stmt);
00136 sqlite3_reset(stmt);
00137 }
00138
00139 int
00140 found_rowid(sqlite3_stmt* stmt)
00141 {
00142 return sqlite3_step(stmt) == SQLITE_ROW ?
00143 sqlite3_column_int64(stmt, 0) :
00144 throw art::Exception(art::errors::SQLExecutionError)
00145 << "ROWID not found for EventRanges.\n"
00146 << "Contact artists@fnal.gov.\n";
00147 }
00148
00149 unsigned
00150 getNewRangeSetID(sqlite3* db,
00151 art::BranchType const bt,
00152 art::RunNumber_t const r)
00153 {
00154 sqlite::Transaction txn{ db };
00155 sqlite3_stmt* stmt{ nullptr };
00156 std::string const ddl{ "INSERT INTO " + art::BranchTypeToString(bt) + "RangeSets(Run) VALUES(?);" };
00157 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt, nullptr);
00158 insert_rangeSets_row(stmt, r);
00159 unsigned const rsID = sqlite3_last_insert_rowid(db);
00160 sqlite3_finalize(stmt);
00161 txn.commit();
00162 return rsID;
00163 }
00164
00165 vector<unsigned>
00166 getExistingRangeSetIDs(sqlite3* db, art::RangeSet const& rs)
00167 {
00168 vector<unsigned> rangeSetIDs;
00169 for (auto const& range : rs)
00170 {
00171 sqlite::Transaction txn{ db };
00172 sqlite3_stmt* stmt{ nullptr };
00173 std::string const ddl{ "SELECT ROWID FROM EventRanges WHERE "
00174 "SubRun=" + std::to_string(range.subRun()) + " AND "
00175 "begin=" + std::to_string(range.begin()) + " AND "
00176 "end=" + std::to_string(range.end()) + ";" };
00177 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt, nullptr);
00178 rangeSetIDs.push_back(found_rowid(stmt));
00179 sqlite3_finalize(stmt);
00180 txn.commit();
00181 }
00182 return rangeSetIDs;
00183 }
00184
00185 void
00186 insertIntoEventRanges(sqlite3* db, art::RangeSet const& rs)
00187 {
00188 sqlite::Transaction txn{ db };
00189 sqlite3_stmt* stmt{ nullptr };
00190 std::string const ddl{ "INSERT INTO EventRanges(SubRun, begin, end) "
00191 "VALUES(?, ?, ?);" };
00192 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt, nullptr);
00193 for (auto const& range : rs)
00194 {
00195 insert_eventRanges_row(stmt, range.subRun(), range.begin(), range.end());
00196 }
00197 sqlite3_finalize(stmt);
00198 txn.commit();
00199 }
00200
00201 void
00202 insertIntoJoinTable(sqlite3* db,
00203 art::BranchType const bt,
00204 unsigned const rsID,
00205 vector<unsigned> const& eventRangesIDs)
00206 {
00207 sqlite::Transaction txn{ db };
00208 sqlite3_stmt* stmt{ nullptr };
00209 std::string const ddl{ "INSERT INTO " + art::BranchTypeToString(bt) +
00210 "RangeSets_EventRanges(RangeSetsID, EventRangesID) Values(?,?);" };
00211 sqlite3_prepare_v2(db, ddl.c_str(), -1, &stmt, nullptr);
00212 cet::for_all(eventRangesIDs,
00213 [stmt, rsID](auto const eventRangeID)
00214 {
00215 insert_rangeSets_eventSets_row(stmt, rsID, eventRangeID);
00216 });
00217 sqlite3_finalize(stmt);
00218 txn.commit();
00219 }
00220
00221 void
00222 maybeInvalidateRangeSet(BranchType const bt,
00223 art::RangeSet const& principalRS,
00224 art::RangeSet& productRS)
00225 {
00226 if (!productRS.is_valid())
00227 return;
00228
00229 assert(principalRS.is_sorted());
00230 assert(productRS.is_sorted());
00231
00232 if (bt == art::InRun && productRS.is_full_run()) return;
00233 if (bt == art::InSubRun && productRS.is_full_subRun()) return;
00234 assert(!productRS.ranges().empty());
00235
00236 auto const r = productRS.run();
00237 auto const& productFront = productRS.ranges().front();
00238 if (!principalRS.contains(r, productFront.subRun(), productFront.begin()))
00239 productRS = art::RangeSet::invalid();
00240 }
00241
00242 using art::detail::RangeSetsSupported;
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283 template <BranchType BT>
00284 std::enable_if_t<RangeSetsSupported<BT>::value, art::RangeSet>
00285 getRangeSet(art::OutputHandle const& oh,
00286 art::RangeSet const& principalRS,
00287 bool const producedInThisProcess)
00288 {
00289 auto rs = oh.isValid() ? oh.rangeOfValidity() : art::RangeSet::invalid();
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 if (!producedInThisProcess)
00301 {
00302 maybeInvalidateRangeSet(BT, principalRS, rs);
00303 }
00304 return rs;
00305 }
00306
00307 template <BranchType BT>
00308 std::enable_if_t<!RangeSetsSupported<BT>::value, art::RangeSet>
00309 getRangeSet(art::OutputHandle const&,
00310 art::RangeSet const& ,
00311 bool const )
00312 {
00313 return art::RangeSet::invalid();
00314 }
00315
00316 template <BranchType BT>
00317 std::enable_if_t<!RangeSetsSupported<BT>::value>
00318 setProductRangeSetID(art::RangeSet const& ,
00319 sqlite3*,
00320 art::EDProduct*,
00321 std::map<unsigned, unsigned>& )
00322 {}
00323
00324 template <BranchType BT>
00325 std::enable_if_t<RangeSetsSupported<BT>::value>
00326 setProductRangeSetID(art::RangeSet const& rs,
00327 sqlite3* db,
00328 art::EDProduct* product,
00329 std::map<unsigned, unsigned>& checksumToIndexLookup)
00330 {
00331 if (!rs.is_valid())
00332 return;
00333
00334
00335 auto it = checksumToIndexLookup.find(rs.checksum());
00336 if (it != checksumToIndexLookup.cend())
00337 {
00338 product->setRangeSetID(it->second);
00339 }
00340 else
00341 {
00342 unsigned const rsID = getNewRangeSetID(db, BT, rs.run());
00343 product->setRangeSetID(rsID);
00344 checksumToIndexLookup.emplace(rs.checksum(), rsID);
00345 insertIntoEventRanges(db, rs);
00346 auto const& eventRangesIDs = getExistingRangeSetIDs(db, rs);
00347 insertIntoJoinTable(db, BT, rsID, eventRangesIDs);
00348 }
00349 }
00350
00351 }
00352
00353 art::
00354 RootDAQOutFile::
00355 RootDAQOutFile(OutputModule* om,
00356 string const& fileName,
00357 ClosingCriteria const& fileSwitchCriteria,
00358 int const compressionLevel,
00359 int64_t const saveMemoryObjectThreshold,
00360 int64_t const treeMaxVirtualSize,
00361 int const splitLevel,
00362 int const basketSize,
00363 DropMetaData dropMetaData,
00364 bool const dropMetaDataForDroppedData,
00365 bool const fastCloning)
00366 : om_{ om }
00367 , file_{ fileName }
00368 , fileSwitchCriteria_{ fileSwitchCriteria }
00369 , compressionLevel_{ compressionLevel }
00370 , saveMemoryObjectThreshold_{ saveMemoryObjectThreshold }
00371 , treeMaxVirtualSize_{ treeMaxVirtualSize }
00372 , splitLevel_{ splitLevel }
00373 , basketSize_{ basketSize }
00374 , dropMetaData_{ dropMetaData }
00375 , dropMetaDataForDroppedData_{ dropMetaDataForDroppedData }
00376 , fastCloning_{ fastCloning }
00377 , filePtr_{ TFile::Open(file_.c_str(), "recreate", "", compressionLevel) }
00378 , treePointers_{
00379 std::make_unique<RootOutputTree>(
00380 filePtr_.get(), InEvent, pEventAux_,
00381 pEventProductProvenanceVector_, basketSize, splitLevel,
00382 treeMaxVirtualSize, saveMemoryObjectThreshold),
00383 std::make_unique<RootOutputTree>(
00384 filePtr_.get(), InSubRun, pSubRunAux_,
00385 pSubRunProductProvenanceVector_, basketSize, splitLevel,
00386 treeMaxVirtualSize, saveMemoryObjectThreshold),
00387 std::make_unique<RootOutputTree>(
00388 filePtr_.get(), InRun, pRunAux_,
00389 pRunProductProvenanceVector_, basketSize, splitLevel,
00390 treeMaxVirtualSize, saveMemoryObjectThreshold),
00391 std::make_unique<RootOutputTree>(
00392 filePtr_.get(), InResults, pResultsAux_,
00393 pResultsProductProvenanceVector_, basketSize, splitLevel,
00394 treeMaxVirtualSize, saveMemoryObjectThreshold) }
00395 , rootFileDB_{ ServiceHandle<DatabaseConnection>{}->get<TKeyVFSOpenPolicy>("RootFileDB",
00396 filePtr_.get(),
00397 SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE) }
00398 {
00399
00400 metaDataTree_ = RootOutputTree::makeTTree(filePtr_.get(), rootNames::metaDataTreeName(), 0);
00401 fileIndexTree_ = RootOutputTree::makeTTree(filePtr_.get(), rootNames::fileIndexTreeName(), 0);
00402 parentageTree_ = RootOutputTree::makeTTree(filePtr_.get(), rootNames::parentageTreeName(), 0);
00403
00404 eventHistoryTree_ = RootOutputTree::makeTTree(filePtr_.get(), rootNames::eventHistoryTreeName(), splitLevel);
00405 if (!eventHistoryTree_)
00406 {
00407 throw art::Exception(art::errors::FatalRootError)
00408 << "Failed to create the tree for History objects\n";
00409 }
00410
00411
00412 pHistory_ = new History;
00413 if (!eventHistoryTree_->Branch(rootNames::eventHistoryBranchName().c_str(), &pHistory_, basketSize, 0))
00414 {
00415 throw art::Exception(art::errors::FatalRootError)
00416 << "Failed to create a branch for History in the output file\n";
00417 }
00418 delete pHistory_;
00419 pHistory_ = nullptr;
00420
00421 createDatabaseTables();
00422 }
00423
00424 art::
00425 RootDAQOutFile::OutputItem::Sorter::
00426 Sorter(TTree* tree)
00427 {
00428
00429
00430 if (!tree)
00431 {
00432 return;
00433 }
00434 auto branches = tree->GetListOfBranches();
00435 for (int i = 0, sz = branches->GetEntries(); i != sz; ++i)
00436 {
00437 auto br = reinterpret_cast<TBranchElement*>(branches->At(i));
00438 treeMap_.emplace(string(br->GetName()), i);
00439 }
00440 }
00441
00442 bool
00443 art::
00444 RootDAQOutFile::OutputItem::Sorter::
00445 operator()(OutputItem const& lh, OutputItem const& rh) const
00446 {
00447
00448
00449
00450
00451 if (treeMap_.empty())
00452 {
00453 return lh < rh;
00454 }
00455 auto const& lname = lh.branchDescription_->branchName();
00456 auto const& rname = rh.branchDescription_->branchName();
00457 auto lit = treeMap_.find(lname);
00458 auto rit = treeMap_.find(rname);
00459 bool lfound = (lit != treeMap_.end());
00460 bool rfound = (rit != treeMap_.end());
00461 if (lfound && rfound)
00462 {
00463 return lit->second < rit->second;
00464 }
00465 if (lfound)
00466 {
00467 return true;
00468 }
00469 if (rfound)
00470 {
00471 return false;
00472 }
00473 return lh < rh;
00474 }
00475
00476 void
00477 art::RootDAQOutFile::createDatabaseTables()
00478 {
00479
00480
00481
00482
00483
00484
00485 create_table(rootFileDB_, "EventRanges",
00486 { "SubRun INTEGER", "begin INTEGER", "end INTEGER", "UNIQUE (SubRun,begin,end) ON CONFLICT IGNORE" });
00487
00488
00489 create_table(rootFileDB_, "SubRunRangeSets",
00490 { "Run INTEGER" });
00491 create_table(rootFileDB_, "SubRunRangeSets_EventRanges",
00492 { "RangeSetsID INTEGER", "EventRangesID INTEGER", "PRIMARY KEY(RangeSetsID,EventRangesID)" },
00493 "WITHOUT ROWID");
00494
00495
00496 create_table(rootFileDB_, "RunRangeSets",
00497 { "Run INTEGER" });
00498 create_table(rootFileDB_, "RunRangeSets_EventRanges",
00499 { "RangeSetsID INTEGER", "EventRangesID INTEGER", "PRIMARY KEY(RangeSetsID,EventRangesID)" },
00500 "WITHOUT ROWID");
00501 }
00502
00503 void
00504 art::
00505 RootDAQOutFile::
00506 selectProducts(FileBlock const& fb)
00507 {
00508 for (int i = InEvent; i < NumBranchTypes; ++i)
00509 {
00510 auto bt = static_cast<BranchType>(i);
00511 auto& items = selectedOutputItemList_[bt];
00512 for (auto const& val : items)
00513 {
00514 treePointers_[bt]->resetOutputBranchAddress(*val.branchDescription_);
00515 }
00516 items.clear();
00517 for (auto const& bd : om_->keptProducts()[bt])
00518 {
00519 if ((bt < InResults) || bd->produced())
00520 {
00521 items.emplace_back(bd);
00522 }
00523 }
00524 if ((bt == InEvent) && (fb.tree() != nullptr))
00525 {
00526
00527
00528 sort(items.begin(), items.end(), OutputItem::Sorter(fb.tree()));
00529 }
00530 for (auto const& val : items)
00531 {
00532 treePointers_[bt]->addOutputBranch(*val.branchDescription_, val.product_);
00533 }
00534 }
00535 }
00536
00537 void
00538 art::
00539 RootDAQOutFile::
00540 beginInputFile(FileBlock const& fb, bool fastClone)
00541 {
00542 selectProducts(fb);
00543 auto const origCurrentlyFastCloning = currentlyFastCloning_;
00544 currentlyFastCloning_ = fastCloning_ && fastClone;
00545 if (currentlyFastCloning_ &&
00546 !treePointers_[InEvent]->checkSplitLevelAndBasketSize(fb.tree()))
00547 {
00548 mf::LogWarning("FastCloning")
00549 << "Fast cloning deactivated for this input file due to "
00550 << "splitting level and/or basket size.";
00551 currentlyFastCloning_ = false;
00552 }
00553 else if (fb.tree() && fb.tree()->GetCurrentFile()->GetVersion() < 60001)
00554 {
00555 mf::LogWarning("FastCloning")
00556 << "Fast cloning deactivated for this input file due to "
00557 << "ROOT version used to write it (< 6.00/01)\n"
00558 "having a different splitting policy.";
00559 currentlyFastCloning_ = false;
00560 }
00561
00562 if (currentlyFastCloning_ && fb.fileFormatVersion().value_ < 9)
00563 {
00564 mf::LogWarning("FastCloning")
00565 << "Fast cloning deactivated for this input file due to "
00566 << "reading in file that does not support RangeSets.";
00567 currentlyFastCloning_ = false;
00568 }
00569
00570 if (currentlyFastCloning_ && !origCurrentlyFastCloning)
00571 {
00572 mf::LogWarning("FastCloning")
00573 << "Fast cloning reactivated for this input file.";
00574 }
00575 treePointers_[InEvent]->beginInputFile(currentlyFastCloning_);
00576 treePointers_[InEvent]->fastCloneTree(fb.tree());
00577 }
00578
00579 void
00580 art::RootDAQOutFile::incrementInputFileNumber()
00581 {
00582 fp_.update<Granularity::InputFile>();
00583 }
00584
00585 void
00586 art::
00587 RootDAQOutFile::
00588 respondToCloseInputFile(FileBlock const&)
00589 {
00590 cet::for_all(treePointers_, [](auto const& p) { p->setEntries(); });
00591 }
00592
00593 bool
00594 art::
00595 RootDAQOutFile::
00596 requestsToCloseFile()
00597 {
00598 using namespace std::chrono;
00599 unsigned int constexpr oneK{ 1024u };
00600 TLOG(10) << "RootDAQOutFile::requestsToCloseFile start";
00601 unsigned sz = filePtr_->GetSize();
00602 TLOG(10) << "RootDAQOutFile::requestsToCloseFile after filePtr_->GetSize()";
00603 fp_.updateSize(sz / oneK);
00604 fp_.updateAge(duration_cast<seconds>(steady_clock::now() - beginTime_));
00605 bool ret = fileSwitchCriteria_.should_close(fp_);
00606 TLOG(10) << "RootDAQOutFile::requestsToCloseFile done/return";
00607 return ret;
00608 }
00609
00610 void art::RootDAQOutFile::writeOne(EventPrincipal const& e)
00611 {
00612 TLOG(10) << "RootDAQOutFile::writeOne begin";
00613
00614
00615
00616 pEventAux_ = &e.aux();
00617
00618
00619
00620 fillBranches<InEvent>(e, pEventProductProvenanceVector_);
00621
00622 History historyForOutput{ e.history() };
00623 historyForOutput.addEventSelectionEntry(om_->selectorConfig());
00624 pHistory_ = &historyForOutput;
00625 int sz = eventHistoryTree_->Fill();
00626 if (sz <= 0)
00627 {
00628 throw art::Exception(art::errors::FatalRootError)
00629 << "Failed to fill the History tree for event: "
00630 << e.id()
00631 << "\nTTree::Fill() returned "
00632 << sz
00633 << " bytes written."
00634 << endl;
00635 }
00636
00637 if (!dataTypeReported_)
00638 {
00639 string dataType{ "MC" };
00640 if (pEventAux_->isRealData())
00641 {
00642 dataType = "Data";
00643 }
00644 dataTypeReported_ = true;
00645 }
00646 pHistory_ = &e.history();
00647
00648 fileIndex_.addEntry(pEventAux_->id(), fp_.eventEntryNumber());
00649 fp_.update<Granularity::Event>(status_);
00650 TLOG(10) << "RootDAQOutFile::writeOne done/return";
00651 }
00652
00653 void
00654 art::
00655 RootDAQOutFile::
00656 writeSubRun(SubRunPrincipal const& sr)
00657 {
00658 pSubRunAux_ = &sr.aux();
00659 pSubRunAux_->setRangeSetID(subRunRSID_);
00660 fillBranches<InSubRun>(sr, pSubRunProductProvenanceVector_);
00661 fileIndex_.addEntry(EventID::invalidEvent(pSubRunAux_->id()), fp_.subRunEntryNumber());
00662 fp_.update<Granularity::SubRun>(status_);
00663 }
00664
00665 void
00666 art::
00667 RootDAQOutFile::
00668 writeRun(RunPrincipal const& r)
00669 {
00670 pRunAux_ = &r.aux();
00671 pRunAux_->setRangeSetID(runRSID_);
00672 fillBranches<InRun>(r, pRunProductProvenanceVector_);
00673 fileIndex_.addEntry(EventID::invalidEvent(pRunAux_->id()), fp_.runEntryNumber());
00674 fp_.update<Granularity::Run>(status_);
00675 }
00676
00677 void
00678 art::
00679 RootDAQOutFile::
00680 writeParentageRegistry()
00681 {
00682 ParentageID const* hash = new ParentageID;
00683 if (!parentageTree_->Branch(rootNames::parentageIDBranchName().c_str(),
00684 &hash, basketSize_, 0))
00685 {
00686 throw art::Exception(art::errors::FatalRootError)
00687 << "Failed to create a branch for ParentageIDs in the output file";
00688 }
00689 delete hash;
00690 hash = nullptr;
00691 Parentage const* desc = new Parentage;
00692 if (!parentageTree_->Branch(rootNames::parentageBranchName().c_str(), &desc,
00693 basketSize_, 0))
00694 {
00695 throw art::Exception(art::errors::FatalRootError)
00696 << "Failed to create a branch for Parentages in the output file";
00697 }
00698 delete desc;
00699 desc = nullptr;
00700 for (auto const& pr : ParentageRegistry::get())
00701 {
00702 hash = &pr.first;
00703 desc = &pr.second;
00704 parentageTree_->Fill();
00705 }
00706 parentageTree_->SetBranchAddress(rootNames::parentageIDBranchName().c_str(), nullptr);
00707 parentageTree_->SetBranchAddress(rootNames::parentageBranchName().c_str(), nullptr);
00708 }
00709
00710 void
00711 art::
00712 RootDAQOutFile::
00713 writeFileFormatVersion()
00714 {
00715 FileFormatVersion ver(getFileFormatVersion(), getFileFormatEra());
00716 FileFormatVersion* pver = &ver;
00717 TBranch* b = metaDataTree_->Branch(metaBranchRootName<FileFormatVersion>(),
00718 &pver, basketSize_, 0);
00719
00720 assert(b);
00721 b->Fill();
00722 }
00723
00724 void
00725 art::
00726 RootDAQOutFile::
00727 writeFileIndex()
00728 {
00729 fileIndex_.sortBy_Run_SubRun_Event();
00730 FileIndex::Element elem{};
00731 auto findexElemPtr = &elem;
00732 TBranch* b = fileIndexTree_->Branch(metaBranchRootName<FileIndex::Element>(),
00733 &findexElemPtr, basketSize_, 0);
00734
00735 assert(b);
00736 for (auto& entry : fileIndex_)
00737 {
00738 findexElemPtr = &entry;
00739 b->Fill();
00740 }
00741 b->SetAddress(0);
00742 }
00743
00744 void
00745 art::
00746 RootDAQOutFile::
00747 writeEventHistory()
00748 {
00749 RootOutputTree::writeTTree(eventHistoryTree_);
00750 }
00751
00752 void
00753 art::
00754 RootDAQOutFile::
00755 writeProcessConfigurationRegistry()
00756 {
00757
00758
00759 }
00760
00761 void
00762 art::
00763 RootDAQOutFile::
00764 writeProcessHistoryRegistry()
00765 {
00766 ProcessHistoryMap pHistMap;
00767 for (auto const& pr : ProcessHistoryRegistry::get())
00768 {
00769 pHistMap.emplace(pr);
00770 }
00771 auto const* p = &pHistMap;
00772 TBranch* b = metaDataTree_->Branch(metaBranchRootName<ProcessHistoryMap>(),
00773 &p, basketSize_, 0);
00774 if (b != nullptr)
00775 {
00776 b->Fill();
00777 }
00778 else
00779 {
00780 throw Exception(errors::LogicError)
00781 << "Unable to locate required ProcessHistoryMap branch in output metadata tree.\n";
00782 }
00783 }
00784
00785 void
00786 art::
00787 RootDAQOutFile::
00788 writeBranchIDListRegistry()
00789 {
00790 BranchIDLists const* p = &BranchIDListRegistry::instance().data();
00791 TBranch* b = metaDataTree_->Branch(metaBranchRootName<BranchIDLists>(), &p,
00792 basketSize_, 0);
00793
00794 assert(b);
00795 b->Fill();
00796 }
00797
00798 void
00799 art::
00800 RootDAQOutFile::
00801 writeFileCatalogMetadata(FileStatsCollector const& stats,
00802 FileCatalogMetadata::collection_type const& md,
00803 FileCatalogMetadata::collection_type const& ssmd)
00804 {
00805 using namespace cet::sqlite;
00806 Ntuple<std::string, std::string> fileCatalogMetadata{ rootFileDB_, "FileCatalog_metadata", {"Name","Value"}, true };
00807 Transaction txn{ rootFileDB_ };
00808 for (auto const& kv : md)
00809 {
00810 fileCatalogMetadata.insert(kv.first, kv.second);
00811 }
00812
00813 fileCatalogMetadata.insert("file_format", "\"artroot\"");
00814 fileCatalogMetadata.insert("file_format_era", cet::canonical_string(getFileFormatEra()));
00815 fileCatalogMetadata.insert("file_format_version", to_string(getFileFormatVersion()));
00816
00817
00818 namespace bpt = boost::posix_time;
00819 auto formatted_time = [](auto const& t) { return cet::canonical_string(bpt::to_iso_extended_string(t)); };
00820 fileCatalogMetadata.insert("start_time", formatted_time(stats.outputFileOpenTime()));
00821
00822 fileCatalogMetadata.insert("end_time", formatted_time(boost::posix_time::second_clock::universal_time()));
00823
00824
00825 if (!stats.seenSubRuns().empty())
00826 {
00827
00828 auto I = find_if(md.crbegin(), md.crend(),
00829 [](auto const& p) { return p.first == "run_type"; });
00830
00831 if (I != md.crend())
00832 {
00833 ostringstream buf;
00834 buf << "[ ";
00835 for (auto const& srid : stats.seenSubRuns())
00836 {
00837 buf << "[ "
00838 << srid.run()
00839 << ", "
00840 << srid.subRun()
00841 << ", "
00842 << cet::canonical_string(I->second)
00843 << " ], ";
00844 }
00845
00846 buf.seekp(-2, ios_base::cur);
00847 buf << " ]";
00848 fileCatalogMetadata.insert("runs", buf.str());
00849 }
00850 }
00851
00852 fileCatalogMetadata.insert("event_count", to_string(stats.eventsThisFile()));
00853
00854 auto eidToTuple = [](EventID const & eid)->string
00855 {
00856 ostringstream eidStr;
00857 eidStr << "[ "
00858 << eid.run()
00859 << ", "
00860 << eid.subRun()
00861 << ", "
00862 << eid.event()
00863 << " ]";
00864 return eidStr.str();
00865 };
00866 fileCatalogMetadata.insert("first_event", eidToTuple(stats.lowestEventID()));
00867 fileCatalogMetadata.insert("last_event", eidToTuple(stats.highestEventID()));
00868
00869 if (!stats.parents().empty())
00870 {
00871 ostringstream pstring;
00872 pstring << "[ ";
00873 for (auto const& parent : stats.parents())
00874 {
00875 pstring << cet::canonical_string(parent) << ", ";
00876 }
00877
00878 pstring.seekp(-2, ios_base::cur);
00879 pstring << " ]";
00880 fileCatalogMetadata.insert("parents", pstring.str());
00881 }
00882
00883 for (auto const& kv : ssmd)
00884 {
00885 fileCatalogMetadata.insert(kv.first, kv.second);
00886 }
00887 txn.commit();
00888 }
00889
00890 void
00891 art::
00892 RootDAQOutFile::
00893 writeParameterSetRegistry()
00894 {
00895 fhicl::ParameterSetRegistry::exportTo(rootFileDB_);
00896 }
00897
00898 void
00899 art::
00900 RootDAQOutFile::
00901 writeProductDescriptionRegistry()
00902 {
00903
00904
00905 auto end = branchesWithStoredHistory_.end();
00906
00907 ProductRegistry reg;
00908 for (auto const& pr : ProductMetaData::instance().productList())
00909 {
00910 if (branchesWithStoredHistory_.find(pr.second.branchID()) == end)
00911 {
00912 continue;
00913 }
00914 reg.productList_.emplace_hint(reg.productList_.end(), pr);
00915 }
00916
00917 auto* regp = ®
00918 TBranch* b = metaDataTree_->Branch(metaBranchRootName<ProductRegistry>(),
00919 ®p, basketSize_, 0);
00920
00921 assert(b);
00922 b->Fill();
00923 }
00924
00925 void
00926 art::
00927 RootDAQOutFile::
00928 writeProductDependencies()
00929 {
00930 BranchChildren& pDeps = const_cast<BranchChildren&>(om_->branchChildren());
00931 BranchChildren* ppDeps = &pDeps;
00932 TBranch* b = metaDataTree_->Branch(metaBranchRootName<BranchChildren>(),
00933 &ppDeps, basketSize_, 0);
00934
00935 assert(b);
00936 b->Fill();
00937 }
00938
00939 void
00940 art::
00941 RootDAQOutFile::
00942 writeResults(ResultsPrincipal & resp)
00943 {
00944 pResultsAux_ = &resp.aux();
00945 fillBranches<InResults>(resp, pResultsProductProvenanceVector_);
00946 }
00947
00948 void
00949 art::RootDAQOutFile::writeTTrees()
00950 {
00951 RootOutputTree::writeTTree(metaDataTree_);
00952 RootOutputTree::writeTTree(fileIndexTree_);
00953 RootOutputTree::writeTTree(parentageTree_);
00954
00955 for (int i = InEvent; i < NumBranchTypes; ++i)
00956 {
00957 auto const branchType = static_cast<BranchType>(i);
00958 treePointers_[branchType]->writeTree();
00959 }
00960 }
00961
00962 template <art::BranchType BT>
00963 void art::RootDAQOutFile::fillBranches(Principal const& principal,
00964 vector<ProductProvenance>* vpp)
00965 {
00966 TLOG(11) << "RootDAQOutFile::fillBranches begin";
00967 bool const fastCloning = (BT == InEvent) && currentlyFastCloning_;
00968 detail::KeptProvenance keptProvenance{ dropMetaData_, dropMetaDataForDroppedData_, branchesWithStoredHistory_ };
00969 map<unsigned, unsigned> checksumToIndex;
00970
00971 auto const& principalRS = principal.seenRanges();
00972
00973 for (auto const& val : selectedOutputItemList_[BT])
00974 {
00975 auto const* bd = val.branchDescription_;
00976 auto const bid = bd->branchID();
00977 branchesWithStoredHistory_.insert(bid);
00978 bool const produced{ bd->produced() };
00979 bool const resolveProd = (produced || !fastCloning ||
00980 treePointers_[BT]->uncloned(bd->branchName()));
00981
00982
00983 bool const keepProvenance = (dropMetaData_ == DropMetaData::DropNone ||
00984 (dropMetaData_ == DropMetaData::DropPrior &&
00985 produced));
00986 auto const& oh = principal.getForOutput(bid, resolveProd);
00987
00988 unique_ptr<ProductProvenance> prov{ nullptr };
00989 if (keepProvenance)
00990 {
00991 if (oh.productProvenance())
00992 {
00993 prov = std::make_unique<ProductProvenance>(keptProvenance.insert(*oh.productProvenance()));
00994 keptProvenance.insertAncestors(*oh.productProvenance(), principal);
00995 }
00996 else
00997 {
00998
00999
01000 auto const status = produced ? productstatus::neverCreated() : productstatus::dropped();
01001 prov = std::make_unique<ProductProvenance>(keptProvenance.emplace(bid, status));
01002 }
01003 }
01004
01005
01006 if (resolveProd)
01007 {
01008 auto const& rs = getRangeSet<BT>(oh, principalRS, produced);
01009 if (RangeSetsSupported<BT>::value && !rs.is_valid())
01010 {
01011
01012
01013
01014
01015 keptProvenance.setStatus(*prov, productstatus::unknown());
01016 }
01017
01018 auto const* product = getProduct<BT>(oh, rs, bd->wrappedName());
01019 setProductRangeSetID<BT>(rs,
01020 rootFileDB_,
01021 const_cast<EDProduct*>(product),
01022 checksumToIndex);
01023 val.product_ = product;
01024 }
01025 }
01026 vpp->assign(keptProvenance.begin(), keptProvenance.end());
01027 treePointers_[BT]->fillTree();
01028 vpp->clear();
01029 TLOG(11) << "RootDAQOutFile::fillBranches done/return";
01030 }
01031
01032 void
01033 art::
01034 RootDAQOutFile::
01035 setSubRunAuxiliaryRangeSetID(RangeSet const& ranges)
01036 {
01037 subRunRSID_ = getNewRangeSetID(rootFileDB_, InSubRun, ranges.run());
01038 insertIntoEventRanges(rootFileDB_, ranges);
01039 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
01040 insertIntoJoinTable(rootFileDB_, InSubRun, subRunRSID_, eventRangesIDs);
01041 }
01042
01043 void
01044 art::
01045 RootDAQOutFile::
01046 setRunAuxiliaryRangeSetID(RangeSet const& ranges)
01047 {
01048 runRSID_ = getNewRangeSetID(rootFileDB_, InRun, ranges.run());
01049 insertIntoEventRanges(rootFileDB_, ranges);
01050 auto const& eventRangesIDs = getExistingRangeSetIDs(rootFileDB_, ranges);
01051 insertIntoJoinTable(rootFileDB_, InRun, runRSID_, eventRangesIDs);
01052 }
01053
01054 template <BranchType BT>
01055 std::enable_if_t<!RangeSetsSupported<BT>::value, art::EDProduct const*>
01056 art::RootDAQOutFile::getProduct(art::OutputHandle const& oh,
01057 art::RangeSet const& ,
01058 std::string const& wrappedName)
01059 {
01060 if (oh.isValid())
01061 return oh.wrapper();
01062 else
01063 return dummyProductCache_.product(wrappedName);
01064 }
01065
01066 template <BranchType BT>
01067 std::enable_if_t<RangeSetsSupported<BT>::value, art::EDProduct const*>
01068 art::RootDAQOutFile::getProduct(art::OutputHandle const& oh,
01069 art::RangeSet const& prunedProductRS,
01070 std::string const& wrappedName)
01071 {
01072 if (oh.isValid() && prunedProductRS.is_valid())
01073 return oh.wrapper();
01074 else
01075 return dummyProductCache_.product(wrappedName);
01076 }