Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS dbe source for the DUNE DAQ project.
3 : // Fork baseline commit: dbe-02-12-17 (2022-05-12).
4 : // Renamed since fork: no.
5 :
6 : /*
7 : * dbcontroller.cpp
8 : *
9 : * Created on: Oct 30, 2015
10 : * Author: lgeorgop
11 : */
12 :
13 : #include "dbe/dbcontroller.hpp"
14 : #include "dbe/config_reference_copy.hpp"
15 : #include "dbe/messenger.hpp"
16 : #include "dbe/msghandler.hpp"
17 :
18 : #include <utility>
19 :
20 : using namespace dunedaq::conffwk;
21 :
22 : namespace dbe {
23 : namespace inner {
24 :
25 : namespace configobject {
26 : //------------------------------------------------------------------------------------------
27 : // NAMESPACE
28 : // DBE::INNER::CONFIGOBJECT
29 : //------------------------------------------------------------------------------------------
30 :
31 : //------------------------------------------------------------------------------------------
32 : template<typename T>
33 : std::vector<T>
34 0 : ref_interface<T>::referenced_by(std::string const& name, bool check_composite_only) const
35 : {
36 0 : std::vector<ConfigObject> referees;
37 0 : std::vector<tref> result;
38 :
39 0 : static_cast<ConfigObject&>(*this).referenced_by(referees, name, check_composite_only);
40 :
41 0 : for (ConfigObject const& x : referees) {
42 : try {
43 0 : result.push_back(inner::dbcontroller::get({ x.UID(), x.class_name() }));
44 0 : } catch (daq::dbe::config_object_retrieval_result_is_null const& e) {
45 : // Nothing needed to do here, this is normal, just the query has resulted in null
46 : }
47 : }
48 :
49 0 : return result;
50 0 : }
51 :
52 : template std::vector<tref>
53 : ref_interface<tref>::referenced_by(std::string const&, bool) const;
54 :
55 : //------------------------------------------------------------------------------------------
56 :
57 : //------------------------------------------------------------------------------------------
58 : template<typename T>
59 : void
60 0 : gref<T>::record(tref const& o)
61 : {
62 0 : t_extractor obj(o);
63 0 : for (auto const& linked : obj.relations) {
64 0 : for (auto const& candidate : linked.second) {
65 0 : record(candidate.ref());
66 : }
67 : }
68 0 : this_remove_stack.push_back(obj);
69 0 : }
70 :
71 : template<typename T>
72 : void
73 0 : gref<T>::post()
74 : {
75 0 : type_extractor_stack acopy;
76 0 : std::swap(acopy, this_remove_stack);
77 :
78 0 : while (not acopy.empty()) {
79 0 : t_extractor candidate = acopy.front();
80 : // Keep only objects that have been deleted
81 0 : if (not dbe::config::api::info::has_obj(candidate.ref.class_name(), candidate.ref.UID())) {
82 0 : this_remove_stack.push_back(candidate);
83 : }
84 0 : acopy.pop_front();
85 : }
86 0 : }
87 :
88 : template<typename T>
89 : void
90 0 : gref<T>::notify(config_action_notifiable tele)
91 : {
92 0 : if (this_notify_stack.empty()) {
93 0 : for (typename type_extractor_stack::value_type const& val : this_remove_stack) {
94 0 : tele(val.ref);
95 : }
96 : } else {
97 0 : for (typename type_ref_container::value_type const& val : this_notify_stack) {
98 0 : tele(val);
99 : }
100 : }
101 0 : }
102 :
103 : template<typename T>
104 : tref
105 0 : gref<T>::rebuild()
106 : {
107 0 : if (not this_remove_stack.empty()) {
108 0 : for (;;) {
109 0 : t_extractor record = this_remove_stack.front();
110 0 : tref last = dbcontroller::create_object_request(record.toimage());
111 0 : this_remove_stack.pop_front();
112 0 : if (not last.is_null()) {
113 0 : this_notify_stack.push_back(last);
114 : }
115 0 : if (this_remove_stack.empty()) {
116 0 : return last;
117 : }
118 : }
119 : }
120 0 : throw daq::dbe::gref_empty_internal_queue_is_invalid_state(ERS_HERE);
121 : }
122 :
123 : template<typename T>
124 : bool
125 : gref<T>::is_null() const
126 : {
127 : return this_remove_stack.front().is_null();
128 : }
129 : //------------------------------------------------------------------------------------------
130 :
131 : //------------------------------------------------------------------------------------------
132 : template<typename T>
133 : tref
134 0 : authorized_getter<T, tref>::operator()(std::string const& key)
135 : {
136 0 : ConfigObject voisin{ this->that->template getdirect<ConfigObject>(key) };
137 :
138 0 : if (voisin.is_null()) {
139 0 : throw daq::dbe::config_object_retrieval_result_is_null(ERS_HERE, key);
140 : }
141 :
142 : // There is no need to catch the resulting exception from get because the object
143 : // has just been retrieved from the database, and the call to get just generates
144 : // the tref and adds the object to the internal lookup table.
145 0 : return dbcontroller::get({ voisin.UID(), voisin.class_name() });
146 0 : }
147 :
148 : template<typename T>
149 : std::vector<tref>
150 0 : authorized_getter<T, std::vector<tref>>::operator()(std::string const& key)
151 : {
152 0 : std::vector<ConfigObject> voisins{ this->that->template getdirect<std::vector<ConfigObject>>(key) };
153 :
154 0 : std::vector<tref> references;
155 :
156 0 : for (ConfigObject const& voisin : voisins) {
157 : try {
158 0 : references.push_back(dbcontroller::get({ voisin.UID(), voisin.class_name() }));
159 0 : } catch (daq::dbe::config_object_retrieval_result_is_null const& ex) {
160 : // Actually there is no need to handle this error here ,
161 : // since the object will not be added to the result list of references,
162 : // and can be safely ignored
163 : }
164 : }
165 :
166 0 : return references;
167 0 : }
168 :
169 : template class authorized_getter<tref, tref>;
170 : template class authorized_getter<tref, std::vector<tref>>;
171 : //------------------------------------------------------------------------------------------
172 :
173 : } // end namespace configobject
174 :
175 : //------------------------------------------------------------------------------------------
176 : // NAMESPACE
177 : // DBE::INNER
178 : //------------------------------------------------------------------------------------------
179 :
180 : dbcontroller::t_mutex dbcontroller::this_lock;
181 :
182 : //------------------------------------------------------------------------------------------
183 2 : dbcontroller::dbcontroller() = default;
184 : //------------------------------------------------------------------------------------------
185 :
186 : //------------------------------------------------------------------------------------------
187 : dbcontroller&
188 14 : dbcontroller::ref()
189 : {
190 14 : static dbcontroller self;
191 14 : return self;
192 : }
193 : //------------------------------------------------------------------------------------------
194 :
195 : //------------------------------------------------------------------------------------------
196 : void
197 6 : dbcontroller::flush()
198 : {
199 6 : dbcontroller& me = dbcontroller::ref();
200 6 : locker l(me.this_lock);
201 6 : me.this_allobjects.clear();
202 6 : }
203 : //------------------------------------------------------------------------------------------
204 :
205 : //------------------------------------------------------------------------------------------
206 : std::vector<tref>
207 0 : dbcontroller::referenced_by(configobject::tref objref, std::string const& name, bool check_composite_only)
208 : {
209 0 : std::vector<ConfigObject> linked;
210 0 : objref.ref().referenced_by(linked, name, check_composite_only);
211 :
212 0 : std::vector<configobject::tref> references;
213 :
214 0 : for (ConfigObject const& anobj : linked) {
215 0 : try {
216 0 : references.push_back(get({ anobj.UID(), anobj.class_name() }));
217 0 : } catch (daq::dbe::config_object_retrieval_result_is_null const& e) {
218 : // nothing needed to do here, since this just signal that
219 : // some of the relation results are null
220 0 : }
221 : }
222 :
223 0 : return references;
224 0 : }
225 : //------------------------------------------------------------------------------------------
226 :
227 : //------------------------------------------------------------------------------------------
228 : template<typename T>
229 : configobject::gref<T>
230 0 : dbcontroller::delete_object_request(configobject::tref const& obj,
231 : typename configobject::gref<T>::config_action_notifiable notice)
232 : {
233 0 : configobject::gref<T> subgraph = dbcontroller::ref().remove<T>(obj);
234 0 : subgraph.notify(notice);
235 0 : return subgraph;
236 0 : }
237 :
238 : template configobject::gref<dbe::config_object_aggregates<std::string>>
239 : dbcontroller::delete_object_request(
240 : configobject::tref const&,
241 : configobject::gref<dbe::config_object_aggregates<std::string>>::config_action_notifiable);
242 :
243 : //------------------------------------------------------------------------------------------
244 :
245 : //------------------------------------------------------------------------------------------
246 : /*
247 : * Create an object in the database.
248 : *
249 : * If the object cannot be created an exception will be thrown
250 : * by the underlying database access layer, as it cannot be handled here.
251 : *
252 : * If the object is already in the underlying container the object reference will be updated
253 : * to point to the new object reference, transparently to user classes of the controller
254 : */
255 : configobject::tref
256 0 : dbcontroller::create_object_request(dbe::t_config_object_preimage const& image)
257 : {
258 0 : ConfigObject result = config::api::rwdacc::create_object(image.fn, image.ref.this_class, image.ref.this_name);
259 :
260 0 : tref el = dbcontroller::ref().insert(result);
261 0 : try {
262 0 : return dbe::config::api::rwdacc::set_object(el, image.attributes, image.relations);
263 0 : } catch (dunedaq::conffwk::Exception const& e) {
264 : // just need to remove the object from the underlying database
265 0 : dbcontroller::ref().remove<config_object_aggregator>(el);
266 0 : throw;
267 0 : } catch (daq::dbe::Exception const& e) {
268 : // just need to remove the object from the underlying database
269 0 : dbcontroller::ref().remove<config_object_aggregator>(el);
270 0 : throw;
271 0 : }
272 0 : }
273 :
274 : template<typename T>
275 : configobject::tref
276 : dbcontroller::create_object_request(configobject::aref<T> const& obj)
277 : {
278 : return dbcontroller::create_object_request(obj.this_object_image);
279 : }
280 :
281 : template<typename T>
282 : configobject::tref
283 : dbcontroller::create_object_request(configobject::gref<T> const& obj)
284 : {
285 : return obj.rebuild();
286 : }
287 :
288 : template<typename T>
289 : configobject::tref
290 0 : dbcontroller::create_object_request(configobject::gref<T>& obj,
291 : typename configobject::gref<T>::config_action_notifiable notice)
292 : {
293 0 : tref ret = obj.rebuild();
294 0 : obj.notify(notice);
295 0 : return ret;
296 0 : }
297 :
298 : template dbe::inner::configobject::tref
299 : dbe::inner::dbcontroller::create_object_request<dbe::config_object_aggregates<std::string>>(
300 : dbe::inner::configobject::gref<dbe::config_object_aggregates<std::string>>&,
301 : dbe::inner::configobject::gref<dbe::config_object_aggregates<std::string>>::config_action_notifiable);
302 : //------------------------------------------------------------------------------------------
303 :
304 : //------------------------------------------------------------------------------------------
305 : configobject::tref
306 0 : dbcontroller::move_object_request(configobject::tref objref, std::string const& destfile)
307 : {
308 0 : if (not objref.is_null()) {
309 0 : static_cast<ConfigObject&>(*(objref.refered)).move(destfile);
310 : }
311 :
312 0 : return objref;
313 : }
314 : //------------------------------------------------------------------------------------------
315 :
316 : //------------------------------------------------------------------------------------------
317 : configobject::tref
318 0 : dbcontroller::rename_object_request(configobject::tref objref, std::string const& newname)
319 : {
320 0 : return dbcontroller::ref().rename(objref, newname);
321 : }
322 : //------------------------------------------------------------------------------------------
323 :
324 : //------------------------------------------------------------------------------------------
325 : configobject::tref
326 0 : dbcontroller::rename(configobject::tref objref, std::string const& aname)
327 : {
328 0 : if (not objref.is_null()) {
329 : // pick up the pointer
330 0 : std::shared_ptr<configobject::oref> current_ptr = objref.refered;
331 :
332 : // remove the current reference from the internal map
333 0 : this_allobjects.erase(*current_ptr);
334 0 : try {
335 : // rename the refered object
336 0 : dbe::config::api::rwdacc::rename_object(static_cast<ConfigObject&>(*current_ptr), aname);
337 0 : } catch (dunedaq::conffwk::Generic const& e) {
338 : // Logging the error but this may not affect program execution per-se
339 0 : FAIL("Object rename failure", dbe::config::errors::parse(e).c_str());
340 0 : }
341 : // position it in its proper place
342 0 : bool nofail;
343 0 : t_object_map::iterator position;
344 0 : std::tie(position, nofail) = this_allobjects.emplace(*current_ptr, current_ptr);
345 :
346 0 : if (not nofail) {
347 0 : throw daq::dbe::dbcontroller_internal_cache_failure(ERS_HERE);
348 : }
349 0 : return position->second;
350 0 : }
351 0 : return objref;
352 : }
353 : //------------------------------------------------------------------------------------------
354 :
355 : //------------------------------------------------------------------------------------------
356 : configobject::tref
357 2 : dbcontroller::get(dbe::cokey const& key)
358 : {
359 2 : return dbcontroller::ref().lookup(key);
360 : }
361 :
362 : std::vector<configobject::tref>
363 2 : dbcontroller::gets(std::string const& cname, std::string const& query)
364 : {
365 2 : std::vector<ConfigObject> database_objects = config::api::rwdacc::query_class(cname, query);
366 2 : std::vector<configobject::tref> result;
367 :
368 8 : for (ConfigObject const& keyin : database_objects) {
369 6 : try {
370 6 : result.push_back(dbcontroller::ref().lookup({ keyin.UID(), keyin.class_name() }));
371 0 : } catch (daq::dbe::config_object_retrieval_result_is_null const& e) {
372 : // nothing needs be done to specifically handle this case, it just that in some
373 : // cases the underlying database does not contain initialized objects
374 0 : }
375 : }
376 2 : return result;
377 2 : }
378 : //------------------------------------------------------------------------------------------
379 :
380 : //------------------------------------------------------------------------------------------
381 : configobject::tref
382 8 : dbcontroller::lookup(dbe::cokey const& key)
383 : {
384 : // Find the object in the database
385 8 : t_object_map::iterator position = this_allobjects.find(key);
386 :
387 8 : if (position == this_allobjects.end()) {
388 : // if it is not in the cache we need to add it
389 5 : ConfigObject toinsert = dbe::config::api::rwdacc::get_object(key.this_class, key.this_name);
390 5 : if (not toinsert.is_null()) {
391 5 : return insert(static_cast<ConfigObject>(toinsert));
392 : }
393 5 : } else {
394 3 : return position->second;
395 : }
396 :
397 0 : throw daq::dbe::config_object_retrieval_result_is_null(ERS_HERE, key.this_name + "@" + key.this_class);
398 : }
399 : //------------------------------------------------------------------------------------------
400 :
401 : //------------------------------------------------------------------------------------------
402 : configobject::tref
403 5 : dbcontroller::insert(ConfigObject const& obj)
404 : {
405 : // Construct the oref to add in the internal map
406 5 : std::shared_ptr<configobject::oref> element(new configobject::oref(obj));
407 :
408 5 : bool object_inserted;
409 5 : t_object_map::iterator position;
410 :
411 5 : locker l(this_lock);
412 5 : std::tie(position, object_inserted) = this_allobjects.emplace(*element, element);
413 :
414 5 : if (not object_inserted) {
415 : // Object is already defined in the database and we replace the old reference with the new.
416 : // A case is if there have been external modification and we try to replay changes
417 0 : static_cast<ConfigObject&>(*position->second) = obj;
418 : }
419 :
420 10 : return position->second;
421 5 : }
422 : //------------------------------------------------------------------------------------------
423 :
424 : //------------------------------------------------------------------------------------------
425 : template<typename T>
426 : configobject::gref<T>
427 0 : dbcontroller::remove(dbe::tref ref)
428 : {
429 0 : configobject::gref<T> subgraph;
430 :
431 : {
432 0 : locker l(this_lock);
433 : // Record the associated subgraph
434 0 : if (not ref.is_null()) {
435 0 : subgraph.record(ref);
436 : }
437 :
438 : // Need to remove from the internal map all candidates, they will be added at post processing
439 0 : for (T const& key : subgraph.this_remove_stack) {
440 : // Remove from the internal map
441 0 : this_allobjects.erase({ key.ref.UID(), key.ref.class_name() });
442 : }
443 0 : }
444 :
445 : // Delete the object from the database
446 0 : dbe::config::api::rwdacc::destroy_object(ref.ref());
447 : // Post-process the object recorded subgraph
448 0 : subgraph.post();
449 :
450 0 : return subgraph;
451 0 : }
452 : //------------------------------------------------------------------------------------------
453 :
454 : }
455 : // namespace inner
456 :
457 : template<typename S>
458 : inner::configobject::tref
459 0 : config_object_description<S>::ref() const
460 : {
461 0 : if (this_referenced_object.is_null()) {
462 0 : this_referenced_object = dbe::inner::dbcontroller::get({ this->this_name, this->this_class });
463 : }
464 0 : return this_referenced_object;
465 : }
466 :
467 : } // namespace dbe
|