12 #include <framework/modules/rootio/RootInputModule.h>
14 #include <framework/io/RootIOUtilities.h>
15 #include <framework/io/RootFileInfo.h>
16 #include <framework/core/FileCatalog.h>
17 #include <framework/core/InputController.h>
18 #include <framework/pcore/Mergeable.h>
19 #include <framework/datastore/StoreObjPtr.h>
20 #include <framework/datastore/DataStore.h>
21 #include <framework/datastore/DependencyMap.h>
22 #include <framework/dataobjects/EventMetaData.h>
23 #include <framework/utilities/NumberSequence.h>
24 #include <framework/utilities/ScopeGuard.h>
25 #include <framework/database/Configuration.h>
27 #include <TClonesArray.h>
28 #include <TEventList.h>
29 #include <TObjArray.h>
30 #include <TChainElement.h>
37 using namespace RootIOUtilities;
44 setDescription(
"Reads objects/arrays from one or more .root files saved by the RootOutput module and makes them available through the DataStore. Files do not necessarily have to be local, http:// and root:// (for files in xrootd) URLs are supported as well.");
48 vector<string> emptyvector;
49 addParam(
"inputFileName", m_inputFileName,
50 "Input file name. For multiple files, use inputFileNames or wildcards instead. Can be overridden using the -i argument to basf2.",
52 addParam(
"inputFileNames", m_inputFileNames,
53 "List of input files. You may use shell-like expansions to specify multiple files, e.g. 'somePrefix_*.root' or 'file_[a,b]_[1-15].root'. Can be overridden using the -i argument to basf2.",
55 addParam(
"entrySequences", m_entrySequences,
56 "The number sequences (e.g. 23:42,101) defining the entries which are processed for each inputFileName."
57 "Must be specified exactly once for each file to be opened."
58 "The first event has the entry number 0.", emptyvector);
59 addParam(
"ignoreCommandLineOverride" , m_ignoreCommandLineOverride,
60 "Ignore override of file name via command line argument -i.",
false);
62 addParam(
"skipNEvents", m_skipNEvents,
"Skip this number of events before starting.", 0u);
63 addParam(
"skipToEvent", m_skipToEvent,
"Skip events until the event with "
64 "the specified (experiment, run, event number) occurs. This parameter "
65 "is useful for debugging to start with a specific event.", m_skipToEvent);
68 "Names of event durability branches to be read. Empty means all branches. (EventMetaData is always read)", emptyvector);
70 "Names of persistent durability branches to be read. Empty means all branches. (FileMetaData is always read)", emptyvector);
73 "Names of event durability branches NOT to be read. Takes precedence over branchNames.", emptyvector);
74 vector<string> excludePersistent({
"ProcessStatistics"});
76 "Names of persistent durability branches NOT to be read. Takes precedence over branchNamesPersistent.", excludePersistent);
78 addParam(
"parentLevel", m_parentLevel,
79 "Number of generations of parent files (files used as input when creating a file) to be read. This can be useful if a file is missing some information available in its parent. See https://confluence.desy.de/display/BI/Software+ParentFiles for details.",
82 addParam(
"collectStatistics" , m_collectStatistics,
83 "Collect statistics on amount of data read and print statistics (seperate for input & parent files) after processing. Data is collected from TFile using GetBytesRead(), GetBytesReadExtra(), GetReadCalls()",
85 addParam(
"cacheSize", m_cacheSize,
86 "file cache size in Mbytes. If negative, use root default", 0);
88 addParam(
"discardErrorEvents", m_discardErrorEvents,
89 "Discard events with an error flag != 0", m_discardErrorEvents);
90 addParam(
"silentErrrorDiscardMask", m_discardErrorMask,
91 "Bitmask of error flags to silently discard without raising a WARNING. Should be a combination of the ErrorFlags defined "
92 "in the EventMetaData. No Warning will be issued when discarding an event if the error flag consists exclusively of flags "
93 "present in this mask", m_discardErrorMask);
96 RootInputModule::~RootInputModule() =
default;
98 void RootInputModule::initialize()
100 unsigned int skipNEventsOverride = Environment::Instance().getSkipEventsOverride();
101 if (skipNEventsOverride != 0)
102 m_skipNEvents = skipNEventsOverride;
104 auto entrySequencesOverride = Environment::Instance().getEntrySequencesOverride();
105 if (entrySequencesOverride.size() > 0)
106 m_entrySequences = entrySequencesOverride;
108 m_nextEntry = m_skipNEvents;
109 m_lastPersistentEntry = -1;
110 m_lastParentFileLFN =
"";
112 const vector<string>& inputFiles = getFileNames();
113 if (inputFiles.empty()) {
114 B2FATAL(
"You have to set either the 'inputFileName' or the 'inputFileNames' parameter, or start basf2 with the '-i MyFile.root' option.");
116 if (!m_inputFileName.empty() && !m_inputFileNames.empty()) {
117 B2FATAL(
"Cannot use both 'inputFileName' and 'inputFileNames' parameters!");
120 if (m_inputFileNames.empty()) {
121 B2FATAL(
"No valid files specified!");
124 if (m_entrySequences.size() > 0 and m_inputFileNames.size() != m_entrySequences.size()) {
125 B2FATAL(
"Number of provided filenames does not match the number of given entrySequences parameters: len(inputFileNames) = "
126 << m_inputFileNames.size() <<
" len(entrySequences) = " << m_entrySequences.size());
129 m_inputFileName =
"";
133 m_persistent =
new TChain(
c_treeNames[DataStore::c_Persistent].c_str());
134 m_tree =
new TChain(
c_treeNames[DataStore::c_Event].c_str());
147 std::set<std::string> requiredEventBranches;
148 std::set<std::string> requiredPersistentBranches;
150 std::vector<FileMetaData> fileMetaData;
152 std::result_of<decltype(&FileMetaData::getMcEvents)(
FileMetaData)>::type sumInputMCEvents{0};
157 auto rootWarningGuard = ScopeGuard::guardValue(gErrorIgnoreLevel, kWarning + 1);
159 bool validInputMCEvents{
true};
160 for (
const string& fileName : m_inputFileNames) {
165 if (meta.getNEvents() == 0) {
166 B2WARNING(
"File appears to be empty, skipping" <<
LogVar(
"filename", fileName));
169 realDataWorkaround(meta);
170 fileMetaData.push_back(meta);
172 if (fileMetaData.front().isMC() != meta.isMC()) {
173 throw std::runtime_error(
"Mixing real data and simulated data for input files is not supported");
176 if (validInputMCEvents) {
178 if ((sumInputMCEvents > 0 and meta.getMcEvents() == 0)) {
179 B2WARNING(
"inconsistent input files: zero mcEvents, setting total number of MC events to zero" <<
LogVar(
"filename", fileName));
180 validInputMCEvents =
false;
183 if (__builtin_add_overflow(sumInputMCEvents, meta.getMcEvents(), &sumInputMCEvents)) {
184 B2FATAL(
"Number of MC events is too large and cannot be represented anymore");
188 if (requiredEventBranches.empty()) {
198 requiredEventBranches = RootIOUtilities::filterBranches(requiredEventBranches, m_branchNames[DataStore::c_Event],
199 m_excludeBranchNames[DataStore::c_Event], DataStore::c_Event);
201 requiredEventBranches.emplace(
"EventMetaData");
206 requiredPersistentBranches = RootIOUtilities::filterBranches(requiredPersistentBranches, m_branchNames[DataStore::c_Persistent],
207 m_excludeBranchNames[DataStore::c_Persistent], DataStore::c_Persistent);
214 if (m_tree->AddFile(fileName.c_str(), meta.getNEvents()) == 0 || m_persistent->AddFile(fileName.c_str(), 1) == 0) {
215 throw std::runtime_error(
"Could not add file to TChain");
217 B2INFO(
"Added file " + fileName);
218 }
catch (std::exception& e) {
219 B2FATAL(
"Could not open input file " << std::quoted(fileName) <<
": " << e.what());
224 if (m_tree->GetNtrees() == 0) B2FATAL(
"No file could be opened, aborting");
227 if (m_cacheSize >= 0) m_tree->SetCacheSize(m_cacheSize * 1024 * 1024);
234 std::set<std::string> unique_filenames;
238 TObjArray* fileElements = m_tree->GetListOfFiles();
239 TIter next(fileElements);
240 TChainElement* chEl =
nullptr;
241 while ((chEl = (TChainElement*)next())) {
242 if (!unique_filenames.insert(chEl->GetTitle()).second) {
243 B2WARNING(
"The input file '" << chEl->GetTitle() <<
"' was specified more than once");
245 m_processingAllEvents =
false;
248 if ((
unsigned int)m_tree->GetNtrees() != unique_filenames.size() && m_entrySequences.size() > 0) {
249 B2FATAL(
"You specified a file multiple times, and specified a sequence of entries which should be used for each file. "
250 "Please specify each file only once if you're using the sequence feature!");
254 if (m_entrySequences.size() > 0) {
255 auto* elist =
new TEventList(
"input_event_list");
256 for (
unsigned int iFile = 0; iFile < m_entrySequences.size(); ++iFile) {
257 int64_t offset = m_tree->GetTreeOffset()[iFile];
258 int64_t next_offset = m_tree->GetTreeOffset()[iFile + 1];
260 if (m_entrySequences[iFile] ==
":") {
261 for (int64_t global_entry = offset; global_entry < next_offset; ++global_entry)
262 elist->Enter(global_entry);
265 int64_t global_entry = entry + offset;
266 if (global_entry >= next_offset) {
267 B2WARNING(
"Given sequence contains entry numbers which are out of range. "
268 "I won't add any further events to the EventList for the current file.");
271 elist->Enter(global_entry);
276 m_tree->SetEventList(elist);
279 B2DEBUG(33,
"Opened tree '" +
c_treeNames[DataStore::c_Persistent] +
"'" <<
LogVar(
"entries", m_persistent->GetEntriesFast()));
280 B2DEBUG(33,
"Opened tree '" +
c_treeNames[DataStore::c_Event] +
"'" <<
LogVar(
"entries", m_tree->GetEntriesFast()));
282 connectBranches(m_persistent, DataStore::c_Persistent, &m_persistentStoreEntries);
283 readPersistentEntry(0);
285 if (!connectBranches(m_tree, DataStore::c_Event, &m_storeEntries)) {
289 InputController::setCanControlInput(
true);
290 InputController::setChain(m_tree);
293 if (m_parentLevel > 0) {
294 createParentStoreEntries();
295 }
else if (m_parentLevel < 0) {
296 B2ERROR(
"parentLevel must be >= 0!");
304 unsigned int maxEvent = Environment::Instance().getNumberEventsOverride();
305 m_processingAllEvents &= m_skipNEvents == 0 && m_entrySequences.size() == 0;
306 m_processingAllEvents &= (maxEvent == 0 || maxEvent >= InputController::numEntries());
308 if (!m_skipToEvent.empty()) {
310 m_processingAllEvents =
false;
312 if (m_skipToEvent.size() != 3) {
313 B2ERROR(
"skipToEvent must be a list of three values: experiment, run, event number");
315 m_skipToEvent.clear();
317 InputController::setNextEntry(m_skipToEvent[0], m_skipToEvent[1], m_skipToEvent[2]);
319 if (m_nextEntry > 0) {
320 B2ERROR(
"You cannot supply a number of events to skip (skipNEvents) and an "
321 "event to skip to (skipToEvent) at the same time, ignoring skipNEvents");
328 if (m_processingAllEvents) {
329 Environment::Instance().setNumberOfMCEvents(sumInputMCEvents);
332 Conditions::Configuration::getInstance().setInputMetadata(fileMetaData);
336 void RootInputModule::event()
342 const long nextEntry = InputController::getNextEntry();
343 if (nextEntry >= 0 && nextEntry < InputController::numEntries()) {
344 B2INFO(
"RootInput: will read entry " << nextEntry <<
" next.");
345 m_nextEntry = nextEntry;
346 }
else if (InputController::getNextExperiment() >= 0 && InputController::getNextRun() >= 0
347 && InputController::getNextEvent() >= 0) {
348 const long entry = RootIOUtilities::getEntryNumberWithEvtRunExp(m_tree->GetTree(), InputController::getNextEvent(),
349 InputController::getNextRun(), InputController::getNextExperiment());
351 const long chainentry = m_tree->GetChainEntryNumber(entry);
352 B2INFO(
"RootInput: will read entry " << chainentry <<
" (entry " << entry <<
" in current file) next.");
353 m_nextEntry = chainentry;
355 B2ERROR(
"Couldn't find entry (" << InputController::getNextEvent() <<
", " << InputController::getNextRun() <<
", " <<
356 InputController::getNextExperiment() <<
") in file! Loading entry " << m_nextEntry <<
" instead.");
359 InputController::eventLoaded(m_nextEntry);
365 unsigned int errorFlag = 0;
366 if (m_discardErrorEvents && (m_nextEntry >= 0)) {
368 errorFlag = eventMetaData->getErrorFlag();
369 if (errorFlag != 0) {
370 if (errorFlag & ~m_discardErrorMask) {
371 B2WARNING(
"Discarding corrupted event" <<
LogVar(
"errorFlag", errorFlag) <<
LogVar(
"experiment", eventMetaData->getExperiment())
372 <<
LogVar(
"run", eventMetaData->getRun()) <<
LogVar(
"event", eventMetaData->getEvent()));
375 eventMetaData->setEndOfData();
378 if (errorFlag == 0)
break;
383 void RootInputModule::terminate()
385 if (m_collectStatistics and m_tree) {
387 m_readStats.addFromFile(m_tree->GetFile());
392 for (
const auto& entry : m_parentTrees) {
393 TFile* f = entry.second->GetCurrentFile();
394 if (m_collectStatistics)
400 if (m_collectStatistics) {
401 B2INFO(
"Statistics for event tree: " << m_readStats.getString());
402 B2INFO(
"Statistics for event tree (parent files): " << parentReadStats.
getString());
405 for (
auto& branch : m_connectedBranches) {
408 m_storeEntries.clear();
409 m_persistentStoreEntries.clear();
410 m_parentStoreEntries.clear();
411 m_parentTrees.clear();
415 void RootInputModule::readTree()
422 if (m_collectStatistics) {
427 int localEntryNumber = m_nextEntry;
428 if (m_entrySequences.size() > 0) {
429 localEntryNumber = m_tree->GetEntryNumber(localEntryNumber);
431 localEntryNumber = m_tree->LoadTree(localEntryNumber);
433 if (localEntryNumber == -2) {
436 }
else if (localEntryNumber < 0) {
437 B2FATAL(
"Failed to load tree, corrupt file? Check standard error for additional messages. (TChain::LoadTree() returned error " <<
438 localEntryNumber <<
")");
440 B2DEBUG(39,
"Reading file entry " << m_nextEntry);
443 for (
auto entry : m_storeEntries) {
444 entry->resetForGetEntry();
446 for (
const auto& storeEntries : m_parentStoreEntries) {
447 for (
auto entry : storeEntries) {
448 entry->resetForGetEntry();
452 int bytesRead = m_tree->GetTree()->GetEntry(localEntryNumber);
453 if (bytesRead <= 0) {
454 B2FATAL(
"Could not read 'tree' entry " << m_nextEntry <<
" in file " << m_tree->GetCurrentFile()->GetName());
465 const long treeNum = m_tree->GetTreeNumber();
466 const bool fileChanged = (m_lastPersistentEntry != treeNum);
468 if (m_collectStatistics) {
469 m_readStats.add(currentEventStats);
472 readPersistentEntry(treeNum);
473 B2INFO(
"Loading new input file"
474 <<
LogVar(
"filename", m_tree->GetFile()->GetName())
475 <<
LogVar(
"metadata LFN", fileMetaData->getLfn()));
477 realDataWorkaround(*fileMetaData);
479 for (
auto entry : m_storeEntries) {
480 if (!entry->object) {
481 entryNotFound(
"Event durability tree (global entry: " + std::to_string(m_nextEntry) +
")", entry->name, fileChanged);
482 entry->recoverFromNullObject();
483 entry->ptr =
nullptr;
485 entry->ptr = entry->object;
489 if (m_parentLevel > 0) {
490 if (!readParentTrees())
491 B2FATAL(
"Could not read data from parent file!");
498 B2DEBUG(30,
"File changed, loading persistent data.");
501 const TObjArray* branchesObjArray = tree->GetListOfBranches();
502 if (!branchesObjArray) {
503 B2FATAL(
"Tree '" << tree->GetName() <<
"' doesn't contain any branches!");
505 std::vector<TBranch*> branches;
506 set<string> branchList;
507 for (
int jj = 0; jj < branchesObjArray->GetEntriesFast(); jj++) {
508 auto* branch =
static_cast<TBranch*
>(branchesObjArray->At(jj));
509 if (!branch)
continue;
510 branchList.insert(branch->GetName());
511 branches.emplace_back(branch);
516 branchList =
filterBranches(branchList, m_branchNames[durability], m_excludeBranchNames[durability], durability,
true);
517 for (TBranch* branch : branches) {
518 const std::string branchName = branch->GetName();
520 if (m_connectedBranches[durability].find(branchName) != m_connectedBranches[durability].end())
523 if ((branchList.count(branchName) == 0) and
524 ((branchName !=
"FileMetaData") || (tree != m_persistent)) and
525 ((branchName !=
"EventMetaData") || (tree != m_tree))) {
529 B2DEBUG(32,
"Enabling branch" <<
LogVar(
"branchName", branchName)
530 <<
LogVar(
"children found", found));
533 TObject* objectPtr =
nullptr;
534 branch->SetAddress(&objectPtr);
536 bool array = (string(branch->GetClassName()) ==
"TClonesArray");
537 TClass* objClass =
nullptr;
539 objClass = (
static_cast<TClonesArray*
>(objectPtr))->GetClass();
541 objClass = objectPtr->IsA();
545 if (!DataStore::Instance().registerEntry(branchName, durability, objClass, array, DataStore::c_WriteOut)) {
546 B2FATAL(
"Cannot connect branch to datastore" <<
LogVar(
"branchName", branchName));
550 tree->SetBranchAddress(branch->GetName(), &(entry.
object));
551 if (storeEntries) storeEntries->push_back(&entry);
554 m_connectedBranches[durability].insert(branchName);
561 bool RootInputModule::createParentStoreEntries()
564 TBranch* branch = m_tree->GetBranch(
"EventMetaData");
565 char* address = branch->GetAddress();
567 branch->SetAddress(&eventMetaData);
570 int run = eventMetaData->
getRun();
571 unsigned int event = eventMetaData->
getEvent();
573 branch->SetAddress(address);
576 for (
int level = 0; level < m_parentLevel; level++) {
578 TDirectory* dir = gDirectory;
579 const std::string parentPfn = FileCatalog::Instance().getPhysicalFileName(parentLfn);
580 TFile* file = TFile::Open(parentPfn.c_str(),
"READ");
582 if (!file || !file->IsOpen()) {
583 B2ERROR(
"Couldn't open parent file. Maybe you need to create a file catalog using b2file-catalog-add?"
584 <<
LogVar(
"LFN", parentLfn) <<
LogVar(
"PFN", parentPfn));
589 auto* tree =
dynamic_cast<TTree*
>(file->Get(
c_treeNames[DataStore::c_Event].c_str()));
591 B2ERROR(
"No tree " <<
c_treeNames[DataStore::c_Event] <<
" found in " << parentPfn);
594 if (
int(m_parentStoreEntries.size()) <= level) m_parentStoreEntries.resize(level + 1);
595 connectBranches(tree, DataStore::c_Event, &m_parentStoreEntries[level]);
596 m_parentTrees.insert(std::make_pair(parentLfn, tree));
599 auto* persistent =
dynamic_cast<TTree*
>(file->Get(
c_treeNames[DataStore::c_Persistent].c_str()));
601 B2ERROR(
"No tree " <<
c_treeNames[DataStore::c_Persistent] <<
" found in " << parentPfn);
604 connectBranches(persistent, DataStore::c_Persistent,
nullptr);
608 tree->SetBranchAddress(
"EventMetaData", &metaData);
609 long entry = RootIOUtilities::getEntryNumberWithEvtRunExp(tree, event, run, experiment);
610 tree->GetBranch(
"EventMetaData")->GetEntry(entry);
618 bool RootInputModule::readParentTrees()
621 int experiment = eventMetaData->getExperiment();
622 int run = eventMetaData->getRun();
623 unsigned int event = eventMetaData->getEvent();
625 std::string parentLfn = eventMetaData->getParentLfn();
626 for (
int level = 0; level < m_parentLevel; level++) {
627 const std::string& parentPfn = FileCatalog::Instance().getPhysicalFileName(parentLfn);
630 TTree* tree =
nullptr;
631 if (m_parentTrees.find(parentLfn) == m_parentTrees.end()) {
632 TDirectory* dir = gDirectory;
633 B2DEBUG(30,
"Opening parent file" <<
LogVar(
"PFN", parentPfn));
634 TFile* file = TFile::Open(parentPfn.c_str(),
"READ");
636 if (!file || !file->IsOpen()) {
637 B2ERROR(
"Couldn't open parent file " << parentPfn);
640 tree =
dynamic_cast<TTree*
>(file->Get(
c_treeNames[DataStore::c_Event].c_str()));
642 B2ERROR(
"No tree " <<
c_treeNames[DataStore::c_Event] <<
" found in " << parentPfn);
645 for (
auto entry : m_parentStoreEntries[level]) {
646 tree->SetBranchAddress(entry->name.c_str(), &(entry->object));
648 m_parentTrees.insert(std::make_pair(parentLfn, tree));
650 tree = m_parentTrees[parentLfn];
654 long entryNumber = RootIOUtilities::getEntryNumberWithEvtRunExp(tree, event, run, experiment);
655 if (entryNumber < 0) {
656 B2ERROR(
"No event " << experiment <<
"/" << run <<
"/" << event <<
" in parent file " << parentPfn);
662 tree->SetBranchAddress(
"EventMetaData", &parentMetaData);
663 tree->GetEntry(entryNumber);
664 for (
auto entry : m_parentStoreEntries[level]) {
665 entry->ptr = entry->object;
672 addEventListForIndexFile(parentLfn);
677 void RootInputModule::addEventListForIndexFile(
const std::string& parentLfn)
680 if (!(m_parentLevel > 0 and m_storeEntries.size() == 1))
683 if (parentLfn == m_lastParentFileLFN)
685 m_lastParentFileLFN = parentLfn;
687 B2INFO(
"Index file detected, scanning to generate event list.");
688 TTree* tree = m_parentTrees.at(parentLfn);
691 auto* elist =
new TEventList(
"parent_entrylist");
694 TBranch* branch = m_tree->GetBranch(
"EventMetaData");
695 auto* address = branch->GetAddress();
697 branch->SetAddress(&eventMetaData);
698 long nEntries = m_tree->GetEntries();
699 for (
long i = m_nextEntry; i < nEntries; i++) {
702 int run = eventMetaData->
getRun();
703 unsigned int event = eventMetaData->
getEvent();
704 const std::string& newParentLfn = eventMetaData->
getParentLfn();
706 if (parentLfn != newParentLfn) {
710 long entry = RootIOUtilities::getEntryNumberWithEvtRunExp(tree, event, run, experiment);
713 branch->SetAddress(address);
716 tree->SetEventList(elist);
721 void RootInputModule::entryNotFound(
const std::string& entryOrigin,
const std::string& name,
bool fileChanged)
723 if (name ==
"ProcessStatistics" or DataStore::Instance().getDependencyMap().isUsedAs(name, DependencyMap::c_Input)) {
724 B2FATAL(entryOrigin <<
" in " << m_tree->GetFile()->GetName() <<
" does not contain required object " << name <<
", aborting.");
725 }
else if (fileChanged) {
726 B2WARNING(entryOrigin <<
" in " << m_tree->GetFile()->GetName() <<
" does not contain object " << name <<
727 " that was present in a previous entry.");
731 void RootInputModule::readPersistentEntry(
long fileEntry)
733 m_lastPersistentEntry = fileEntry;
735 for (
auto entry : m_persistentStoreEntries) {
736 bool isMergeable = entry->object->InheritsFrom(Mergeable::Class());
737 TObject* copyOfPreviousVersion =
nullptr;
739 copyOfPreviousVersion = entry->object->Clone();
741 entry->resetForGetEntry();
743 entry->ptr = copyOfPreviousVersion;
746 int bytesRead = m_persistent->GetEntry(fileEntry);
747 if (bytesRead <= 0) {
748 const char* name = m_tree->GetCurrentFile() ? m_tree->GetCurrentFile()->GetName() :
"<unknown>";
749 B2FATAL(
"Could not read 'persistent' TTree #" << fileEntry <<
" in file " << name);
752 for (
auto entry : m_persistentStoreEntries) {
754 bool isMergeable = entry->object->InheritsFrom(Mergeable::Class());
757 auto* newObj =
static_cast<Mergeable*
>(entry->object);
758 newObj->
merge(oldObj);
762 entry->ptr = entry->object;
764 entryNotFound(
"Persistent tree", entry->name);
765 entry->recoverFromNullObject();
766 entry->ptr =
nullptr;
773 if ((metaData.
getSite().find(
"bfe0") == 0) && (metaData.
getDate().compare(
"2019-06-30") < 0) &&