DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
Configuration.cpp
Go to the documentation of this file.
1//
2// DUNE DAQ modification notice:
3// This file has been modified from the original ATLAS config source for the DUNE DAQ project.
4// Fork baseline commit: 67a24e731 (2022-10-27).
5// Renamed since fork: no.
6//
7
8#include <iostream>
9#include <regex>
10#include <sstream>
11#include <stdlib.h>
12#include <unordered_map>
13
14#include <dlfcn.h>
15
16#include "ers/ers.hpp"
18
19#include "conffwk/Change.hpp"
25#include "conffwk/DalObject.hpp"
27#include "conffwk/Schema.hpp"
28
29namespace dunedaq {
30
31ERS_DEFINE_ISSUE_CXX(conffwk, Exception, , )
32
34
38 type << " \"" << data << "\" is not found",
39 ,
40 ((const char*)type)((const char*)data))
41
45 "object \'" << object_id << '@' << class_name << "\' was deleted",
46 ,
47 ((const char*)class_name)((const char*)object_id))
48
49namespace conffwk {
50
51template<typename T>
52static T*
53get_new(ConfigObject& co, const std::string& attrname)
54{
55 T* retval = new T;
56 co.get(attrname, *retval);
57 return retval;
58}
59
60void
62{
63 std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
64 m_actions.push_back(ac);
65}
66
67void
69{
70 std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
71 m_actions.remove(ac);
72}
73
74void
75Configuration::action_on_update(const ConfigObject& obj, const std::string& name)
76{
77 std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
78 for (auto& i : m_actions)
79 i->update(obj, name);
80}
81
83
84static bool
86{
87 return (getenv("TDAQ_DB_PREFETCH_ALL_DATA") != nullptr);
88}
89
91
93 : p_number_of_cache_hits(0)
94 , p_number_of_template_object_created(0)
95 , p_number_of_template_object_read(0)
96 , m_impl(nullptr)
97 , m_shlib_h(nullptr)
98 , m_registry(*this)
99{
100}
101
102Configuration::Configuration(const std::string& spec)
106 , m_impl(nullptr)
107 , m_shlib_h(nullptr)
108 , m_registry(*this)
109{
110 std::string s;
111
112 if (spec.empty()) {
113 if (const char* env = getenv("TDAQ_DB"))
114 m_impl_spec = env;
115 } else {
116 m_impl_spec = spec;
117 }
118
119 if (m_impl_spec.empty())
120 throw dunedaq::conffwk::Generic(
121 ERS_HERE,
122 "no database parameter found (check parameter of the constructor or value of TDAQ_DB environment variable)");
123
124 std::string::size_type idx = m_impl_spec.find_first_of(':');
125
126 if (idx == std::string::npos) {
128 } else {
129 m_impl_name = m_impl_spec.substr(0, idx);
130 m_impl_param = m_impl_spec.substr(idx + 1);
131 }
132
133 std::string plugin_name = std::string("lib") + m_impl_name + ".so";
134 std::string impl_creator = std::string("_") + m_impl_name + "_creator_";
135
136 // load plug-in
137 m_shlib_h = dlopen(plugin_name.c_str(), RTLD_LAZY | RTLD_GLOBAL);
138
139 if (!m_shlib_h) {
140 std::ostringstream text;
141 text << "failed to load implementation plug-in \'" << plugin_name << "\': \"" << dlerror() << '\"';
142 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str()));
143 }
144
145 // search in plug-in implementation creator function
146
147 ConfigurationImpl* (*f)(const std::string& spec);
148
149 f = (ConfigurationImpl * (*)(const std::string&)) dlsym(m_shlib_h, impl_creator.c_str());
150
151 char* error = 0;
152
153 if ((error = dlerror()) != 0) {
154 std::ostringstream text;
155 text << "failed to find implementation creator function \'" << impl_creator << "\' in plug-in \'" << plugin_name
156 << "\': \"" << error << '\"';
157 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str()));
158 }
159
160 // create implementation
161
162 m_impl = (*f)(m_impl_param);
163
164 if (m_impl) {
165 // m_impl->get_superclasses(p_superclasses);
166 // set_subclasses();
168 m_impl->set(this);
169 }
170
173
174 TLOG_DEBUG(2) << "\n*** DUMP CONFIGURATION ***\n" << *this;
175}
176
177void
179{
180 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
181
182 std::cout << "Configuration profiler report:\n"
183 " number of created template objects: "
185 << "\n"
186 " number of read template objects: "
188 << "\n"
189 " number of cache hits: "
190 << p_number_of_cache_hits << std::endl;
191
192 // FIXME: re-implement for the dal registry
193 // const char * s = ::getenv("TDAQ_DUMP_CONFFWK_PROFILER_INFO");
194 // if (s && !strcmp(s, "DEBUG"))
195 // {
196 // std::cout << " Details of accessed objects:\n";
197
198 // for (auto & i : m_cache_map)
199 // {
200 // Cache<DalObject> *c = static_cast<Cache<DalObject>*>(i.second);
201 // std::cout << " *** " << c->m_cache.size() << " objects is class \'" << *i.first << "\' were accessed
202 // ***\n"; for (auto & j : c->m_cache)
203 // std::cout << " - object \'" << j.first << '\'' << std::endl;
204 // }
205 // }
206
207 if (m_impl) {
210 }
211}
212
214{
215 if (::getenv("TDAQ_DUMP_CONFFWK_PROFILER_INFO"))
217
218 try {
219 unload();
220
221 if (m_shlib_h) {
222 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
223
224 delete m_impl;
225 m_impl = 0;
226 // dlclose(m_shlib_h);
227 m_shlib_h = 0;
228 }
229 } catch (dunedaq::conffwk::Generic& ex) {
230 ers::error(ex);
231 }
232}
233
234void
235Configuration::get(const std::string& class_name,
236 const std::string& id,
237 ConfigObject& object,
238 unsigned long rlevel,
239 const std::vector<std::string>* rclasses)
240{
241 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
242 _get(class_name, id, object, rlevel, rclasses);
243}
244
245void
246Configuration::_get(const std::string& class_name,
247 const std::string& name,
248 ConfigObject& object,
249 unsigned long rlevel,
250 const std::vector<std::string>* rclasses)
251{
252 try {
253 m_impl->get(class_name, name, object, rlevel, rclasses);
254 } catch (dunedaq::conffwk::Generic& ex) {
255 std::ostringstream text;
256 text << "failed to get object \'" << name << '@' << class_name << '\'';
257 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
258 }
259}
260
261void
262Configuration::get(const std::string& class_name,
263 std::vector<ConfigObject>& objects,
264 const std::string& query,
265 unsigned long rlevel,
266 const std::vector<std::string>* rclasses)
267{
268 try {
269 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
270 m_impl->get(class_name, objects, query, rlevel, rclasses);
271 } catch (dunedaq::conffwk::Generic& ex) {
272 std::ostringstream text;
273 text << "failed to get objects of class \'" << class_name << '\'';
274 if (!query.empty()) {
275 text << " with query \'" << query << '\'';
276 }
277 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
278 }
279}
280
281void
283 const std::string& query,
284 std::vector<ConfigObject>& objects,
285 unsigned long rlevel,
286 const std::vector<std::string>* rclasses)
287{
288 try {
289 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
290 m_impl->get(obj_from, query, objects, rlevel, rclasses);
291 } catch (dunedaq::conffwk::Generic& ex) {
292 std::ostringstream text;
293 text << "failed to get path \'" << query << "\' from object \'" << obj_from << '\'';
294 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
295 }
296}
297
298bool
299Configuration::loaded() const noexcept
300{
301 return (m_impl != nullptr) ? m_impl->loaded() : false;
302}
303
304void
305Configuration::load(const std::string& db_name)
306{
307 std::string name;
308
309 if (db_name.empty()) {
310 if (!m_impl_spec.empty() && !m_impl_param.empty()) {
311 name = m_impl_param;
312 } else {
313 const char* s = ::getenv("TDAQ_DB_NAME");
314 if (s == 0 || *s == 0)
315 s = ::getenv("TDAQ_DB_DATA");
316
317 if (s && *s) {
318 name = s;
319 } else {
320 throw(dunedaq::conffwk::Generic(ERS_HERE, "no database name was provided"));
321 }
322 }
323 } else {
324 name = db_name;
325 }
326
327 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
328
329 // call conffwk actions if any
330 {
331 std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
332 for (auto& i : m_actions) {
333 i->load();
334 }
335 }
336
337 if (m_impl) {
338 m_impl->open_db(name);
339 // m_impl->get_superclasses(p_superclasses);
340 // set_subclasses();
342 m_impl->set(this);
343
344 if (check_prefetch_needs()) {
346 }
347
348 TLOG_DEBUG(2) << "\n*** DUMP CONFIGURATION ***\n" << *this;
349 } else {
350 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
351 }
352}
353
354void
356{
357 if (m_impl == nullptr)
358 throw dunedaq::conffwk::Generic(ERS_HERE, "nothing to unload");
359
360 std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
361 std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
362
363 // call conffwk actions if any
364 {
365 std::lock_guard<std::mutex> scoped_lock(m_actn_mutex);
366 for (auto& i : m_actions) {
367 i->unload();
368 }
369 }
370
371 // for (auto& i : m_cache_map) {
372 // delete i.second;
373 // }
374
375 // m_cache_map.clear();
377
378 {
379 std::lock_guard<std::mutex> scoped_lock3(m_else_mutex);
380
381 for (auto& cb : m_callbacks)
382 delete cb;
383
384 for (auto& cb : m_pre_callbacks)
385 delete cb;
386
387 m_callbacks.clear();
388 m_pre_callbacks.clear();
389
391
392 for (auto& l : m_convert_map) {
393 for (auto& a : *l.second)
394 delete a;
395
396 delete l.second;
397 }
398
399 m_convert_map.clear();
400 }
401
402 p_superclasses.clear();
403
404 for (auto& j : p_direct_classes_desc_cache)
405 delete j.second;
406
407 for (auto& j : p_all_classes_desc_cache)
408 delete j.second;
409
412
413 m_impl->close_db();
414}
415
416void
417Configuration::create(const std::string& db_name, const std::list<std::string>& includes)
418{
419 if (m_impl == nullptr)
420 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
421
422 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
423
424 try {
425 m_impl->create(db_name, includes);
427 } catch (dunedaq::conffwk::Generic& ex) {
428 std::ostringstream text;
429 text << "failed to create database \'" << db_name << '\'';
430 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
431 }
432}
433
434bool
435Configuration::is_writable(const std::string& db_name) const
436{
437 if (m_impl == nullptr)
438 throw(dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded"));
439
440 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
441
442 try {
443 return m_impl->is_writable(db_name);
444 } catch (dunedaq::conffwk::Generic& ex) {
445 std::ostringstream text;
446 text << "failed to get write access status for database \'" << db_name << '\'';
447 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
448 }
449}
450
451void
452Configuration::add_include(const std::string& db_name, const std::string& include)
453{
454 if (m_impl == nullptr)
455 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
456
457 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
458
459 try {
460 m_impl->add_include(db_name, include);
461 // m_impl->get_superclasses(p_superclasses);
462 // set_subclasses();
464 } catch (dunedaq::conffwk::Generic& ex) {
465 std::ostringstream text;
466 text << "failed to add include \'" << include << "\' to database \'" << db_name << '\'';
467 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
468 }
469}
470
471void
472Configuration::remove_include(const std::string& db_name, const std::string& include)
473{
474 if (m_impl == nullptr)
475 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
476
477 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
478 std::lock_guard<std::mutex> scoped_lock2(m_tmpl_mutex);
479
480 try {
481 m_impl->remove_include(db_name, include);
482 // m_impl->get_superclasses(p_superclasses);
483 // set_subclasses();
485 } catch (dunedaq::conffwk::Generic& ex) {
486 std::ostringstream text;
487 text << "failed to remove include \'" << include << "\' from database \'" << db_name << '\'';
488 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
489 }
490}
491
492void
493Configuration::get_includes(const std::string& db_name, std::list<std::string>& includes) const
494{
495 if (m_impl == nullptr)
496 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
497
498 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
499
500 try {
501 m_impl->get_includes(db_name, includes);
502 } catch (dunedaq::conffwk::Generic& ex) {
503 std::ostringstream text;
504 text << "failed to get includes of database \'" << db_name << '\'';
505 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
506 }
507}
508
509void
510Configuration::get_updated_dbs(std::list<std::string>& dbs) const
511{
512 if (m_impl == nullptr)
513 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
514
515 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
516
517 try {
519 } catch (dunedaq::conffwk::Generic& ex) {
520 throw(dunedaq::conffwk::Generic(ERS_HERE, "get_updated_dbs failed", ex));
521 }
522}
523
524void
525Configuration::set_commit_credentials(const std::string& user, const std::string& password)
526{
527 if (m_impl == nullptr)
528 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
529
530 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
531
532 try {
533 m_impl->set_commit_credentials(user, password);
534 } catch (dunedaq::conffwk::Generic& ex) {
535 throw(dunedaq::conffwk::Generic(ERS_HERE, "set_commit_credentials failed", ex));
536 }
537}
538
539void
540Configuration::commit(const std::string& log_message)
541{
542 TLOG_DEBUG(1) << "call commit";
543
544 if (m_impl == nullptr)
545 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
546
547 std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
548 std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
549
550 try {
551 m_impl->commit(log_message);
552 } catch (dunedaq::conffwk::Generic& ex) {
553 throw(dunedaq::conffwk::Generic(ERS_HERE, "commit failed", ex));
554 }
555}
556
557void
559{
560 TLOG_DEBUG(1) << "call abort";
561
562 if (m_impl == nullptr)
563 throw dunedaq::conffwk::Generic(ERS_HERE, "no implementation loaded");
564
565 std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
566 std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
567
568 try {
569 m_impl->abort();
572 // m_impl->get_superclasses(p_superclasses);
573 // set_subclasses();
575
576 } catch (dunedaq::conffwk::Generic& ex) {
577 throw(dunedaq::conffwk::Generic(ERS_HERE, "abort failed", ex));
578 }
579}
580
581void
583{
584 std::lock_guard<std::mutex> scoped_lock1(m_tmpl_mutex); // always lock template objects mutex first
585 std::lock_guard<std::mutex> scoped_lock2(m_impl_mutex);
586
587 try {
589 } catch (dunedaq::conffwk::Generic& ex) {
590 throw(dunedaq::conffwk::Generic(ERS_HERE, "prefetch all data failed", ex));
591 }
592}
593
594void
595Configuration::unread_all_objects(bool unread_implementation_objs) noexcept
596{
597 if (unread_implementation_objs)
599
601}
602
603// FIXME: find better name?
604void
609
610void
612{
613 for (auto& i : m_impl->m_impl_objects)
614 for (auto& j : *i.second) {
615 std::lock_guard<std::mutex> scoped_lock(j.second->m_mutex);
616 j.second->clear();
617 j.second->m_state = state;
618 }
619
620 for (auto& x : m_impl->m_tangled_objects) {
621 std::lock_guard<std::mutex> scoped_lock(x->m_mutex);
622 x->clear();
623 x->m_state = state;
624 }
625}
626
627void
629{
630 p_subclasses.clear();
631
632 for (const auto& i : p_superclasses)
633 for (const auto& j : i.second)
634 p_subclasses[j].insert(i.first);
635}
636
637void
645
646std::deque<std::set<std::string>>
648{
649 std::deque<std::set<std::string>> domains;
650
651 std::deque<dunedaq::conffwk::class_t> seeds;
652 for (const auto& c : get_class_list()) {
653 auto ci = this->_get_class_info(c);
654 if (ci.p_superclasses.empty())
655 seeds.push_back(ci);
656 }
657
658 for (const auto& ci : seeds) {
659 // Make a candidate domain based using the seed subclasses
660 std::set<std::string> class_domain;
661 class_domain.insert(ci.p_name);
662 class_domain.insert(ci.p_subclasses.begin(), ci.p_subclasses.end());
663
664 // Look for overlaps with other domains
665 std::deque<std::set<std::string>> overlapping;
666 for (auto& d : domains) {
667 std::set<std::string> intersection;
668 std::set_intersection(d.begin(),
669 d.end(),
670 class_domain.begin(),
671 class_domain.end(),
672 std::inserter(intersection, intersection.begin()));
673 // non-zero intersection, overlap found
674 if (intersection.size() > 0) {
675 overlapping.push_back(d);
676 }
677 }
678
679 // If overlapping are found, add all overlapping to
680 // the new domain and remove them from the domain list
681 if (!overlapping.empty()) {
682 for (auto& d : overlapping) {
683 // merge the existing cluster in class_domain
684 class_domain.insert(d.begin(), d.end());
685 // Remove the old cluster from the list
686 auto it = std::find(domains.begin(), domains.end(), d);
687 if (it != domains.end()) {
688 domains.erase(it);
689 }
690 }
691 }
692
693 domains.push_back(class_domain);
694 }
695
696 return domains;
697}
698
699void
701{
702
703 p_class_domain_map.clear();
704
705 auto domains = this->find_class_domains();
706 for (size_t i(0); i < domains.size(); ++i) {
707 const auto& dom = domains[i];
708 for (const auto& class_name : dom) {
709 p_class_domain_map[&conffwk::DalFactory::instance().get_known_class_name_ref(class_name)] = i;
710 }
711 }
712}
713
715
716//
717// Test, create and destroy object methods
718//
719
721
722bool
723Configuration::test_object(const std::string& class_name,
724 const std::string& id,
725 unsigned long rlevel,
726 const std::vector<std::string>* rclasses)
727{
728 try {
729 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
730 return m_impl->test_object(class_name, id, rlevel, rclasses);
731 } catch (dunedaq::conffwk::Generic& ex) {
732 std::ostringstream text;
733 text << "failed to test existence of object \'" << id << '@' << class_name << '\'';
734 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
735 }
736}
737
738void
739Configuration::create(const std::string& at, const std::string& class_name, const std::string& id, ConfigObject& object)
740{
741 try {
742 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
743 m_impl->create(at, class_name, id, object);
744 } catch (dunedaq::conffwk::Generic& ex) {
745 std::ostringstream text;
746 text << "failed to create object \'" << id << '@' << class_name << '\'';
747 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
748 }
749}
750
751void
753 const std::string& class_name,
754 const std::string& id,
755 ConfigObject& object)
756{
757 try {
758 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
759 m_impl->create(at, class_name, id, object);
760 } catch (dunedaq::conffwk::Generic& ex) {
761 std::ostringstream text;
762 text << "failed to create object \'" << id << '@' << class_name << '\'';
763 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
764 }
765}
766
767void
769{
770 try {
771 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
772 std::lock_guard<std::mutex> scoped_lock2(m_tmpl_mutex);
773 m_impl->destroy(object);
774 } catch (dunedaq::conffwk::Generic& ex) {
775 std::ostringstream text;
776 text << "failed to destroy object \'" << object << '\'';
777 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
778 }
779}
780
781void
783{
784 std::lock_guard<std::mutex> scoped_impl_lock(m_tmpl_mutex); // always lock template objects mutex first
785 std::lock_guard<std::mutex> scoped_tmpl_lock(m_impl_mutex);
786
787 std::lock_guard<std::mutex> scoped_obj_lock(obj.m_impl->m_mutex);
788
789 const std::string old_id(obj.m_impl->m_id);
790
791 obj.m_impl->throw_if_deleted();
792 obj.m_impl->rename(new_id);
793 obj.m_impl->m_id = new_id;
794 m_impl->rename_impl_object(obj.m_impl->m_class_name, old_id, new_id);
795
796 TLOG_DEBUG(3) << " * call rename \'" << old_id << "\' to \'" << new_id << "\' in class \'" << obj.class_name()
797 << "\')";
798
799 m_registry._rename_object(obj.class_name(), old_id, new_id);
800
801 // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(&obj.class_name());
802 // if (j != m_cache_map.end())
803 // j->second->m_functions.m_rename_object_fn(j->second, old_id, new_id);
804
805 // conffwk::fmap<conffwk::fset>::const_iterator sc = p_superclasses.find(&obj.class_name());
806
807 // if (sc != p_superclasses.end())
808 // for (conffwk::fset::const_iterator c = sc->second.begin(); c != sc->second.end(); ++c)
809 // {
810 // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(*c);
811
812 // if (j != m_cache_map.end())
813 // j->second->m_functions.m_rename_object_fn(j->second, old_id, new_id);
814 // }
815}
816
818//
819// Meta-information access methods
820//
822
824Configuration::get_class_info(const std::string& class_name, bool direct_only)
825{
826 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
827
828 return this->_get_class_info(class_name, direct_only);
829}
830
832Configuration::_get_class_info(const std::string& class_name, bool direct_only)
833{
836
838
839 if (i != d_cache.end())
840 return *(i->second);
841
842 try {
843 dunedaq::conffwk::class_t* d = m_impl->get(class_name, direct_only);
844 d_cache[class_name] = d;
845 return *d;
846 }
847 // catch Generic exception only; the NotFound is forwarded from implementation
848 catch (dunedaq::conffwk::Generic& ex) {
849 std::ostringstream text;
850 text << "failed to get description of class \'" << class_name << '\'';
851 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex);
852 }
853}
854
856
857static void
858init_regex(std::unique_ptr<std::regex>& ptr, const std::string& str, const char* what)
859{
860 if (!str.empty())
861 try {
862 ptr = std::make_unique<std::regex>(str);
863 } catch (const std::regex_error& ex) {
864 std::ostringstream text;
865 text << "failed to create " << what << " regex \"" << str << "\": " << ex.what();
866 throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str());
867 }
868}
869
870template<class T>
871static void
872add_array_item(boost::property_tree::ptree& pt, const T& val)
873{
874 boost::property_tree::ptree child;
875 child.put("", val);
876 pt.push_back(std::make_pair("", child));
877}
878
879void
880Configuration::export_schema(boost::property_tree::ptree& pt, const std::string& classes_str, bool direct_only)
881{
882 std::unique_ptr<std::regex> classes_regex;
883
884 init_regex(classes_regex, classes_str, "classes");
885
886 auto cmp_str_ptr = [](const std::string* s1, const std::string* s2) { return *s1 < *s2; };
887 std::set<const std::string*, decltype(cmp_str_ptr)> sorted_classes(cmp_str_ptr);
888
889 for (const auto& c : superclasses())
890 if (classes_str.empty() || std::regex_match(*c.first, *classes_regex.get()))
891 sorted_classes.insert(c.first);
892
893 for (const auto& c : sorted_classes)
894 if (classes_str.empty() || std::regex_match(*c, *classes_regex.get())) {
895 const dunedaq::conffwk::class_t& info(get_class_info(*c, direct_only));
896
897 boost::property_tree::ptree class_pt;
898
899 class_pt.put("abstract", info.p_abstract);
900 if (!info.p_description.empty())
901 class_pt.put("description", info.p_description);
902
903 if (!info.p_superclasses.empty()) {
904 boost::property_tree::ptree superclasses;
905
906 for (const auto& x : info.p_superclasses)
908
909 class_pt.add_child("superclasses", superclasses);
910 }
911
912 if (!info.p_attributes.empty()) {
913 boost::property_tree::ptree attributes;
914
915 for (const auto& x : info.p_attributes) {
916 boost::property_tree::ptree attribute;
917
918 attribute.put("type", dunedaq::conffwk::attribute_t::type(x.p_type));
919 if (!x.p_range.empty())
920 attribute.put("range", x.p_range);
921 if (x.p_int_format != dunedaq::conffwk::na_int_format)
922 attribute.put("format", dunedaq::conffwk::attribute_t::format2str(x.p_int_format));
923 if (x.p_is_not_null)
924 attribute.put("is-not-null", x.p_is_not_null);
925 if (x.p_is_multi_value)
926 attribute.put("is-multi-value", x.p_is_multi_value);
927 if (!x.p_default_value.empty())
928 attribute.put("default-value", x.p_default_value);
929 if (!x.p_description.empty())
930 attribute.put("description", x.p_description);
931
932 attributes.push_back(boost::property_tree::ptree::value_type(x.p_name, attribute));
933 }
934
935 class_pt.add_child("attributes", attributes);
936 }
937
938 if (!info.p_relationships.empty()) {
939 boost::property_tree::ptree relationships;
940
941 for (const auto& x : info.p_relationships) {
942 boost::property_tree::ptree relationship;
943
944 relationship.put("type", x.p_type);
945 relationship.put("cardinality", dunedaq::conffwk::relationship_t::card2str(x.p_cardinality));
946 if (!x.p_is_aggregation)
947 relationship.put("is-aggregation", x.p_is_aggregation);
948 if (!x.p_description.empty())
949 relationship.put("description", x.p_description);
950
951 relationships.push_back(boost::property_tree::ptree::value_type(x.p_name, relationship));
952 }
953
954 class_pt.add_child("relationships", relationships);
955 }
956
957 pt.put_child(boost::property_tree::ptree::path_type(*c), class_pt);
958 }
959}
960
961template<class T>
962static void
963add_data(boost::property_tree::ptree& pt,
964 const ConfigObject& obj,
965 const dunedaq::conffwk::attribute_t& attribute,
966 const std::string& empty_array_item)
967{
968 auto& o = const_cast<ConfigObject&>(obj);
969 if (!attribute.p_is_multi_value) {
970 T val;
971 const_cast<ConfigObject&>(obj).get(attribute.p_name, val);
972 pt.put(attribute.p_name, val);
973 } else {
974 std::vector<T> values;
975 o.get(attribute.p_name, values);
976
977 boost::property_tree::ptree children;
978
979 if (!values.empty())
980 for (const auto& v : values)
981 add_array_item(children, v);
982
983 else if (!empty_array_item.empty())
984 add_array_item(children, empty_array_item);
985
986 pt.add_child(attribute.p_name, children);
987 }
988}
989
990static void
991add_data(boost::property_tree::ptree& pt,
992 const ConfigObject& obj,
993 const dunedaq::conffwk::relationship_t& relationship,
994 const std::string& empty_array_item)
995{
996 if (relationship.p_cardinality == dunedaq::conffwk::zero_or_many ||
998 std::vector<ConfigObject> values;
999 const_cast<ConfigObject&>(obj).get(relationship.p_name, values);
1000
1001 boost::property_tree::ptree children;
1002
1003 if (!values.empty())
1004 for (const auto& v : values)
1005 add_array_item(children, v.full_name());
1006
1007 else if (!empty_array_item.empty())
1008 add_array_item(children, empty_array_item);
1009
1010 pt.add_child(relationship.p_name, children);
1011 } else {
1012 ConfigObject val;
1013 const_cast<ConfigObject&>(obj).get(relationship.p_name, val);
1014 pt.put(relationship.p_name, !val.is_null() ? val.full_name() : "");
1015 }
1016}
1017
1018void
1019Configuration::export_data(boost::property_tree::ptree& pt,
1020 const std::string& classes_str,
1021 const std::string& objects_str,
1022 const std::string& files_str,
1023 const std::string& empty_array_item)
1024{
1025 std::unique_ptr<std::regex> classes_regex, objects_regex, files_regex;
1026
1027 init_regex(classes_regex, classes_str, "classes");
1028 init_regex(objects_regex, objects_str, "objects");
1029 init_regex(files_regex, files_str, "files");
1030
1031 auto cmp_str_ptr = [](const std::string* s1, const std::string* s2) { return *s1 < *s2; };
1032 std::set<const std::string*, decltype(cmp_str_ptr)> sorted_classes(cmp_str_ptr);
1033
1034 for (const auto& c : superclasses())
1035 if (classes_str.empty() || std::regex_match(*c.first, *classes_regex.get()))
1036 sorted_classes.insert(c.first);
1037
1038 for (const auto& c : sorted_classes)
1039 if (classes_str.empty() || std::regex_match(*c, *classes_regex.get())) {
1041
1042 boost::property_tree::ptree pt_objects;
1043
1044 std::vector<ConfigObject> objects;
1045 get(*c, objects);
1046
1047 auto comp_obj_ptr = [](const ConfigObject* o1, const ConfigObject* o2) { return o1->UID() < o2->UID(); };
1048 std::set<const ConfigObject*, decltype(comp_obj_ptr)> sorted_objects(comp_obj_ptr);
1049
1050 for (const auto& x : objects)
1051 if (objects_str.empty() || std::regex_match(x.UID(), *objects_regex.get()))
1052 if (x.class_name() == *c)
1053 if (files_str.empty() || std::regex_match(x.contained_in(), *files_regex.get()))
1054 sorted_objects.insert(&x);
1055
1056 if (!sorted_objects.empty()) {
1057 boost::property_tree::ptree pt_objects;
1058
1059 for (const auto& x : sorted_objects) {
1060 boost::property_tree::ptree data;
1061
1062 for (const auto& a : info.p_attributes)
1063 switch (a.p_type) {
1065 add_data<bool>(data, *x, a, empty_array_item);
1066 break;
1068 add_data<int8_t>(data, *x, a, empty_array_item);
1069 break;
1071 add_data<uint8_t>(data, *x, a, empty_array_item);
1072 break;
1074 add_data<int16_t>(data, *x, a, empty_array_item);
1075 break;
1077 add_data<uint16_t>(data, *x, a, empty_array_item);
1078 break;
1080 add_data<int32_t>(data, *x, a, empty_array_item);
1081 break;
1083 add_data<uint32_t>(data, *x, a, empty_array_item);
1084 break;
1086 add_data<int64_t>(data, *x, a, empty_array_item);
1087 break;
1089 add_data<uint64_t>(data, *x, a, empty_array_item);
1090 break;
1092 add_data<float>(data, *x, a, empty_array_item);
1093 break;
1095 add_data<double>(data, *x, a, empty_array_item);
1096 break;
1102 add_data<std::string>(data, *x, a, empty_array_item);
1103 break;
1104 default:
1105 throw std::runtime_error("Invalid type of attribute " + a.p_name);
1106 }
1107
1108 for (const auto& r : info.p_relationships)
1109 add_data(data, *x, r, empty_array_item);
1110
1111 pt_objects.push_back(boost::property_tree::ptree::value_type(x->UID(), data));
1112 }
1113
1114 pt.put_child(boost::property_tree::ptree::path_type(*c), pt_objects);
1115 }
1116 }
1117}
1118
1120
1121//
1122// Methods to get versions
1123//
1124
1126
1127std::vector<dunedaq::conffwk::Version>
1129{
1130 try {
1131 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
1132 return m_impl->get_changes();
1133 } catch (dunedaq::conffwk::Generic& ex) {
1134 throw dunedaq::conffwk::Generic(ERS_HERE, "failed to get new versions", ex);
1135 }
1136}
1137
1138std::vector<dunedaq::conffwk::Version>
1139Configuration::get_versions(const std::string& since,
1140 const std::string& until,
1142 bool skip_irrelevant)
1143{
1144 try {
1145 std::lock_guard<std::mutex> scoped_lock(m_impl_mutex);
1146 return m_impl->get_versions(since, until, type, skip_irrelevant);
1147 } catch (dunedaq::conffwk::Generic& ex) {
1148 throw dunedaq::conffwk::Generic(ERS_HERE, "failed to get versions", ex);
1149 }
1150}
1151
1153
1154//
1155// Subscription and notification methods
1156//
1157
1159
1160// The methods checks that given callback exists
1161
1164{
1165 return ((!cb_handler || (m_callbacks.find(cb_handler) == m_callbacks.end())) ? 0 : cb_handler);
1166}
1167
1169Configuration::subscribe(const ConfigurationSubscriptionCriteria& criteria, notify user_cb, void* parameter)
1170{
1171 // check if there is no subscription function provided
1172
1173 if (!user_cb) {
1174 throw dunedaq::conffwk::Generic(ERS_HERE, "callback function is not defined");
1175 }
1176
1177 // create callback subscription structure
1178
1179 Configuration::CallbackSubscription* cs = new CallbackSubscription();
1180
1181 cs->m_criteria = criteria;
1182 cs->m_cb = user_cb;
1183 cs->m_param = parameter;
1184
1185 // FIXME: bug in OksConfiguration subscribe() with enter_loop=true
1186 std::lock_guard<std::mutex> scoped_lock(m_else_mutex); // TEST 2010-02-03
1187
1188 m_callbacks.insert(cs);
1189
1190 try {
1192 return cs;
1193 } catch (dunedaq::conffwk::Generic& ex) {
1194 m_callbacks.erase(cs);
1195 delete cs;
1196 throw dunedaq::conffwk::Generic(ERS_HERE, "subscription failed", ex);
1197 }
1198}
1199
1201Configuration::subscribe(pre_notify user_cb, void* parameter)
1202{
1203 // check if there is no subscription function provided
1204
1205 if (!user_cb)
1206 throw(dunedaq::conffwk::Generic(ERS_HERE, "callback function is not defined"));
1207
1208 // create callback subscription structure
1209
1211
1212 cs->m_cb = user_cb;
1213 cs->m_param = parameter;
1214
1215 {
1216 std::lock_guard<std::mutex> scoped_lock(m_else_mutex);
1217 m_pre_callbacks.insert(cs);
1218 }
1219
1220 return reinterpret_cast<CallbackSubscription*>(cs);
1221}
1222
1223void
1225{
1226 std::lock_guard<std::mutex> scoped_lock(m_else_mutex);
1227
1228 if (id) {
1229 CallbackSet::iterator i = m_callbacks.find(id);
1230 PreCallbackSet::iterator j = m_pre_callbacks.find(reinterpret_cast<CallbackPreSubscription*>(id));
1231
1232 if (i != m_callbacks.end()) {
1233 delete id;
1234 m_callbacks.erase(i);
1235 } else if (j != m_pre_callbacks.end()) {
1236 delete reinterpret_cast<CallbackPreSubscription*>(id);
1237 m_pre_callbacks.erase(j);
1238 } else {
1239 std::ostringstream text;
1240 text << "unsubscription failed for CallbackId = " << (void*)id << " (no such callback id found)";
1241 throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str()));
1242 }
1243 } else {
1244 for (auto& i : m_callbacks)
1245 delete i;
1246
1247 for (auto& i : m_pre_callbacks)
1248 delete i;
1249
1250 m_callbacks.clear();
1251 m_pre_callbacks.clear();
1252 }
1253
1254 try {
1256 } catch (dunedaq::conffwk::Generic& ex) {
1257 throw dunedaq::conffwk::Generic(ERS_HERE, "unsubscription failed", ex);
1258 }
1259}
1260
1261void
1263{
1264 // check that there is no at least one subscription
1265 // if NO, then unsubscribe
1266
1267 if (m_callbacks.empty()) {
1269 return;
1270 }
1271
1272 // prepare subscription criteria
1273
1275 std::set<std::string> class_subscriptions;
1276
1277 // among existing subscriptions find one who has all subscriptions
1278
1279 bool found_subscribe_all = false;
1280
1281 for (const auto& i : m_callbacks)
1282 if (i->m_criteria.get_classes_subscription().empty() && i->m_criteria.get_objects_subscription().empty()) {
1283 found_subscribe_all = true;
1284 break;
1285 }
1286
1287 if (found_subscribe_all == false) {
1288 // build list of all classes for which there is a subscription
1289 for (const auto& i : m_callbacks)
1290 for (const auto& j : i->m_criteria.get_classes_subscription())
1291 class_subscriptions.insert(j);
1292
1293 // build list of all objects for which there is a subscription (if there is no such class)
1294 for (const auto& i : m_callbacks)
1295 for (const auto& j : i->m_criteria.get_objects_subscription()) {
1296 const std::string& obj_class_name = j.first;
1297 if (class_subscriptions.find(obj_class_name) == class_subscriptions.end())
1298 for (const auto& k : j.second)
1299 obj_subscriptions[obj_class_name].insert(k);
1300 }
1301 }
1302
1303 m_impl->subscribe(class_subscriptions, obj_subscriptions, system_cb, system_pre_cb);
1304}
1305
1306void
1308 ConfigurationChange& change,
1309 const std::string* class_name)
1310{
1311 if (change.get_removed_objs().empty() == false) {
1312 conffwk::pmap<conffwk::map<ConfigObjectImpl*>*>::iterator i = cache.find(class_name);
1313
1314 if (i != cache.end()) {
1315 for (auto& x : change.get_removed_objs()) {
1316 conffwk::map<ConfigObjectImpl*>::iterator j = i->second->find(x);
1317 if (j != i->second->end()) {
1318 TLOG_DEBUG(2) << "set implementation object " << x << '@' << *class_name << " [" << (void*)j->second
1319 << "] deleted";
1320
1321 std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1322 j->second->m_state = dunedaq::conffwk::Deleted;
1323 j->second->clear();
1324 }
1325 }
1326 }
1327 }
1328
1329 if (change.get_created_objs().empty() == false) {
1330 conffwk::pmap<conffwk::map<ConfigObjectImpl*>*>::iterator i = cache.find(class_name);
1331
1332 if (i != cache.end()) {
1333 for (auto& x : change.get_created_objs()) {
1334 conffwk::map<ConfigObjectImpl*>::iterator j = i->second->find(x);
1335 if (j != i->second->end()) {
1336 TLOG_DEBUG(2) << "re-set created implementation object " << x << '@' << *class_name << " ["
1337 << (void*)j->second << ']';
1338
1339 std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1340 j->second->reset(); // it does not matter what the state was, always reset
1341 }
1342 }
1343 }
1344 }
1345
1346 if (change.get_modified_objs().empty() == false) {
1347 conffwk::pmap<conffwk::map<ConfigObjectImpl*>*>::iterator i = cache.find(class_name);
1348
1349 if (i != cache.end()) {
1350 for (auto& x : change.get_modified_objs()) {
1351 conffwk::map<ConfigObjectImpl*>::iterator j = i->second->find(x);
1352 if (j != i->second->end()) {
1353 TLOG_DEBUG(2) << "clear implementation object " << x << '@' << *class_name << " [" << (void*)j->second << ']';
1354
1355 std::lock_guard<std::mutex> scoped_lock(j->second->m_mutex);
1356
1357 if (j->second->m_state != dunedaq::conffwk::Valid)
1358 j->second->reset();
1359 else
1360 j->second->clear();
1361 }
1362 }
1363 }
1364 }
1365}
1366
1367// note, the std::lock_guard<std::mutex> scoped_lock(conf->m_tmpl_mutex) is already set by caller
1368
1369void
1370Configuration::update_cache(std::vector<ConfigurationChange*>& changes) noexcept
1371{
1372 TLOG_DEBUG(3) << "*** Enter Configuration::update_cache() with changes:\n" << changes;
1373
1374 // Remove deleted and update modified implementation objects first
1375 for (const auto& i : changes) {
1376 const std::string* class_name = &DalFactory::instance().get_known_class_name_ref(i->get_class_name());
1377
1378 update_impl_objects(m_impl->m_impl_objects, *i, class_name);
1379
1380 // delete/update implementation objects defined in superclasses
1382
1383 if (sc != p_superclasses.end())
1384 for (const auto& c : sc->second)
1385 update_impl_objects(m_impl->m_impl_objects, *i, c);
1386
1387 // delete/update implementation objects defined in subclasses
1388 sc = p_subclasses.find(class_name);
1389
1390 if (sc != p_subclasses.end())
1391 for (const auto& c : sc->second)
1392 update_impl_objects(m_impl->m_impl_objects, *i, c);
1393 }
1394
1395 for (const auto& i : changes) {
1396
1397 m_registry.update(i->get_class_name(), i->get_modified_objs(), i->get_removed_objs(), i->get_created_objs());
1398
1399 // const std::string * class_name = &DalFactory::instance().get_known_class_name_ref(i->get_class_name()); // FIXME:
1400 // optimise with above
1401
1402 // // invoke configuration update if there are template objects of given class
1403
1404 // {
1405 // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(class_name);
1406
1407 // if (j != m_cache_map.end())
1408 // {
1409 // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects";
1410 // j->second->m_functions.m_update_fn(*this, i);
1411 // }
1412 // }
1413
1414 // // invoke configuration update if there are template objects in super-classes
1415
1416 // {
1417 // conffwk::fmap<conffwk::fset>::const_iterator sc = p_superclasses.find(class_name);
1418
1419 // if (sc != p_superclasses.end())
1420 // {
1421 // for (const auto& c : sc->second)
1422 // {
1423 // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(c);
1424
1425 // if (j != m_cache_map.end())
1426 // {
1427 // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects (as super-class of
1428 // \'" << *class_name << "\')"; j->second->m_functions.m_update_fn(*this, i);
1429 // }
1430 // }
1431 // }
1432 // }
1433
1434 // // invoke configuration update if there are template objects in sub-classes
1435
1436 // {
1437 // conffwk::fmap<conffwk::fset>::const_iterator sc = p_subclasses.find(class_name);
1438
1439 // if (sc != p_subclasses.end())
1440 // {
1441 // for (const auto& c : sc->second)
1442 // {
1443 // conffwk::fmap<CacheBase*>::iterator j = m_cache_map.find(c);
1444
1445 // if (j != m_cache_map.end())
1446 // {
1447 // TLOG_DEBUG(3) << " * call update on \'" << j->first << "\' template objects (as sub-class of \'"
1448 // << *class_name << "\')"; j->second->m_functions.m_update_fn(*this, i);
1449 // }
1450 // }
1451 // }
1452 // }
1453 }
1454}
1455
1456void
1457Configuration::system_cb(std::vector<ConfigurationChange*>& changes, Configuration* conf) noexcept
1458{
1459
1460 TLOG_DEBUG(3) << "*** Enter Configuration::system_cb()\n"
1461 "*** Number of user subscriptions: "
1462 << conf->m_callbacks.size();
1463
1464 // call conffwk actions if any
1465 {
1466 std::lock_guard<std::mutex> scoped_lock(conf->m_impl_mutex);
1467 std::lock_guard<std::mutex> scoped_lock2(conf->m_actn_mutex);
1468 for (auto& i : conf->m_actions)
1469 i->notify(changes);
1470 }
1471
1472 // update template objects in cache
1473 {
1474 std::lock_guard<std::mutex> scoped_lock(conf->m_tmpl_mutex); // always lock template objects mutex first
1475 std::lock_guard<std::mutex> scoped_lock2(conf->m_impl_mutex);
1476 conf->update_cache(changes);
1477 }
1478
1479 // user removed all subscriptions
1480 if (conf->m_callbacks.empty())
1481 return;
1482
1483 // note, one cannot lock m_tmpl_mutex or m_impl_mutex here,
1484 // since user callback may call arbitrary get() methods to access conffwk
1485 // and template objects locking above two mutexes
1486 std::lock_guard<std::mutex> scoped_lock(conf->m_else_mutex);
1487
1488 // check if there is only one subscription
1489 if (conf->m_callbacks.size() == 1) {
1490 auto j = *conf->m_callbacks.begin();
1491 (*(j->m_cb))(changes, j->m_param);
1492 }
1493 // may need to calculate the changes for each subscription
1494 else {
1495 for (const auto& j : conf->m_callbacks) {
1496
1497 if (ers::debug_level() >= 3) {
1498 std::ostringstream text;
1499
1500 text << "*** Process subscription " << (void*)j
1501 << "\n"
1502 " class subscription done for "
1503 << j->m_criteria.get_classes_subscription().size() << " classes:\n";
1504
1505 for (const auto& i1 : j->m_criteria.get_classes_subscription())
1506 text << " * class \"" << i1 << "\"\n";
1507
1508 text << " object subscription done in " << j->m_criteria.get_objects_subscription().size() << " classes:\n";
1509
1510 for (const auto& i2 : j->m_criteria.get_objects_subscription()) {
1511 text << " * class \"" << (i2.first) << "\":\n";
1512 for (const auto& i3 : i2.second)
1513 text << " - \"" << i3 << "\"\n";
1514 }
1515
1516 TLOG_DEBUG(3) << text.str();
1517 }
1518
1519 if (j->m_criteria.get_classes_subscription().empty() && j->m_criteria.get_objects_subscription().empty()) {
1520 try {
1521 TLOG_DEBUG(3) << "*** Invoke callback " << (void*)j << " with\n" << changes;
1522 (*(j->m_cb))(changes, j->m_param);
1523 } catch (const ers::Issue& ex) {
1524 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown ers exception", ex));
1525 } catch (const std::exception& ex) {
1526 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown std exception", ex));
1527 } catch (...) {
1528 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown unknown exception"));
1529 }
1530 } else {
1531 std::vector<ConfigurationChange*> changes1;
1532
1533 for (const auto& i : changes) {
1534 const std::string& cname = i->get_class_name();
1535 ConfigurationChange* class_changes = nullptr;
1536
1537 ConfigurationSubscriptionCriteria::ObjectMap::const_iterator p =
1538 j->m_criteria.get_objects_subscription().find(cname);
1539 const bool found_obj_subscription(p != j->m_criteria.get_objects_subscription().end());
1540 const bool found_class_subscription(j->m_criteria.get_classes_subscription().find(cname) !=
1541 j->m_criteria.get_classes_subscription().end());
1542
1543 if (found_class_subscription || found_obj_subscription)
1544 class_changes = new ConfigurationChange(cname);
1545
1546 if (found_class_subscription) {
1547 for (const auto& k : i->m_modified)
1548 class_changes->m_modified.push_back(k);
1549
1550 for (const auto& k : i->m_created)
1551 class_changes->m_created.push_back(k);
1552
1553 for (const auto& k : i->m_removed)
1554 class_changes->m_removed.push_back(k);
1555 }
1556
1557 if (found_obj_subscription) {
1558 for (const auto& obj_id : i->m_modified)
1559 if (p->second.find(obj_id) != p->second.end())
1560 class_changes->m_modified.push_back(obj_id);
1561
1562 for (const auto& obj_id : i->m_removed)
1563 if (p->second.find(obj_id) != p->second.end())
1564 class_changes->m_removed.push_back(obj_id);
1565 }
1566
1567 // the changes for given class can be empty if there is subscription on objects of given class, but no such
1568 // objects were modified
1569 if (class_changes) {
1570 if (class_changes->m_modified.empty() && class_changes->m_created.empty() &&
1571 class_changes->m_removed.empty())
1572 delete class_changes;
1573 else
1574 changes1.push_back(class_changes);
1575 }
1576 }
1577
1578 if (!changes1.empty()) {
1579 TLOG_DEBUG(3) << "*** Invoke callback " << (void*)j << " with\n" << changes1;
1580
1581 try {
1582 (*(j->m_cb))(changes1, j->m_param);
1583 } catch (const ers::Issue& ex) {
1584 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown ers exception", ex));
1585 } catch (const std::exception& ex) {
1586 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown std exception", ex));
1587 } catch (...) {
1588 ers::error(dunedaq::conffwk::Generic(ERS_HERE, "user callback thrown unknown exception"));
1589 }
1590
1591 for (const auto& i : changes1)
1592 delete i;
1593 }
1594 }
1595 }
1596 }
1597
1598 TLOG_DEBUG(3) << "*** Leave Configuration::system_cb()";
1599}
1600
1601void
1603{
1604 TLOG_DEBUG(3) << "*** Enter Configuration::system_pre_cb()";
1605
1606 std::lock_guard<std::mutex> scoped_lock(conf->m_else_mutex);
1607
1608 for (auto& j : conf->m_pre_callbacks) {
1609 TLOG_DEBUG(3) << "*** Invoke callback " << (void*)(j);
1610 (*(j->m_cb))(j->m_param);
1611 }
1612
1613 TLOG_DEBUG(3) << "*** Leave Configuration::system_pre_cb()";
1614}
1615
1616void
1617ConfigurationChange::add(std::vector<ConfigurationChange*>& changes,
1618 const std::string& class_name,
1619 const std::string& obj_name,
1620 const char action)
1621{
1622 ConfigurationChange* class_changes = nullptr;
1623
1624 for (const auto& c : changes)
1625 if (class_name == c->get_class_name()) {
1626 class_changes = c;
1627 break;
1628 }
1629
1630 if (!class_changes) {
1631 class_changes = new ConfigurationChange(class_name);
1632 changes.push_back(class_changes);
1633 }
1634
1635 std::vector<std::string>& clist = (action == '+' ? class_changes->m_created
1636 : action == '-' ? class_changes->m_removed
1637 : class_changes->m_modified);
1638
1639 clist.push_back(obj_name);
1640}
1641
1642void
1643ConfigurationChange::clear(std::vector<ConfigurationChange*>& changes)
1644{
1645 for (const auto& i : changes)
1646 delete i;
1647
1648 changes.clear();
1649}
1650
1651static void
1652print_svect(std::ostream& s, const std::vector<std::string>& v, const char* name)
1653{
1654 s << " * " << v.size() << name;
1655
1656 for (auto i = v.begin(); i != v.end(); ++i) {
1657 s << ((i == v.begin()) ? ": " : ", ");
1658 s << '\"' << *i << '\"';
1659 }
1660
1661 s << std::endl;
1662}
1663
1664std::ostream&
1665operator<<(std::ostream& s, const ConfigurationChange& c)
1666{
1667 s << " changes for class \'" << c.get_class_name() << "\' include:\n";
1668
1669 print_svect(s, c.get_modified_objs(), " modified object(s)");
1670 print_svect(s, c.get_created_objs(), " created object(s)");
1671 print_svect(s, c.get_removed_objs(), " removed object(s)");
1672
1673 return s;
1674}
1675
1676std::ostream&
1677operator<<(std::ostream& s, const std::vector<ConfigurationChange*>& v)
1678{
1679 s << "There are configuration changes in " << v.size() << " classes:\n";
1680
1681 for (const auto& i : v)
1682 s << *i;
1683
1684 return s;
1685}
1686
1687void
1688Configuration::print(std::ostream& s) const noexcept
1689{
1690 s << "Configuration object:\n Inheritance Hierarchy (class - all it's superclasses):\n";
1691
1692 for (const auto& i : p_superclasses) {
1693 s << " * \'" << *i.first << "\' - ";
1694 if (i.second.empty())
1695 s << "(null)";
1696 else
1697 for (auto j = i.second.begin(); j != i.second.end(); ++j) {
1698 if (j != i.second.begin())
1699 s << ", ";
1700 s << '\'' << **j << '\'';
1701 }
1702 s << std::endl;
1703 }
1704}
1705
1706bool
1707Configuration::try_cast(const std::string& target, const std::string& source) noexcept
1708{
1709 return is_superclass_of(target, source);
1710}
1711
1712bool
1713Configuration::try_cast(const std::string* target, const std::string* source) noexcept
1714{
1715 return is_superclass_of(target, source);
1716}
1717
1718bool
1719Configuration::is_superclass_of(const std::string& base_class, const std::string& child_class) noexcept
1720{
1721 return is_superclass_of(&DalFactory::instance().get_known_class_name_ref(base_class),
1722 &DalFactory::instance().get_known_class_name_ref(child_class));
1723}
1724
1725bool
1726Configuration::is_superclass_of(const std::string* base_class, const std::string* child_class) noexcept
1727{
1728 if (base_class == child_class) {
1729 TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is allowed (equal classes)";
1730 return true;
1731 }
1732
1733 conffwk::fmap<conffwk::fset>::iterator i = p_superclasses.find(child_class);
1734
1735 if (i == p_superclasses.end()) {
1736 TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class
1737 << "\' is not possible (base class is not loaded)";
1738 return false;
1739 }
1740
1741 if (i->second.find(base_class) != i->second.end()) {
1742 TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is allowed (use inheritance)";
1743 return true;
1744 }
1745
1746 TLOG_DEBUG(50) << "cast \'" << *child_class << "\' => \'" << *base_class << "\' is not allowed (class \'"
1747 << *child_class << "\' has no \'" << *base_class << "\' as a superclass)";
1748
1749 return false;
1750}
1751
1752std::ostream&
1753operator<<(std::ostream& s, const Configuration& c)
1754{
1755 c.print(s);
1756 return s;
1757}
1758
1759// std::ostream&
1760// operator<<(std::ostream& s, const DalObject * obj)
1761// {
1762// if (obj == nullptr)
1763// DalObject::p_null(s);
1764// else if (obj->is_deleted())
1765// s << "(deleted object " << obj->UID() << '@' << obj->class_name() << ')';
1766// else
1767// s << '\'' << obj->UID() << '@' << obj->class_name() << '\'';
1768
1769// return s;
1770// }
1771
1772// std::ostream&
1773// operator<<(std::ostream& s, const DalObject * obj)
1774// {
1775// if (obj == nullptr)
1776// DalObject::p_null(s);
1777// else if (obj->is_deleted())
1778// s << "(deleted object " << obj->UID() << '@' << obj->class_name() << ')';
1779// else
1780// s << '\'' << obj->UID() << '@' << obj->class_name() << '\'';
1781
1782// return s;
1783// }
1784
1785std::string
1787 const std::string& cname,
1788 const std::string& rname,
1789 const ConfigObject& obj) noexcept
1790{
1791 std::ostringstream text;
1792 text << "failed to get " << what << " of class \'" << cname << "\' via relationship \'" << rname << "\' of object \'"
1793 << obj << '\'';
1794 return text.str();
1795}
1796
1797std::string
1798Configuration::mk_ref_by_ex_text(const std::string& cname, const std::string& rname, const ConfigObject& obj) noexcept
1799{
1800 std::ostringstream text;
1801 text << "failed to get objects of class \'" << cname << "\' referencing object \'" << obj << "\' via relationship \'"
1802 << rname << '\'';
1803 return text.str();
1804}
1805
1806// std::vector<const DalObject*>
1807// Configuration::make_dal_objects(std::vector<ConfigObject>& objs, bool upcast_unregistered)
1808// {
1809// std::vector<const DalObject*> result;
1810
1811// for (auto &i : objs)
1812// // if (DalObject *o = DalFactory::instance().get(*this, i, i.UID(), upcast_unregistered)) // FIXME: 2018-11-09:
1813// pass right UID() if (DalObject *o = m_registry.get(i,upcast_unregistered)) // FIXME: 2018-11-09: pass right UID()
1814// result.push_back(o);
1815
1816// return result;
1817// }
1818
1819// const DalObject*
1820// Configuration::make_dal_object(ConfigObject& obj, const std::string& uid, const std::string& class_name)
1821// {
1822// return DalFactory::instance().get(*this, obj, uid, class_name);
1823// return m_registry.get(*this, obj, uid, class_name);
1824// }
1825
1826std::vector<const DalObject*>
1828 const std::string& relationship_name,
1829 bool check_composite_only,
1830 bool upcast_unregistered,
1831 bool /*init*/,
1832 unsigned long rlevel,
1833 const std::vector<std::string>* rclasses)
1834{
1835 try {
1836 std::vector<ConfigObject> objs;
1837 std::lock_guard<std::mutex> scoped_lock(m_tmpl_mutex);
1838
1839 obj.p_obj.referenced_by(objs, relationship_name, check_composite_only, rlevel, rclasses);
1840 // return make_dal_objects(objs, upcast_unregistered);
1841 return m_registry.get(objs, upcast_unregistered);
1842 } catch (dunedaq::conffwk::Generic& ex) {
1843 throw(
1844 dunedaq::conffwk::Generic(ERS_HERE, mk_ref_by_ex_text("DalObject", relationship_name, obj.p_obj).c_str(), ex));
1845 }
1846}
1847
1848std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
1849Configuration::attributes_pybind(const std::string& class_name, bool all)
1850{
1851
1852 std::unordered_map<std::string, std::unordered_map<std::string, std::string>> all_attributes_properties;
1853
1854 const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
1855
1856 for (const auto& ap : c.p_attributes) {
1857 std::unordered_map<std::string, std::string> attribute_properties;
1858 attribute_properties["type"] = dunedaq::conffwk::attribute_t::type(ap.p_type);
1859
1860 attribute_properties["range"] = ap.p_range.empty() ? "None" : ap.p_range;
1861
1862 attribute_properties["description"] = ap.p_description;
1863
1864 attribute_properties["multivalue"] = ap.p_is_multi_value ? "True" : "False";
1865
1866 attribute_properties["not-null"] = ap.p_is_not_null ? "True" : "False";
1867
1868 attribute_properties["init-value"] = ap.p_default_value.empty() ? "None" : ap.p_default_value;
1869
1870 all_attributes_properties[ap.p_name] = attribute_properties;
1871 }
1872
1873 return all_attributes_properties;
1874}
1875
1876std::vector<std::string>
1878{
1879 std::vector<std::string> classes;
1880 for (const auto& it : this->superclasses()) {
1881 classes.push_back(*it.first);
1882 }
1883
1884 return classes;
1885}
1886
1888Configuration::create_and_return_obj_pybind(const std::string& at, const std::string& class_name, const std::string& id)
1889{
1890 auto co = new ConfigObject;
1891 this->create(at, class_name, id, *co);
1892 return co;
1893}
1894
1897 const std::string& class_name,
1898 const std::string& id)
1899{
1900 auto co = new ConfigObject;
1901 this->create(at, class_name, id, *co);
1902 return co;
1903}
1904
1906Configuration::get_obj_pybind(const std::string& class_name, const std::string& id)
1907{
1908 auto co = new ConfigObject;
1909 this->get(class_name, id, *co);
1910 if (co->is_null()) {
1911 delete co;
1912 co = nullptr;
1913 }
1914 return co;
1915}
1916
1917std::vector<ConfigObject>*
1918Configuration::get_objs_pybind(const std::string& class_name, const std::string& query)
1919{
1920 auto objs = new std::vector<ConfigObject>;
1921 this->get(class_name, *objs, query);
1922 return objs;
1923}
1924
1925std::unordered_map<std::string, std::unordered_map<std::string, std::string>>
1926Configuration::relations_pybind(const std::string& class_name, bool all)
1927{
1928
1929 std::unordered_map<std::string, std::unordered_map<std::string, std::string>> all_relationships_properties;
1930
1931 const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
1932
1933 for (const auto& rp : c.p_relationships) {
1934 std::unordered_map<std::string, std::string> relationship_properties;
1935
1936 relationship_properties["type"] = rp.p_type;
1937 relationship_properties["description"] = rp.p_description;
1938 relationship_properties["multivalue"] =
1939 (rp.p_cardinality == dunedaq::conffwk::zero_or_many || rp.p_cardinality == dunedaq::conffwk::one_or_many)
1940 ? "True"
1941 : "False";
1942 relationship_properties["aggregation"] = rp.p_is_aggregation ? "True" : "False";
1943 relationship_properties["not-null"] =
1944 (rp.p_cardinality == dunedaq::conffwk::only_one || rp.p_cardinality == dunedaq::conffwk::one_or_many) ? "True"
1945 : "False";
1946
1947 all_relationships_properties[rp.p_name] = relationship_properties;
1948 }
1949
1950 return all_relationships_properties;
1951}
1952
1953std::list<std::string>*
1954Configuration::return_includes_pybind(const std::string& db_name)
1955{
1956 auto l = new std::list<std::string>;
1957 this->get_includes(db_name, *l);
1958 return l;
1959}
1960
1961std::vector<std::string>
1962Configuration::subclasses_pybind(const std::string& class_name, bool all)
1963{
1964
1965 const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
1966 return c.p_subclasses;
1967}
1968
1969std::vector<std::string>
1970Configuration::superclasses_pybind(const std::string& class_name, bool all)
1971{
1972
1973 const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, !all);
1974 return c.p_superclasses;
1975}
1976
1977const std::string&
1978Configuration::get_schema_path_pybind(const std::string& class_name)
1979{
1980 const dunedaq::conffwk::class_t& c = this->get_class_info(class_name, false);
1981 return c.p_schema_path;
1982}
1983} // namespace conffwk
1984} // namespace dunedaq
#define ERS_DEFINE_ISSUE_CXX(namespace_name, class_name, message, attributes)
#define ERS_HERE
Represents database objects.
const std::string & UID() const noexcept
Return object identity.
Describes changes inside a class returned by the notification mechanism.
Definition Change.hpp:43
const std::vector< std::string > & get_created_objs() const
Return vector of identies of created objects.
Definition Change.hpp:59
std::vector< std::string > m_removed
Definition Change.hpp:112
static void clear(std::vector< ConfigurationChange * > &changes)
Helper method to clear vector of changes (pointers).
ConfigurationChange(const ConfigurationChange &)
std::vector< std::string > m_created
Definition Change.hpp:111
std::vector< std::string > m_modified
Definition Change.hpp:110
static void add(std::vector< ConfigurationChange * > &changes, const std::string &class_name, const std::string &obj_id, const char action)
Helper method to add object to the vector of existing changes.
const std::vector< std::string > & get_modified_objs() const
Return vector of identies of modified objects.
Definition Change.hpp:55
const std::vector< std::string > & get_removed_objs() const
Return vector of identies of removed objects.
Definition Change.hpp:63
virtual bool test_object(const std::string &class_name, const std::string &id, unsigned long rlevel, const std::vector< std::string > *rclasses)=0
Test object existence (used by Python binding).
virtual void subscribe(const std::set< std::string > &class_names, const std::map< std::string, std::set< std::string > > &objs, notify cb, pre_notify pre_cb)=0
Subscribe on database changes.
virtual void set_commit_credentials(const std::string &user, const std::string &password)=0
Set commit credentials.
virtual void close_db()=0
Close database implementation.
virtual void get_superclasses(conffwk::fmap< conffwk::fset > &schema)=0
Get inheritance hierarchy.
virtual void abort()=0
Abort database changes.
virtual void get(const std::string &class_name, const std::string &id, ConfigObject &object, unsigned long rlevel, const std::vector< std::string > *rclasses)=0
Get object of class by id.
virtual void get_includes(const std::string &db_name, std::list< std::string > &includes) const =0
Get included files.
virtual void print_profiling_info() noexcept=0
Print implementation specific profiling information.
virtual void prefetch_all_data()=0
Prefetch all data into client cache.
virtual void get_updated_dbs(std::list< std::string > &dbs) const =0
Get uncommitted files.
virtual bool is_writable(const std::string &db_name)=0
Return write access status.
virtual std::vector< dunedaq::conffwk::Version > get_changes()=0
Get newly available versions.
virtual bool loaded() const noexcept=0
Check if a database is loaded.
void rename_impl_object(const std::string *class_name, const std::string &old_id, const std::string &new_id) noexcept
rename object in cache
virtual void destroy(ConfigObject &object)=0
Destroy object of class by id.
virtual void add_include(const std::string &db_name, const std::string &include)=0
Add include file.
virtual void commit(const std::string &log_message)=0
Commit database changes.
void print_cache_info() noexcept
Print profiling information about objects in cache.
virtual std::vector< dunedaq::conffwk::Version > get_versions(const std::string &since, const std::string &until, dunedaq::conffwk::Version::QueryType type, bool skip_irrelevant)=0
Get archived versions.
virtual void remove_include(const std::string &db_name, const std::string &include)=0
Remove include file.
void set(Configuration *db) noexcept
set configuration object
virtual void create(const std::string &db_name, const std::list< std::string > &includes)=0
Create database.
virtual void open_db(const std::string &db_name)=0
Open database implementation in accordance with given name.
virtual void unsubscribe()=0
Remove subscription on database changes.
std::map< std::string, std::set< std::string > > ObjectMap
The map stores full subsription information.
void update_cache(std::vector< ConfigurationChange * > &changes) noexcept
System function invoked in case of modifications.
std::vector< ConfigObject > * get_objs_pybind(const std::string &class_name, const std::string &query="")
void _get(const std::string &class_name, const std::string &id, ConfigObject &object, unsigned long rlevel, const std::vector< std::string > *rclasses)
const conffwk::fmap< conffwk::fset > & superclasses() const noexcept
static void update_impl_objects(conffwk::pmap< conffwk::map< ConfigObjectImpl * > * > &cache, ConfigurationChange &change, const std::string *class_name)
void get(const std::string &class_name, const std::string &id, ConfigObject &object, unsigned long rlevel=0, const std::vector< std::string > *rclasses=0)
Get object by class name and object id (multi-thread safe).
void _unread_implementation_objects(dunedaq::conffwk::ObjectState state) noexcept
static void system_cb(std::vector< ConfigurationChange * > &, Configuration *) noexcept
System callback function invoked in case of modifications.
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > attributes_pybind(const std::string &class_name, bool all)
void destroy_obj(ConfigObject &object)
Destroy object.
std::unordered_map< std::string, std::unordered_map< std::string, std::string > > relations_pybind(const std::string &class_name, bool all)
void remove_include(const std::string &db_name, const std::string &include)
Remove include file.
void get_updated_dbs(std::list< std::string > &dbs) const
Get list of updated files to be committed.
void prefetch_all_data()
Prefetch all data into client cache.
void load(const std::string &db_name)
Load database according to the name. If name is empty, take it from TDAQ_DB_NAME and TDAQ_DB_DATA env...
Configuration(const std::string &spec)
Constructor to build a configuration object using implementation plug-in.
void action_on_update(const ConfigObject &obj, const std::string &name)
void remove_action(ConfigAction *ac)
bool is_writable(const std::string &db_name) const
Get write access status.
void set_commit_credentials(const std::string &user, const std::string &password)
Set commit credentials.
void print(std::ostream &) const noexcept
Prints out details of configuration object.
~Configuration() noexcept
Destructor to destroy a configuration object.
void add_action(ConfigAction *ac)
std::atomic< uint_least64_t > p_number_of_template_object_created
void unread_template_objects() noexcept
Unread all template (i.e. set their state as uninitialized) objects.
static void system_pre_cb(Configuration *) noexcept
System callback function invoked in case of pre-modifications.
conffwk::fmap< conffwk::fset > p_subclasses
conffwk::map< dunedaq::conffwk::class_t * > p_all_classes_desc_cache
void referenced_by(const T &obj, std::vector< const V * > &objects, const std::string &relationship_name="*", bool check_composite_only=true, bool init=false, unsigned long rlevel=0, const std::vector< std::string > *rclasses=nullptr)
Get template DAL objects holding references on this object via given relationship (multi-thread safe)...
std::vector< std::string > superclasses_pybind(const std::string &class_name, bool all)
CallbackSubscription * find_callback(CallbackId cb_handler) const
void create(const std::string &at, const std::string &class_name, const std::string &id, ConfigObject &object)
Create new object by class name and object id.
static std::string mk_ref_ex_text(const char *what, const std::string &cname, const std::string &rname, const ConfigObject &obj) noexcept
CallbackSubscription * CallbackId
Callback identifier.
const dunedaq::conffwk::class_t & _get_class_info(const std::string &class_name, bool direct_only=false)
std::vector< std::string > subclasses_pybind(const std::string &class_name, bool all)
std::list< std::string > * return_includes_pybind(const std::string &db_name)
bool loaded() const noexcept
Check if database is correctly loaded.
std::vector< std::string > get_class_list() const
void unread_all_objects(bool unread_implementation_objs=false) noexcept
Unread all template (i.e. set their state as uninitialized) and implementation objects (i....
std::list< ConfigAction * > m_actions
std::deque< std::set< std::string > > find_class_domains()
const std::string & get_schema_path_pybind(const std::string &class_name)
const dunedaq::conffwk::class_t & get_class_info(const std::string &class_name, bool direct_only=false)
The method provides access to description of class.
void get_includes(const std::string &db_name, std::list< std::string > &includes) const
Get include files.
conffwk::map< std::list< AttributeConverterBase * > * > m_convert_map
conffwk::fmap< conffwk::fset > p_superclasses
std::vector< dunedaq::conffwk::Version > get_changes()
Get new conffwk versions.
void commit(const std::string &log_message="")
Commit database changes.
conffwk::fmap< uint > p_class_domain_map
bool is_superclass_of(const std::string &target, const std::string &source) noexcept
void export_data(boost::property_tree::ptree &tree, const std::string &classes="", const std::string &objects="", const std::string &files="", const std::string &empty_array_item="")
Export configuration data into ptree.
static std::string mk_ref_by_ex_text(const std::string &cname, const std::string &rname, const ConfigObject &obj) noexcept
void unread_implementation_objects(dunedaq::conffwk::ObjectState state) noexcept
Unread implementation objects (i.e. clear their cache).
ConfigObject * get_obj_pybind(const std::string &class_name, const std::string &id)
void export_schema(boost::property_tree::ptree &tree, const std::string &classes="", bool direct_only=false)
Export configuration schema into ptree.
void unsubscribe(CallbackId cb_handler=0)
Remove callback function.
void print_profiling_info() noexcept
Print out profiling information.
std::vector< dunedaq::conffwk::Version > get_versions(const std::string &since, const std::string &until, dunedaq::conffwk::Version::QueryType type=dunedaq::conffwk::Version::query_by_date, bool skip_irrelevant=true)
Get repository versions in interval.
std::atomic< uint_least64_t > p_number_of_template_object_read
void abort()
Abort database changes.
void unload()
Unload database.
bool test_object(const std::string &class_name, const std::string &id, unsigned long rlevel=0, const std::vector< std::string > *rclasses=0)
Test the object existence.
void add_include(const std::string &db_name, const std::string &include)
Add include file to existing database.
std::atomic< uint_least64_t > p_number_of_cache_hits
conffwk::map< dunedaq::conffwk::class_t * > p_direct_classes_desc_cache
ConfigObject * create_and_return_obj_pybind(const std::string &at, const std::string &class_name, const std::string &id)
CallbackId subscribe(const ConfigurationSubscriptionCriteria &criteria, notify user_cb, void *user_param=nullptr)
Subscribe on configuration changes.
bool try_cast(const std::string &target, const std::string &source) noexcept
Checks if cast from source class to target class is allowed.
void rename_object(ConfigObject &obj, const std::string &new_id)
Cache of template object of given type.
The base class for any generated DAL object.
Definition DalObject.hpp:51
DalObject * get(ConfigObject &obj, bool upcast_unregistered=false)
void _rename_object(std::string class_name, std::string old_id, std::string new_id)
Rename object of given template class (multi-thread unsafe).
void clear()
Clear the content of the registy.
void unread_all()
Set the status of all objects in cache to unread.
void update_class_maps()
Update the internal class domains map.
Base class for all conffwk exceptions.
Generic configuration exception.
Base class for any user define issue.
Definition Issue.hpp:76
conffwk entry point
#define TLOG_DEBUG(lvl,...)
Definition Logging.hpp:116
The DUNE-DAQ namespace.
ERS_DEFINE_ISSUE_BASE_CXX(conffwk, Generic, conffwk::Exception, what,,((const char *) what)) ERS_DEFINE_ISSUE_BASE_CXX(conffwk
msgpack::object obj
DeletedObject
Definition Errors.hpp:67
static void init_regex(std::unique_ptr< std::regex > &ptr, const std::string &str, const char *what)
static bool check_prefetch_needs()
static type<< " \""<< data<< "\" is not found",,((const char *) type)((const char *) data)) ERS_DEFINE_ISSUE_BASE_CXX(conffwk, DeletedObject, conffwk::Exception, "object \'"<< object_id<< '@'<< class_name<< "\' was deleted",,((const char *) class_name)((const char *) object_id)) namespace conffwk {template< typename T > T * get_new(ConfigObject &co, const std::string &attrname)
static void add_data(boost::property_tree::ptree &pt, const ConfigObject &obj, const dunedaq::conffwk::attribute_t &attribute, const std::string &empty_array_item)
static void add_array_item(boost::property_tree::ptree &pt, const T &val)
std::ostream & operator<<(std::ostream &s, const ConfigurationChange &c)
default char v[0]
static void print_svect(std::ostream &s, const std::vector< std::string > &v, const char *name)
CIB Buffer std::string descriptor Message from std::string descriptor CIB process error
int debug_level()
Definition ers.hpp:80
void error(const Issue &issue)
Definition ers.hpp:101
static const char * type(type_t type)
static const char * format2str(int_format_t format)
static const char * card2str(cardinality_t cardinality)