Belle II Software  release-08-01-10
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  assert(obj);
40  bool isArray = dynamic_cast<const TClonesArray*>(obj) != nullptr;
41  TClass* objClass = isArray ? (dynamic_cast<const TClonesArray*>(obj)->GetClass()) : (obj->IsA());
42  return DBStoreEntry(c_Object, name, objClass, isArray, isRequired);
43  }
44 
46  {
47  // if intra run dependency: object owned by the IntraRunDependency object so don't delete the object itself.
48  if (m_intraRunDependency) m_object = nullptr;
49  // and free all memory
50  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
51  if (!m_accessors.empty()) B2DEBUG(38, "DBEntry " << m_name << " destroyed, notifying accessors");
52  notifyAccessors(true);
53  }
54 
56  {
57  // if we don't have intra run dependency we don't care about event number
58  if (!m_intraRunDependency) return;
59  // otherwise update the object and call notify all accessors on change
60  TObject* old = m_object;
62  if (old != m_object) {
63  B2DEBUG(35, "IntraRunDependency for " << m_name << ": new object (" << old << ", " << m_object << "), notifying accessors");
65  }
66  }
67 
69  {
70  m_globaltag = "";
71  m_revision = 0;
73  m_keep = false;
74  m_filename = "";
75  m_checksum = "";
76  // If the old object was intra run dependent then m_object is owned by the
77  // intra run dependency object. So set the pointer to null to not delete the object.
78  if (m_intraRunDependency) m_object = nullptr;
79  // and delete the old intra run dependency if it exists
80  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
81  }
82 
83  void DBStoreEntry::updatePayload(unsigned int revision, const IntervalOfValidity& iov, const std::string& filename,
84  const std::string& checksum, const std::string& globaltag, const EventMetaData& event)
85  {
86  m_iov = iov;
87  m_globaltag = globaltag;
88  // File is the same as before, no need to update anything else. We could
89  // check all identifiers like revision, filename and checksum
90  // > if (revision == m_revision && filename == m_filename && m_checksum == checksum) return;
91  // but this is a bit strict as we know we have some payloads with the same
92  // checksum but multiple revisions and there's no need to actually update
93  // the object. But at least lets make sure the revision number is reported the same as in the db
94  m_revision = revision;
95  if (m_checksum == checksum) return;
96  m_keep = false;
97  m_checksum = checksum;
98  m_filename = filename;
99  // If the old object was intra run dependent then m_object is owned by the
100  // intra run dependency object. So set the pointer to null to not delete the object.
101  if (m_intraRunDependency) m_object = nullptr;
102  // and delete the old intra run dependency if it exists
103  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
104  loadPayload(event);
105  B2DEBUG(30, "DBEntry changed"
106  << LogVar("name", m_name)
107  << LogVar("globaltag", m_globaltag)
108  << LogVar("revision", m_revision)
109  << LogVar("checksum", m_checksum)
110  << LogVar("filename", m_filename)
111  << LogVar("validity", m_iov));
112  notifyAccessors();
113  }
114 
116  {
117  if (m_filename == "") {
118  // invalid payload nothing else to do
119  return;
120  }
121  if (m_payloadType != c_RawFile) {
122  // Open the payload file but make sure to go back to the previous
123  // directory to not disturb other code.
124  TDirectory* oldDirectory = gDirectory;
125  m_tfile = TFile::Open(m_filename.c_str());
126  gDirectory = oldDirectory;
127  // Check if the file is open
128  if (!m_tfile || !m_tfile->IsOpen()) {
129  B2ERROR("Cannot open " << std::quoted(m_filename) << " for reading");
130  deleteAndSetNullptr(m_tfile);
131  return;
132  }
133  m_tfile->SetBit(kCanDelete, false);
134  // File is open and we are a normal object entry?
135  if (m_payloadType == c_Object) {
136  // get the object
137  m_object = m_tfile->Get(m_name.c_str());
138  if (!m_object) {
139  B2ERROR("Failed to get " << std::quoted(m_name) << " from payload file "
140  << std::quoted(m_filename) << ".");
141  return;
142  }
143  m_object->SetBit(kCanDelete, false);
144  // check that it is compatible with what it should be
146  // resolve run dependency
147  if (m_object->InheritsFrom(IntraRunDependency::Class())) {
150  B2DEBUG(34, "Found intra run dependency for " << m_name << ": " << m_intraRunDependency << ", " << m_object);
151  }
152  // TODO: depending on the object type we could now close the file. I
153  // guess we cannot close the file in case of TTree but we have to find
154  // out exactly which object types are safe before doing that?
155  }
156  }
157  }
158 
159  void DBStoreEntry::overrideObject(TObject* obj, const IntervalOfValidity& iov)
160  {
161  if (!checkType(obj)) return;
162 
163  m_globaltag = "";
164  m_revision = 0;
165  m_filename = "";
166  m_iov = iov;
167  m_keep = true;
168  // object unchanged, nothing to do
169  if (m_object == obj) {
170  B2DEBUG(34, "DBEntry " << std::quoted(m_name) << " override unchanged");
171  return;
172  }
173  // We need to clean up the object but if someone hands us the same object
174  // we already own this would lead to invalid access later so make sure we
175  // only delete it when appropriate
176  if (!isIntraRunDependent()) {
177  delete m_object;
178  }
179  // clean up the other memory
180  deleteAndSetNullptr(m_intraRunDependency, m_tfile);
181  // and set, ready go
182  m_object = obj;
183  B2DEBUG(34, "DBEntry " << this << " " << std::quoted(m_name) << " override created: " << std::endl
184  << " object = " << m_object << std::endl
185  << " validity = " << m_iov << std::endl
186  << " -> notiying accessors");
187  notifyAccessors();
188  }
189 
190  void DBStoreEntry::notifyAccessors(bool onDestruction)
191  {
192  // Just notify all registered accessors ...
193  for (DBAccessorBase* object : m_accessors) object->storeEntryChanged(onDestruction);
194  // on destruction we also should clear the list ... we will not call them again
195  if (onDestruction) m_accessors.clear();
196  }
197 
198  bool DBStoreEntry::checkType(EPayloadType type, const TClass* objClass, bool array, bool inverse) const
199  {
200  if (type != m_payloadType) {
201  B2FATAL("Existing entry '" << m_name << "' is of a different type than requested");
202  }
203  // OK, all other checks only make sense for objects
204  if (type != c_Object) return true;
205  // Check whether the existing entry and the requested object are both arrays or both single objects
206  if (m_isArray != array) {
207  B2FATAL("Existing entry '" << m_name << "' is an " << ((m_isArray) ? "array" : "object") <<
208  " and the requested one an " << ((array) ? "array" : "object"));
209  }
210 
211  // Check whether the existing entry and the requested object have the same type
212  if (!inverse) {
213  if (!m_objClass->InheritsFrom(objClass)) {
214  B2FATAL("Existing entry '" << m_name << "' of type " <<
215  m_objClass->GetName() << " doesn't match requested type " <<
216  objClass->GetName());
217  }
218  } else {
219  if (!objClass->InheritsFrom(m_objClass)) {
220  B2FATAL("Existing entry '" << m_name << "' of type " <<
221  m_objClass->GetName() << " doesn't match actual type " <<
222  objClass->GetName());
223  }
224  }
225  return true;
226  }
227 
228  bool DBStoreEntry::checkType(const TObject* object) const
229  {
230  // Get class information from object
231  if (object->InheritsFrom(IntraRunDependency::Class())) {
232  object = static_cast<const IntraRunDependency*>(object)->getAnyObject();
233  }
234  TClass* objClass = object->IsA();
235  bool array = (objClass == TClonesArray::Class());
236  if (array) {
237  objClass = static_cast<const TClonesArray*>(object)->GetClass();
238  }
239 
240  return checkType(c_Object, objClass, array, true);
241  }
242 
244 }
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:68
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:55
~DBStoreEntry()
Clean up memory.
Definition: DBStoreEntry.cc:45
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:83
Abstract base class for different kinds of events.