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

Generated by: LCOV version 2.0-1