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