LCOV - code coverage report
Current view: top level - oksconflibs/src - OksConfiguration.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 28.9 % 710 205
Test Date: 2026-10-11 15:05:20 Functions: 38.9 % 72 28

            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 : }
        

Generated by: LCOV version 2.0-1