Belle II Software  release-05-02-19
DBStoreEntry.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2015-2018 Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Thomas Kuhr, Martin Ritter *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 #include <framework/database/DBStoreEntry.h>
12 #include <framework/database/DBAccessorBase.h>
13 #include <framework/database/IntraRunDependency.h>
14 #include <framework/dataobjects/EventMetaData.h>
15 #include <framework/logging/Logger.h>
16 #include <iomanip>
17 #include <TFile.h>
18 #include <TClonesArray.h>
19 #include <TClass.h>
20 
21 namespace {
23  void deleteAndSetNullptr() {}
27  template<class T, class... Args> void deleteAndSetNullptr(T*& ptr, Args&& ... args)
28  {
29  delete ptr;
30  ptr = nullptr;
31  deleteAndSetNullptr(std::forward<Args>(args)...);
32  }
33 }
34 
35 namespace Belle2 {
40  DBStoreEntry DBStoreEntry::fromObject(const std::string& name, const TObject* obj, bool isRequired)
41  {
42  bool isArray = dynamic_cast<const TClonesArray*>(obj) != nullptr;
43  TClass* objClass = isArray ? (dynamic_cast<const TClonesArray*>(obj)->GetClass()) : (obj->IsA());
44  return DBStoreEntry(c_Object, name, objClass, isArray, isRequired);
45  }
46 
48  {
49  // if intra run dependency: object owned by the IntraRunDependency object so don't delete the object itself.
50  if (m_intraRunDependency) m_object = nullptr;
51  // and free all memory
52  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
53  if (!m_accessors.empty()) B2DEBUG(38, "DBEntry " << m_name << " destroyed, notifying accessors");
54  notifyAccessors(true);
55  }
56 
58  {
59  // if we don't have intra run dependency we don't care about event number
60  if (!m_intraRunDependency) return;
61  // otherwise update the object and call notify all accessors on change
62  TObject* old = m_object;
64  if (old != m_object) {
65  B2DEBUG(35, "IntraRunDependency for " << m_name << ": new object (" << old << ", " << m_object << "), notifying accessors");
67  }
68  }
69 
71  {
72  m_revision = 0;
74  m_keep = false;
75  m_filename = "";
76  m_checksum = "";
77  // If the old object was intra run dependent then m_object is owned by the
78  // intra run dependency object. So set the pointer to null to not delete the object.
79  if (m_intraRunDependency) m_object = nullptr;
80  // and delete the old intra run dependency if it exists
81  deleteAndSetNullptr(m_object, m_intraRunDependency, m_tfile);
82  }
83 
84  void DBStoreEntry::updatePayload(unsigned int revision, const IntervalOfValidity& iov, const std::string& filename,
85  const std::string& checksum, const EventMetaData& event)
86  {
87  m_iov = iov;
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("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_revision = 0;
163  m_filename = "";
164  m_iov = iov;
165  m_keep = true;
166  // object unchanged, nothing to do
167  if (m_object == obj) {
168  B2DEBUG(34, "DBEntry " << std::quoted(m_name) << " override unchanged");
169  return;
170  }
171  // We need to clean up the object but if someone hands us the same object
172  // we already own this would lead to invalid access later so make sure we
173  // only delete it when appropriate
174  if (!isIntraRunDependent()) {
175  delete m_object;
176  }
177  // clean up the other memory
178  deleteAndSetNullptr(m_intraRunDependency, m_tfile);
179  // and set, ready go
180  m_object = obj;
181  B2DEBUG(34, "DBEntry " << this << " " << std::quoted(m_name) << " override created: " << std::endl
182  << " object = " << m_object << std::endl
183  << " validity = " << m_iov << std::endl
184  << " -> notiying accessors");
185  notifyAccessors();
186  }
187 
188  void DBStoreEntry::notifyAccessors(bool onDestruction)
189  {
190  // Just notify all registered accessors ...
191  for (DBAccessorBase* object : m_accessors) object->storeEntryChanged(onDestruction);
192  // on destruction we also should clear the list ... we will not call them again
193  if (onDestruction) m_accessors.clear();
194  }
195 
196  bool DBStoreEntry::checkType(EPayloadType type, const TClass* objClass, bool array, bool inverse) const
197  {
198  if (type != m_payloadType) {
199  B2FATAL("Existing entry '" << m_name << "' is of a different type than requested");
200  }
201  // OK, all other checks only make sense for objects
202  if (type != c_Object) return true;
203  // Check whether the existing entry and the requested object are both arrays or both single objects
204  if (m_isArray != array) {
205  B2FATAL("Existing entry '" << m_name << "' is an " << ((m_isArray) ? "array" : "object") <<
206  " and the requested one an " << ((array) ? "array" : "object"));
207  }
208 
209  // Check whether the existing entry and the requested object have the same type
210  if (!inverse) {
211  if (!m_objClass->InheritsFrom(objClass)) {
212  B2FATAL("Existing entry '" << m_name << "' of type " <<
213  m_objClass->GetName() << " doesn't match requested type " <<
214  objClass->GetName());
215  }
216  } else {
217  if (!objClass->InheritsFrom(m_objClass)) {
218  B2FATAL("Existing entry '" << m_name << "' of type " <<
219  m_objClass->GetName() << " doesn't match actual type " <<
220  objClass->GetName());
221  }
222  }
223  return true;
224  }
225 
226  bool DBStoreEntry::checkType(const TObject* object) const
227  {
228  // Get class information from object
229  if (object->InheritsFrom(IntraRunDependency::Class())) {
230  object = static_cast<const IntraRunDependency*>(object)->getAnyObject();
231  }
232  TClass* objClass = object->IsA();
233  bool array = (objClass == TClonesArray::Class());
234  if (array) {
235  objClass = static_cast<const TClonesArray*>(object)->GetClass();
236  }
237 
238  return checkType(c_Object, objClass, array, true);
239  }
240 
242 }
Belle2::IntervalOfValidity
A class that describes the interval of experiments/runs for which an object in the database is valid.
Definition: IntervalOfValidity.h:35
Belle2::DBStoreEntry::m_object
TObject * m_object
Pointer to the actual payload object.
Definition: DBStoreEntry.h:187
Belle2::DBStoreEntry::m_checksum
std::string m_checksum
checksum of the payload file
Definition: DBStoreEntry.h:183
Belle2::DBStoreEntry::c_Object
@ c_Object
A ROOT file containing a object with the name of the DBStoreEntry.
Definition: DBStoreEntry.h:58
Belle2::DBStoreEntry::isRequired
bool isRequired() const
check whether this payload is required for operation
Definition: DBStoreEntry.h:112
Belle2::DBStoreEntry::m_iov
IntervalOfValidity m_iov
validity of this payload
Definition: DBStoreEntry.h:179
Belle2::DBStoreEntry
Class to hold one entry from the ConditionsDB in the DBStore.
Definition: DBStoreEntry.h:49
Belle2::DBStoreEntry::m_revision
unsigned int m_revision
revision of this payload
Definition: DBStoreEntry.h:177
Belle2::DBStoreEntry::~DBStoreEntry
~DBStoreEntry()
Clean up memory.
Definition: DBStoreEntry.cc:47
Belle2::DBStoreEntry::isArray
bool isArray() const
get whether this payload is an array of objects or a single objects
Definition: DBStoreEntry.h:110
Belle2::DBStoreEntry::m_filename
std::string m_filename
filename containing which contains the actual payload data
Definition: DBStoreEntry.h:181
Belle2::DBStoreEntry::overrideObject
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...
Definition: DBStoreEntry.cc:158
Belle2::DBAccessorBase
Base class for DBObjPtr and DBArray for easier common treatment.
Definition: DBAccessorBase.h:28
Belle2::DBStoreEntry::m_keep
bool m_keep
if True this payload should not be updated unless it's really out of date.
Definition: DBStoreEntry.h:175
Belle2::DBStoreEntry::DBStoreEntry
DBStoreEntry(EPayloadType type, const std::string &name, const TClass *objClass, bool isArray, bool isRequired)
Construct a new DBStoreEntry.
Definition: DBStoreEntry.h:68
Belle2::DBStoreEntry::EPayloadType
EPayloadType
Possible Store entry types.
Definition: DBStoreEntry.h:52
Belle2::DBStoreEntry::m_accessors
std::unordered_set< DBAccessorBase * > m_accessors
Vector of all the accessors registered with this entry.
Definition: DBStoreEntry.h:192
Belle2::DBStoreEntry::m_intraRunDependency
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:190
Belle2::DBStoreEntry::notifyAccessors
void notifyAccessors(bool onDestruction=false)
Notify all the registered accessors.
Definition: DBStoreEntry.cc:188
Belle2::DBStoreEntry::loadPayload
void loadPayload(const EventMetaData &event)
Actual load the payload from file after all info is set.
Definition: DBStoreEntry.cc:114
Belle2::DBStoreEntry::checkType
bool checkType(const TObject *object) const
Check if a given TObject instance is compatible with the type of this entry.
Definition: DBStoreEntry.cc:226
Belle2::DBStoreEntry::updatePayload
void updatePayload(unsigned int revision, const IntervalOfValidity &iov, const std::string &filename, const std::string &checksum, const EventMetaData &event)
Update the payload information for this entry and if appropriate open the new file and extract the ob...
Definition: DBStoreEntry.cc:84
Belle2::DBStoreEntry::fromObject
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:40
Belle2::DBStoreEntry::m_isArray
const bool m_isArray
True if this payload is an array of objects.
Definition: DBStoreEntry.h:169
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::DBStoreEntry::m_objClass
const TClass *const m_objClass
Class of this payload.
Definition: DBStoreEntry.h:167
Belle2::IntraRunDependency::getObject
TObject * getObject(const EventMetaData &event) const
Get the conditions object that is valid for the given event.
Definition: IntraRunDependency.h:57
LogVar
Class to store variables with their name which were sent to the logging service.
Definition: LogVariableStream.h:24
Belle2::IntraRunDependency
Base class for handling changing conditions during a run.
Definition: IntraRunDependency.h:36
Belle2::DBStoreEntry::m_name
const std::string m_name
Name of this payload.
Definition: DBStoreEntry.h:165
Belle2::DBStoreEntry::m_payloadType
const EPayloadType m_payloadType
Type of this payload.
Definition: DBStoreEntry.h:163
Belle2::EventMetaData
Store event, run, and experiment numbers.
Definition: EventMetaData.h:43
Belle2::DBStoreEntry::updateObject
void updateObject(const EventMetaData &event)
update the payload object according to the new event information.
Definition: DBStoreEntry.cc:57
Belle2::DBStoreEntry::isIntraRunDependent
bool isIntraRunDependent() const
return whether or not the payload might change even during the run
Definition: DBStoreEntry.h:116
Belle2::DBStoreEntry::m_tfile
TFile * m_tfile
Pointer to the open ROOT TFile pointer for m_filename.
Definition: DBStoreEntry.h:185
Belle2::DBStoreEntry::c_RawFile
@ c_RawFile
Just a plain old file, we don't look at it just provide the filename.
Definition: DBStoreEntry.h:54
Belle2::DBStoreEntry::resetPayload
void resetPayload()
reset the payload to nothing
Definition: DBStoreEntry.cc:70