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