Belle II Software development
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
18namespace {
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
32namespace 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));
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
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");
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
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.