Belle II Software  light-2212-foldex
DBStoreEntry.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/DBStoreEntry.h>
10 #include <framework/database/DBAccessorBase.h>
11 #include <framework/dataobjects/EventMetaData.h>
12 #include <framework/logging/Logger.h>
13 #include <iomanip>
14 #include <TFile.h>
15 #include <TClonesArray.h>
16 #include <TClass.h>
17 
18 namespace {
20  void deleteAndSetNullptr() {}
24  template<class T, class... Args> void deleteAndSetNullptr(T*& ptr, Args&& ... args)
25  {
26  delete ptr;
27  ptr = nullptr;
28  deleteAndSetNullptr(std::forward<Args>(args)...);
29  }
30 }
31 
32 namespace Belle2 {
37  DBStoreEntry DBStoreEntry::fromObject(const std::string& name, const TObject* obj, bool isRequired)
38  {
39  bool isArray = dynamic_cast<const TClonesArray*>(obj) != nullptr;
40  TClass* objClass = isArray ? (dynamic_cast<const TClonesArray*>(obj)->GetClass()) : (obj->IsA());
41  return DBStoreEntry(c_Object, name, objClass, isArray, isRequired);
42  }
43 
45  {
46  // if intra run dependency: object owned by the IntraRunDependency object so don't delete the object itself.
47  if (m_intraRunDependency) m_object = nullptr;
48  // and free all memory
49  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
50  if (!m_accessors.empty()) B2DEBUG(38, "DBEntry " << m_name << " destroyed, notifying accessors");
51  notifyAccessors(true);
52  }
53 
55  {
56  // if we don't have intra run dependency we don't care about event number
57  if (!m_intraRunDependency) return;
58  // otherwise update the object and call notify all accessors on change
59  TObject* old = m_object;
61  if (old != m_object) {
62  B2DEBUG(35, "IntraRunDependency for " << m_name << ": new object (" << old << ", " << m_object << "), notifying accessors");
64  }
65  }
66 
68  {
69  m_globaltag = "";
70  m_revision = 0;
72  m_keep = false;
73  m_filename = "";
74  m_checksum = "";
75  // If the old object was intra run dependent then m_object is owned by the
76  // intra run dependency object. So set the pointer to null to not delete the object.
77  if (m_intraRunDependency) m_object = nullptr;
78  // and delete the old intra run dependency if it exists
79  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
80  }
81 
82  void DBStoreEntry::updatePayload(unsigned int revision, const IntervalOfValidity& iov, const std::string& filename,
83  const std::string& checksum, const std::string& globaltag, const EventMetaData& event)
84  {
85  m_iov = iov;
86  m_globaltag = globaltag;
87  // File is the same as before, no need to update anything else. We could
88  // check all identifiers like revision, filename and checksum
89  // > if (revision == m_revision && filename == m_filename && m_checksum == checksum) return;
90  // but this is a bit strict as we know we have some payloads with the same
91  // checksum but multiple revisions and there's no need to actually update
92  // the object. But at least lets make sure the revision number is reported the same as in the db
93  m_revision = revision;
94  if (m_checksum == checksum) return;
95  m_keep = false;
96  m_checksum = checksum;
97  m_filename = filename;
98  // If the old object was intra run dependent then m_object is owned by the
99  // intra run dependency object. So set the pointer to null to not delete the object.
100  if (m_intraRunDependency) m_object = nullptr;
101  // and delete the old intra run dependency if it exists
102  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
103  loadPayload(event);
104  B2DEBUG(30, "DBEntry changed"
105  << LogVar("name", m_name)
106  << LogVar("globaltag", m_globaltag)
107  << LogVar("revision", m_revision)
108  << LogVar("checksum", m_checksum)
109  << LogVar("filename", m_filename)
110  << LogVar("validity", m_iov));
111  notifyAccessors();
112  }
113 
115  {
116  if (m_filename == "") {
117  // invalid payload nothing else to do
118  return;
119  }
120  if (m_payloadType != c_RawFile) {
121  // Open the payload file but make sure to go back to the previous
122  // directory to not disturb other code.
123  TDirectory* oldDirectory = gDirectory;
124  m_tfile = TFile::Open(m_filename.c_str());
125  gDirectory = oldDirectory;
126  // Check if the file is open
127  if (!m_tfile || !m_tfile->IsOpen()) {
128  B2ERROR("Cannot open " << std::quoted(m_filename) << " for reading");
129  deleteAndSetNullptr(m_tfile);
130  return;
131  }
132  m_tfile->SetBit(kCanDelete, false);
133  // File is open and we are a normal object entry?
134  if (m_payloadType == c_Object) {
135  // get the object
136  m_object = m_tfile->Get(m_name.c_str());
137  if (!m_object) {
138  B2ERROR("Failed to get " << std::quoted(m_name) << " from payload file "
139  << std::quoted(m_filename) << ".");
140  return;
141  }
142  m_object->SetBit(kCanDelete, false);
143  // check that it is compatible with what it should be
145  // resolve run dependency
146  if (m_object->InheritsFrom(IntraRunDependency::Class())) {
149  B2DEBUG(34, "Found intra run dependency for " << m_name << ": " << m_intraRunDependency << ", " << m_object);
150  }
151  // TODO: depending on the object type we could now close the file. I
152  // guess we cannot close the file in case of TTree but we have to find
153  // out exactly which object types are safe before doing that?
154  }
155  }
156  }
157 
158  void DBStoreEntry::overrideObject(TObject* obj, const IntervalOfValidity& iov)
159  {
160  if (!checkType(obj)) return;
161 
162  m_globaltag = "";
163  m_revision = 0;
164  m_filename = "";
165  m_iov = iov;
166  m_keep = true;
167  // object unchanged, nothing to do
168  if (m_object == obj) {
169  B2DEBUG(34, "DBEntry " << std::quoted(m_name) << " override unchanged");
170  return;
171  }
172  // We need to clean up the object but if someone hands us the same object
173  // we already own this would lead to invalid access later so make sure we
174  // only delete it when appropriate
175  if (!isIntraRunDependent()) {
176  delete m_object;
177  }
178  // clean up the other memory
179  deleteAndSetNullptr(m_intraRunDependency, m_tfile);
180  // and set, ready go
181  m_object = obj;
182  B2DEBUG(34, "DBEntry " << this << " " << std::quoted(m_name) << " override created: " << std::endl
183  << " object = " << m_object << std::endl
184  << " validity = " << m_iov << std::endl
185  << " -> notiying accessors");
186  notifyAccessors();
187  }
188 
189  void DBStoreEntry::notifyAccessors(bool onDestruction)
190  {
191  // Just notify all registered accessors ...
192  for (DBAccessorBase* object : m_accessors) object->storeEntryChanged(onDestruction);
193  // on destruction we also should clear the list ... we will not call them again
194  if (onDestruction) m_accessors.clear();
195  }
196 
197  bool DBStoreEntry::checkType(EPayloadType type, const TClass* objClass, bool array, bool inverse) const
198  {
199  if (type != m_payloadType) {
200  B2FATAL("Existing entry '" << m_name << "' is of a different type than requested");
201  }
202  // OK, all other checks only make sense for objects
203  if (type != c_Object) return true;
204  // Check whether the existing entry and the requested object are both arrays or both single objects
205  if (m_isArray != array) {
206  B2FATAL("Existing entry '" << m_name << "' is an " << ((m_isArray) ? "array" : "object") <<
207  " and the requested one an " << ((array) ? "array" : "object"));
208  }
209 
210  // Check whether the existing entry and the requested object have the same type
211  if (!inverse) {
212  if (!m_objClass->InheritsFrom(objClass)) {
213  B2FATAL("Existing entry '" << m_name << "' of type " <<
214  m_objClass->GetName() << " doesn't match requested type " <<
215  objClass->GetName());
216  }
217  } else {
218  if (!objClass->InheritsFrom(m_objClass)) {
219  B2FATAL("Existing entry '" << m_name << "' of type " <<
220  m_objClass->GetName() << " doesn't match actual type " <<
221  objClass->GetName());
222  }
223  }
224  return true;
225  }
226 
227  bool DBStoreEntry::checkType(const TObject* object) const
228  {
229  // Get class information from object
230  if (object->InheritsFrom(IntraRunDependency::Class())) {
231  object = static_cast<const IntraRunDependency*>(object)->getAnyObject();
232  }
233  TClass* objClass = object->IsA();
234  bool array = (objClass == TClonesArray::Class());
235  if (array) {
236  objClass = static_cast<const TClonesArray*>(object)->GetClass();
237  }
238 
239  return checkType(c_Object, objClass, array, true);
240  }
241 
243 }
Base class for DBObjPtr and DBArray for easier common treatment.
Class to hold one entry from the ConditionsDB in the DBStore.
Definition: DBStoreEntry.h:47
std::unordered_set< DBAccessorBase * > m_accessors
Vector of all the accessors registered with this entry.
Definition: DBStoreEntry.h:202
EPayloadType
Possible Store entry types.
Definition: DBStoreEntry.h:50
@ c_RawFile
Just a plain old file, we don't look at it just provide the filename.
Definition: DBStoreEntry.h:52
@ c_Object
A ROOT file containing a object with the name of the DBStoreEntry.
Definition: DBStoreEntry.h:56
bool isIntraRunDependent() const
return whether or not the payload might change even during the run
Definition: DBStoreEntry.h:119
IntraRunDependency * m_intraRunDependency
If the payload has intra run dependency this will point to the whole payload and m_object will just p...
Definition: DBStoreEntry.h:200
IntervalOfValidity m_iov
validity of this payload
Definition: DBStoreEntry.h:189
unsigned int m_revision
revision of this payload
Definition: DBStoreEntry.h:187
DBStoreEntry(EPayloadType type, const std::string &name, const TClass *objClass, bool isArray, bool isRequired)
Construct a new DBStoreEntry.
Definition: DBStoreEntry.h:68
std::string m_checksum
checksum of the payload file
Definition: DBStoreEntry.h:193
const std::string m_name
Name of this payload.
Definition: DBStoreEntry.h:173
bool m_keep
if True this payload should not be updated unless it's really out of date.
Definition: DBStoreEntry.h:183
bool isRequired() const
check whether this payload is required for operation
Definition: DBStoreEntry.h:115
const EPayloadType m_payloadType
Type of this payload.
Definition: DBStoreEntry.h:171
TFile * m_tfile
Pointer to the open ROOT TFile pointer for m_filename.
Definition: DBStoreEntry.h:195
std::string m_filename
filename containing which contains the actual payload data
Definition: DBStoreEntry.h:191
const bool m_isArray
True if this payload is an array of objects.
Definition: DBStoreEntry.h:177
std::string m_globaltag
globaltag name (or testing payloads path) from which this payload is picked.
Definition: DBStoreEntry.h:185
bool isArray() const
get whether this payload is an array of objects or a single objects
Definition: DBStoreEntry.h:113
const TClass *const m_objClass
Class of this payload.
Definition: DBStoreEntry.h:175
TObject * m_object
Pointer to the actual payload object.
Definition: DBStoreEntry.h:197
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.
Base class for handling changing conditions during a run.
TObject * getObject(const EventMetaData &event) const
Get the conditions object that is valid for the given event.
Class to store variables with their name which were sent to the logging service.
void notifyAccessors(bool onDestruction=false)
Notify all the registered accessors.
void resetPayload()
reset the payload to nothing
Definition: DBStoreEntry.cc:67
bool checkType(const TObject *object) const
Check if a given TObject instance is compatible with the type of this entry.
void updateObject(const EventMetaData &event)
update the payload object according to the new event information.
Definition: DBStoreEntry.cc:54
~DBStoreEntry()
Clean up memory.
Definition: DBStoreEntry.cc:44
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...
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 loadPayload(const EventMetaData &event)
Actual load the payload from file after all info is set.
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:82
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23