Belle II Software  release-08-01-10
DBStore.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/database/DBStore.h>
10 #include <framework/database/Database.h>
11 #include <framework/logging/Logger.h>
12 
13 #include <boost/none.hpp>
14 
15 #include <TClass.h>
16 
17 namespace Belle2 {
24  {
25  reset();
26  }
27 
29  {
30  static DBStore instance;
31  return instance;
32  }
33 
35  const TClass* objClass, bool array, bool required)
36  {
37  // Check whether the map entry already exists
38  const auto& entry = m_dbEntries.find(name);
39  if (entry != m_dbEntries.end()) {
40  DBStoreEntry& dbEntry = entry->second;
41 
42  // Check whether the types match
43  if (!dbEntry.checkType(type, objClass, array)) return nullptr;
44 
45  B2DEBUG(39, "DBEntry " << name << " was requested once more.");
46  if (required && !dbEntry.isRequired()) {
47  dbEntry.require();
48  B2DEBUG(34, "DBEntry " << name << " is now required");
49  }
50  return &dbEntry;
51  }
52 
53  // Add the DBStore entry
54  const auto iter = m_dbEntries.emplace(name, DBStoreEntry{type, name, objClass, array, required});
55  DBStoreEntry& dbEntry = iter.first->second;
56  B2DEBUG(34, "DBEntry " << name << " was created (" << (required ? "required" : "optional") << ")");
57 
58  // If no object was obtained from the database yet, but it should be available, get it
59 
60  // Check if we have a non-DataStore event to use
61  if (m_manualEvent) {
62  Database::DBQuery query(name, required);
63  if (Database::Instance().getData(*m_manualEvent, query)) {
64  dbEntry.updatePayload(query.revision, query.iov, query.filename, query.checksum, query.globaltag, *m_manualEvent);
65  }
66  if (dbEntry.isIntraRunDependent()) m_intraRunDependencies.insert(&dbEntry);
67  }
68  // Otherwise use the DataStore if it is valid
69  else if (m_storeEvent.isValid()) {
70  Database::DBQuery query(name, required);
71  if (Database::Instance().getData(*m_storeEvent, query)) {
72  dbEntry.updatePayload(query.revision, query.iov, query.filename, query.checksum, query.globaltag, *m_storeEvent);
73  }
74  if (dbEntry.isIntraRunDependent()) m_intraRunDependencies.insert(&dbEntry);
75  }
76  return &dbEntry;
77  }
78 
80  {
81  if (m_dbEntries.empty()) {
82  // make sure we at least fix the list of globaltags on the first time
84  return;
85  }
86 
87  // Make sure our EventMetaData pointer is reconnected as it could get
88  // disconnected if the DataStore is reset.
89  // TODO: This can be removed once BII-1262 is fixed.
91  m_storeEvent = event;
92  // Clear the m_manualEvent to indicate that we now want to use the DataStore event numbers
93  m_manualEvent = std::nullopt;
95  }
96 
97  void DBStore::update(const EventMetaData& event)
98  {
99  if (m_dbEntries.empty()) {
100  // make sure we at least fix the list of globaltags on the first time
102  return;
103  }
104  m_manualEvent = event;
106  }
107 
109  {
110  // For the time being we will request updates for all payloads just to make
111  // sure we never miss an update. This is done once per run so it should be
112  // fine from performance.
113  // TODO: once we are sure somehow to not have duplicate iovs we can relax
114  // this requirement.
115  std::vector<Database::DBQuery> entries;
116  entries.reserve(m_dbEntries.size());
117  for (auto& entry : m_dbEntries) {
118  bool expired = !entry.second.getIoV().contains(event);
119  if (expired) {
120  B2DEBUG(34, "DBEntry " << entry.first << " out of date, will need update");
121  }
122  if (!entry.second.keepUntilExpired() || expired)
123  entries.emplace_back(entry.first, entry.second.isRequired());
124  // remove from intra run handling, will be added again after update if needed.
125  m_intraRunDependencies.erase(&entry.second);
126  }
127 
128  // nothing to update
129  if (entries.empty()) return;
130 
131  // Request new objects and IoVs from database
132  Database::Instance().getData(event, entries);
133 
134  // Update DBStore entries
135  for (auto& query : entries) {
136  auto& dbEntry = m_dbEntries.find(query.name)->second;
137  dbEntry.updatePayload(query.revision, query.iov, query.filename, query.checksum, query.globaltag, event);
138  if (dbEntry.isIntraRunDependent()) m_intraRunDependencies.insert(&dbEntry);
139  }
140  }
141 
143  {
144  if (!m_manualEvent) {
146  } else {
147  B2WARNING("DBStore is currently using manual event information. But you are asking for the DataStore's EventMetaData "
148  "to be used to update the Intra-run dependencies. Update could not proceed. "
149  "Did you forget to call DBStore::Instance().update() before calling this function?");
150  }
151  }
152 
153  void DBStore::updateEvent(const unsigned int eventNumber)
154  {
155  // As m_manualEvent doesn't use the DataStore, it isn't automatically updated and we must manually update the event
156  // number prior to updating the intra-run objects.
157  // This also updates it ready for getData if a DBObject gets constructed later.
158  if (m_manualEvent) {
159  m_manualEvent->setEvent(eventNumber);
161  } else {
162  B2WARNING("DBStore is not currently using manual event information. But you are asking for the event number to be set "
163  " to a custom value. Update of the Intra-run dependencies could not proceed. "
164  "Did you forget to call DBStore::Instance().update(event), or accidentally call DBStore::Instance().update() "
165  "prior to to this?");
166  }
167  }
168 
170  {
171  // loop over intra-run dependent conditions and update the objects if needed
172  for (auto& dbEntry : m_intraRunDependencies) {
173  dbEntry->updateObject(event);
174  }
175  }
176 
177  void DBStore::reset(bool keepEntries)
178  {
179  if (!m_dbEntries.empty())
180  B2DEBUG(31, "DBStore::reset(): Cleaning all database information");
181  m_intraRunDependencies.clear();
182  if (!keepEntries) {
183  m_dbEntries.clear();
184  } else {
185  for (auto& entry : m_dbEntries) {
186  entry.second.resetPayload();
187  }
188  }
189  // Make sure our EventMetaData pointer is reconnected on next access ...
190  // because probably this is after resetting the DataStore (BII-1262)
192  m_storeEvent = event;
193  m_manualEvent = std::nullopt;
194  }
195 
196  std::set<std::string> DBStore::getAllEntryNames()
197  {
198  std::set<std::string> s{};
199  for (auto& [key, value] : m_dbEntries)
200  s.emplace(key);
201  return s;
202  };
203 
204  void DBStore::addConstantOverride(const std::string& name, TObject* obj, bool oneRun)
205  {
207  if (oneRun) {
208  int exp, run;
209  if (m_manualEvent) {
210  exp = m_manualEvent->getExperiment();
211  run = m_manualEvent->getRun();
212  } else {
213  exp = m_storeEvent->getExperiment();
214  run = m_storeEvent->getRun();
215  }
216  iov = IntervalOfValidity(exp, run, exp, run);
217  }
218  // Add the DBStore entry
219  auto iter = m_dbEntries.find(name);
220  if (iter == end(m_dbEntries)) {
221  iter = m_dbEntries.emplace(name, DBStoreEntry::fromObject(name, obj, true)).first;
222  }
223  DBStoreEntry& dbEntry = iter->second;
224  dbEntry.overrideObject(obj, iov);
225  // we need to remove this entry from the intraRunDependencies list now.
226  // Otherwise it will reset the object on the next event call
227  m_intraRunDependencies.erase(&dbEntry);
228  B2WARNING("An override for DBEntry " << name << " was created.");
229  }
230 
232 } // namespace Belle2
Class to hold one entry from the ConditionsDB in the DBStore.
Definition: DBStoreEntry.h:47
EPayloadType
Possible Store entry types.
Definition: DBStoreEntry.h:50
bool isIntraRunDependent() const
return whether or not the payload might change even during the run
Definition: DBStoreEntry.h:119
void require()
Change status of this payload to required.
Definition: DBStoreEntry.h:169
bool isRequired() const
check whether this payload is required for operation
Definition: DBStoreEntry.h:115
Singleton class to cache database objects.
Definition: DBStore.h:31
StoreObjPtr< EventMetaData > m_storeEvent
StoreObjPtr for the EventMetaData to get the current experiment and run from the DataStore.
Definition: DBStore.h:174
std::set< DBStoreEntry * > m_intraRunDependencies
List of intra-run dependent conditions.
Definition: DBStore.h:169
std::optional< EventMetaData > m_manualEvent
Optional EventMetaData variable.
Definition: DBStore.h:181
std::unordered_map< std::string, DBStoreEntry > m_dbEntries
Map names to DBEntry objects.
Definition: DBStore.h:166
@ c_InitGlobaltagList
Globaltag list has been finalized metadata providers not and globaltags are not checked for usability...
Definition: Database.h:49
Store event, run, and experiment numbers.
Definition: EventMetaData.h:33
A class that describes the interval of experiments/runs for which an object in the database is valid.
static IntervalOfValidity always()
Function that returns an interval of validity that is always valid, c.f.
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
void reset(bool keepEntries=false)
Invalidate all payloads.
Definition: DBStore.cc:177
void initialize(const EDatabaseState target=c_Ready)
Initialize the database connection settings on first use.
Definition: Database.cc:197
bool checkType(const TObject *object) const
Check if a given TObject instance is compatible with the type of this entry.
~DBStore()
Destructor.
Definition: DBStore.cc:23
std::pair< TObject *, IntervalOfValidity > getData(const EventMetaData &event, const std::string &name)
Request an object from the database.
Definition: Database.cc:72
void performUpdateEvent(const EventMetaData &event)
The main code that does an updateEvent.
Definition: DBStore.cc:169
static Database & Instance()
Instance of a singleton Database.
Definition: Database.cc:42
static DBStore & Instance()
Instance of a singleton DBStore.
Definition: DBStore.cc:28
void performUpdate(const EventMetaData &event)
The main code that does an update, factored out so it can be used by both update and update(event).
Definition: DBStore.cc:108
void overrideObject(TObject *obj, const IntervalOfValidity &iov)
Set an override object in case we want to use a different object then actually provided by the databa...
DBStoreEntry * getEntry(DBStoreEntry::EPayloadType payloadType, const std::string &name, const TClass *objClass, bool array, bool required=true)
Returns the entry with the requested name in the DBStore.
Definition: DBStore.cc:34
void updateEvent()
Updates all intra-run dependent objects.
Definition: DBStore.cc:142
void update()
Updates all objects that are outside their interval of validity.
Definition: DBStore.cc:79
static DBStoreEntry fromObject(const std::string &name, const TObject *obj, bool isRequired)
Construct a new DBStoreEntry with a requested name and an object directly.
Definition: DBStoreEntry.cc:37
void addConstantOverride(const std::string &name, TObject *obj, bool oneRun=false)
Add constant override payload.
Definition: DBStore.cc:204
std::set< std::string > getAllEntryNames()
Return the names of all the payloads stored in the database at the time of this function is called.
Definition: DBStore.cc:196
void updatePayload(unsigned int revision, const IntervalOfValidity &iov, const std::string &filename, const std::string &checksum, const std::string &globaltag, const EventMetaData &event)
Update the payload information for this entry and if appropriate open the new file and extract the ob...
Definition: DBStoreEntry.cc:83
Abstract base class for different kinds of events.
Simple struct to group all information necessary for a single payload.