Line data Source code
1 : //
2 : // DUNE DAQ modification notice:
3 : // This file has been modified from the original ATLAS oksconfig source for the DUNE DAQ project.
4 : // Fork baseline commit: oksconfig-03-02-00 (2021-04-20).
5 : // Renamed since fork: no.
6 : //
7 :
8 : #include <stdlib.h>
9 : #include <unistd.h>
10 : #include <sys/stat.h>
11 : #include <errno.h>
12 :
13 : #include <algorithm>
14 : #include <memory>
15 :
16 : #include "ers/ers.hpp"
17 :
18 : #include "oks/file.hpp"
19 : #include "oks/kernel.hpp"
20 : #include "oks/object.hpp"
21 : #include "oks/query.hpp"
22 : #include "oks/relationship.hpp"
23 : #include "oksutils/oks/access.hpp"
24 :
25 : #include "conffwk/Configuration.hpp"
26 : #include "conffwk/ConfigObject.hpp"
27 : #include "conffwk/Change.hpp"
28 : #include "conffwk/Schema.hpp"
29 :
30 : #include "oksconflibs/OksConfiguration.hpp"
31 : #include "oksconflibs/OksConfigObject.hpp"
32 :
33 : namespace dunedaq{
34 18 : ERS_DECLARE_ISSUE( oksconflibs, Exception, , )
35 : }
36 : using namespace dunedaq;
37 : using namespace dunedaq::oks;
38 : using namespace dunedaq::oksconflibs;
39 : // to be used as plug-in
40 :
41 87 : extern "C" conffwk::ConfigurationImpl * _oksconflibs_creator_ (const std::string& spec) {
42 87 : try {
43 87 : std::unique_ptr<OksConfiguration> impl(new OksConfiguration());
44 87 : if(!spec.empty()) { impl->open_db(spec); }
45 174 : return impl.release();
46 87 : }
47 0 : catch(dunedaq::conffwk::Exception & ex) {
48 0 : throw dunedaq::conffwk::Generic(ERS_HERE, "oksconflibs initialization error", ex);
49 0 : }
50 0 : catch(...) {
51 0 : throw dunedaq::conffwk::Generic(ERS_HERE, "oksconflibs initialization error:\n***** caught unknown exception *****");
52 0 : }
53 : }
54 :
55 :
56 : struct dunedaq::oksconflibs::OksConfigurationCheckDB {
57 :
58 : OksConfiguration * m_db;
59 : bool m_run;
60 :
61 3 : OksConfigurationCheckDB(OksConfiguration * db) : m_db(db), m_run(true) { ; }
62 :
63 3 : ~OksConfigurationCheckDB() {
64 3 : TLOG_DEBUG( 3 ) << "Call destructor of OksConfigurationCheckDB object" ;
65 3 : m_db = nullptr;
66 3 : }
67 :
68 : void
69 3 : operator()()
70 : {
71 3 : TLOG_DEBUG(2) << "Call user notification" ;
72 :
73 6 : while (m_run)
74 : {
75 3 : sleep(1);
76 3 : try
77 : {
78 3 : m_db->check_db();
79 : }
80 0 : catch (dunedaq::conffwk::Generic& ex)
81 : {
82 0 : m_db->m_check_db_thread = nullptr;
83 0 : m_db->m_check_db_obj = nullptr;
84 :
85 0 : if (getenv("OKSCONFLIBS_NO_RELOAD_ABORT") != nullptr)
86 : {
87 0 : ers::fatal(dunedaq::conffwk::Generic( ERS_HERE, "database reload has failed, unsubscribing...", ex ) );
88 0 : return;
89 : }
90 : else
91 : {
92 0 : ers::fatal ( dunedaq::conffwk::Generic( ERS_HERE, "database reload has failed, aborting...", ex ) );
93 0 : abort();
94 : }
95 0 : }
96 : }
97 :
98 3 : TLOG_DEBUG( 4 ) << "Destroy OksConfigurationCheckDB object = " << (void *)this ;
99 :
100 3 : delete this;
101 :
102 3 : TLOG_DEBUG( 2 ) << "Exit user notification" ;
103 : }
104 :
105 : };
106 :
107 :
108 : bool
109 87 : is_repo_name(const std::string& name)
110 : {
111 87 : if (!OksKernel::get_repository_root().empty())
112 : {
113 0 : std::string s(name);
114 :
115 0 : Oks::substitute_variables(s);
116 :
117 0 : bool is_absolute_path = (s[0] == '/');
118 :
119 0 : if (!is_absolute_path)
120 0 : s = std::string(OksKernel::get_cwd()) + '/' + s;
121 :
122 : // if file system path exists
123 0 : if (Oks::real_path(s, true))
124 : {
125 0 : if (!OksKernel::get_repository_mapping_dir().empty() && s.find(OksKernel::get_repository_mapping_dir()) == 0)
126 : return true;
127 :
128 0 : static std::string user_repo_dir;
129 0 : static std::once_flag flag;
130 :
131 0 : std::call_once(flag, []()
132 : {
133 0 : if (const char * s = getenv("TDAQ_DB_USER_REPOSITORY"))
134 : {
135 0 : user_repo_dir = s;
136 :
137 0 : try
138 : {
139 0 : Oks::real_path(user_repo_dir, false);
140 : }
141 0 : catch(oks::exception& ex)
142 : {
143 0 : TLOG_DEBUG( 0) << "Failed to read TDAQ_DB_USER_REPOSITORY = \'" << s << "\':\n\tcaused by: " << ex.what() ;
144 0 : }
145 : }
146 0 : }
147 : );
148 :
149 0 : if (!user_repo_dir.empty() && s.find(user_repo_dir) == 0)
150 : return true;
151 :
152 : return false;
153 : }
154 : else
155 : return true;
156 0 : }
157 :
158 : return false;
159 : }
160 :
161 : void
162 82 : OksConfiguration::open_db(const std::string& spec_params)
163 : {
164 : // separate parameters first
165 :
166 82 : std::string::size_type idx = spec_params.find_first_of('&');
167 :
168 82 : std::string data, params;
169 :
170 82 : if (idx == std::string::npos)
171 : {
172 82 : data = spec_params;
173 : }
174 : else
175 : {
176 0 : data = spec_params.substr(0, idx);
177 0 : params = spec_params.substr(idx + 1);
178 : }
179 :
180 82 : std::string token;
181 :
182 : // guess about oks kernel mode based on the file names
183 :
184 82 : {
185 82 : Oks::Tokenizer t(data, ":");
186 :
187 164 : while (!(token = t.next()).empty())
188 : {
189 82 : if (is_repo_name(token) == false)
190 82 : m_oks_kernel_no_repo = true;
191 : }
192 82 : }
193 :
194 : // create OKS kernel if it was not created
195 :
196 82 : if (m_kernel == nullptr)
197 : {
198 82 : if (!params.empty())
199 : {
200 0 : Oks::Tokenizer t(params, ";");
201 :
202 0 : while (!(token = t.next()).empty())
203 : {
204 0 : if(token == "norepo")
205 0 : m_oks_kernel_no_repo = true;
206 : }
207 0 : }
208 :
209 82 : m_kernel = new OksKernel(m_oks_kernel_silence, false, false, !m_oks_kernel_no_repo);
210 : }
211 :
212 82 : Oks::Tokenizer t(data, ":");
213 :
214 164 : while(!(token = t.next()).empty()) {
215 82 : try {
216 82 : m_kernel->load_file(token);
217 : }
218 0 : catch (oks::exception & e) {
219 0 : std::ostringstream text;
220 0 : text << "cannot load file \'" << token << "\':\n" << e.what();
221 0 : close_db();
222 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
223 0 : }
224 0 : catch (...) {
225 0 : std::ostringstream text;
226 0 : text << "cannot load file \'" << token << '\'';
227 0 : close_db();
228 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
229 0 : }
230 : }
231 82 : }
232 :
233 : void
234 174 : OksConfiguration::close_database(bool call_unsubscribe)
235 : {
236 174 : clean(); // clean implementation cache
237 :
238 174 : if(m_kernel) try {
239 87 : if(m_check_db_obj) {
240 0 : if(call_unsubscribe)
241 0 : unsubscribe();
242 : else
243 0 : m_check_db_obj->m_run = false;
244 : }
245 :
246 87 : m_kernel->subscribe_create_object(0, 0);
247 87 : m_kernel->subscribe_change_object(0, 0);
248 87 : m_kernel->subscribe_delete_object(0, 0);
249 :
250 87 : m_kernel->close_all_data();
251 87 : m_kernel->close_all_schema();
252 :
253 87 : delete m_kernel;
254 87 : m_kernel = 0;
255 : }
256 0 : catch(oksconflibs::Exception& ex) {
257 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to close database", ex ) );
258 0 : }
259 0 : catch(std::exception& ex) {
260 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to close database", ex ) );
261 0 : }
262 174 : }
263 :
264 :
265 : void
266 5 : OksConfiguration::create(const std::string& db_name, const std::list<std::string>& includes)
267 : {
268 : // create OKS kernel if it was not created
269 :
270 5 : if (m_kernel == nullptr)
271 : {
272 5 : if (is_repo_name(db_name) == false)
273 5 : m_oks_kernel_no_repo = true;
274 :
275 5 : m_kernel = new OksKernel(m_oks_kernel_silence, false, false, !m_oks_kernel_no_repo);
276 : }
277 :
278 :
279 : // create new data file
280 :
281 5 : try {
282 5 : OksFile * h = m_kernel->new_data(db_name);
283 5 : m_created_files.insert(h);
284 :
285 : // add includes
286 :
287 15 : for(std::list<std::string>::const_iterator i = includes.begin(); i != includes.end(); ++i) {
288 10 : try {
289 10 : h->add_include_file(*i);
290 : }
291 0 : catch (oks::exception & e) {
292 0 : std::ostringstream text;
293 0 : text << "cannot add and load include file \'" << *i << "\' to \'" << db_name << "\':\n" << e.what();
294 0 : close_db();
295 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
296 0 : }
297 0 : catch (...) {
298 0 : std::ostringstream text;
299 0 : text << "cannot add and load include file \'" << *i << "\' to \'" << db_name << '\'';
300 0 : close_db();
301 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
302 0 : }
303 : }
304 :
305 5 : m_kernel->bind_objects();
306 : }
307 0 : catch (oks::exception & ex) {
308 0 : close_db();
309 0 : std::ostringstream text;
310 0 : text << "cannot create new data file \'" << db_name << "\': " << ex.what();
311 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
312 0 : }
313 0 : catch (dunedaq::conffwk::Generic & ex) {
314 0 : close_db();
315 0 : std::ostringstream text;
316 0 : text << "cannot create new data file \'" << db_name << "\'";
317 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str(), ex ) );
318 0 : }
319 0 : catch (...) {
320 0 : close_db();
321 0 : std::ostringstream text;
322 0 : text << "cannot create new data file \'" << db_name << '\'';
323 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
324 0 : }
325 5 : }
326 :
327 : static std::string
328 0 : mk_no_file_error_text(const std::string &db)
329 : {
330 0 : std::ostringstream text;
331 0 : text << "cannot find file \'" << db << '\'';
332 0 : return text.str();
333 0 : }
334 :
335 : static std::string
336 0 : mk_add_include_error_text(const std::string &db, const std::string &include, const char *error = nullptr)
337 : {
338 0 : std::ostringstream text;
339 0 : text << "cannot add and load include file \'" << include << "\' to \'" << db << '\'';
340 0 : if (error)
341 0 : text << ":\n" << error;
342 0 : return text.str();
343 0 : }
344 :
345 :
346 : void
347 0 : OksConfiguration::get_updated_dbs(std::list<std::string>& dbs) const
348 : {
349 0 : for (const auto& i : m_kernel->data_files())
350 : {
351 0 : if (i.second->is_updated())
352 0 : dbs.push_back(i.second->get_full_file_name());
353 : }
354 0 : }
355 :
356 :
357 : void
358 0 : OksConfiguration::set_commit_credentials(const std::string& user, const std::string& password)
359 : {
360 0 : m_user = user;
361 0 : m_password = password;
362 0 : }
363 :
364 0 : static void throw_update_exception(const OksFile * file_h, const char * action, const char * reason)
365 : {
366 0 : std::ostringstream text;
367 0 : text << "cannot " << action << " file \'" << file_h->get_full_file_name() << "\' since " << reason;
368 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() );
369 0 : }
370 :
371 : void
372 0 : OksConfiguration::commit(const std::string& log_message)
373 : {
374 0 : try
375 : {
376 0 : m_kernel->set_active_data(nullptr);
377 : }
378 0 : catch (oks::exception &ex)
379 : {
380 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, ex.what()));
381 0 : }
382 :
383 0 : const bool commit2repo(!m_kernel->get_user_repository_root().empty() && m_kernel->is_user_repository_created());
384 0 : unsigned int count(0);
385 :
386 0 : for (const auto &i : m_kernel->data_files())
387 : {
388 0 : OksFile *file_h = i.second;
389 :
390 0 : if (file_h->is_updated())
391 : {
392 0 : const OksFile::FileStatus file_status = file_h->get_status_of_file();
393 :
394 0 : if (file_status == OksFile::FileModified)
395 0 : throw_update_exception(file_h, "save", "it was externally modified");
396 0 : else if (file_status == OksFile::FileRemoved)
397 0 : throw_update_exception(file_h, "save", "it was externally removed");
398 :
399 0 : try
400 : {
401 0 : if (!commit2repo && !log_message.empty())
402 0 : file_h->add_comment(log_message, m_kernel->get_user_name());
403 :
404 0 : m_kernel->save_data(file_h);
405 :
406 0 : count++;
407 : }
408 0 : catch (oks::exception &ex)
409 : {
410 0 : std::ostringstream text;
411 0 : text << "cannot save updated data file \'" << *(i.first) << "\':\n" << ex.what();
412 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str()));
413 0 : }
414 : }
415 : }
416 :
417 0 : if (commit2repo && count)
418 : {
419 0 : try
420 : {
421 0 : m_kernel->commit_repository(log_message);
422 : }
423 0 : catch (oks::exception &ex)
424 : {
425 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, ex.what()));
426 0 : }
427 : }
428 :
429 0 : m_created_files.clear();
430 0 : }
431 :
432 : namespace dunedaq{
433 : namespace oksconflibs{
434 : class ResubscribeGuard {
435 :
436 : public:
437 :
438 0 : ResubscribeGuard(OksConfiguration & db) : m_db(db) {
439 0 : if(m_db.m_check_db_obj) {
440 0 : m_db.unsubscribe();
441 0 : m_restart = true;
442 : }
443 : else {
444 0 : m_restart = false;
445 : }
446 :
447 0 : m_db.m_created.clear();
448 0 : m_db.m_modified.clear();
449 0 : m_db.m_removed.clear();
450 0 : }
451 :
452 0 : ~ResubscribeGuard() {
453 0 : if(m_restart) {
454 0 : m_db.subscribe();
455 : }
456 0 : }
457 :
458 : private:
459 :
460 : OksConfiguration& m_db;
461 : bool m_restart;
462 :
463 : };
464 :
465 : void
466 0 : OksConfiguration::abort()
467 : {
468 : // unsubscribe changes; if there are any, re-subscribe on return from this method
469 :
470 0 : ResubscribeGuard __rg__(*this);
471 :
472 :
473 : // destroy any newly created files
474 0 : for (const auto& i : m_created_files)
475 : {
476 0 : const std::string file_name(i->get_full_file_name());
477 :
478 0 : TLOG_DEBUG(1) << "destroy created file \'" << file_name << "\')" ;
479 0 : m_kernel->close_data(i);
480 :
481 0 : if (int result = unlink(file_name.c_str()))
482 : {
483 0 : std::ostringstream text;
484 0 : text << "abort changes failed since cannot erase created file \'" << file_name << "\'; unlink failed with code " << result << ": " << dunedaq::oks::strerror(errno);
485 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
486 0 : }
487 0 : }
488 :
489 0 : m_created_files.clear();
490 :
491 :
492 :
493 : // add to "updated" any modified file
494 0 : std::set<OksFile *> updated;
495 :
496 0 : for (const auto& i : m_kernel->data_files())
497 : {
498 0 : if (i.second->is_updated())
499 : {
500 0 : updated.insert(i.second);
501 0 : TLOG_DEBUG(2) << "file \'" << i.second->get_full_file_name() << "\' was updated, to be reloaded..." ;
502 : }
503 : }
504 :
505 0 : if (!m_kernel->get_user_repository_root().empty())
506 : {
507 0 : std::set<OksFile *> mfs, rfs;
508 0 : try
509 : {
510 0 : m_kernel->get_modified_files(mfs, rfs, "origin/master");
511 : }
512 0 : catch (const oks::exception& ex)
513 : {
514 0 : std::ostringstream text;
515 0 : text << "failed to get differences between revisions " << m_kernel->get_repository_version() << " and origin/master: " << ex.what() << '\n';
516 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str(), ex));
517 0 : }
518 0 : }
519 :
520 0 : if (!updated.empty())
521 : {
522 0 : try
523 : {
524 0 : if (!m_kernel->get_user_repository_root().empty())
525 0 : m_kernel->update_repository("origin/master", OksKernel::RepositoryUpdateType::DiscardChanges);
526 :
527 0 : m_kernel->reload_data(updated);
528 : }
529 0 : catch (oks::exception & ex)
530 : {
531 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot reload updated data files", ex));
532 0 : }
533 0 : catch (...)
534 : {
535 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot reload updated data files"));
536 0 : }
537 : }
538 0 : }
539 :
540 :
541 : static std::vector<dunedaq::conffwk::Version>
542 0 : oks2config(const std::vector<OksRepositoryVersion>& in)
543 : {
544 0 : std::vector<dunedaq::conffwk::Version> out;
545 0 : out.reserve(in.size());
546 :
547 0 : for (auto& x : in)
548 0 : out.emplace_back(x.m_commit_hash, x.m_user, x.m_date, x.m_comment, x.m_files);
549 :
550 0 : return out;
551 0 : }
552 :
553 : std::vector<dunedaq::conffwk::Version>
554 0 : OksConfiguration::get_changes()
555 : {
556 0 : if (!m_kernel->get_repository_root().empty())
557 : {
558 0 : try
559 : {
560 0 : return oks2config(m_kernel->get_repository_versions_by_hash(true, m_kernel->get_repository_version()));
561 : }
562 0 : catch (const oks::exception& ex)
563 : {
564 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get new versions", ex));
565 0 : }
566 : }
567 : else
568 : {
569 0 : std::vector<dunedaq::conffwk::Version> out;
570 :
571 0 : std::set<OksFile *> oks_files;
572 0 : m_kernel->get_modified_files(oks_files, oks_files, "");
573 :
574 0 : if (!oks_files.empty())
575 : {
576 0 : std::vector<std::string> files;
577 :
578 0 : for(const auto& x : oks_files)
579 0 : files.push_back(x->get_well_formed_name());
580 :
581 0 : out.emplace_back("", "", 0, "", files);
582 0 : }
583 :
584 0 : return out;
585 0 : }
586 : }
587 :
588 :
589 : std::vector<dunedaq::conffwk::Version>
590 0 : OksConfiguration::get_versions(const std::string& since, const std::string& until, dunedaq::conffwk::Version::QueryType type, bool skip_irrelevant)
591 : {
592 0 : if (!m_kernel->get_repository_root().empty())
593 : {
594 0 : try
595 : {
596 0 : return oks2config(type == dunedaq::conffwk::Version::query_by_date ? m_kernel->get_repository_versions_by_date(skip_irrelevant, since, until) : m_kernel->get_repository_versions_by_hash(skip_irrelevant, since, until));
597 : }
598 0 : catch (const oks::exception& ex)
599 : {
600 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get repository versions", ex));
601 0 : }
602 : }
603 : else
604 : {
605 0 : throw(dunedaq::conffwk::Generic(ERS_HERE, "cannot get versions, repository is not set"));
606 : }
607 : }
608 :
609 : }}
610 :
611 : dunedaq::oksconflibs::OksConfigObject *
612 1408 : dunedaq::oksconflibs::OksConfiguration::new_object(oks::OksObject * obj) noexcept
613 : {
614 1408 : return insert_object<dunedaq::oksconflibs::OksConfigObject>(obj, obj->GetId(), obj->GetClass()->get_name());
615 : }
616 :
617 : bool
618 0 : OksConfiguration::test_object(const std::string& class_name, const std::string& name, unsigned long /*rlevel*/, const std::vector<std::string> * /*rclasses*/)
619 : {
620 : // Looking for the class. If it does not exist, we return false.
621 0 : OksClass * cl = m_kernel->find_class(class_name);
622 0 : if (!cl)
623 : return false;
624 :
625 : // The object exist for this class?
626 0 : if (cl->get_object(name))
627 : return true;
628 :
629 : // Trying all subclasses
630 0 : if (const OksClass::FList * subclasses = cl->all_sub_classes())
631 : {
632 0 : for (OksClass::FList::const_iterator it = subclasses->begin(); it != subclasses->end(); ++it)
633 : {
634 0 : if ((*it)->get_object(name))
635 0 : return true;
636 : }
637 : }
638 : // If we get here, we found the class, but not the object.
639 : return false;
640 : }
641 :
642 : void
643 122 : dunedaq::oksconflibs::OksConfiguration::get(const std::string &class_name, const std::string &name,
644 : dunedaq::conffwk::ConfigObject &object, unsigned long /*rlevel*/, const std::vector<std::string>* /* rclasses */)
645 : {
646 122 : if (OksClass * cl = m_kernel->find_class(class_name))
647 : {
648 122 : OksObject * obj = cl->get_object(name);
649 122 : if (obj == nullptr)
650 : {
651 : // try all subclasses
652 2 : if (const OksClass::FList *subclasses = cl->all_sub_classes())
653 : {
654 2 : for (const auto& it : *subclasses)
655 : {
656 0 : obj = it->get_object(name);
657 0 : if (obj != nullptr)
658 : break;
659 : }
660 : }
661 2 : if (obj == nullptr)
662 : {
663 2 : const std::string id(name + '@' + class_name);
664 2 : throw dunedaq::conffwk::NotFound(ERS_HERE, "object", id.c_str());
665 2 : }
666 : }
667 :
668 120 : object = new_object(obj);
669 : }
670 : else
671 : {
672 0 : throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
673 : }
674 120 : }
675 :
676 : void
677 45 : OksConfiguration::get(const std::string& class_name, std::vector<conffwk::ConfigObject>& objects, const std::string& query, unsigned long /*rlevel*/, const std::vector<std::string> * /* rclasses */)
678 : {
679 45 : if(OksClass * cl = m_kernel->find_class(class_name)) {
680 45 : objects.clear();
681 :
682 45 : OksObject::List * objs = 0;
683 :
684 45 : if(query.empty()) {
685 45 : objs = cl->create_list_of_all_objects();
686 : }
687 : else {
688 0 : try {
689 0 : std::unique_ptr<OksQuery> qe(new OksQuery(cl, query.c_str()));
690 0 : if(qe->good() == false) {
691 0 : std::ostringstream text;
692 0 : text << "bad query syntax \"" << query << "\" in scope of class \"" << class_name << '\"';
693 0 : throw dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str());
694 0 : }
695 0 : objs = cl->execute_query(qe.get()); // FIXME: check .get()
696 0 : }
697 0 : catch(oks::exception& ex) {
698 0 : std::ostringstream text;
699 0 : text << "failed to execute query:\n" << ex.what();
700 0 : throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str());
701 0 : }
702 : }
703 :
704 45 : if(objs) {
705 217 : for(OksObject::List::iterator i = objs->begin(); i != objs->end(); ++i) {
706 172 : objects.push_back(new_object(*i));
707 : }
708 45 : delete objs;
709 : }
710 : }
711 : else {
712 0 : throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
713 : }
714 45 : }
715 :
716 : void
717 0 : OksConfiguration::get(const conffwk::ConfigObject& obj_from, const std::string& query, std::vector<conffwk::ConfigObject>& objects, unsigned long /*rlevel*/, const std::vector<std::string> * /* rclasses */)
718 : {
719 0 : if(obj_from.is_null()) {
720 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "parameter \'obj_from\' is (null)" ) );
721 : }
722 :
723 0 : OksObject * o = (static_cast<const OksConfigObject *>(obj_from.implementation()))->m_obj;
724 :
725 0 : try {
726 0 : oks::QueryPath q(query, *m_kernel);
727 0 : if(OksObject::List * objs = o->find_path(q)) {
728 0 : for(OksObject::List::iterator i = objs->begin(); i != objs->end(); ++i) {
729 0 : objects.push_back(new_object(*i));
730 : }
731 0 : delete objs;
732 : }
733 0 : }
734 0 : catch ( oks::bad_query_syntax& e ) {
735 0 : std::ostringstream text;
736 0 : text << "bad path-query \"" << query << "\" to object " << o;
737 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
738 0 : }
739 0 : }
740 :
741 :
742 : dunedaq::conffwk::class_t *
743 6521 : OksConfiguration::get(const std::string& class_name, bool direct_only)
744 : {
745 6521 : OksClass * c = m_kernel->find_class(class_name);
746 :
747 6521 : if(c == 0) {
748 2 : throw dunedaq::conffwk::NotFound(ERS_HERE, "class", class_name.c_str());
749 : }
750 :
751 6519 : dunedaq::conffwk::class_t * d = new dunedaq::conffwk::class_t(c->get_name(), c->get_description(), c->get_file()->get_full_file_name(), c->get_is_abstract());
752 :
753 6519 : if(direct_only) {
754 1 : if(const std::list<std::string *> * classes = c->direct_super_classes()) {
755 2 : for(const auto& i : *classes) {
756 1 : const_cast< std::vector<std::string>& >(d->p_superclasses).push_back(*i);
757 : }
758 : }
759 : }
760 : else {
761 6518 : if(const OksClass::FList * classes = c->all_super_classes()) {
762 13048 : for(const auto& i : *classes) {
763 6530 : const_cast< std::vector<std::string>& >(d->p_superclasses).push_back(i->get_name());
764 : }
765 : }
766 : }
767 :
768 6519 : if(const OksClass::FList * subclasses = c->all_sub_classes()) {
769 13049 : for(const auto& i : *subclasses) {
770 6530 : if(direct_only == false || i->has_direct_super_class(c->get_name()) == true) {
771 6530 : const_cast< std::vector<std::string>& >(d->p_subclasses).push_back(i->get_name());
772 : }
773 : }
774 : }
775 :
776 6519 : if(const std::list<OksAttribute *> * attrs = (direct_only ? c->direct_attributes() : c->all_attributes())) {
777 23846 : for(const auto& i : *attrs) {
778 17327 : OksAttribute::Format format = i->get_format();
779 17327 : OksData::Type type = i->get_data_type();
780 :
781 17327 : const_cast< std::vector<dunedaq::conffwk::attribute_t>& >(d->p_attributes).push_back(
782 17327 : dunedaq::conffwk::attribute_t(
783 : i->get_name(),
784 : (
785 : type == OksData::string_type ? dunedaq::conffwk::string_type :
786 : type == OksData::enum_type ? dunedaq::conffwk::enum_type :
787 : type == OksData::bool_type ? dunedaq::conffwk::bool_type :
788 : type == OksData::s8_int_type ? dunedaq::conffwk::s8_type :
789 : type == OksData::u8_int_type ? dunedaq::conffwk::u8_type :
790 : type == OksData::s16_int_type ? dunedaq::conffwk::s16_type :
791 : type == OksData::u16_int_type ? dunedaq::conffwk::u16_type :
792 : type == OksData::s32_int_type ? dunedaq::conffwk::s32_type :
793 : type == OksData::u32_int_type ? dunedaq::conffwk::u32_type :
794 : type == OksData::s64_int_type ? dunedaq::conffwk::s64_type :
795 : type == OksData::u64_int_type ? dunedaq::conffwk::u64_type :
796 : type == OksData::float_type ? dunedaq::conffwk::float_type :
797 : type == OksData::double_type ? dunedaq::conffwk::double_type :
798 : type == OksData::date_type ? dunedaq::conffwk::date_type :
799 : type == OksData::time_type ? dunedaq::conffwk::time_type :
800 : dunedaq::conffwk::class_type
801 : ),
802 : i->get_range(),
803 : (
804 17327 : i->is_integer() == false ? dunedaq::conffwk::na_int_format :
805 : (
806 5976 : format == OksAttribute::Dec ? dunedaq::conffwk::dec_int_format :
807 45 : format == OksAttribute::Hex ? dunedaq::conffwk::hex_int_format :
808 : dunedaq::conffwk::oct_int_format
809 : )
810 : ),
811 17327 : i->get_is_no_null(),
812 17327 : i->get_is_multi_values(),
813 : i->get_init_value(),
814 : i->get_description()
815 40630 : )
816 : );
817 :
818 : }
819 : }
820 :
821 6519 : if(const std::list<OksRelationship *> * rels = (direct_only ? c->direct_relationships() : c->all_relationships())) {
822 18589 : for(const auto& i : *rels) {
823 12071 : const_cast< std::vector<dunedaq::conffwk::relationship_t>& >(d->p_relationships).push_back(
824 12071 : dunedaq::conffwk::relationship_t(
825 : i->get_name(),
826 : i->get_type(),
827 12071 : (i->get_low_cardinality_constraint() == OksRelationship::Zero),
828 12071 : (i->get_high_cardinality_constraint() == OksRelationship::Many),
829 12071 : i->get_is_composite(),
830 : i->get_description()
831 12071 : )
832 : );
833 : }
834 : }
835 :
836 6519 : return d;
837 : }
838 :
839 : void
840 92 : OksConfiguration::get_superclasses(conffwk::fmap<conffwk::fset>& schema)
841 : {
842 92 : schema.clear();
843 :
844 92 : if(!m_kernel) {
845 : return; // throw ( dunedaq::conffwk::Generic( ERS_HERE, "database is not loaded" ) );
846 : }
847 :
848 87 : schema.reserve(m_kernel->classes().size() * 3);
849 :
850 6605 : for(OksClass::Map::const_iterator i = m_kernel->classes().begin(); i != m_kernel->classes().end(); ++i) {
851 6518 : if(const OksClass::FList * scl = i->second->all_super_classes()) {
852 6518 : const std::string* name = &conffwk::DalFactory::instance().get_known_class_name_ref(i->second->get_name());
853 :
854 6518 : auto& subclasses = schema[name];
855 :
856 6518 : if(!scl->empty()) {
857 3579 : subclasses.reserve(scl->size() * 3);
858 10109 : for(OksClass::FList::const_iterator j = scl->begin(); j != scl->end(); ++j) {
859 6530 : subclasses.insert(&conffwk::DalFactory::instance().get_known_class_name_ref((*j)->get_name()));
860 : }
861 : }
862 : }
863 : }
864 : }
865 :
866 :
867 : void
868 27 : OksConfiguration::create(OksFile * at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
869 : {
870 27 : try {
871 27 : m_kernel->set_active_data(at);
872 : }
873 0 : catch(oks::exception& ex) {
874 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, ex.what()) );
875 0 : }
876 :
877 27 : OksClass * c = m_kernel->find_class(class_name);
878 :
879 27 : if(c == nullptr) {
880 0 : std::ostringstream text;
881 0 : text << "cannot find class \"" << class_name << '\"';
882 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
883 0 : }
884 27 : else if(id.empty() == false) {
885 27 : if(OksObject * obj = c->get_object(id)) {
886 0 : std::ostringstream text;
887 0 : text << "object \"" << id << '@' << class_name << "\" already exists in file \"" << obj->get_file()->get_full_file_name() << '\"';
888 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
889 0 : }
890 : }
891 :
892 27 : if(m_kernel->get_test_duplicated_objects_via_inheritance_mode() == false)
893 : {
894 5 : m_kernel->set_test_duplicated_objects_via_inheritance_mode(true);
895 5 : m_kernel->registrate_all_classes();
896 : }
897 :
898 27 : try {
899 27 : object = new_object(new OksObject(c, id.c_str()));
900 : }
901 0 : catch(oks::exception& ex)
902 : {
903 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "cannot create configuration object", ex ) );
904 0 : }
905 27 : }
906 :
907 : void
908 27 : OksConfiguration::create(const std::string& at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
909 : {
910 27 : if(at.empty() == true) {
911 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "parameter \'at\' (i.e. filename) cannot be empty" ) );
912 : }
913 :
914 27 : if(OksFile * h = m_kernel->find_data_file(at)) {
915 27 : return create(h, class_name, id, object);
916 : }
917 : else {
918 0 : std::ostringstream text;
919 0 : text << "file \"" << at << "\" is not loaded";
920 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
921 0 : }
922 : }
923 :
924 : void
925 0 : OksConfiguration::create(const conffwk::ConfigObject& at, const std::string& class_name, const std::string& id, conffwk::ConfigObject& object)
926 : {
927 0 : create((static_cast<const OksConfigObject *>(at.implementation()))->m_obj->get_file(), class_name, id, object);
928 0 : }
929 :
930 : void
931 0 : OksConfiguration::create_notify(OksObject * o, void * p) noexcept
932 : {
933 0 : reinterpret_cast<OksConfiguration *>(p)->m_created.push_back(o);
934 0 : }
935 :
936 : void
937 0 : OksConfiguration::change_notify(OksObject * o, void * p) noexcept
938 : {
939 0 : reinterpret_cast<OksConfiguration *>(p)->m_modified.insert(o);
940 0 : }
941 :
942 : void
943 0 : OksConfiguration::delete_notify(OksObject * o, void * p) noexcept
944 : {
945 0 : reinterpret_cast<OksConfiguration *>(p)->m_removed[o->GetClass()->get_name()].insert(o->GetId());
946 0 : }
947 :
948 :
949 : struct InheritanceData {
950 :
951 : InheritanceData(const OksKernel&);
952 :
953 0 : const OksConfiguration::SMap& data() const { return m_data; }
954 :
955 : OksConfiguration::SMap m_data;
956 :
957 : };
958 :
959 0 : InheritanceData::InheritanceData(const OksKernel &kernel)
960 : {
961 0 : for (OksClass::Map::const_iterator i = kernel.classes().begin(); i != kernel.classes().end(); ++i)
962 0 : if (const OksClass::FList *slist = i->second->all_super_classes())
963 : {
964 0 : std::set<std::string> &data(m_data[i->second->get_name()]);
965 0 : for (const auto &j : *slist)
966 0 : data.insert(j->get_name());
967 : }
968 0 : }
969 :
970 :
971 : /**
972 : * The function checks if the object satisfies the subscription
973 : * and adds to changes.
974 : * The actions could be:
975 : * '+' - created
976 : * '~' - changed
977 : * '-' - deleted
978 : */
979 :
980 : static void
981 0 : check(std::vector<conffwk::ConfigurationChange *>& changes,
982 : const InheritanceData & inheritance,
983 : const std::set<std::string>& class_names,
984 : const OksConfiguration::SMap & objects,
985 : const std::string& obj_class,
986 : const std::string& obj_id,
987 : const char action
988 : ) {
989 :
990 0 : bool any = (class_names.empty() && objects.empty());
991 :
992 :
993 : // check subscription on objects
994 : //
995 : // omi iterator in non-null, if on an object of class 'obj_class'
996 : // there is explicit subscription
997 :
998 0 : OksConfiguration::SMap::const_iterator omi = objects.end();
999 :
1000 0 : if(action != '+') {
1001 0 : omi = objects.find(obj_class);
1002 0 : if(omi != objects.end()) {
1003 0 : std::set<std::string>::const_iterator i = omi->second.find(obj_id);
1004 :
1005 0 : if(i != omi->second.end()) {
1006 0 : conffwk::ConfigurationChange::add(changes, obj_class, obj_id, action);
1007 : }
1008 : }
1009 : }
1010 :
1011 :
1012 : // process the class
1013 :
1014 0 : if(action == '+' || omi == objects.end()) {
1015 0 : if(any || class_names.find(obj_class) != class_names.end()) {
1016 0 : conffwk::ConfigurationChange::add(changes, obj_class, obj_id, action);
1017 : }
1018 : }
1019 :
1020 :
1021 : // process subclasses
1022 :
1023 0 : OksConfiguration::SMap::const_iterator it = inheritance.data().find(obj_class);
1024 0 : if(it != inheritance.data().end()) {
1025 0 : for(std::set<std::string>::const_iterator j = it->second.begin(); j != it->second.end(); ++j) {
1026 0 : omi = (action != '+' ? objects.find(*j) : objects.end());
1027 :
1028 : // 1. add objects if criteria is 'any'
1029 : // 2. add object of class which has subscription and has no explicit object subscription
1030 : // 3. add explicitly subscribed object
1031 :
1032 0 : if(
1033 0 : any ||
1034 : (
1035 0 : omi == objects.end() &&
1036 0 : class_names.find(*j) != class_names.end()
1037 0 : ) ||
1038 : (
1039 0 : omi != objects.end() &&
1040 0 : omi->second.find(obj_id) != omi->second.end()
1041 : )
1042 : ) {
1043 0 : conffwk::ConfigurationChange::add(changes, *j, obj_id, action);
1044 : }
1045 : }
1046 : }
1047 0 : }
1048 :
1049 :
1050 : class DestroyGuard1 {
1051 :
1052 : public:
1053 :
1054 0 : DestroyGuard1(OksKernel & kernel) : m_kernel(kernel) { ; }
1055 :
1056 0 : ~DestroyGuard1() {
1057 0 : m_kernel.subscribe_delete_object(0, 0);
1058 0 : }
1059 :
1060 : private:
1061 :
1062 : OksKernel& m_kernel;
1063 :
1064 : };
1065 :
1066 : class DestroyGuard2 {
1067 :
1068 : public:
1069 :
1070 0 : DestroyGuard2(OksConfiguration::SMap& removed) : m_removed(removed) { ; }
1071 :
1072 0 : ~DestroyGuard2() {
1073 0 : m_removed.clear();
1074 0 : }
1075 :
1076 : private:
1077 :
1078 : OksConfiguration::SMap& m_removed;
1079 :
1080 : };
1081 :
1082 :
1083 : void
1084 0 : OksConfiguration::destroy(conffwk::ConfigObject& obj)
1085 : {
1086 0 : OksObject * o((static_cast<const OksConfigObject *>(obj.implementation()))->m_obj);
1087 :
1088 0 : DestroyGuard2 dg2(m_removed); // => on exit from method, call m_removed.clear();
1089 :
1090 0 : InheritanceData inheritance(*m_kernel);
1091 :
1092 0 : try {
1093 0 : m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
1094 0 : DestroyGuard1 dg1(*m_kernel); // => on exit from try block, call m_kernel->subscribe_delete_object(0, 0);
1095 0 : OksObject::destroy(o);
1096 0 : }
1097 0 : catch(oks::exception& ex) {
1098 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, ex.what()) );
1099 0 : }
1100 :
1101 0 : if(m_conf) {
1102 0 : std::vector<conffwk::ConfigurationChange *> changes;
1103 :
1104 0 : for(SMap::iterator i = m_removed.begin(); i != m_removed.end(); ++i) {
1105 0 : for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
1106 0 : check(changes, inheritance, m_class_names, m_objects, i->first, *j, '-');
1107 : }
1108 : }
1109 :
1110 0 : if(!changes.empty()) {
1111 0 : m_conf->update_cache(changes);
1112 0 : conffwk::ConfigurationChange::clear(changes);
1113 : }
1114 0 : }
1115 0 : }
1116 :
1117 : bool
1118 0 : OksConfiguration::is_writable(const std::string& db_name)
1119 : {
1120 0 : if (OksFile * h = m_kernel->find_data_file(db_name))
1121 : {
1122 0 : try
1123 : {
1124 0 : if (!m_kernel->get_user_repository_root().empty())
1125 : {
1126 0 : return oksutils::access::is_writable(*h, OksKernel::get_user_name());
1127 : }
1128 : else
1129 : {
1130 0 : return !OksKernel::check_read_only(h);
1131 : }
1132 : }
1133 0 : catch (const std::exception& ex)
1134 : {
1135 0 : std::ostringstream text;
1136 0 : text << "cannot check access status of file \'" << db_name << "\': " << ex.what();
1137 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1138 0 : }
1139 : }
1140 : else
1141 : {
1142 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
1143 : }
1144 : }
1145 :
1146 : static std::string
1147 0 : mk_rm_include_error_text(const std::string &db, const std::string &include, const char *error = 0)
1148 : {
1149 0 : std::ostringstream text;
1150 0 : text << "cannot remove include file \'" << include << "\' from \'" << db << '\'';
1151 0 : if (error)
1152 0 : text << ":\n" << error;
1153 0 : return text.str();
1154 0 : }
1155 :
1156 : void
1157 0 : OksConfiguration::add_include(const std::string& db_name, const std::string& include)
1158 : {
1159 0 : if(OksFile * h = m_kernel->find_data_file(db_name)) {
1160 0 : try {
1161 0 : h->add_include_file(include);
1162 : }
1163 0 : catch(dunedaq::conffwk::Generic& ex) {
1164 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include).c_str() ), ex );
1165 0 : }
1166 0 : catch (oks::exception & ex) {
1167 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include, ex.what()).c_str() ) );
1168 0 : }
1169 0 : catch (...) {
1170 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_add_include_error_text(db_name, include).c_str() ) );
1171 0 : }
1172 : }
1173 : else {
1174 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
1175 : }
1176 0 : }
1177 :
1178 : void
1179 0 : OksConfiguration::remove_include(const std::string& db_name, const std::string& include)
1180 : {
1181 0 : InheritanceData inheritance(*m_kernel);
1182 :
1183 0 : DestroyGuard2 dg2(m_removed); // => on exit from method, call m_removed.clear();
1184 :
1185 0 : if(OksFile * h = m_kernel->find_data_file(db_name)) {
1186 0 : try {
1187 0 : m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
1188 0 : DestroyGuard1 dg1(*m_kernel); // => on exit from try block, call m_kernel->subscribe_delete_object(0, 0);
1189 0 : h->remove_include_file(include);
1190 0 : }
1191 0 : catch(dunedaq::conffwk::Generic& ex) {
1192 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include).c_str() ), ex );
1193 0 : }
1194 0 : catch (oks::exception & ex) {
1195 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include, ex.what()).c_str() ) );
1196 0 : }
1197 0 : catch (...) {
1198 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_rm_include_error_text(db_name, include).c_str() ) );
1199 0 : }
1200 : }
1201 : else {
1202 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
1203 : }
1204 :
1205 0 : std::vector<conffwk::ConfigurationChange *> changes;
1206 :
1207 0 : for(SMap::iterator i = m_removed.begin(); i != m_removed.end(); ++i) {
1208 0 : for(std::set<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
1209 0 : check(changes, inheritance, m_class_names, m_objects, i->first, *j, '-');
1210 : }
1211 : }
1212 :
1213 0 : if(!changes.empty()) {
1214 0 : m_conf->update_cache(changes);
1215 0 : conffwk::ConfigurationChange::clear(changes);
1216 : }
1217 0 : }
1218 :
1219 :
1220 : void
1221 0 : OksConfiguration::get_includes(const std::string& db_name, std::list<std::string>& includes) const
1222 : {
1223 0 : if (db_name.empty())
1224 : {
1225 0 : for (auto& i : m_kernel->data_files())
1226 : {
1227 0 : if(i.second->get_parent() == nullptr)
1228 0 : includes.push_back(*i.first);
1229 : }
1230 : }
1231 : else
1232 : {
1233 0 : if (OksFile * h = m_kernel->find_data_file(db_name))
1234 : {
1235 0 : for (auto& i : h->get_include_files())
1236 : {
1237 0 : includes.push_back(i);
1238 : }
1239 : }
1240 : else
1241 : {
1242 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, mk_no_file_error_text(db_name).c_str() ) );
1243 : }
1244 : }
1245 0 : }
1246 :
1247 :
1248 : void
1249 3 : OksConfiguration::check_db()
1250 : {
1251 6 : static const std::string version("origin/master");
1252 :
1253 3 : if (m_fn)
1254 : {
1255 3 : std::set<OksFile *> ufs, rfs;
1256 :
1257 3 : try
1258 : {
1259 3 : m_kernel->get_modified_files(ufs, rfs, version);
1260 3 : m_repo_error_count = 0;
1261 : }
1262 0 : catch(const oks::RepositoryOperationFailed& ex)
1263 : {
1264 0 : std::ostringstream text;
1265 0 : text << "cannot get modified repository files (attempt " << ++m_repo_error_count << "): " << ex.what();
1266 0 : ers::error(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1267 0 : }
1268 0 : catch(const oks::exception& ex)
1269 : {
1270 0 : std::ostringstream text;
1271 0 : text << "cannot get modified files: " << ex.what();
1272 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1273 0 : }
1274 :
1275 3 : for (const auto& x : ufs)
1276 : {
1277 0 : if (x->get_oks_format() == "schema")
1278 : {
1279 0 : std::ostringstream text;
1280 0 : text << "reload of schema files is not supported (\'" << x->get_well_formed_name() << "\')";
1281 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1282 0 : }
1283 : }
1284 :
1285 3 : if (ufs.empty() == false)
1286 : {
1287 0 : InheritanceData inheritance(*m_kernel);
1288 :
1289 0 : m_kernel->subscribe_create_object(create_notify, reinterpret_cast<void *>(this));
1290 0 : m_kernel->subscribe_change_object(change_notify, reinterpret_cast<void *>(this));
1291 0 : m_kernel->subscribe_delete_object(delete_notify, reinterpret_cast<void *>(this));
1292 :
1293 0 : (*m_pre_fn)(m_conf);
1294 :
1295 0 : try
1296 : {
1297 0 : if(!m_kernel->get_user_repository_root().empty())
1298 0 : m_kernel->update_repository(version, OksKernel::RepositoryUpdateType::DiscardChanges);
1299 :
1300 0 : m_kernel->reload_data(ufs, false);
1301 : }
1302 0 : catch (oks::exception & ex)
1303 : {
1304 0 : close_database(false);
1305 0 : m_fn = 0;
1306 0 : std::ostringstream text;
1307 0 : text << "failed to reload updated files:\n" << ex.what();
1308 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, text.str().c_str() ) );
1309 0 : }
1310 0 : catch (...)
1311 : {
1312 0 : close_database(false);
1313 0 : m_fn = 0;
1314 0 : throw ( dunedaq::conffwk::Generic( ERS_HERE, "failed to reload updated files" ) );
1315 0 : }
1316 :
1317 :
1318 0 : m_kernel->subscribe_create_object(0, 0);
1319 0 : m_kernel->subscribe_change_object(0, 0);
1320 0 : m_kernel->subscribe_delete_object(0, 0);
1321 :
1322 0 : std::vector<conffwk::ConfigurationChange *> changes;
1323 :
1324 0 : {
1325 0 : for (auto& i : m_created)
1326 : {
1327 0 : check(changes, inheritance, m_class_names, m_objects, i->GetClass()->get_name(), i->GetId(), '+');
1328 :
1329 0 : std::set<OksObject *>::iterator j = m_modified.find(i);
1330 0 : if (j != m_modified.end())
1331 : {
1332 0 : TLOG_DEBUG(1) << "created object " << i << " appears in \'modified\' set, removing..." ;
1333 0 : m_modified.erase(j);
1334 : }
1335 : }
1336 : }
1337 :
1338 0 : {
1339 0 : for (auto& i : m_modified)
1340 : {
1341 0 : if (m_kernel->is_dangling(i))
1342 : {
1343 0 : TLOG_DEBUG(1) << "object " << (void *)(i) << " is dangling, ignore..." ;
1344 : }
1345 : else
1346 : {
1347 0 : check(changes, inheritance, m_class_names, m_objects, i->GetClass()->get_name(), i->GetId(), '~');
1348 : }
1349 : }
1350 : }
1351 :
1352 0 : {
1353 0 : for (auto& i : m_removed)
1354 : {
1355 0 : for (auto& j : i.second)
1356 : {
1357 0 : check(changes, inheritance, m_class_names, m_objects, i.first, j, '-');
1358 : }
1359 : }
1360 : }
1361 :
1362 0 : if (!changes.empty())
1363 : {
1364 0 : (*m_fn)(changes, m_conf);
1365 0 : conffwk::ConfigurationChange::clear(changes);
1366 : }
1367 :
1368 0 : m_created.clear();
1369 0 : m_modified.clear();
1370 0 : m_removed.clear();
1371 0 : }
1372 3 : }
1373 : else
1374 : {
1375 0 : throw(dunedaq::conffwk::Generic( ERS_HERE, "no subscription has been done" ) );
1376 : }
1377 3 : }
1378 :
1379 :
1380 : //
1381 : // Subscribe on changes by class name
1382 : //
1383 :
1384 : void
1385 3 : OksConfiguration::subscribe(const std::set<std::string>& class_names,
1386 : const SMap& objs,
1387 : ConfigurationImpl::notify cb,
1388 : ConfigurationImpl::pre_notify pre_cb)
1389 : {
1390 3 : m_fn = cb;
1391 3 : m_pre_fn = pre_cb;
1392 3 : m_class_names = class_names;
1393 3 : m_objects = objs;
1394 :
1395 3 : subscribe();
1396 3 : }
1397 :
1398 : // Start subscription thread
1399 :
1400 : void
1401 3 : OksConfiguration::subscribe()
1402 : {
1403 3 : if(m_check_db_obj == 0) {
1404 3 : TLOG_DEBUG( 2) << "starting CheckDB thread ..." ;
1405 3 : m_check_db_obj = new OksConfigurationCheckDB(this);
1406 3 : m_check_db_thread = new std::thread(std::ref(*m_check_db_obj));
1407 : }
1408 3 : }
1409 :
1410 :
1411 : //
1412 : // Unsubscribe
1413 : //
1414 :
1415 : void
1416 87 : OksConfiguration::unsubscribe()
1417 : {
1418 87 : if(m_check_db_obj) {
1419 3 : TLOG_DEBUG( 2) << "stopping CheckDB thread ..." ;
1420 3 : m_check_db_obj->m_run = false;
1421 3 : m_check_db_thread->join(); // wait thread termination
1422 3 : delete m_check_db_thread;
1423 3 : m_check_db_thread = 0;
1424 3 : m_check_db_obj = 0;
1425 3 : TLOG_DEBUG( 2) << "the CheckDB thread has been terminated" ;
1426 : }
1427 87 : }
1428 :
1429 :
1430 : void
1431 0 : OksConfiguration::print_profiling_info() noexcept
1432 : {
1433 0 : std::cout <<
1434 : "OksConfiguration profiler report:\n"
1435 0 : " number of loaded schema files: " << (m_kernel ? m_kernel->schema_files().size() : 0) << "\n"
1436 0 : " number of loaded data files: " << (m_kernel ? m_kernel->data_files().size() : 0) << "\n"
1437 0 : " number of loaded classes: " << (m_kernel ? m_kernel->classes().size() : 0) << "\n"
1438 0 : " number of loaded objects: " << (m_kernel ? m_kernel->objects().size() : 0) << std::endl;
1439 0 : }
1440 :
1441 :
1442 : // read OksKernel parameters from environment (silence mode)
1443 :
1444 : void
1445 87 : OksConfiguration::init_env()
1446 : {
1447 87 : m_oks_kernel_silence = (getenv("OKSCONFLIBS_NO_KERNEL_SILENCE") == nullptr);
1448 87 : }
|