Belle II Software  release-06-02-00
DataStore.cc
1 /**************************************************************************
2  * basf2 (Belle II Analysis Software Framework) *
3  * Author: The Belle II Collaboration *
4  * *
5  * See git log for contributors and copyright holders. *
6  * This file is licensed under LGPL-3.0, see LICENSE.md. *
7  **************************************************************************/
8 
9 #include <framework/datastore/DataStore.h>
10 
11 #include <framework/logging/Logger.h>
12 #include <framework/datastore/RelationEntry.h>
13 #include <framework/datastore/DependencyMap.h>
14 #include <framework/dataobjects/RelationContainer.h>
15 #include <framework/datastore/RelationIndex.h>
16 #include <framework/datastore/RelationIndexManager.h>
17 #include <framework/datastore/RelationsObject.h>
18 #include <framework/datastore/StoreAccessorBase.h>
19 
20 #include <TClonesArray.h>
21 #include <TClass.h>
22 
23 #include <unordered_map>
24 #include <algorithm>
25 #include <cstdlib>
26 
27 using namespace std;
28 using namespace Belle2;
29 
30 namespace {
36  void cleanDataStore()
37  {
38  DataStore::Instance().reset();
39  }
40 
44  void fixAbsorbObjects(TClonesArray* from, TClonesArray* to)
45  {
46  to->AbsorbObjects(from, 0, from->GetEntriesFast() - 1);
47  }
48 }
49 
50 bool DataStore::s_DoCleanup = false;
51 
52 DataStore& DataStore::Instance()
53 {
54  static DataStore instance;
55  return instance;
56 }
57 
58 
59 DataStore::DataStore() : m_initializeActive(true), m_dependencyMap(new DependencyMap)
60 {
61 }
62 
64 {
65  if (s_DoCleanup) {
66  //release all memory in data store
67  reset();
68  }
69  delete m_dependencyMap;
70 }
71 
73 {
74  B2DEBUG(31, "DataStore::reset(): Removing all elements from DataStore");
75  m_initializeActive = true;
77 
78  for (int i = 0; i < c_NDurabilityTypes; i++)
79  reset((EDurability)i);
80 
82 }
83 
84 void DataStore::reset(EDurability durability)
85 {
86  m_storeEntryMap.reset(durability);
87 
88  //invalidate any cached relations (expect RelationArrays to remain valid)
90 }
91 
93 {
94  m_initializeActive = active;
95 
96  static bool firstCall = true;
97  if (firstCall) {
98  atexit(cleanDataStore);
99  firstCall = false;
100  }
101 }
102 
103 TClass* DataStore::getTClassFromDefaultObjectName(const std::string& objectName)
104 {
105  // First look for an name without the namespace Belle2::
106  TClass* cl = TClass::GetClass(("Belle2::" + objectName).c_str());
107  if (not cl) {
108  // If this fails look for a name that already has the full namespace.
109  cl = TClass::GetClass(objectName.c_str());
110  }
111  return cl;
112 }
113 
114 TClass* DataStore::getTClassFromDefaultArrayName(const std::string& arrayName)
115 {
116  if (arrayName.empty()) {
117  return nullptr;
118  } else if ('s' == arrayName.back()) {
119  std::string objectName = arrayName.substr(0, arrayName.size() - 1);
121  } else {
122  return nullptr;
123  }
124 }
125 
126 std::string DataStore::defaultObjectName(const std::string& classname)
127 {
128  const static string gfclass = "genfit::Track";
129  const static string gfobjectname = "GF2Track";
130  if (classname == gfclass)
131  return gfobjectname;
132  //Strip qualifiers like namespaces
133  size_t colon = classname.rfind(':');
134  if (colon != std::string::npos) {
135  return classname.substr(colon + 1);
136  }
137  return classname;
138 }
139 
140 
141 std::string DataStore::defaultObjectName(const TClass* t)
142 {
143  B2ASSERT("Cannot deduce default object name from null pointer TClass", t);
144  const std::string s = defaultObjectName(t->GetName());
145  return s;
146 }
147 
148 
149 std::string DataStore::objectName(const TClass* t, const std::string& name)
150 {
151  return ((name.empty()) ? defaultObjectName(t) : name);
152 }
153 
154 
155 std::string DataStore::defaultArrayName(const TClass* t)
156 {
157  const std::string s = defaultArrayName(defaultObjectName(t));
158  return s;
159 }
160 
161 
162 std::string DataStore::arrayName(const TClass* t, const std::string& name)
163 {
164  return ((name.empty()) ? defaultArrayName(t) : name);
165 }
166 
167 
168 bool DataStore::checkType(const StoreEntry& entry, const StoreAccessorBase& accessor) const
169 {
170  // Check whether the existing entry and the requested object are both arrays or both single objects
171  const char* entryType = (entry.isArray) ? "array" : "object";
172  if (entry.isArray != accessor.isArray()) {
173  B2FATAL("Existing entry '" << entry.name << "' is an " << entryType << " and the requested one an " << ((
174  accessor.isArray()) ? "array" : "object"));
175  }
176 
177  // Check whether the existing entry has the same type
178  const TClass* entryClass = entry.objClass;
179  if (!entryClass->InheritsFrom(accessor.getClass())) {
180  B2FATAL("Existing " << accessor.readableName() << " of type " << entryClass->GetName() << " doesn't match requested type " <<
181  accessor.getClass()->GetName());
182  }
183 
184  return true;
185 }
186 
187 
188 bool DataStore::registerEntry(const std::string& name, EDurability durability,
189  TClass* objClass, bool array, EStoreFlags storeFlags)
190 {
191  const StoreAccessorBase accessor(name, durability, objClass, array);
192  // Check whether this method is called in the initialization phase
193  if (!m_initializeActive) {
194  B2ERROR("Attempt to register " << accessor.readableName() <<
195  " outside of the initialization phase. Please move calls to registerInDataStore() into your Module's initialize() function.");
196  return false;
197  }
198  const bool dontwriteout = storeFlags & c_DontWriteOut;
199 
200  //add to current module's outputs
201  m_dependencyMap->getCurrentModuleInfo().addEntry(name, DependencyMap::c_Output, (objClass == RelationContainer::Class()));
202 
203  // Check whether the map entry already exists
204  const auto& it = m_storeEntryMap[durability].find(name);
205  if (it != m_storeEntryMap[durability].end()) {
206  StoreEntry& entry = it->second;
207 
208  // Complain about existing entry
209  if (storeFlags & c_ErrorIfAlreadyRegistered) {
210  B2ERROR("An " << accessor.readableName() << " of type " << entry.object->ClassName() <<
211  " was already registered before. (Multiple calls to registerInDataStore() are fine if the c_ErrorIfAlreadyRegistered flag is not set. For objects you will want to make sure that you don't discard existing data from other modules in that case.");
212  return false;
213  }
214 
215  // Check whether the types match
216  if (!checkType(entry, accessor)) return false;
217 
218  // Check whether the persistency type matches
219  if (entry.dontWriteOut != dontwriteout) {
220  B2WARNING("Existing " << accessor.readableName() << " has different persistency type than requested. Changing to " <<
221  (dontwriteout ? "c_DontWriteOut" : "c_WriteOut") << ".");
222  entry.dontWriteOut = dontwriteout;
223  }
224 
225  B2DEBUG(100, "An " << accessor.readableName() << " was registered once more.");
226  return true;
227  }
228 
229  // check reserved names
230  if (array and name == "ALL") {
231  B2ERROR("Creating an array with the reserved name 'ALL' is not allowed!");
232  return false;
233  }
234 
235  // Add the DataStore entry
236  m_storeEntryMap[durability][name] = StoreEntry(array, objClass, name, dontwriteout);
237 
238  B2DEBUG(100, "Successfully registered " << accessor.readableName());
239  return true;
240 }
241 
242 bool DataStore::registerRelation(const StoreAccessorBase& fromArray, const StoreAccessorBase& toArray, EDurability durability,
243  EStoreFlags storeFlags, const std::string& namedRelation)
244 {
245  if (!fromArray.isArray())
246  B2FATAL(fromArray.readableName() << " is not an array!");
247  if (!toArray.isArray())
248  B2FATAL(toArray.readableName() << " is not an array!");
249 
250  // check the the namedRelation only contains regular characters
251  if (!std::regex_match(namedRelation, m_regexNamedRelationCheck))
252  B2FATAL("Named Relations can only contain alphabetic characters, given was: " << namedRelation);
253 
254  const std::string& relName = relationName(fromArray.getName(), toArray.getName(), namedRelation);
255  /*
256  if ((fromArray.notWrittenOut() or toArray.notWrittenOut()) and !(storeFlags & c_DontWriteOut)) {
257  B2WARNING("You're trying to register a persistent relation " << relName << " from/to an array which is not written out (DataStore::c_DontWriteOut flag)! Relation will also not be saved!");
258  storeFlags |= c_DontWriteOut;
259  }
260  */
261 
262  if (fromArray.getDurability() > durability or toArray.getDurability() > durability) {
263  B2FATAL("Tried to create a relation '" << relName << "' with a durability larger than the StoreArrays it relates");
264  }
265 
266  return DataStore::Instance().registerEntry(relName, durability, RelationContainer::Class(), false, storeFlags);
267 }
268 
269 bool DataStore::hasRelation(const StoreAccessorBase& fromArray, const StoreAccessorBase& toArray, EDurability durability,
270  const std::string& namedRelation)
271 {
272  // check that the input makes sense
273  if (!fromArray.isArray())
274  B2FATAL(fromArray.readableName() << " is not an array!");
275  if (!toArray.isArray())
276  B2FATAL(toArray.readableName() << " is not an array!");
277 
278  // check the the namedRelation only contains regular characters
279  if (!std::regex_match(namedRelation, m_regexNamedRelationCheck))
280  B2FATAL("Named Relations can only contain alphabetic characters, given was: " << namedRelation);
281 
282  // get the internal relation name from the name provided
283  const std::string& realname = relationName(fromArray.getName(), toArray.getName(), namedRelation);
284 
285  // check whether the map entry exists
286  const auto& it = m_storeEntryMap[durability].find(realname);
287  if (it != m_storeEntryMap[durability].end()) return true;
288 
289  return false;
290 }
291 
293 {
294  const auto& it = m_storeEntryMap[accessor.getDurability()].find(accessor.getName());
295 
296  if (it != m_storeEntryMap[accessor.getDurability()].end() and checkType((it->second), accessor)) {
297  return &(it->second);
298  } else {
299  return nullptr;
300  }
301 }
302 
303 
304 TObject** DataStore::getObject(const StoreAccessorBase& accessor)
305 {
306  StoreEntry* entry = getEntry(accessor);
307  if (!entry) {
308  return nullptr;
309  }
310  return &(entry->ptr);
311 }
312 
313 
314 bool DataStore::createObject(TObject* object, bool replace, const StoreAccessorBase& accessor)
315 {
316  StoreEntry* entry = getEntry(accessor);
317  if (!entry) {
318  B2ERROR("No " << accessor.readableName() <<
319  " exists in the DataStore, did you forget to register it in your Module's initialize() function? Note: direct accesses to it will crash!");
320  return false;
321  }
322 
323  if (entry->ptr && !replace && object != entry->object) {
324  B2ERROR("An " << accessor.readableName() << " was already created in the DataStore.");
325  return false;
326  }
327 
328  if (object) {
329  if (object != entry->object) {
330  delete entry->object;
331  entry->object = object;
332  }
333  entry->ptr = entry->object;
334  } else {
335  entry->recreate();
336  }
337 
338  return true;
339 }
340 
342 {
343  StoreEntry* fromEntry = getEntry(from);
344  StoreEntry* toEntry = getEntry(to);
345  if (!fromEntry)
346  B2FATAL("No " << from.readableName() << " exists in the DataStore!");
347  if (!toEntry)
348  B2FATAL("No " << to.readableName() << " exists in the DataStore!");
349  if (from.isArray() != to.isArray() or from.getClass() != to.getClass())
350  B2FATAL("cannot replace " << to.readableName() << " with " << from.readableName() << " (incompatible types)!");
351 
352  if (!fromEntry->ptr) {
353  //since we don't need to move any data, just invalidate toEntry instead.
354  toEntry->ptr = nullptr;
355  } else if (fromEntry->isArray) {
356  if (!toEntry->ptr)
357  toEntry->ptr = toEntry->object;
358  toEntry->getPtrAsArray()->Delete();
359 
360  fixAbsorbObjects(fromEntry->getPtrAsArray(), toEntry->getPtrAsArray());
361  updateRelationsObjectCache(*toEntry);
362  } else if (fromEntry->objClass == RelationContainer::Class()) {
363  if (!toEntry->ptr)
364  toEntry->ptr = toEntry->object;
365  auto* fromRel = static_cast<RelationContainer*>(fromEntry->ptr);
366  auto* toRel = static_cast<RelationContainer*>(toEntry->ptr);
367 
368  toRel->elements().Delete();
369 
370  fixAbsorbObjects(&fromRel->elements(), &toRel->elements());
371 
372  //indices need a rebuild
373  fromRel->setModified(true);
374  toRel->setModified(true);
375  } else {
376  delete toEntry->object;
377 
378  toEntry->object = fromEntry->ptr->Clone();
379  toEntry->ptr = toEntry->object;
380 
381  fromEntry->ptr = nullptr;
382  }
383 }
384 
386 {
387  const TClonesArray* array = static_cast<TClonesArray*>(entry.ptr);
388  const int nEntries = array->GetEntriesFast();
389  for (int i = 0; i < nEntries; i++) {
390  auto* relobj = static_cast<RelationsObject*>(array->At(i));
391  relobj->m_cacheArrayIndex = i;
392  relobj->m_cacheDataStoreEntry = &entry;
393  }
394 }
395 
396 bool DataStore::findStoreEntry(const TObject* object, DataStore::StoreEntry*& entry, int& index)
397 {
398  if (!entry or index < 0) {
399  //usually entry/index should be passed for RelationsObject,
400  //but there are exceptions -> let's check again
401  const auto* relObj = dynamic_cast<const RelationsObject*>(object);
402  if (relObj) {
403  entry = relObj->m_cacheDataStoreEntry;
404  index = relObj->m_cacheArrayIndex;
405  }
406  }
407  // check whether the cached information is (still) valid
408  if (entry && entry->ptr && (index >= 0)) {
409  const TClonesArray* array = static_cast<TClonesArray*>(entry->ptr);
410  if (array->At(index) == object) return true;
411  B2INFO("findStoreEntry: cached index invalid, probably harmless but odd : " << entry->name << " idx " << index);
412  index = array->IndexOf(object);
413  if (index >= 0) return true;
414  B2INFO("findStoreEntry: cached entry was also wrong");
415  }
416  entry = nullptr;
417  index = -1;
418 
419  //searching for nullptr should be safe
420  if (!object)
421  return false;
422 
423  // search for the object and set the entry and index
424  const TClass* objectClass = object->IsA();
425  for (auto& mapEntry : m_storeEntryMap[c_Event]) {
426  if (mapEntry.second.ptr && mapEntry.second.isArray) {
427  const TClass* arrayClass = mapEntry.second.objClass;
428  if (arrayClass != objectClass)
429  continue;
430 
431  const TClonesArray* array = static_cast<TClonesArray*>(mapEntry.second.ptr);
432  if (object == array->Last()) {
433  //quickly find entry if it's at the end of the array
434  index = array->GetLast();
435  } else {
436  if (arrayClass->InheritsFrom(RelationsObject::Class())) {
437  //update cache for entire array
438  updateRelationsObjectCache(mapEntry.second);
439 
440  //if found, m_cacheArrayIndex is now correct, otherwise still -1
441  StoreEntry* objEntry = static_cast<const RelationsObject*>(object)->m_cacheDataStoreEntry;
442  index = static_cast<const RelationsObject*>(object)->m_cacheArrayIndex;
443  if (index >= 0 and objEntry) {
444  //if the cache of 'object' is filled, make sure to also set entry!
445  entry = objEntry;
446  return true;
447  }
448  } else {
449  //not a RelationsObject, so no caching
450  index = array->IndexOf(object);
451  }
452  }
453 
454  if (index >= 0) {
455  entry = &mapEntry.second;
456  return true;
457  }
458  }
459  }
460  return false;
461 }
462 
463 const std::vector<std::string>& DataStore::getArrayNames(const std::string& name, const TClass* arrayClass,
464  EDurability durability) const
465 {
466  static vector<string> arrayNames;
467  arrayNames.clear();
468  if (name.empty()) {
469  static std::unordered_map<const TClass*, string> classToArrayName;
470  const auto& it = classToArrayName.find(arrayClass);
471  if (it != classToArrayName.end()) {
472  arrayNames.emplace_back(it->second);
473  } else {
474  const std::string& result = defaultArrayName(arrayClass->GetName());
475  classToArrayName[arrayClass] = result;
476  arrayNames.emplace_back(result);
477  }
478  } else if (name == "ALL") {
479  for (auto& mapEntry : m_storeEntryMap[durability]) {
480  if (mapEntry.second.object and mapEntry.second.isArray and mapEntry.second.objClass->InheritsFrom(arrayClass)) {
481  arrayNames.emplace_back(mapEntry.second.name);
482  }
483  }
484  } else {
485  arrayNames.emplace_back(name);
486  }
487  return arrayNames;
488 }
489 
490 void DataStore::addRelation(const TObject* fromObject, StoreEntry*& fromEntry, int& fromIndex, const TObject* toObject,
491  StoreEntry*& toEntry, int& toIndex, float weight, const std::string& namedRelation)
492 {
493  if (!fromObject or !toObject)
494  return;
495 
496  // get entry from which the relation points
497  if (!findStoreEntry(fromObject, fromEntry, fromIndex)) {
498  B2FATAL("Couldn't find from-side entry for relation between " << fromObject->ClassName() << " and " << toObject->ClassName() <<
499  ". Please make sure the object is part of a StoreArray before adding a relation.");
500  }
501 
502  // get entry to which the relation points
503  if (!findStoreEntry(toObject, toEntry, toIndex)) {
504  B2FATAL("Couldn't find to-side entry for relation between " << fromObject->ClassName() << " and " << toObject->ClassName() <<
505  ". Please make sure the object is part of a StoreArray before adding a relation.");
506  }
507 
508  // get the relations from -> to
509  const string& relationsName = relationName(fromEntry->name, toEntry->name, namedRelation);
510  const StoreEntryIter& it = m_storeEntryMap[c_Event].find(relationsName);
511  if (it == m_storeEntryMap[c_Event].end()) {
512  B2FATAL("No relation '" << relationsName <<
513  "' found. Please register it (using StoreArray::registerRelationTo()) before trying to add relations.");
514  }
515  StoreEntry* entry = &(it->second);
516 
517  // auto create relations if needed (both if null pointer, or uninitialised object read from TTree)
518  if (!entry->ptr)
519  entry->recreate();
520  auto* relContainer = static_cast<RelationContainer*>(entry->ptr);
521  if (relContainer->isDefaultConstructed()) {
522  relContainer->setFromName(fromEntry->name);
523  relContainer->setFromDurability(c_Event);
524  relContainer->setToName(toEntry->name);
525  relContainer->setToDurability(c_Event);
526  }
527 
528  // add relation
529  TClonesArray& relations = relContainer->elements();
530  new(relations.AddrAt(relations.GetLast() + 1)) RelationElement(fromIndex, toIndex, weight);
531 
532  std::shared_ptr<RelationIndexContainer<TObject, TObject>> relIndex =
533  RelationIndexManager::Instance().getIndexIfExists<TObject, TObject>(relationsName, c_Event);
534  if (relIndex) {
535  // add it to index (so we avoid expensive rebuilding later)
536  relIndex->index().emplace(fromIndex, toIndex, fromObject, toObject, weight);
537  } else {
538  //mark for rebuilding later on
539  relContainer->setModified(true);
540  }
541 }
542 
544  int& index, const TClass* withClass, const std::string& withName, const std::string& namedRelation)
545 {
546  if (searchSide == c_BothSides) {
547  auto result = getRelationsWith(c_ToSide, object, entry, index, withClass, withName, namedRelation);
548  const auto& fromResult = getRelationsWith(c_FromSide, object, entry, index, withClass, withName, namedRelation);
549  result.add(fromResult);
550  return result;
551  }
552 
553  std::vector<RelationEntry> result;
554 
555  // get StoreEntry for 'object'
556  if (!findStoreEntry(object, entry, index)) return RelationVectorBase();
557 
558  // get names of store arrays to search
559  const std::vector<string>& names = getArrayNames(withName, withClass);
560  vector<string> relationNames;
561 
562  // loop over found store arrays
563  for (const std::string& name : names) {
564  // get the relations from -> to
565  const string& relationsName = (searchSide == c_ToSide) ? relationName(entry->name, name, namedRelation) : relationName(name,
566  entry->name, namedRelation);
567  RelationIndex<TObject, TObject> relIndex(relationsName, c_Event);
568  if (!relIndex)
569  continue;
570 
571  const size_t prevsize = result.size();
572 
573  //get relations with object
574  if (searchSide == c_ToSide) {
575  for (const auto& rel : relIndex.getElementsFrom(object)) {
576  auto* const toObject = const_cast<TObject*>(rel.to);
577  if (toObject)
578  result.emplace_back(toObject, rel.weight);
579  }
580  } else {
581  for (const auto& rel : relIndex.getElementsTo(object)) {
582  auto* const fromObject = const_cast<TObject*>(rel.from);
583  if (fromObject)
584  result.emplace_back(fromObject, rel.weight);
585  }
586  }
587 
588  if (result.size() != prevsize)
589  relationNames.push_back(relationsName);
590  }
591 
592  return RelationVectorBase(entry->name, index, result, relationNames);
593 }
594 
595 RelationEntry DataStore::getRelationWith(ESearchSide searchSide, const TObject* object, DataStore::StoreEntry*& entry, int& index,
596  const TClass* withClass, const std::string& withName, const std::string& namedRelation)
597 {
598  if (searchSide == c_BothSides) {
599  RelationEntry result = getRelationWith(c_ToSide, object, entry, index, withClass, withName, namedRelation);
600  if (!result.object) {
601  result = getRelationWith(c_FromSide, object, entry, index, withClass, withName, namedRelation);
602  }
603  return result;
604  }
605 
606  // get StoreEntry for 'object'
607  if (!findStoreEntry(object, entry, index)) return RelationEntry(nullptr);
608 
609  // get names of store arrays to search
610  const std::vector<string>& names = getArrayNames(withName, withClass);
611 
612  // loop over found store arrays
613  for (const std::string& name : names) {
614  // get the relations from -> to
615  const string& relationsName = (searchSide == c_ToSide) ? relationName(entry->name, name, namedRelation) : relationName(name,
616  entry->name, namedRelation);
617  RelationIndex<TObject, TObject> relIndex(relationsName, c_Event);
618  if (!relIndex)
619  continue;
620 
621  // get first element
622  if (searchSide == c_ToSide) {
623  const RelationIndex<TObject, TObject>::Element* element = relIndex.getFirstElementFrom(object);
624  if (element && element->to) {
625  return RelationEntry(const_cast<TObject*>(element->to), element->weight);
626  }
627  } else {
628  const RelationIndex<TObject, TObject>::Element* element = relIndex.getFirstElementTo(object);
629  if (element && element->from) {
630  return RelationEntry(const_cast<TObject*>(element->from), element->weight);
631  }
632  }
633  }
634 
635  return RelationEntry(nullptr);
636 }
637 
638 std::vector<std::string> DataStore::getListOfRelatedArrays(const StoreAccessorBase& array) const
639 {
640  std::vector<std::string> arrays;
641  if (!array.isArray()) {
642  B2ERROR("getListOfRelatedArrays(): " << array.readableName() << " is not an array!");
643  return arrays;
644  }
645 
646  //loop over all arrays
647  EDurability durability = array.getDurability();
648  for (auto& mapEntry : m_storeEntryMap[durability]) {
649  if (mapEntry.second.isArray) {
650  const std::string& name = mapEntry.second.name;
651 
652  //check both from & to 'array'
653  for (int searchSide = 0; searchSide < c_BothSides; searchSide++) {
654  const string& relationsName = (searchSide == c_ToSide) ? relationName(array.getName(), name) : relationName(name, array.getName());
655  const StoreEntryConstIter& it = m_storeEntryMap[durability].find(relationsName);
656  if (it != m_storeEntryMap[durability].end())
657  arrays.emplace_back(name);
658  }
659  }
660  }
661 
662  return arrays;
663 }
664 std::vector<std::string> DataStore::getListOfArrays(const TClass* arrayClass, EDurability durability) const
665 {
666  return getArrayNames("ALL", arrayClass, durability);
667 }
668 
669 std::vector<std::string> DataStore::getListOfObjects(const TClass* objClass, EDurability durability) const
670 {
671  vector<string> list;
673  for (const auto& entrypair : map) {
674  if (!entrypair.second.isArray) {
675  const TObject* obj = entrypair.second.object;
676  if (dynamic_cast<const RelationContainer*>(obj))
677  continue; //ignore relations in list
678 
679  if (obj and obj->IsA()->InheritsFrom(objClass))
680  list.emplace_back(entrypair.first);
681  }
682  }
683  return list;
684 }
685 
687 {
688  B2DEBUG(100, "Invalidating objects for durability " << durability);
689  m_storeEntryMap.invalidateData(durability);
691 }
692 
694 {
695  if (m_initializeActive) {
697  (accessor.getClass() == RelationContainer::Class()));
698  } else {
699  B2FATAL("Attempt to require input " << accessor.readableName() <<
700  " outside of the initialization phase. Please move isRequired() calls into your Module's initialize() function.");
701  }
702 
703  if (!getEntry(accessor)) {
704  B2ERROR("The required " << accessor.readableName() << " does not exist. Maybe you forgot the module that registers it?");
705  return false;
706  }
707  return true;
708 }
709 
711 {
712  if (m_initializeActive) {
714  (accessor.getClass() == RelationContainer::Class()));
715  }
716 
717  return (getEntry(accessor) != nullptr);
718 }
719 
720 bool DataStore::requireRelation(const StoreAccessorBase& fromArray, const StoreAccessorBase& toArray, EDurability durability,
721  std::string const& namedRelation)
722 {
723  if (!m_initializeActive) {
724  B2FATAL("Attempt to require relation " << fromArray.readableName() << " -> " << toArray.readableName() <<
725  " outside of the initialization phase. Please move requireRelationTo() calls into your Module's initialize() function.");
726  }
727 
728  if (!fromArray.isArray())
729  B2FATAL(fromArray.readableName() << " is not an array!");
730  if (!toArray.isArray())
731  B2FATAL(toArray.readableName() << " is not an array!");
732 
733  const std::string& relName = relationName(fromArray.getName(), toArray.getName(), namedRelation);
734  return DataStore::Instance().requireInput(StoreAccessorBase(relName, durability, RelationContainer::Class(), false));
735 }
736 
737 bool DataStore::optionalRelation(const StoreAccessorBase& fromArray, const StoreAccessorBase& toArray, EDurability durability,
738  std::string const& namedRelation)
739 {
740  if (!fromArray.isArray())
741  B2FATAL(fromArray.readableName() << " is not an array!");
742  if (!toArray.isArray())
743  B2FATAL(toArray.readableName() << " is not an array!");
744 
745  const std::string& relName = relationName(fromArray.getName(), toArray.getName(), namedRelation);
746  return DataStore::Instance().optionalInput(StoreAccessorBase(relName, durability, RelationContainer::Class(), false));
747 }
748 
749 
750 void DataStore::createNewDataStoreID(const std::string& id)
751 {
753 }
754 
755 std::string DataStore::currentID() const
756 {
757  return m_storeEntryMap.currentID();
758 }
759 
760 void DataStore::switchID(const std::string& id)
761 {
762  if (id == m_storeEntryMap.currentID())
763  return;
764 
765  //remember to clear caches
767 
769 }
770 
771 void DataStore::copyEntriesTo(const std::string& id, const std::vector<std::string>& entrylist_event)
772 {
773  m_storeEntryMap.copyEntriesTo(id, entrylist_event);
774 }
775 
776 void DataStore::copyContentsTo(const std::string& id, const std::vector<std::string>& entrylist_event)
777 {
778  m_storeEntryMap.copyContentsTo(id, entrylist_event);
779 }
780 
781 
782 DataStore::SwitchableDataStoreContents::SwitchableDataStoreContents():
783  m_entries(1)
784 {
785  m_idToIndexMap[""] = 0;
786 }
787 
789 {
790  //does this id already exist?
791  if (m_idToIndexMap.count(id) > 0)
792  return;
793 
794  copyEntriesTo(id);
795  //copy actual contents, fixing pointers
796  copyContentsTo(id);
797 }
798 void DataStore::SwitchableDataStoreContents::copyEntriesTo(const std::string& id, const std::vector<std::string>& entrylist_event)
799 {
800  int targetidx;
801  if (m_idToIndexMap.count(id) == 0) {
802  //new DataStore & full copy
803  if (!entrylist_event.empty())
804  B2FATAL("entrlylist_event given for new DS id. This shouldn't happen, report to framework author.");
805  targetidx = m_entries.size();
806  m_idToIndexMap[id] = targetidx;
807 
808  //copy entries
809  m_entries.push_back(m_entries[m_currentIdx]);
810  } else if (!entrylist_event.empty()) {
811  //copy only given entries (in c_Event)
812  targetidx = m_idToIndexMap.at(id);
813  for (const auto& entryname : entrylist_event) {
814  if (m_entries[m_currentIdx][c_Event].count(entryname) == 0)
815  continue;
816  if (m_entries[targetidx][c_Event].count(entryname) != 0) {
817  B2WARNING("Independent path: entry '" << entryname << "' already exists in DataStore '" << id <<
818  "'! This will likely break something.");
819  }
820  m_entries[targetidx][c_Event][entryname] = m_entries[m_currentIdx][c_Event][entryname];
821  }
822  } else {
823  B2FATAL("no entrlylist_event given, not new DS id. This shouldn't happen, report to framework author.");
824  }
825 
826  //fix duplicate pointers
827  for (int iDurability = 0; iDurability < c_NDurabilityTypes; iDurability++) {
828  for (auto& entrypair : m_entries[targetidx][iDurability]) {
829  if (not entrypair.second.object)
830  B2FATAL("createNewDataStoreID(): object '" << entrypair.first << " already null (this should never happen).");
831  if (!entrylist_event.empty()) {
832  //skip all entries of other durabilities
833  if (iDurability != c_Event)
834  continue;
835  //skip all entries not found in entrylist_event
836  if (std::find(entrylist_event.begin(), entrylist_event.end(), entrypair.first) == entrylist_event.end())
837  continue;
838  }
839 
840  entrypair.second.object = nullptr; //remove duplicate ownership
841  entrypair.second.ptr = nullptr;
842  }
843  }
844 }
845 
846 void DataStore::SwitchableDataStoreContents::copyContentsTo(const std::string& id, const std::vector<std::string>& entrylist_event)
847 {
848  int targetidx = m_idToIndexMap.at(id);
849  auto& targetMaps = m_entries[targetidx];
850  const auto& sourceMaps = m_entries[m_currentIdx];
851 
852  for (int iDurability = 0; iDurability < c_NDurabilityTypes; iDurability++) {
853  for (const auto& entrypair : sourceMaps[iDurability]) {
854  const StoreEntry& fromEntry = entrypair.second;
855  //does this exist in target?
856  if (targetMaps[iDurability].count(fromEntry.name) == 0) {
857  continue;
858  }
859 
860  if (!entrylist_event.empty()) {
861  //skip all entries of other durabilities
862  if (iDurability != c_Event)
863  continue;
864  //skip all entries not found in entrylist_event
865  if (std::find(entrylist_event.begin(), entrylist_event.end(), fromEntry.name) == entrylist_event.end())
866  continue;
867  }
868 
869  StoreEntry& target = targetMaps[iDurability][fromEntry.name];
870 
871  //copy contents into target object
872  if (not fromEntry.ptr) {
873  if (!target.object)
874  target.recoverFromNullObject();
875  target.ptr = nullptr;
876  } else {
877  //TODO there is some optimisation opportunity here, e.g. by only cloning the entries of a TClonesArray instead of the array itself
878  delete target.object;
879  target.object = fromEntry.object->Clone();
880  target.ptr = target.object;
881  }
882  }
883  }
884 
885 }
886 
888 {
889  //switch
890  m_currentID = id;
891  m_currentIdx = m_idToIndexMap.at(id);
892 
893  if ((unsigned int)m_currentIdx >= m_entries.size())
894  B2FATAL("out of bounds in SwitchableDataStoreContents::switchID(): " << m_currentIdx << " >= size " << m_entries.size());
895 }
896 
898 {
899  for (int i = 0; i < c_NDurabilityTypes; i++)
900  reset((EDurability)i);
901 
902  m_entries.clear();
903  m_entries.resize(1);
904  m_idToIndexMap.clear();
905  m_idToIndexMap[""] = 0;
906  m_currentID = "";
907  m_currentIdx = 0;
908 }
909 
911 {
912  for (auto& map : m_entries) {
913  for (auto& mapEntry : map[durability])
914  delete mapEntry.second.object;
915  map[durability].clear();
916  }
917 }
918 
920 {
921  for (auto& map : m_entries)
922  for (auto& mapEntry : map[durability])
923  mapEntry.second.invalidate();
924 }
const std::string & currentID() const
returns ID of current DataStore.
Definition: DataStore.h:592
void createNewDataStoreID(const std::string &id)
creates new datastore with given id, copying the registered objects/arrays from the current one.
Definition: DataStore.cc:788
void switchID(const std::string &id)
switch to DataStore with given ID.
Definition: DataStore.cc:887
std::map< std::string, int > m_idToIndexMap
Maps DataStore ID to index in m_entries.
Definition: DataStore.h:601
void copyContentsTo(const std::string &id, const std::vector< std::string > &entrylist_event={})
copy contents (actual array / object contents) of current DataStore to the DataStore with given ID.
Definition: DataStore.cc:846
void clear()
same as calling reset() for all durabilities + all non-default datastore IDs are removed.
Definition: DataStore.cc:897
void reset(EDurability durability)
Frees memory occupied by data store items and removes all objects from the map.
Definition: DataStore.cc:910
void invalidateData(EDurability durability)
Clears all registered StoreEntry objects of a specified durability, invalidating all objects.
Definition: DataStore.cc:919
void copyEntriesTo(const std::string &id, const std::vector< std::string > &entrylist_event={})
copy entries (not contents) of current DataStore to the DataStore with given ID.
Definition: DataStore.cc:798
In the store you can park objects that have to be accessed by various modules.
Definition: DataStore.h:51
static std::string objectName(const TClass *t, const std::string &name)
Return the storage name for an object of the given TClass and name.
Definition: DataStore.cc:149
StoreEntryMap::const_iterator StoreEntryConstIter
const_iterator for a StoreEntry map.
Definition: DataStore.h:89
std::vector< std::string > getListOfRelatedArrays(const StoreAccessorBase &array) const
Returns a list of names of arrays which have registered relations that point to or from 'array'.
Definition: DataStore.cc:638
void createNewDataStoreID(const std::string &id)
creates new datastore with given id, copying the registered objects/arrays from the current one.
Definition: DataStore.cc:750
bool findStoreEntry(const TObject *object, StoreEntry *&entry, int &index)
Find an object in an array in the data store.
Definition: DataStore.cc:396
const std::vector< std::string > & getArrayNames(const std::string &arrayName, const TClass *arrayClass, EDurability durability=c_Event) const
Returns a vector with the names of store arrays matching the given name and class.
Definition: DataStore.cc:463
static std::string defaultObjectName()
Return the default storage name for an object of the given type.
Definition: DataStore.h:127
bool checkType(const StoreEntry &entry, const StoreAccessorBase &accessor) const
Check whether the given entry and the requested class match.
Definition: DataStore.cc:168
bool optionalRelation(const StoreAccessorBase &fromArray, const StoreAccessorBase &toArray, EDurability durability, std::string const &namedRelation)
Register the given relation as an optional input.
Definition: DataStore.cc:737
EStoreFlags
Flags describing behaviours of objects etc.
Definition: DataStore.h:69
@ c_DontWriteOut
Object/array should be NOT saved by output modules.
Definition: DataStore.h:71
@ c_ErrorIfAlreadyRegistered
If the object/array was already registered, produce an error (aborting initialisation).
Definition: DataStore.h:72
void switchID(const std::string &id)
switch to DataStore with given ID.
Definition: DataStore.cc:760
StoreEntryMap::iterator StoreEntryIter
Iterator for a StoreEntry map.
Definition: DataStore.h:88
const std::regex m_regexNamedRelationCheck
Regular expression to check that no special characters and no white spaces are in the string given fo...
Definition: DataStore.h:619
static TClass * getTClassFromDefaultArrayName(const std::string &arrayName)
Tries to deduce the TClass from a default array name, which is generally the name of the C++ class wi...
Definition: DataStore.cc:114
void addRelation(const TObject *fromObject, StoreEntry *&fromEntry, int &fromIndex, const TObject *toObject, StoreEntry *&toEntry, int &toIndex, float weight, const std::string &namedRelation)
Add a relation from an object in a store array to another object in a store array.
Definition: DataStore.cc:490
bool registerRelation(const StoreAccessorBase &fromArray, const StoreAccessorBase &toArray, EDurability durability, EStoreFlags storeFlags, const std::string &namedRelation)
Register a relation in the DataStore map.
Definition: DataStore.cc:242
static TClass * getTClassFromDefaultObjectName(const std::string &objectName)
Tries to deduce the TClass from a default object name, which is generally the name of the C++ class.
Definition: DataStore.cc:103
StoreEntryMap & getStoreEntryMap(EDurability durability)
Get a reference to the object/array map.
Definition: DataStore.h:326
DependencyMap * m_dependencyMap
Collect information about the dependencies between modules.
Definition: DataStore.h:622
~DataStore()
Destructor.
Definition: DataStore.cc:63
static std::string defaultArrayName()
Return the default storage name for an array of the given type.
Definition: DataStore.h:157
std::vector< std::string > getListOfArrays(const TClass *arrayClass, EDurability durability) const
Returns a list of names of arrays which are of type (or inherit from) arrayClass.
Definition: DataStore.cc:664
ESearchSide
Which side of relations should be returned?
Definition: DataStore.h:76
@ c_BothSides
Combination of c_FromSide and c_ToSide.
Definition: DataStore.h:79
@ c_FromSide
Return relations/objects pointed from (to a given object).
Definition: DataStore.h:77
@ c_ToSide
Return relations/objects pointed to (from a given object).
Definition: DataStore.h:78
static void updateRelationsObjectCache(StoreEntry &entry)
For an array containing RelationsObjects, update index and entry cache for entire contents.
Definition: DataStore.cc:385
static const int c_NDurabilityTypes
Number of Durability Types.
Definition: DataStore.h:63
std::vector< std::string > getListOfObjects(const TClass *objClass, EDurability durability) const
Returns a list of names of StoreObjPtr-objects whose class is (or inherits from) objClass.
Definition: DataStore.cc:669
void copyContentsTo(const std::string &id, const std::vector< std::string > &entrylist_event={})
copy contents (actual array / object contents) of current DataStore to the DataStore with given ID.
Definition: DataStore.cc:776
bool requireInput(const StoreAccessorBase &accessor)
Produce ERROR message if no entry of the given type is registered in the DataStore.
Definition: DataStore.cc:693
EDurability
Durability types.
Definition: DataStore.h:58
@ c_Event
Different object in each event, all objects/arrays are invalidated after event() function has been ca...
Definition: DataStore.h:59
Belle2::StoreEntry StoreEntry
Wraps a stored array/object, stored under unique (name, durability) key.
Definition: DataStore.h:84
bool requireRelation(const StoreAccessorBase &fromArray, const StoreAccessorBase &toArray, EDurability durability, std::string const &namedRelation)
Produce ERROR message if no relation of given durability exists between fromArray and toArray (in tha...
Definition: DataStore.cc:720
std::string currentID() const
returns ID of current DataStore.
Definition: DataStore.cc:755
static DataStore & Instance()
Instance of singleton Store.
Definition: DataStore.cc:52
bool hasRelation(const StoreAccessorBase &fromArray, const StoreAccessorBase &toArray, EDurability durability, const std::string &namedRelation)
Check for the existence of a relation in the DataStore map.
Definition: DataStore.cc:269
void setInitializeActive(bool active)
Setter for m_initializeActive.
Definition: DataStore.cc:92
static std::string relationName(const std::string &fromName, const std::string &toName, std::string const &namedRelation="")
Return storage name for a relation between two arrays of the given names.
Definition: DataStore.h:180
static bool s_DoCleanup
Global flag to to decide if we can do normal cleanup.
Definition: DataStore.h:100
void reset()
Clears contents of the datastore (all durabilities)
Definition: DataStore.cc:72
StoreEntry * getEntry(const StoreAccessorBase &accessor)
Check whether an entry with the correct type is registered in the DataStore map and return it.
Definition: DataStore.cc:292
void invalidateData(EDurability durability)
Clears all registered StoreEntry objects of a specified durability, invalidating all objects.
Definition: DataStore.cc:686
RelationVectorBase getRelationsWith(ESearchSide searchSide, const TObject *object, StoreEntry *&entry, int &index, const TClass *withClass, const std::string &withName, const std::string &namedRelation)
Get the relations between an object and other objects in a store array.
Definition: DataStore.cc:543
void copyEntriesTo(const std::string &id, const std::vector< std::string > &entrylist_event={})
copy entries (not contents) of current DataStore to the DataStore with given ID.
Definition: DataStore.cc:771
Belle2::RelationEntry getRelationWith(ESearchSide searchSide, const TObject *object, StoreEntry *&entry, int &index, const TClass *withClass, const std::string &withName, const std::string &namedRelation)
Get the first relation between an object and another object in a store array.
Definition: DataStore.cc:595
bool createObject(TObject *object, bool replace, const StoreAccessorBase &accessor)
Create a new object/array in the DataStore or add an existing one.
Definition: DataStore.cc:314
TObject ** getObject(const StoreAccessorBase &accessor)
Get a pointer to a pointer of an object in the DataStore.
Definition: DataStore.cc:304
static std::string arrayName(const TClass *t, const std::string &name)
Return the storage name for an object of the given TClass and name.
Definition: DataStore.cc:162
bool m_initializeActive
True if modules are currently being initialized.
Definition: DataStore.h:613
bool registerEntry(const std::string &name, EDurability durability, TClass *objClass, bool array, EStoreFlags storeFlags)
Register an entry in the DataStore map.
Definition: DataStore.cc:188
bool optionalInput(const StoreAccessorBase &accessor)
Register the given object/array as an optional input.
Definition: DataStore.cc:710
SwitchableDataStoreContents m_storeEntryMap
Maps (name, durability) key to StoreEntry objects.
Definition: DataStore.h:606
void replaceData(const StoreAccessorBase &from, const StoreAccessorBase &to)
For two StoreAccessors of same type, move all data in 'from' into 'to', discarding previous contents ...
Definition: DataStore.cc:341
std::map< std::string, StoreEntry > StoreEntryMap
Map for StoreEntries.
Definition: DataStore.h:87
Collect information about the dependencies between modules.
Definition: DependencyMap.h:29
@ c_Input
required input.
Definition: DependencyMap.h:33
@ c_Output
registered output.
Definition: DependencyMap.h:35
@ c_OptionalInput
optional input.
Definition: DependencyMap.h:34
ModuleInfo & getCurrentModuleInfo()
Get info for current module.
Definition: DependencyMap.h:63
void clear()
Reset all collected data.
Definition: DependencyMap.h:69
Class to store relations between StoreArrays in the DataStore.
TClonesArray & elements()
Get reference to the elements.
void setFromName(const std::string &name)
Set name of the StoreArray we relate from.
Class to store a single element of a relation.
std::shared_ptr< RelationIndexContainer< FROM, TO > > getIndexIfExists(const std::string &name, DataStore::EDurability durability) const
if the index exists in the cache, it is returned; otherwise NULL.
static RelationIndexManager & Instance()
Returns the singleton instance.
void clear(DataStore::EDurability durability=DataStore::c_Event)
Clear the cache of RelationIndexContainers with the given durability.
void reset()
Reset the cache completely, that is clear all caches and don't even keep the Index objects around.
Provides access to fast ( O(log n) ) bi-directional lookups on a specified relation.
Definition: RelationIndex.h:76
const Element * getFirstElementFrom(const FROM &from) const
Return a pointer to the first relation Element of the given object.
range_from getElementsFrom(const FROM *from) const
Return a range of all elements pointing from the given object.
const Element * getFirstElementTo(const TO &to) const
Return a pointer to the first relation Element of the given object.
range_to getElementsTo(const TO *to) const
Return a range of all elements pointing to the given object.
base class for RelationVector<T>
Defines interface for accessing relations of objects in StoreArray.
int m_cacheArrayIndex
Cache of the index in the TClonesArray to which this object belongs.
Base class for StoreObjPtr and StoreArray for easier common treatment.
DataStore::EDurability getDurability() const
Return durability with which the object is saved in the DataStore.
const std::string & getName() const
Return name under which the object is saved in the DataStore.
std::string readableName() const
Convert this acessor into a readable string (for messages).
TClass * getClass() const
The underlying object's type.
bool isArray() const
Is this an accessor for an array?
Abstract base class for different kinds of events.
void addEntry(const std::string &name, EEntryType type, bool isRelation)
Adds given entry/relation.
Struct for relations.
Definition: RelationEntry.h:24
Wraps a stored array/object, stored under unique (name, durability) key.
Definition: StoreEntry.h:22
TObject * ptr
The pointer to the returned object, either equal to 'object' or null, depending on wether the object ...
Definition: StoreEntry.h:51
TClonesArray * getPtrAsArray() const
Return ptr cast to TClonesArray.
Definition: StoreEntry.cc:83
bool dontWriteOut
Flag that indicates whether the object should be written to the output by default.
Definition: StoreEntry.h:40
TObject * object
The pointer to the actual object.
Definition: StoreEntry.h:48
bool isArray
Flag that indicates whether the object is a TClonesArray.
Definition: StoreEntry.h:39
std::string name
Name of the entry.
Definition: StoreEntry.h:53
void recreate()
Reset stored object to defaults, set ptr to new object.
Definition: StoreEntry.cc:68
TClass * objClass
class of object.
Definition: StoreEntry.h:41