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