LCOV - code coverage report
Current view: top level - oks/src - kernel.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 21.6 % 2970 642
Test Date: 2026-07-12 15:23:06 Functions: 31.5 % 260 82

            Line data    Source code
       1              : // DUNE DAQ modification notice:
       2              : // This file has been modified from the original ATLAS oks source for the DUNE DAQ project.
       3              : // Fork baseline commit: oks-08-03-04 (2022-04-14).
       4              : // Renamed since fork: no.
       5              : 
       6              : #define _OksBuildDll_
       7              : 
       8              : #include <errno.h>
       9              : #include <stdio.h>
      10              : #include <stdlib.h>
      11              : #include <string.h>
      12              : #include <unistd.h>
      13              : #include <wchar.h>
      14              : //#include <security/pam_appl.h>
      15              : #include <sys/stat.h>
      16              : #include <sys/wait.h>
      17              : 
      18              : #include <algorithm>
      19              : #include <filesystem>
      20              : #include <fstream>
      21              : #include <sstream>
      22              : #include <stdexcept>
      23              : #include <vector>
      24              : #include <mutex>
      25              : #include <chrono>
      26              : #include <cstring>
      27              : #include <ctime>
      28              : 
      29              : #include "ers/ers.hpp"
      30              : #include "logging/Logging.hpp"
      31              : 
      32              : #include "okssystem/Host.hpp"
      33              : #include "okssystem/User.hpp"
      34              : #include "okssystem/exceptions.hpp"
      35              : 
      36              : //#include <daq_tokens/verify.h>
      37              : 
      38              : #include "oks/kernel.hpp"
      39              : #include "oks/xml.hpp"
      40              : #include "oks/file.hpp"
      41              : #include "oks/attribute.hpp"
      42              : #include "oks/relationship.hpp"
      43              : #include "oks/method.hpp"
      44              : #include "oks/class.hpp"
      45              : #include "oks/object.hpp"
      46              : #include "oks/profiler.hpp"
      47              : #include "oks/pipeline.hpp"
      48              : #include "oks/cstring.hpp"
      49              : 
      50              : #include "oks_utils.hpp"
      51              : 
      52              : namespace dunedaq {
      53              : namespace oks {
      54              : 
      55              : std::mutex OksKernel::p_parallel_out_mutex;
      56              : 
      57              : static std::mutex s_get_cwd_mutex;
      58              : 
      59              : bool OksKernel::p_skip_string_range = false;
      60              : bool OksKernel::p_use_strict_repository_paths = true;
      61              : char * OksKernel::s_cwd = nullptr;
      62              : 
      63              : std::string OksKernel::p_repository_root;
      64              : std::string OksKernel::p_repository_mapping_dir;
      65              : 
      66              : int OksKernel::p_threads_pool_size = 0;
      67              : 
      68              : 
      69              :   class GitFoldersHolder
      70              :   {
      71              :   public:
      72           39 :     ~GitFoldersHolder()
      73              :     {
      74           39 :       std::lock_guard scoped_lock(s_git_folders_mutex);
      75              : 
      76           39 :       for (const auto &x : s_git_folders)
      77            0 :         remove(x);
      78              : 
      79           39 :       s_git_folders.clear();
      80           39 :     }
      81              : 
      82              :     static void
      83            0 :     remove(const std::string &path)
      84              :     {
      85            0 :       try
      86              :         {
      87            0 :           std::filesystem::remove_all(path);
      88              :         }
      89            0 :       catch (std::exception &ex)
      90              :         {
      91            0 :           Oks::error_msg("OksKernel::~OksKernel") << "cannot remove user repository \"" << path << "\"" << ex.what() << std::endl;
      92            0 :         }
      93            0 :     }
      94              : 
      95              :     void
      96            0 :     insert(const std::string& path)
      97              :     {
      98            0 :       std::lock_guard scoped_lock(s_git_folders_mutex);
      99            0 :       s_git_folders.insert(path);
     100            0 :     }
     101              : 
     102              :     void
     103            0 :     erase(const std::string& path)
     104              :     {
     105            0 :       std::lock_guard scoped_lock(s_git_folders_mutex);
     106            0 :       s_git_folders.erase(path);
     107            0 :     }
     108              : 
     109              :   private:
     110              : 
     111              :     std::mutex s_git_folders_mutex;
     112              :     std::set<std::string> s_git_folders;
     113              :   };
     114              : 
     115              :   static GitFoldersHolder s_git_folders;
     116              : 
     117              : 
     118              : const std::string
     119          261 : strerror(int error)
     120              : {
     121          261 :   char buffer[1024];
     122          261 :   buffer[0] = 0;
     123          261 :   return std::string(strerror_r(error, buffer, 1024));
     124              : }
     125              : 
     126              : 
     127           39 :   ERS_DECLARE_ISSUE(
     128              :     kernel,
     129              :     SetGroupIdFailed,
     130              :     "cannot set group ID " << id << " for the file \'" << file << "\': chown() failed with code " << code << " , reason = \'" << why << '\'',
     131              :     ((long)id)
     132              :     ((const char *)file)
     133              :     ((int)code)
     134              :     ((std::string)why)
     135              :   )
     136              : 
     137           39 :   ERS_DECLARE_ISSUE(
     138              :     kernel,
     139              :     BindError,
     140              :     "Found unresolved reference(s):\n" << which,
     141              :     ((std::string)which)
     142              :   )
     143              : 
     144           39 :   ERS_DECLARE_ISSUE(
     145              :     kernel,
     146              :     ClassAlreadyDefined,
     147              :     "class \"" << name << "\" is defined in files \"" << f1 << "\" and \"" << f2 << "\"",
     148              :     ((std::string)name)
     149              :     ((std::string)f1)
     150              :     ((std::string)f2)
     151              :   )
     152              : 
     153           39 :   ERS_DECLARE_ISSUE(
     154              :     kernel,
     155              :     InternalError,
     156              :     "internal error: " << text,
     157              :     ((std::string)text)
     158              :   )
     159              : 
     160              :   std::string
     161            0 :   CanNotOpenFile::fill(const char * prefix, const std::string& name, const std::string& reason) noexcept
     162              :   {
     163            0 :     std::string result(prefix);
     164            0 :     result += "(): ";
     165              : 
     166            0 :     if(name.empty()) return (result + "file name is empty");
     167              :   
     168            0 :     result += "cannot load file \'" + name + '\'' ;
     169              : 
     170            0 :     if(!reason.empty()) {
     171            0 :       result += " because:\n" + reason;
     172              :     }
     173              : 
     174            0 :     return result;
     175            0 :   }
     176              : 
     177              :   std::string
     178            0 :   FailedLoadFile::fill(const std::string& what, const std::string& name, const std::string& reason) noexcept
     179              :   {
     180            0 :     return (std::string("Failed to load ") + what + " \"" + name + "\" because:\n" + reason);
     181              :   }
     182              : 
     183              :   std::string
     184            0 :   FailedReloadFile::fill(const std::string& names, const std::string& reason) noexcept
     185              :   {
     186            0 :     return (std::string("Failed to re-load file(s) ") + names + " because:\n" + reason);
     187              :   }
     188              : 
     189              :   std::string
     190            0 :   RepositoryOperationFailed::fill(const char * op, const std::string& reason) noexcept
     191              :   {
     192            0 :     return (std::string("Failed to ") + op + " file(s) because:\n" + reason);
     193              :   }
     194              : 
     195              :   std::string
     196            0 :   CanNotCreateFile::fill(const char * prefix, const char * what, const std::string& name, const std::string& reason) noexcept
     197              :   {
     198            0 :     return std::string(prefix) + "(): failed to create new " + what + " \'" + name + "\' because:\n" + reason;
     199              :   }
     200              : 
     201              :   std::string
     202            0 :   CanNotCreateRepositoryDir::fill(const char * prefix, const std::string& name) noexcept
     203              :   {
     204            0 :     return std::string(prefix) + "(): failed to create user repository dir, mkdtemp(\'" + name + "\') failed: " + strerror(errno);
     205              :   }
     206              : 
     207              :   std::string
     208            0 :   CanNotWriteToFile::fill(const char * prefix, const char * item, const std::string& name, const std::string& reason) noexcept
     209              :   {
     210            0 :     return (std::string(prefix) + "(): failed to write " + item + " to \'" + name + "\' because:\n" + reason);
     211              :   }
     212              : 
     213              :   std::string
     214            0 :   CanNotBackupFile::fill(const std::string& name, const std::string& reason) noexcept
     215              :   {
     216            0 :     return (std::string("Failed to make a backup file of \'") + name + "\' because:\n" + reason);
     217              :   }
     218              : 
     219              :   std::string
     220            0 :   CanNotSetActiveFile::fill(const char * item, const std::string& name, const std::string& reason) noexcept
     221              :   {
     222            0 :     return (std::string("Failed to set active ") + item + " file \'" + name + "\' because:\n" + reason);
     223              :   }
     224              : 
     225              :   std::string
     226            0 :   CanNotSetFile::fill(const OksClass * c, const OksObject * o, const OksFile& file, const std::string& reason) noexcept
     227              :   {
     228            0 :     std::ostringstream s;
     229            0 :     s << "Failed to move ";
     230            0 :     if(c) s << "class " << c->get_name();
     231            0 :     else s << "object " << o;
     232            0 :     s << " to file \'" << file.get_full_file_name() << "\' because:\n" << reason;
     233            0 :     return s.str();
     234            0 :   }
     235              : 
     236              :   std::string
     237            0 :   CannotAddClass::fill(const OksClass &c, const std::string& reason) noexcept
     238              :   {
     239            0 :     return (std::string("Cannot add class \'") + c.get_name() + "\' because:\n" + reason);
     240              :   }
     241              : 
     242              :   std::string
     243          261 :   CannotResolvePath::fill(const std::string& path, int error_code) noexcept
     244              :   {
     245          261 :     std::ostringstream text;
     246          261 :     text << "realpath(\'" << path << "\') has failed with code " << error_code << ": \'" << strerror(error_code) << '\'';
     247          261 :     return text.str();
     248          261 :   }
     249              : 
     250              : 
     251              :   static const std::string&
     252            0 :   get_temporary_dir()
     253              :   {
     254            0 :     static std::string s_dir;
     255            0 :     static std::once_flag flag;
     256              : 
     257            0 :     std::call_once(flag, []()
     258              :       {
     259            0 :         try
     260              :           {
     261            0 :             if (!getenv("OKS_GIT_NO_VAR_DIR"))
     262              :               {
     263            0 :                 OksSystem::User myself;
     264              : 
     265            0 :                 s_dir = "/var/run/user/";
     266            0 :                 s_dir.append(std::to_string(myself.identity()));
     267              : 
     268            0 :                 if (std::filesystem::is_directory(s_dir) == false)
     269              :                   {
     270            0 :                     TLOG_DEBUG(1) << "directory " << s_dir << " does not exist";
     271            0 :                     s_dir.clear();
     272              :                   }
     273              :                 else
     274              :                   {
     275            0 :                     const std::filesystem::space_info si = std::filesystem::space(s_dir);
     276            0 :                     const double available = static_cast<double>(si.available) / static_cast<double>(si.capacity);
     277              : 
     278            0 :                     if (available < 0.5)
     279              :                       {
     280            0 :                         TLOG_DEBUG(1) << "usage of " << s_dir << " is " << static_cast<int>((1.0 - available) * 100.0) << "%, will use standard temporary path";
     281            0 :                         s_dir.clear();
     282              :                       }
     283              :                   }
     284            0 :               }
     285              : 
     286            0 :             if (s_dir.empty())
     287            0 :               s_dir = std::filesystem::temp_directory_path().string();
     288              :           }
     289            0 :         catch (std::exception& ex)
     290              :           {
     291            0 :             Oks::error_msg("OksKernel::OksKernel") << "cannot get temporary directory path: " << ex.what() << std::endl;
     292            0 :             s_dir = "/tmp";
     293            0 :           }
     294            0 :       }
     295              :     );
     296              : 
     297            0 :     return s_dir;
     298              :   }
     299              : 
     300              : 
     301              : const char *
     302            0 : OksKernel::GetVersion()
     303              : {
     304            0 :   return "862f2957270";
     305              : }
     306              : 
     307              : 
     308              : const std::string&
     309          370 : OksKernel::get_repository_root()
     310              : {
     311          370 :   static std::once_flag flag;
     312              : 
     313          370 :   std::call_once(flag, []()
     314              :     {
     315           18 :        if (const char * s = getenv("TDAQ_DB_REPOSITORY"))
     316              :          {
     317            0 :            std::string rep(s);
     318              : 
     319            0 :            if (!std::all_of(rep.begin(), rep.end(), [](char c) { return std::isspace(c); }))
     320              :              {
     321            0 :                const char * p = getenv("OKS_GIT_PROTOCOL");
     322              : 
     323            0 :                if (p && !*p)
     324            0 :                  p = nullptr;
     325              : 
     326            0 :                Oks::Tokenizer t(rep, "|");
     327            0 :                std::string token;
     328              : 
     329            0 :                while (t.next(token) && p_repository_root.empty())
     330              :                  {
     331            0 :                    if (p)
     332              :                      {
     333            0 :                        if (token.find(p) == 0)
     334              :                          {
     335            0 :                            p_repository_root = token;
     336              :                          }
     337              :                      }
     338              :                    else
     339              :                      {
     340            0 :                        p_repository_root = token;
     341              :                      }
     342              :                  }
     343              : 
     344            0 :                if (p_repository_root.empty())
     345            0 :                  Oks::error_msg("OksKernel::OksKernel") << "cannot find OKS_GIT_PROTOCOL=\"" << p << "\" in TDAQ_DB_REPOSITORY=\"" << rep << '\"' << std::endl;
     346            0 :              }
     347            0 :          }
     348           18 :     }
     349              :   );
     350              : 
     351          370 :   return p_repository_root;
     352              : }
     353              : 
     354              : const std::string&
     355            0 : OksKernel::get_repository_mapping_dir()
     356              : {
     357            0 :   static std::once_flag flag;
     358              : 
     359            0 :   std::call_once(flag, []()
     360              :     {
     361            0 :       if (const char * s = getenv("OKS_REPOSITORY_MAPPING_DIR"))
     362              :         {
     363            0 :           p_repository_mapping_dir = s;
     364            0 :           Oks::real_path(p_repository_mapping_dir, true);
     365              :         }
     366            0 :     }
     367              :   );
     368              : 
     369            0 :   return p_repository_mapping_dir;
     370              : }
     371              : 
     372              : ////////////////////////////////////////////////////////////////////////////////
     373              : 
     374              : const std::string&
     375         1464 : OksKernel::get_user_repository_root() const
     376              : {
     377         1464 :   if (p_allow_repository)
     378              :     {
     379            0 :       OksKernel * k(const_cast<OksKernel*>(this));
     380            0 :       if(!p_user_repository_root_inited) {
     381            0 :         if(const char * s = getenv("TDAQ_DB_USER_REPOSITORY")) {
     382            0 :           if(s[0] != 0) {
     383            0 :             k->set_user_repository_root(s);
     384              :           }
     385              :         }
     386            0 :         k->p_user_repository_root_inited = true;
     387              :       }
     388              :     }
     389              : 
     390         1464 :   return p_user_repository_root;
     391              : }
     392              : 
     393              : void
     394            0 : OksKernel::set_user_repository_root(const std::string& path, const std::string& version)
     395              : {
     396            0 :   if(get_repository_root().empty()) {
     397            0 :     TLOG_DEBUG( 1) << "Failed to set user-repository-root:\n\tcaused by: repository-root is not set" ;
     398            0 :     p_user_repository_root.clear();
     399            0 :     return;
     400              :   }
     401              : 
     402            0 :   if(path.empty()) {
     403            0 :     p_user_repository_root.clear();
     404            0 :     return;
     405              :   }
     406              : 
     407            0 :   std::string s;
     408            0 :   s = path;
     409              : 
     410            0 :   try {
     411            0 :     Oks::real_path(s, false);
     412              :   }
     413            0 :   catch(exception& ex) {
     414            0 :     TLOG_DEBUG( 1) << "Failed to set user-repository-root = \'" << s << "\':\n\tcaused by: " << ex.what() ;
     415            0 :   }
     416              : 
     417            0 :   for(std::string::size_type idx = s.size()-1; idx > 0 && s[idx] == '/' ; idx--) {
     418            0 :     s.erase(idx);
     419              :   }
     420              : 
     421            0 :   p_allow_repository = true;
     422              : 
     423            0 :   p_user_repository_root = s;
     424            0 :   p_user_repository_root_inited = true;
     425              : 
     426              :   // is used for backup restore by RDB
     427            0 :   if (!version.empty())
     428            0 :     p_repository_version = version;
     429            0 : }
     430              : 
     431              : ////////////////////////////////////////////////////////////////////////////////
     432              : 
     433              : std::string&
     434           37 : OksKernel::get_host_name()
     435              : {
     436           55 :   static std::string s_host_name;
     437           37 :   static std::once_flag flag;
     438              : 
     439           37 :   std::call_once(flag, []()
     440              :     {
     441           18 :       s_host_name = OksSystem::LocalHost::instance()->full_local_name();
     442              : 
     443           18 :       if (s_host_name.empty())
     444            0 :         s_host_name = "unknown.host";
     445           18 :     }
     446              :   );
     447              : 
     448           37 :   return s_host_name;
     449              : }
     450              : 
     451              : std::string&
     452            0 : OksKernel::get_domain_name()
     453              : {
     454            0 :   static std::string s_domain_name;
     455            0 :   static std::once_flag flag;
     456              : 
     457            0 :   std::call_once(flag, []()
     458              :     {
     459            0 :       std::string::size_type idx = get_host_name().find('.');
     460              : 
     461            0 :       if (idx != std::string::npos)
     462            0 :         s_domain_name = get_host_name().substr(idx+1);
     463              : 
     464            0 :       if (s_domain_name.empty())
     465            0 :         s_domain_name = "unknown.domain";
     466            0 :     }
     467              :   );
     468              : 
     469            0 :   return s_domain_name;
     470              : }
     471              : 
     472              : std::string&
     473           37 : OksKernel::get_user_name()
     474              : {
     475           55 :   static std::string s_user_name;
     476           37 :   static std::once_flag flag;
     477              : 
     478           37 :   std::call_once(flag, []()
     479              :     {
     480           18 :       OksSystem::User myself;
     481           18 :       s_user_name = myself.name_safe();
     482              : 
     483           18 :       if (s_user_name.empty())
     484            0 :         s_user_name = "unknown.user";
     485           18 :     }
     486              :   );
     487              : 
     488           37 :   return s_user_name;
     489              : }
     490              : 
     491              : 
     492              : ////////////////////////////////////////////////////////////////////////////////
     493              : 
     494              : static long
     495          283 : get_file_length(std::ifstream& f)
     496              : {
     497          283 :   long file_length = 0;
     498              : 
     499              :     // get size of file and check that it is not empty
     500              : 
     501          283 :   f.seekg(0, std::ios::end);
     502              : 
     503              : #if __GNUC__ >= 3
     504          283 :   file_length = static_cast<std::streamoff>(f.tellg());
     505              : #else
     506              :   file_length = f.tellg();
     507              : #endif
     508              : 
     509          283 :   f.seekg(0, std::ios::beg);
     510              : 
     511          283 :   return file_length;
     512              : }
     513              : 
     514              :   // makes name of function with parameters for methods working with files
     515              : 
     516              : std::string
     517         1000 : make_fname(const char * f, size_t f_len, const std::string& file, bool * p, const OksFile * const * fh)
     518              : {
     519         1000 :   const char _prefix [] = "OksKernel::";
     520         1000 :   std::string fname(_prefix, (sizeof(_prefix)-1));
     521              : 
     522         1000 :   fname.append(f, f_len);
     523              : 
     524         1000 :   const char _x1 [] = "(file \'";
     525         1000 :   fname.append(_x1, (sizeof(_x1)-1));
     526         1000 :   fname.append(file);
     527         1000 :   fname.push_back('\'');
     528              : 
     529              :     // add boolean parameter
     530              : 
     531         1000 :   if(p) {
     532          539 :     if(*p) {
     533           92 :       const char _true_str [] = ", true";
     534           92 :       fname.append(_true_str, (sizeof(_true_str)-1));
     535              :     }
     536              :     else {
     537          447 :       const char _false_str [] = ", false";
     538          447 :       fname.append(_false_str, (sizeof(_false_str)-1));
     539              :     }
     540              :   }
     541              : 
     542              :     // add file handler parameter
     543              : 
     544         1000 :   if(fh && *fh) {
     545          664 :     const char _x2 [] = ", included by file \'";
     546          664 :     fname.append(_x2, (sizeof(_x2)-1));
     547          664 :     fname.append((*fh)->get_full_file_name());
     548          664 :     fname.push_back('\'');
     549              :   }
     550              : 
     551         1000 :   fname.push_back(')');
     552              : 
     553         1000 :   return fname;
     554            0 : }
     555              : 
     556              :   //
     557              :   // Prototypes for error and warning messages
     558              :   //
     559              : 
     560              : std::ostream&
     561            0 : Oks::error_msg(const char *msg)
     562              : {
     563            0 :   std::cerr << "ERROR [" << msg << "]:\n"; return std::cerr;
     564              : }
     565              : 
     566              : 
     567              : std::ostream&
     568            0 : Oks::warning_msg(const char *msg)
     569              : {
     570            0 :   std::cerr << "WARNING [" << msg << "]:\n"; return std::cerr;
     571              : }
     572              : 
     573              : 
     574              : void
     575        19757 : Oks::substitute_variables(std::string& s)
     576              : {
     577        19757 :   std::string::size_type pos = 0;       // position of tested string index
     578        19757 :   std::string::size_type p_start = 0;   // begining of variable
     579        19757 :   std::string::size_type p_end = 0;     // begining of variable
     580              : 
     581        19757 :   while(
     582        19757 :    ((p_start = s.find("$(", pos)) != std::string::npos) &&
     583            0 :    ((p_end = s.find(")", p_start + 2)) != std::string::npos)
     584              :   ) {
     585            0 :     std::string var(s, p_start + 2, p_end - p_start - 2);
     586              : 
     587            0 :     char * env = getenv(var.c_str());
     588              : 
     589            0 :     if(env) {
     590            0 :       s.replace(p_start, p_end - p_start + 1, env);
     591              :     }
     592              : 
     593            0 :     pos = p_start + 1;
     594            0 :   }
     595        19757 : }
     596              : 
     597              : 
     598              : bool
     599        19425 : Oks::real_path(std::string& path, bool ignore_errors)
     600              : {
     601        19425 :   char resolved_name[PATH_MAX];
     602              :   
     603        19425 :   if(realpath(path.c_str(), resolved_name) != 0) {
     604         6633 :     path = resolved_name;
     605         6633 :     return true;
     606              :   }
     607              :   else {
     608        12792 :     if(ignore_errors) {
     609        12531 :       TLOG_DEBUG( 3) << "realpath(\'" << path << "\') has failed with code " << errno << ": \'" << strerror(errno) << '\'' ;
     610        12531 :       return false;
     611              :     }
     612              :     else {
     613          261 :       throw CannotResolvePath(path, errno);
     614              :     }
     615              :   }
     616              : }
     617              : 
     618              : 
     619              : unsigned long OksKernel::p_count = 0;
     620              : const char OksNameTable::symbols[] = "0123456789"
     621              :                                      "abcdefghijklmnoprstuvwxyz"
     622              :                                      "ABCDEFGHIJKLMNOPRSTUVWXYZ";
     623              : 
     624              : 
     625              : OksString*
     626            0 : OksNameTable::get()
     627              : {
     628            0 :   static const size_t slen(sizeof(symbols)-1);
     629            0 :   static const size_t slen2(slen*slen);
     630              : 
     631            0 :   char b[16], *buf = b;
     632              : 
     633            0 :   count++;
     634              : 
     635            0 :   *buf++ = symbols[count%slen];
     636              : 
     637            0 :   if((size_t)count >= slen) {
     638            0 :     *buf++ = symbols[(count/slen)%slen];
     639              : 
     640            0 :     if((size_t)count >= slen2) {
     641            0 :       *buf++ = symbols[(count/slen2)%slen];
     642              :     }
     643              :   }
     644              : 
     645            0 :   *buf = '\0';
     646              : 
     647            0 :   return new OksString(b);
     648              : }
     649              : 
     650              : 
     651          125 : OksAliasTable::~OksAliasTable()
     652              : {
     653          125 :   if (p_aliases.empty())
     654          125 :     return;
     655              : 
     656            0 :   for (auto& i : p_aliases)
     657              :     {
     658            0 :       if (OksString *s = i.second->class_name)
     659            0 :         delete s;
     660              : 
     661            0 :       delete i.second;
     662            0 :       delete const_cast<OksString *>(i.first);
     663              :     }
     664              : 
     665            0 :   p_aliases.clear();
     666          125 : }
     667              : 
     668              : 
     669              : std::string
     670            0 : OksKernel::get_tmp_file(const std::string& file)
     671              : {
     672            0 :   unsigned int j = 0;
     673            0 :   std::string s2;
     674            0 :   std::ostringstream s;
     675              : 
     676            0 :   while(j++ < 1000000) {
     677            0 :     s.str("");
     678            0 :     s << file << '.' << get_user_name() << ':' << get_host_name() << ':' << getpid() << ':' << j;
     679              : 
     680            0 :     s2 = s.str();
     681              : 
     682            0 :     std::ofstream f(s2.c_str(), std::ios::in);
     683              : 
     684            0 :     if(!f) return s2;
     685            0 :   }
     686              : 
     687            0 :   std::string s3(file);
     688            0 :   s3 += ".tmp";
     689              : 
     690            0 :   return s3;
     691            0 : }
     692              : 
     693              : const char *
     694           87 : OksKernel::get_cwd()
     695              : {
     696           87 :   std::lock_guard scoped_lock(s_get_cwd_mutex);
     697              : 
     698           87 :   if (!s_cwd)
     699              :   {
     700           87 :     errno = 0;
     701           87 :     long size = pathconf(".", _PC_PATH_MAX);
     702           87 :     if (errno)
     703              :       {
     704            0 :         Oks::error_msg("OksKernel::OksKernel") << "pathconf(\".\", _PC_PATH_MAX) has failed with code " << errno << ": \'" << strerror(errno) << '\'' << std::endl;
     705              :       }
     706              :     else
     707              :       {
     708           87 :         if (size == -1)
     709              :           {
     710            0 :             size = PATH_MAX;
     711              :           }
     712           87 :         s_cwd = new char[size];
     713           87 :         if (!getcwd(s_cwd, (size_t) size))
     714              :           {
     715            0 :             Oks::error_msg("OksKernel::OksKernel") << "getcwd() has failed with code " << errno << ": \'" << strerror(errno) << '\'' << std::endl;
     716            0 :             delete[] s_cwd;
     717            0 :             s_cwd = 0;
     718              :           }
     719              :       }
     720              : 
     721           87 :     if (!s_cwd)
     722              :       {
     723            0 :         s_cwd = new char[2];
     724            0 :         s_cwd[0] = '/';
     725            0 :         s_cwd[1] = 0;
     726              :       }
     727              : 
     728           87 :     TLOG_DEBUG(1) << "Current working dir: \'" << s_cwd << '\'';
     729              :   }
     730              : 
     731           87 :   return s_cwd;
     732           87 : }
     733              : 
     734              : /******************************************************************************/
     735              : /*****************************  OKS Kernel Class  *****************************/
     736              : /******************************************************************************/
     737              : 
     738           87 : OksKernel::OksKernel(bool sm, bool vm, bool tm, bool allow_repository, const char * version, std::string branch_name) :
     739           87 :   p_silence                                   (sm),
     740           87 :   p_verbose                                   (vm),
     741           87 :   p_profiling                                 (tm),
     742           87 :   p_allow_repository                          (allow_repository),
     743           87 :   p_allow_duplicated_classes                  (true),
     744           87 :   p_allow_duplicated_objects                  (false),
     745           87 :   p_test_duplicated_objects_via_inheritance   (false),
     746           87 :   p_user_repository_root_inited               (false),
     747           87 :   p_user_repository_root_created              (false),
     748           87 :   p_active_schema                             (nullptr),
     749           87 :   p_active_data                               (nullptr),
     750           87 :   p_close_all                                 (false),
     751           87 :   profiler                                    (nullptr),
     752           87 :   p_create_object_notify_fn                   (nullptr),
     753           87 :   p_create_object_notify_param                (nullptr),
     754           87 :   p_change_object_notify_fn                   (nullptr),
     755           87 :   p_change_object_notify_param                (nullptr),
     756           87 :   p_delete_object_notify_fn                   (nullptr),
     757           87 :   p_delete_object_notify_param                (nullptr)
     758              : {
     759           87 :   OSK_VERBOSE_REPORT("Enter OksKernel::OksKernel(" << sm << ", " << vm << ", " << tm << ')')
     760              : 
     761           87 :   struct __InitFromEnv__ {
     762              :     const char * name;
     763              :     bool& value;
     764           87 :   } vars[] = {
     765           87 :     {"OKS_KERNEL_VERBOSE",                                 p_verbose                                 },
     766           87 :     {"OKS_KERNEL_SILENCE",                                 p_silence                                 },
     767           87 :     {"OKS_KERNEL_PROFILING",                               p_profiling                               },
     768           87 :     {"OKS_KERNEL_ALLOW_REPOSITORY",                        p_allow_repository                        },
     769           87 :     {"OKS_KERNEL_ALLOW_DUPLICATED_CLASSES",                p_allow_duplicated_classes                },
     770           87 :     {"OKS_KERNEL_ALLOW_DUPLICATED_OBJECTS",                p_allow_duplicated_objects                },
     771           87 :     {"OKS_KERNEL_TEST_DUPLICATED_OBJECTS_VIA_INHERITANCE", p_test_duplicated_objects_via_inheritance },
     772              :     {"OKS_KERNEL_SKIP_STRING_RANGE",                       p_skip_string_range                       }
     773           87 :   };
     774              : 
     775          783 :   for(unsigned int i = 0; i < sizeof(vars) / sizeof(__InitFromEnv__); ++i) {
     776          696 :     if(char * s = getenv(vars[i].name)) {
     777            0 :       vars[i].value = (strcmp(s, "no")) ? true : false;
     778              :     }
     779              :   }
     780              : 
     781           87 :   {
     782           87 :     const char * oks_db_root = getenv("OKS_DB_ROOT");
     783              : 
     784           87 :     if (oks_db_root == nullptr || *oks_db_root == 0)
     785           87 :       oks_db_root = getenv("DUNEDAQ_DB_PATH");
     786              :     else
     787            0 :       p_use_strict_repository_paths = false;
     788              : 
     789           87 :     OSK_VERBOSE_REPORT("database root = \'" << oks_db_root << "\' (as defined by the OKS_DB_ROOT or DUNEDAQ_DB_PATH)");
     790              : 
     791              : 
     792              :       // if not defined, set oks_db_root to empty string (to avoid std::string constructor crash when string is 0) 
     793              : 
     794           87 :     if (oks_db_root == nullptr)
     795            0 :       oks_db_root = "";
     796              : 
     797              : 
     798              :       // temporal set
     799              : 
     800           87 :     Oks::Tokenizer t(oks_db_root, ":");
     801           87 :     std::string token;
     802              : 
     803         6612 :     while (t.next(token))
     804         6438 :       insert_repository_dir(token);
     805           87 :   }
     806              : 
     807              : 
     808              : 
     809              : 
     810           87 :   {
     811           87 :     std::unique_lock lock(p_kernel_mutex);
     812              : 
     813           87 :     if(!p_count++) {
     814           87 :       OksClass::create_notify_fn = 0;
     815           87 :       OksClass::change_notify_fn = 0;
     816           87 :       OksClass::delete_notify_fn = 0;
     817              :     }
     818              : 
     819           87 :     get_cwd();
     820           87 :   }
     821              :   
     822           87 :   {
     823           87 :     static std::once_flag flag;
     824              : 
     825           87 :     std::call_once(flag, []()
     826              :       {
     827           18 :         if (char * s = getenv("OKS_KERNEL_THREADS_POOL_SIZE"))
     828              :           {
     829            0 :             if (*s != '\0')
     830              :               {
     831            0 :                 p_threads_pool_size = atoi(s);
     832            0 :                 if (p_threads_pool_size < 1)
     833            0 :                   p_threads_pool_size = 1;
     834              :               }
     835              :           }
     836              : 
     837           18 :         if (!p_threads_pool_size)
     838              :           {
     839           18 :             errno = 0;
     840           18 :             p_threads_pool_size = sysconf(_SC_NPROCESSORS_ONLN);
     841           18 :             if (p_threads_pool_size == -1 && !errno)
     842              :               {
     843            0 :                 Oks::error_msg("OksKernel::OksKernel()") << " sysconf(_SC_NPROCESSORS_ONLN) has failed with code " << errno << ": \'" << strerror(errno) << '\'' << std::endl;
     844            0 :                 p_threads_pool_size = 0;
     845              :               }
     846              :           }
     847              : 
     848           18 :         if (!p_threads_pool_size)
     849            0 :           p_threads_pool_size = 2;
     850              : 
     851           18 :         TLOG_DEBUG(2) << "Threads pool size: " << p_threads_pool_size;
     852           18 :       }
     853              :     );
     854              : 
     855              :   }
     856              : 
     857              :   // process OKS server URL settings if any
     858           87 :   if (p_allow_repository && !get_repository_root().empty())
     859              :     {
     860            0 :       if (get_user_repository_root().empty())
     861              :         {
     862              :           // parse specific version option if any
     863            0 :           std::string param, val;
     864              : 
     865            0 :           if (!version)
     866            0 :             version = getenv("TDAQ_DB_VERSION");
     867              : 
     868            0 :           if (version)
     869              :             {
     870            0 :               if(*version)
     871              :                 {
     872            0 :                   if(const char * value = strchr(version, ':'))
     873              :                     {
     874            0 :                       param.assign(version, value-version);
     875            0 :                       val.assign(value+1);
     876              :                     }
     877              :                   else
     878            0 :                     Oks::error_msg("OksKernel::OksKernel") << "bad version value \"" << version << "\" expecting parameter:value format (check TDAQ_DB_VERSION variable)" << std::endl;
     879              :                 }
     880              :             }
     881              : 
     882            0 :           try
     883              :             {
     884            0 :               std::string tmp_dirname = OksKernel::create_user_repository_dir();
     885              : 
     886            0 :               set_user_repository_root(tmp_dirname);
     887            0 :               p_user_repository_root_created = true;
     888            0 :               s_git_folders.insert(p_user_repository_root);
     889              : 
     890            0 :               if (branch_name.empty())
     891            0 :                   if (const char *var = getenv("TDAQ_DB_BRANCH"))
     892            0 :                     branch_name = var;
     893              : 
     894            0 :               k_checkout_repository(param, val, branch_name);
     895            0 :             }
     896            0 :           catch(exception& ex)
     897              :             {
     898            0 :               Oks::error_msg("OksKernel::OksKernel") << "cannot check out user repository: " << ex.what() << std::endl;
     899            0 :             }
     900            0 :         }
     901              :       else
     902              :         {
     903            0 :           if(!p_silence)
     904              :             {
     905            0 :               try
     906              :                 {
     907            0 :                   std::lock_guard lock(p_parallel_out_mutex);
     908            0 :                   std::cout << "attach to repository \"" << get_user_repository_root() << "\" version " << read_repository_version() << std::endl;
     909            0 :                 }
     910            0 :               catch(exception& ex)
     911              :                 {
     912            0 :                   Oks::error_msg("OksKernel::OksKernel") << "cannot read user repository version: " << ex.what() << std::endl;
     913            0 :                 }
     914              :             }
     915              :         }
     916              :     }
     917              : 
     918              : #ifndef ERS_NO_DEBUG
     919           87 :   if(p_profiling)
     920            0 :     profiler = (OksProfiler *) new OksProfiler();
     921              : #endif
     922           87 : }
     923              : 
     924            0 : OksKernel::OksKernel(const OksKernel& src, bool copy_repository) :
     925            0 :   p_silence                                   (src.p_silence),
     926            0 :   p_verbose                                   (src.p_verbose),
     927            0 :   p_profiling                                 (src.p_profiling),
     928            0 :   p_allow_repository                          (src.p_allow_repository),
     929            0 :   p_allow_duplicated_classes                  (src.p_allow_duplicated_classes),
     930            0 :   p_allow_duplicated_objects                  (src.p_allow_duplicated_objects),
     931            0 :   p_test_duplicated_objects_via_inheritance   (src.p_test_duplicated_objects_via_inheritance),
     932            0 :   p_user_repository_root                      (src.p_user_repository_root),
     933            0 :   p_user_repository_root_inited               (src.p_user_repository_root_inited),
     934            0 :   p_user_repository_root_created              (false),
     935            0 :   p_repository_version                        (src.p_repository_version),
     936            0 :   p_repository_checkout_ts                    (src.p_repository_checkout_ts),
     937            0 :   p_repository_update_ts                      (src.p_repository_update_ts),
     938            0 :   p_active_schema                             (nullptr),
     939            0 :   p_active_data                               (nullptr),
     940            0 :   p_close_all                                 (false),
     941            0 :   profiler                                    (nullptr),
     942            0 :   p_create_object_notify_fn                   (nullptr),
     943            0 :   p_create_object_notify_param                (nullptr),
     944            0 :   p_change_object_notify_fn                   (nullptr),
     945            0 :   p_change_object_notify_param                (nullptr),
     946            0 :   p_delete_object_notify_fn                   (nullptr),
     947            0 :   p_delete_object_notify_param                (nullptr)
     948              : {
     949              : 
     950            0 :   {
     951            0 :     std::unique_lock lock(p_kernel_mutex);
     952            0 :     p_count++;
     953            0 :   }
     954              : 
     955            0 :   if (copy_repository && p_user_repository_root_inited)
     956              :     {
     957            0 :       try
     958              :         {
     959            0 :           p_user_repository_root = OksKernel::create_user_repository_dir();
     960            0 :           p_user_repository_root_created = true;
     961            0 :           Oks::real_path(p_user_repository_root, false);
     962            0 :           s_git_folders.insert(p_user_repository_root);
     963            0 :           k_copy_repository(src.p_user_repository_root, p_user_repository_root);
     964              :         }
     965            0 :       catch(exception& ex)
     966              :         {
     967            0 :           Oks::error_msg("OksKernel::OksKernel") << "cannot copy user repository: " << ex.what() << std::endl;
     968            0 :           remove_user_repository_dir();
     969            0 :           throw;
     970            0 :         }
     971              : 
     972            0 :       p_repository_dirs.push_back(p_user_repository_root);
     973              :     }
     974              : 
     975              : 
     976              :   // copy repository directories
     977            0 :   for (const auto& i : src.p_repository_dirs)
     978            0 :     p_repository_dirs.push_back(i);
     979              : 
     980              : 
     981              :   // copy schema and data files
     982            0 :   {
     983            0 :     const OksFile::Map * src_files[2] = { &src.p_schema_files, &src.p_data_files };
     984            0 :     OksFile::Map * dst_files[2] = { &p_schema_files, &p_data_files };
     985              : 
     986            0 :     for (int i = 0; i < 2; ++i)
     987              :       {
     988            0 :         for (const auto& j : *src_files[i])
     989              :           {
     990            0 :             OksFile * f = new OksFile(*j.second);
     991            0 :             f->p_kernel = this;
     992            0 :             (*dst_files[i])[&f->p_full_name] = f;
     993              :           }
     994              :       }
     995              :   }
     996              : 
     997              :   // search a class in map is not efficient, if there are many such operations; use array with class index for fast search
     998            0 :   OksClass ** c_table = new OksClass * [src.p_classes.size()];
     999            0 :   unsigned int idx(0);
    1000              : 
    1001              : 
    1002              :   // copy classes: first iteration to define class names and simple properties
    1003            0 :   for(const auto& i : src.p_classes) {
    1004            0 :     const OksClass& src_c(*i.second);
    1005            0 :     OksClass * c = new OksClass (src_c.p_name, src_c.p_description, src_c.p_abstract, nullptr, src_c.p_transient);   // pass 0 kernel to avoid class insertion
    1006              : 
    1007            0 :     c->p_kernel = this;
    1008            0 :     p_classes[c->get_name().c_str()] = c;
    1009              : 
    1010            0 :     const_cast<OksClass&>(src_c).p_id = idx++;
    1011            0 :     c->p_id = src_c.p_id;
    1012            0 :     c_table[c->p_id] = c;
    1013              : 
    1014            0 :     c->p_abstract          = src_c.p_abstract;
    1015            0 :     c->p_to_be_deleted     = src_c.p_to_be_deleted;
    1016            0 :     c->p_instance_size     = src_c.p_instance_size;
    1017            0 :     c->p_file              = (*p_schema_files.find(&src_c.p_file->p_full_name)).second;
    1018            0 :     c->p_objects           = (src_c.p_objects ? new OksObject::Map() : nullptr);
    1019              : 
    1020              : 
    1021              :     // copy super-classes
    1022            0 :     if (const std::list<std::string *> * scls = src_c.p_super_classes)
    1023              :       {
    1024            0 :         c->p_super_classes = new std::list<std::string *>();
    1025              : 
    1026            0 :         for (const auto& j : *scls)
    1027            0 :           c->p_super_classes->push_back(new std::string(*j));
    1028              :       }
    1029              : 
    1030              : 
    1031              :     // copy direct attributes
    1032            0 :     if (const std::list<OksAttribute *> * attrs = src_c.p_attributes)
    1033              :       {
    1034            0 :         c->p_attributes = new std::list<OksAttribute *>();
    1035              : 
    1036            0 :         for (const auto& j : *attrs)
    1037              :           {
    1038            0 :             OksAttribute * a = new OksAttribute(j->p_name, c);
    1039              : 
    1040            0 :             a->p_range = j->p_range;
    1041            0 :             a->p_data_type = j->p_data_type;
    1042            0 :             a->p_multi_values = j->p_multi_values;
    1043            0 :             a->p_no_null = j->p_no_null;
    1044            0 :             a->p_init_value = j->p_init_value;
    1045            0 :             a->p_init_data = j->p_init_data;
    1046            0 :             a->p_format = j->p_format;
    1047            0 :             a->p_description = j->p_description;
    1048              : 
    1049            0 :             if (j->p_enumerators)
    1050            0 :               a->p_enumerators = new std::vector<std::string>(*j->p_enumerators);
    1051              : 
    1052            0 :             c->p_attributes->push_back(a);
    1053              :           }
    1054              :       }
    1055              : 
    1056              : 
    1057              :     // copy direct relationships
    1058            0 :     if (const std::list<OksRelationship *> * rels = src_c.p_relationships)
    1059              :       {
    1060            0 :         c->p_relationships = new std::list<OksRelationship *>();
    1061              : 
    1062            0 :         for (const auto& j : *rels)
    1063              :           {
    1064            0 :             OksRelationship * r = new OksRelationship(j->p_name, c);
    1065              : 
    1066            0 :             r->p_rclass = j->p_rclass;
    1067            0 :             r->p_low_cc = j->p_low_cc;
    1068            0 :             r->p_high_cc = j->p_high_cc;
    1069            0 :             r->p_composite = j->p_composite;
    1070            0 :             r->p_exclusive = j->p_exclusive;
    1071            0 :             r->p_dependent = j->p_dependent;
    1072            0 :             r->p_description = j->p_description;
    1073              : 
    1074            0 :             c->p_relationships->push_back(r);
    1075              :           }
    1076              :       }
    1077              : 
    1078              : 
    1079              :     // copy direct methods
    1080            0 :     if (const std::list<OksMethod *> * mets = src_c.p_methods)
    1081              :       {
    1082            0 :         c->p_methods = new std::list<OksMethod *>();
    1083              : 
    1084            0 :         for (const auto& j : *mets)
    1085              :           {
    1086            0 :             OksMethod * m = new OksMethod(j->p_name, j->p_description, c);
    1087              : 
    1088            0 :             if (const std::list<OksMethodImplementation *> * impls = j->p_implementations)
    1089              :               {
    1090            0 :                 m->p_implementations = new std::list<OksMethodImplementation *>();
    1091              : 
    1092            0 :                 for (const auto& x : *impls)
    1093            0 :                   m->p_implementations->push_back(new OksMethodImplementation(x->get_language(), x->get_prototype(), x->get_body(), m));
    1094              :               }
    1095              : 
    1096            0 :             c->p_methods->push_back(m);
    1097              :           }
    1098              :       }
    1099              :   }
    1100              : 
    1101              : 
    1102              :     // copy classes: second iteration to resolve pointers to classes
    1103              : 
    1104            0 :   for (const auto& i : src.p_classes)
    1105              :     {
    1106            0 :       OksClass * c = c_table[i.second->p_id];
    1107              : 
    1108              :       // link p_class_type of relationship
    1109            0 :       if (const std::list<OksRelationship *> * rels = i.second->p_relationships)
    1110              :         {
    1111            0 :           for (const auto& j : *rels)
    1112            0 :             c->find_relationship(j->get_name())->p_class_type = (j->p_class_type ? c_table[j->p_class_type->p_id] : nullptr);
    1113              :         }
    1114              : 
    1115              :       // copy all super- and sub- classes
    1116            0 :       if (const OksClass::FList * spcls = i.second->p_all_super_classes)
    1117              :         {
    1118            0 :           c->p_all_super_classes = new OksClass::FList();
    1119              : 
    1120            0 :           for (const auto& j : *spcls)
    1121            0 :             c->p_all_super_classes->push_back(c_table[j->p_id]);
    1122              :         }
    1123              : 
    1124            0 :       if (const OksClass::FList * sbcls = i.second->p_all_sub_classes)
    1125              :         {
    1126            0 :           c->p_all_sub_classes = new OksClass::FList();
    1127              : 
    1128            0 :           for (const auto& j : *sbcls)
    1129            0 :             c->p_all_sub_classes->push_back(c_table[j->p_id]);
    1130              :         }
    1131              : 
    1132              :       // create oks object layout information
    1133            0 :       c->p_data_info = new OksDataInfo::Map();
    1134            0 :       size_t instance_size = 0;
    1135              : 
    1136              :       // copy all attributes
    1137            0 :       if (const std::list<OksAttribute *> * attrs = i.second->p_all_attributes)
    1138              :         {
    1139            0 :           c->p_all_attributes = new std::list<OksAttribute *>();
    1140              : 
    1141            0 :           for (const auto& j : *attrs)
    1142              :             {
    1143            0 :               OksAttribute * a = (c_table[j->p_class->p_id])->find_direct_attribute(j->get_name());
    1144            0 :               c->p_all_attributes->push_back(a);
    1145            0 :               (*c->p_data_info)[a->get_name()] = new OksDataInfo(instance_size++, a);
    1146              :             }
    1147              :         }
    1148              : 
    1149              :       // copy all relationships
    1150            0 :       if (const std::list<OksRelationship *> * rels = i.second->p_all_relationships)
    1151              :         {
    1152            0 :           c->p_all_relationships = new std::list<OksRelationship *>();
    1153              : 
    1154            0 :           for (const auto& j : *rels)
    1155              :             {
    1156            0 :               OksRelationship * r = (c_table[j->p_class->p_id])->find_direct_relationship(j->get_name());
    1157            0 :               c->p_all_relationships->push_back(r);
    1158            0 :               (*c->p_data_info)[r->get_name()] = new OksDataInfo(instance_size++, r);
    1159              :             }
    1160              :         }
    1161              : 
    1162              :       // copy all methods
    1163            0 :       if (const std::list<OksMethod *> * mets = i.second->p_all_methods)
    1164              :         {
    1165            0 :           c->p_all_methods = new std::list<OksMethod *>();
    1166              : 
    1167            0 :           for (const auto& j : *mets)
    1168            0 :             c->p_all_methods->push_back((c_table[j->p_class->p_id])->find_direct_method(j->get_name()));
    1169              :         }
    1170              : 
    1171              :       // copy inheritance hierarchy
    1172            0 :       if (const std::vector<OksClass *> * ih = i.second->p_inheritance_hierarchy)
    1173              :         {
    1174            0 :           c->p_inheritance_hierarchy = new std::vector<OksClass *>();
    1175            0 :           c->p_inheritance_hierarchy->reserve(ih->size());
    1176              : 
    1177            0 :           for (const auto& j : *ih)
    1178            0 :             c->p_inheritance_hierarchy->push_back(c_table[j->p_id]);
    1179              :         }
    1180              :     }
    1181              : 
    1182              : 
    1183              :     // copy objects
    1184              : 
    1185            0 :   if(!src.p_objects.empty()) {
    1186              : 
    1187              :       // search an object in a class is not efficien, if there are many such operations
    1188              :       // use array with class index for fast search
    1189              : 
    1190            0 :     OksObject ** o_table = new OksObject * [src.p_objects.size()];
    1191            0 :     idx = 0;
    1192              : 
    1193              :       // first iteration: create objects with attributes
    1194              : 
    1195            0 :     for(OksObject::Set::const_iterator i = src.p_objects.begin(); i != src.p_objects.end(); ++i, ++idx) {
    1196            0 :       OksObject * src_o(*i);
    1197            0 :       src_o->p_user_data = reinterpret_cast<void *>(idx);
    1198              : 
    1199            0 :       OksClass * c = c_table[src_o->uid.class_id->p_id];
    1200              : 
    1201            0 :       OksObject * o = new OksObject(
    1202              :         c,
    1203            0 :         src_o->uid.object_id,
    1204              :         src_o->p_user_data,
    1205              :         src_o->p_int32_id,
    1206              :         src_o->p_duplicated_object_id_idx,
    1207            0 :         (*p_data_files.find(&src_o->file->p_full_name)).second
    1208            0 :       );
    1209              : 
    1210            0 :       o_table[idx] = o;
    1211            0 :       (*c->p_objects)[&o->uid.object_id] = o;
    1212            0 :       p_objects.insert(o);
    1213              : 
    1214            0 :       if(size_t num_of_attrs = c->number_of_all_attributes()) {
    1215            0 :         const OksData * src_data = src_o->data;
    1216            0 :         OksData * dst_data = o->data;
    1217              : 
    1218            0 :         std::list<OksAttribute *>::const_iterator ia_dst = c->all_attributes()->begin();
    1219            0 :         std::list<OksAttribute *>::const_iterator ia_src = src_o->uid.class_id->all_attributes()->begin();
    1220              : 
    1221            0 :         for(size_t j = 0; j < num_of_attrs; ++j) {
    1222            0 :           *dst_data = *src_data;
    1223              : 
    1224            0 :           OksAttribute * a_dst(*ia_dst);
    1225              :           
    1226              :             // process in a special way CLASS type (reference on class)
    1227              :           
    1228            0 :           if(a_dst->get_data_type() == OksData::class_type) {
    1229            0 :             if(a_dst->get_is_multi_values() == false) {
    1230            0 :               dst_data->data.CLASS = c_table[src_data->data.CLASS->p_id];
    1231              :             }
    1232              :             else {
    1233            0 :               OksData::List::iterator li_dst = dst_data->data.LIST->begin();
    1234            0 :               OksData::List::iterator li_src = src_data->data.LIST->begin();
    1235              : 
    1236            0 :               while(li_dst != dst_data->data.LIST->end()) {
    1237            0 :                 (*li_dst)->data.CLASS = c_table[(*li_src)->data.CLASS->p_id];
    1238            0 :                 ++li_dst;
    1239            0 :                 ++li_src;
    1240              :               }
    1241              :             }
    1242              :           }
    1243              : 
    1244              :             // process in a special way ENUM type (reference on attribute's data)
    1245              : 
    1246            0 :           else if(a_dst->get_data_type() == OksData::enum_type) {
    1247            0 :             OksAttribute * a_src(*ia_src);
    1248            0 :             const std::string * p_enumerators_first(&((*(a_src->p_enumerators))[0]));
    1249              : 
    1250            0 :             if(a_dst->get_is_multi_values() == false) {
    1251            0 :               unsigned long dx = src_data->data.ENUMERATION - p_enumerators_first;
    1252            0 :               dst_data->data.ENUMERATION = &((*(a_dst->p_enumerators))[dx]);
    1253              :             }
    1254              :             else {
    1255            0 :               OksData::List::iterator li_dst = dst_data->data.LIST->begin();
    1256            0 :               OksData::List::iterator li_src = src_data->data.LIST->begin();
    1257              : 
    1258            0 :               while(li_dst != dst_data->data.LIST->end()) {
    1259            0 :                 unsigned long dx = (*li_src)->data.ENUMERATION - p_enumerators_first;
    1260            0 :                 (*li_dst)->data.ENUMERATION = &((*(a_dst->p_enumerators))[dx]);
    1261            0 :                 ++li_dst;
    1262            0 :                 ++li_src;
    1263              :               }
    1264              :             }
    1265              :           }
    1266              : 
    1267            0 :           src_data++;
    1268            0 :           dst_data++;
    1269              : 
    1270            0 :           ia_dst++;
    1271            0 :           ia_src++;
    1272              :         }
    1273              :       }
    1274              :     }
    1275              : 
    1276              : 
    1277              :       // second iteration: link relationships of objects
    1278              : 
    1279            0 :     for(const auto& src_o : src.p_objects) {
    1280            0 :       OksClass * c = c_table[src_o->uid.class_id->p_id];
    1281            0 :       OksObject * o(o_table[reinterpret_cast<unsigned long>(src_o->p_user_data)]);
    1282              : 
    1283            0 :       if(size_t num_of_rels = c->number_of_all_relationships()) {
    1284            0 :         const OksData * src_data(src_o->data + c->number_of_all_attributes());
    1285            0 :         OksData * dst_data(o->data + c->number_of_all_attributes());
    1286              : 
    1287            0 :         for(size_t j = 0; j < num_of_rels; ++j) {
    1288            0 :           dst_data->type = src_data->type;
    1289            0 :           switch(src_data->type) {
    1290            0 :             case OksData::list_type:
    1291            0 :               dst_data->data.LIST = new OksData::List();
    1292            0 :               for(const auto& x : *src_data->data.LIST) {
    1293            0 :                 OksData *d = new OksData();
    1294              : 
    1295            0 :                 if(x->type == OksData::object_type)
    1296              :                   {
    1297            0 :                     if(const OksObject * o2 = x->data.OBJECT)
    1298              :                       {
    1299            0 :                         d->Set(o_table[reinterpret_cast<unsigned long>(o2->p_user_data)]);
    1300              :                       }
    1301              :                     else
    1302              :                       {
    1303            0 :                         d->Set((OksObject *)nullptr);
    1304              :                       }
    1305              :                   }
    1306            0 :                 else if(x->type == OksData::uid_type)
    1307              :                   {
    1308            0 :                     d->Set(c_table[x->data.UID.class_id->p_id], *x->data.UID.object_id);
    1309              :                   }
    1310            0 :                 else if(x->type == OksData::uid2_type)
    1311              :                   {
    1312            0 :                     d->Set(*x->data.UID2.class_id, *x->data.UID2.object_id);
    1313              :                   }
    1314              :                 else
    1315              :                   {
    1316            0 :                     ers::error(kernel::InternalError(ERS_HERE, "unexpected data type in relationship list"));
    1317              :                   }
    1318              : 
    1319            0 :                 dst_data->data.LIST->push_back(d);
    1320              :               }
    1321            0 :               break;
    1322              : 
    1323            0 :             case OksData::object_type:
    1324            0 :               if(const OksObject * o2 = src_data->data.OBJECT) {
    1325            0 :                 dst_data->data.OBJECT = o_table[reinterpret_cast<unsigned long>(o2->p_user_data)];
    1326              :               }
    1327              :               else {
    1328            0 :                 dst_data->data.OBJECT = 0;
    1329              :               }
    1330              :               break;
    1331              : 
    1332            0 :             case OksData::uid_type:
    1333            0 :               dst_data->data.UID.class_id  = c_table[src_data->data.UID.class_id->p_id];
    1334            0 :               dst_data->data.UID.object_id = new OksString(*src_data->data.UID.object_id);
    1335              :               break;
    1336              : 
    1337            0 :             case OksData::uid2_type:
    1338            0 :               dst_data->data.UID2.class_id  = new OksString(*src_data->data.UID2.class_id);
    1339            0 :               dst_data->data.UID2.object_id = new OksString(*src_data->data.UID2.object_id);
    1340              :               break;
    1341              : 
    1342            0 :             default:
    1343            0 :               ers::error(kernel::InternalError(ERS_HERE, "unexpected data type in relationship"));
    1344            0 :               break;
    1345              :           }
    1346              : 
    1347            0 :           src_data++;
    1348            0 :           dst_data++;
    1349              :         }
    1350              :       }
    1351              : 
    1352            0 :       if (const std::list<OksRCR *> * src_rcrs = src_o->p_rcr)
    1353              :         {
    1354            0 :           o->p_rcr = new std::list<OksRCR *>();
    1355              : 
    1356            0 :           for (const auto& j : *src_rcrs)
    1357            0 :             o->p_rcr->push_back(
    1358            0 :                 new OksRCR(
    1359            0 :                     o_table[reinterpret_cast<unsigned long>(j->obj->p_user_data)],
    1360            0 :                     (c_table[j->relationship->p_class->p_id])->find_direct_relationship(j->relationship->get_name())
    1361            0 :                 )
    1362              :             );
    1363              :         }
    1364              :       else
    1365              :         {
    1366            0 :           o->p_rcr = nullptr;
    1367              :         }
    1368              :     }
    1369              : 
    1370            0 :     delete [] o_table;
    1371              :   }
    1372              : 
    1373            0 :   delete [] c_table;
    1374              : 
    1375              :   // rename all files
    1376            0 :   if (copy_repository && p_user_repository_root_inited)
    1377              :     {
    1378            0 :       OksFile::Map * files_map[2] = { &p_schema_files, &p_data_files };
    1379              : 
    1380            0 :       for (int i = 0; i < 2; ++i)
    1381              :         {
    1382            0 :           std::vector<OksFile *> files;
    1383              : 
    1384            0 :           for (auto& f : *files_map[i])
    1385            0 :             files.push_back(f.second);
    1386              : 
    1387            0 :           files_map[i]->clear();
    1388              : 
    1389            0 :           for (auto& f : files)
    1390              :             {
    1391            0 :               std::string name = p_user_repository_root;
    1392            0 :               name.push_back('/');
    1393            0 :               name.append(f->get_repository_name());
    1394            0 :               f->rename(name);
    1395            0 :               (*files_map[i])[&f->p_full_name] = f;
    1396            0 :             }
    1397            0 :         }
    1398              :     }
    1399            0 : }
    1400              : 
    1401              : 
    1402              : std::string
    1403         6438 : OksKernel::insert_repository_dir(const std::string& dir, bool push_back)
    1404              : {
    1405         6438 :   std::unique_lock lock(p_kernel_mutex);
    1406              : 
    1407         6438 :   std::string s(dir);
    1408         6438 :   Oks::substitute_variables(s);
    1409              : 
    1410         6438 :   try {
    1411         6438 :     Oks::real_path(s, false);
    1412              : 
    1413         6177 :     if(std::find(p_repository_dirs.begin(), p_repository_dirs.end(), s) == p_repository_dirs.end()) {
    1414         6177 :       if(push_back) p_repository_dirs.push_back(s); else p_repository_dirs.push_front(s);
    1415         6177 :       if(p_verbose) {
    1416            0 :         std::cout << " * push " << (push_back ? "back" : "front") << " repository search directory \'" << s << "\'\n";
    1417              :       }
    1418         6177 :       return s;
    1419              :     }
    1420              :   }
    1421          261 :   catch(exception& ex) {
    1422          261 :     TLOG_DEBUG( 1) << "Cannot insert repository dir \'" << dir << "\':\n\tcaused by: " << ex ;
    1423          261 :   }
    1424              : 
    1425          261 :   return "";
    1426         6438 : }
    1427              : 
    1428              : void
    1429            0 : OksKernel::remove_repository_dir(const std::string& dir)
    1430              : {
    1431            0 :   std::unique_lock lock(p_kernel_mutex);
    1432              : 
    1433            0 :   std::list<std::string>::iterator i = std::find(p_repository_dirs.begin(), p_repository_dirs.end(), dir);
    1434            0 :   if(i != p_repository_dirs.end()) {
    1435            0 :     if(p_verbose) {
    1436            0 :       std::cout << " * remove repository search directory \'" << dir << "\'\n";
    1437              :     }
    1438            0 :     p_repository_dirs.erase(i);
    1439              :   }
    1440            0 : }
    1441              : 
    1442              : 
    1443              : void
    1444            0 : OksKernel::set_profiling_mode(const bool b)
    1445              : {
    1446            0 :   if(p_profiling == b) return;
    1447              : 
    1448            0 :   p_profiling = b;
    1449              : 
    1450              : #ifndef ERS_NO_DEBUG
    1451            0 :   if(p_profiling == true) {
    1452            0 :     if(!profiler) profiler = new OksProfiler();
    1453              :   }
    1454              :   else {
    1455            0 :     if(profiler) {
    1456            0 :       delete profiler;
    1457            0 :       profiler = 0;
    1458              :     }
    1459              :   }
    1460              : #endif
    1461              : }
    1462              : 
    1463              : 
    1464           87 : OksKernel::~OksKernel()
    1465              : {
    1466           87 :   {
    1467           87 :     OSK_PROFILING(OksProfiler::KernelDestructor, this)
    1468           87 :     OSK_VERBOSE_REPORT("ENTER OksKernel::~OksKernel()")
    1469              : 
    1470           87 :     close_all_data();
    1471           87 :     close_all_schema();
    1472              : 
    1473           87 :     std::unique_lock lock(p_kernel_mutex);
    1474              : 
    1475           87 :     p_classes.erase(p_classes.begin(), p_classes.end());
    1476              : 
    1477           87 :     --p_count;
    1478              : 
    1479           87 :     if(p_count == 0) {
    1480           87 :       std::lock_guard scoped_lock(s_get_cwd_mutex);
    1481           87 :       delete [] s_cwd;
    1482           87 :       s_cwd = nullptr;
    1483           87 :     }
    1484              : 
    1485           87 :     remove_user_repository_dir();
    1486           87 :   }
    1487              : 
    1488              : #ifndef ERS_NO_DEBUG
    1489           87 :   if(p_profiling) std::cout << *profiler << std::endl;
    1490              : #endif
    1491              : 
    1492           87 :   OSK_VERBOSE_REPORT("LEAVE OksKernel::~OksKernel()")
    1493           87 : }
    1494              : 
    1495              : 
    1496              : std::ostream&
    1497            0 : operator<<(std::ostream& s, OksKernel& k)
    1498              : {
    1499            0 :   OSK_PROFILING(OksProfiler::KernelOperatorOut, &k)
    1500              : 
    1501            0 :   s << "OKS KERNEL DUMP:\n" << "OKS VERSION: " << k.GetVersion() << std::endl;
    1502              : 
    1503            0 :   if (!k.p_schema_files.empty())
    1504              :     {
    1505            0 :       s << " Loaded schema:\n";
    1506              : 
    1507            0 :       for (const auto& i : k.p_schema_files)
    1508            0 :         s << "   " << i.second->get_full_file_name() << std::endl;
    1509              : 
    1510            0 :       if (!k.p_data_files.empty())
    1511              :         {
    1512            0 :           s << " Loaded data:\n";
    1513              : 
    1514            0 :           for (const auto& j : k.p_data_files)
    1515            0 :             s << "   " << j.second->get_full_file_name() << std::endl;
    1516              :         }
    1517              :       else
    1518            0 :         s << " No loaded data files\n";
    1519              : 
    1520            0 :       if (!k.p_classes.empty())
    1521              :         {
    1522            0 :           s << " The classes:\n";
    1523              : 
    1524            0 :           for (const auto& j : k.p_classes)
    1525            0 :             s << *j.second;
    1526              :         }
    1527              :     }
    1528              :   else
    1529            0 :     s << " No loaded schema files\n";
    1530              : 
    1531            0 :   s << "END OF OKS KERNEL DUMP.\n";
    1532              : 
    1533            0 :   return s;
    1534            0 : }
    1535              : 
    1536              : bool
    1537          297 : OksKernel::check_read_only(OksFile *fp)
    1538              : {
    1539          315 :   static std::string suffix;
    1540          297 :   static std::once_flag flag;
    1541              : 
    1542          297 :   std::call_once(flag, []()
    1543              :     {
    1544           18 :       std::ostringstream s;
    1545           18 :       s << '-' << get_user_name() << ':' << get_host_name() << ':' << getpid() << std::ends;
    1546           18 :       suffix = s.str();
    1547           18 :     }
    1548              :   );
    1549              : 
    1550          297 :   std::string s(fp->p_full_name);
    1551          297 :   s.append(suffix);
    1552              : 
    1553          297 :   {
    1554          297 :     static std::mutex p_check_read_only_mutex;
    1555          297 :     std::lock_guard scoped_lock(p_check_read_only_mutex);
    1556              : 
    1557          297 :     {
    1558          297 :       std::ofstream f(s.c_str(), std::ios::out);
    1559          297 :       fp->p_is_read_only = (!f.good());
    1560          297 :     }
    1561              : 
    1562          297 :     TLOG_DEBUG( 3) << "read-only test on file \"" << s << "\" returns " << fp->p_is_read_only ;
    1563              : 
    1564          297 :     if(!fp->p_is_read_only) {
    1565          297 :       unlink(s.c_str());
    1566              :     }
    1567              : 
    1568          297 :     return fp->p_is_read_only;
    1569          297 :   }
    1570          297 : }
    1571              : 
    1572              : OksFile *
    1573            0 : OksKernel::create_file_info(const std::string& short_path, const std::string& full_path)
    1574              : {
    1575            0 :   OksFile * file_h = 0;
    1576              : 
    1577            0 :   {
    1578            0 :     std::shared_ptr<std::ifstream> f(new std::ifstream(full_path.c_str()));
    1579              : 
    1580            0 :     if(f->good()) {
    1581            0 :       std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    1582            0 :       file_h = new OksFile(xmls, short_path, full_path, this);
    1583            0 :     }
    1584            0 :   }
    1585              :   
    1586              :     // check file access permissions
    1587              : 
    1588            0 :   if(file_h) {
    1589            0 :     check_read_only(file_h);
    1590              :   }
    1591              : 
    1592            0 :   return file_h;
    1593              : }
    1594              : 
    1595              :   // The function tests file existence, touches the file,
    1596              :   // prints out warnings/errors in case of problems
    1597              :   // and finally prints out info message.
    1598              : 
    1599              : static void
    1600            5 : test_file_existence(const std::string& file_name, bool silence, const std::string& fname, const char * msg)
    1601              : {
    1602              :     // test file existence
    1603              : 
    1604            5 :   bool file_exists = false;
    1605              : 
    1606            5 :   {
    1607            5 :     struct stat buf;
    1608            5 :     if(stat(file_name.c_str(), &buf) == 0) {
    1609            5 :       if(!silence) {
    1610            0 :         Oks::warning_msg(fname) << "  File \"" << file_name << "\" already exists\n";
    1611              :       }
    1612              :       file_exists = true;
    1613              :     }
    1614              :   }
    1615              : 
    1616              : 
    1617              :     // test file permissions
    1618              : 
    1619            5 :   {
    1620            5 :     std::ofstream f(file_name.c_str());
    1621              : 
    1622            5 :     if(!f) {
    1623            0 :       if(!silence) {
    1624            0 :         if(file_exists) {
    1625            0 :           throw std::runtime_error("cannot open file in write mode");
    1626              :         }
    1627              :         else {
    1628            0 :           throw std::runtime_error("cannot create file");
    1629              :         }
    1630              :       }
    1631              :     }
    1632            5 :   }
    1633              : 
    1634            5 :   if(!silence)
    1635            0 :     std::cout << "Creating new " << msg << " file \"" << file_name << "\"..." << std::endl;
    1636            5 : }
    1637              : 
    1638              : 
    1639              : inline std::string
    1640        12531 : mk_name_and_test(const std::string& name, const char * test, size_t test_len)
    1641              : {
    1642        12531 :   const char _s1_str[] = " - \'";
    1643        12531 :   const char _s2_str[] = "\' tested as ";
    1644              : 
    1645        12531 :   return ((std::string(_s1_str, sizeof(_s1_str)-1) + name).append(_s2_str, sizeof(_s2_str)-1)).append(test, test_len);
    1646              : }
    1647              : 
    1648              : 
    1649              : #define TEST_PATH_TOKEN(path, file, msg)                                                                                    \
    1650              : std::string token(path);                                                                                                    \
    1651              : token.push_back('/');                                                                                                       \
    1652              : token.append(file);                                                                                                         \
    1653              : Oks::substitute_variables(token);                                                                                           \
    1654              : if(Oks::real_path(token, true)) {                                                                                           \
    1655              :   TLOG_DEBUG(2) << fname << " returns \'" << token << "\' (filename relative to " << msg << " database repository directory)"; \
    1656              :   return token;                                                                                                             \
    1657              : }                                                                                                                           \
    1658              : else {                                                                                                                      \
    1659              :   const char _test_name[] = "relative to database repository directory";                                                    \
    1660              :   tested_files.push_back(mk_name_and_test(token, _test_name, sizeof(_test_name)-1));                                        \
    1661              : }
    1662              : 
    1663              : 
    1664              : std::string
    1665          456 : OksKernel::get_file_path(const std::string& s, const OksFile * file_h, bool strict_paths) const
    1666              : {
    1667          456 :   strict_paths &= p_use_strict_repository_paths;
    1668              : 
    1669          456 :   const char _fname[] = "get_file_path";
    1670          456 :   std::string fname;
    1671              : 
    1672          456 :   TLOG_DEBUG(2) << "ENTER " << make_fname(_fname, sizeof(_fname)-1, s, nullptr, &file_h);
    1673              : 
    1674          456 :   std::list<std::string> tested_files;
    1675              : 
    1676              :   // check absolute path or path relative to working directory
    1677          456 :   bool is_absolute_path = false;
    1678              : 
    1679          456 :   std::string s2(s);
    1680          456 :   Oks::substitute_variables(s2);
    1681          456 :   fname = make_fname(_fname, sizeof(_fname) - 1, s2, nullptr, &file_h);
    1682              : 
    1683              :   // test if file has an absolute path
    1684          456 :   if (s2[0] == '/')
    1685              :   is_absolute_path = true;
    1686              : 
    1687              :   // continue only if the file is an absolute path or it is not included
    1688          400 :   if (is_absolute_path || file_h == 0)
    1689              :     {
    1690           73 :       if (!is_absolute_path && s_cwd && *s_cwd)
    1691              :         {
    1692           73 :           std::string s3 = s_cwd;
    1693           73 :           s3.push_back('/');
    1694           73 :           s2 = s3 + s2;
    1695           73 :         }
    1696              : 
    1697          129 :       if (Oks::real_path(s2, true))
    1698              :         {
    1699           56 :           if (!get_user_repository_root().empty() && strict_paths)
    1700              :             {
    1701            0 :               if (!get_repository_mapping_dir().empty() && s2.find(get_repository_mapping_dir()) == 0)
    1702              :                 {
    1703            0 :                   s2.erase(0, get_repository_mapping_dir().size()+1);
    1704            0 :                   TEST_PATH_TOKEN(get_user_repository_root(), s2, "user")
    1705            0 :                 }
    1706            0 :               else if (s2.find(get_user_repository_root()) == 0)
    1707              :                 {
    1708              :                   // presumably from explicitly set TDAQ_DB_USER_REPOSITORY created externally
    1709            0 :                   TLOG_DEBUG(2) << fname << " returns external \'" << s2 << "\' (an absolute filename or relative to CWD=\'" << s_cwd << "\')";
    1710            0 :                   return s2;
    1711              :                 }
    1712              : 
    1713            0 :               std::ostringstream text;
    1714            0 :               text << fname << " file does not belong to oks git repository\n"
    1715            0 :                   "provide file repository name, or unset TDAQ_DB_REPOSITORY and try again with the DUNEDAQ_DB_PATH environment variable";
    1716            0 :               throw std::runtime_error(text.str().c_str());
    1717            0 :             }
    1718              :           else
    1719              :             {
    1720           56 :               TLOG_DEBUG(2) << fname << " returns \'" << s2 << "\' (an absolute filename or relative to CWD=\'" << s_cwd << "\')";
    1721           56 :               return s2;
    1722              :             }
    1723              :         }
    1724              :       else
    1725              :         {
    1726           73 :           if (is_absolute_path)
    1727              :             {
    1728            0 :               const char _test_name[] = "an absolute file name";
    1729            0 :               tested_files.push_back(mk_name_and_test(s2, _test_name, sizeof(_test_name) - 1));
    1730              :             }
    1731              :           else
    1732              :             {
    1733           73 :               const char _test_name[] = "relative to current working directory";
    1734           73 :               tested_files.push_back(mk_name_and_test(s2, _test_name, sizeof(_test_name) - 1));
    1735              :             }
    1736              :         }
    1737              :     }
    1738              : 
    1739          400 :   if( !get_user_repository_root().empty())
    1740              :     {
    1741            0 :       TEST_PATH_TOKEN(get_user_repository_root(), s, "user")
    1742            0 :     }
    1743              : 
    1744          400 :   if(get_user_repository_root().empty() || !p_use_strict_repository_paths)
    1745              :     {
    1746              :     // check paths relative to OKS database root directories
    1747          400 :     if (!is_absolute_path)
    1748        12858 :       for (auto & i : p_repository_dirs)
    1749              :         {
    1750        12858 :           TEST_PATH_TOKEN(i, s, "DUNEDAQ_DB_PATH")
    1751        12858 :         }
    1752              : 
    1753              :     // check non-absolute path relative to parent file if any
    1754            0 :     if (file_h && !is_absolute_path)
    1755              :       {
    1756            0 :         std::string s2(file_h->get_full_file_name());
    1757            0 :         std::string::size_type pos = s2.find_last_of('/');
    1758              : 
    1759            0 :         if (pos != std::string::npos)
    1760              :           {
    1761            0 :             s2.erase(pos + 1);
    1762            0 :             s2.append(s);
    1763            0 :             Oks::substitute_variables(s2);
    1764              : 
    1765            0 :             if (Oks::real_path(s2, true))
    1766              :               {
    1767            0 :                 TLOG_DEBUG(2) << fname << " returns \'" << s2 << "\' (filename relative to parent file)";
    1768            0 :                 return s2;
    1769              :               }
    1770              :             else
    1771              :               {
    1772            0 :                 const char _test_name[] = "relative to parent file";
    1773            0 :                 tested_files.push_back(mk_name_and_test(s2, _test_name, sizeof(_test_name) - 1));
    1774              :               }
    1775              :           }
    1776            0 :       }
    1777              :   }
    1778              : 
    1779            0 :   TLOG_DEBUG(2) << fname << " throw exception (file was not found)";
    1780              : 
    1781            0 :   std::ostringstream text;
    1782            0 :   text << fname << " found no readable file among " << tested_files.size() << " tested:\n";
    1783            0 :   for (auto & i : tested_files)
    1784            0 :     text << i << std::endl;
    1785              : 
    1786            0 :   throw std::runtime_error(text.str().c_str());
    1787          456 : }
    1788              : 
    1789              : 
    1790              :   // user-allowed method
    1791              : 
    1792              : OksFile *
    1793           82 : OksKernel::load_file(const std::string& short_file_name, bool bind)
    1794              : {
    1795           82 :   std::unique_lock lock(p_kernel_mutex);
    1796          164 :   return k_load_file(short_file_name, bind, 0, 0);
    1797           82 : }
    1798              : 
    1799              : 
    1800              :   // kernel method
    1801              : 
    1802              : OksFile *
    1803          409 : OksKernel::k_load_file(const std::string& short_file_name, bool bind, const OksFile * parent_h, OksPipeline * pipeline)
    1804              : {
    1805          409 :   const char _fname[] = "k_load_file";
    1806          409 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, short_file_name, &bind, &parent_h);
    1807              : 
    1808          409 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    1809              : 
    1810          409 :   std::string full_file_name;
    1811              : 
    1812          409 :   try {
    1813          409 :     full_file_name = get_file_path(short_file_name, parent_h);
    1814              :   }
    1815            0 :   catch (std::exception & e) {
    1816            0 :     throw CanNotOpenFile("k_load_file", short_file_name, e.what());
    1817            0 :   }
    1818              : 
    1819          409 :   try {
    1820              : 
    1821              :       // check if the file is already loaded
    1822              : 
    1823          409 :     OksFile::Map::const_iterator i = p_schema_files.find(&full_file_name);
    1824          409 :     if(i != p_schema_files.end()) return i->second->check_parent(parent_h);
    1825              : 
    1826          283 :     i = p_data_files.find(&full_file_name);
    1827          283 :     if(i != p_data_files.end()) return i->second->check_parent(parent_h);
    1828              : 
    1829          283 :     std::shared_ptr<std::ifstream> f(new std::ifstream(full_file_name.c_str()));
    1830              : 
    1831          283 :     if(f->good()) {
    1832          283 :       long file_length(get_file_length(*f));
    1833              :       
    1834          283 :       if(!file_length) {
    1835            0 :         throw std::runtime_error("k_load_file(): file is empty");
    1836              :       }
    1837              : 
    1838              :         // read file header and decide what to load
    1839              : 
    1840          283 :       std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    1841              : 
    1842          283 :       OksFile * file_h = new OksFile(xmls, short_file_name, full_file_name, this);
    1843              : 
    1844          283 :       if(file_h->p_oks_format.size() == 6 && cmp_str6n(file_h->p_oks_format.c_str(), "schema")) {
    1845          158 :         k_load_schema(file_h, xmls, parent_h);
    1846              :       }
    1847              :       else {
    1848          125 :         char format;
    1849              : 
    1850          125 :         if(file_h->p_oks_format.size() == 4 && cmp_str4n(file_h->p_oks_format.c_str(), "data"))
    1851              :           format = 'n';
    1852            0 :         else if(file_h->p_oks_format.size() == 8 && cmp_str8n(file_h->p_oks_format.c_str(), "extended"))
    1853              :           format = 'X';
    1854            0 :         else if(file_h->p_oks_format.size() == 7 && cmp_str7n(file_h->p_oks_format.c_str(), "compact"))
    1855              :           format = 'c';
    1856              :         else {
    1857            0 :           delete file_h;
    1858            0 :           throw std::runtime_error("k_load_file(): failed to parse header");
    1859              :         }
    1860              : 
    1861          125 :         k_load_data(file_h, format, xmls, file_length, bind, parent_h, pipeline);
    1862              :       }
    1863              : 
    1864          283 :       OSK_VERBOSE_REPORT("LEAVE " << fname)
    1865              : 
    1866          283 :       return file_h;
    1867          283 :     }
    1868              :     else {
    1869            0 :       throw std::runtime_error("k_load_file(): cannot open file");
    1870              :     }
    1871          283 :   }
    1872            0 :   catch (exception & e) {
    1873            0 :     throw FailedLoadFile("file", full_file_name, e);
    1874            0 :   }
    1875            0 :   catch (std::exception & e) {
    1876            0 :     throw FailedLoadFile("file", full_file_name, e.what());
    1877            0 :   }
    1878            0 :   catch (...) {
    1879            0 :     throw FailedLoadFile("file", full_file_name, "caught unknown exception");
    1880            0 :   }
    1881          409 : }
    1882              : 
    1883              : 
    1884              : void
    1885          283 : OksKernel::k_load_includes(const OksFile& f, OksPipeline * pipeline)
    1886              : {
    1887          600 :   for(std::list<std::string>::const_iterator i = f.p_list_of_include_files.begin(); i != f.p_list_of_include_files.end(); ++i) {
    1888          317 :     if(!(*i).empty()) {
    1889              :       //if(f.get_repository() != OksFile::NoneRepository) {
    1890          317 :       if(!get_user_repository_root().empty()) {
    1891            0 :         if((*i)[0] == '/') {
    1892            0 :           throw FailedLoadFile("include", *i, "inclusion of files with absolute pathname (like \"/foo/bar\") is not allowed by repository files; include files relative to repository root (like \"foo/bar\")");
    1893              :         }
    1894            0 :         else if((*i)[0] == '.') {
    1895            0 :           throw FailedLoadFile("include", *i, "inclusion of files with file-related relative pathnames (like \"../foo/bar\" or \"./bar\") is not supported by repository files; include files relative to repository root (like \"foo/bar\")");
    1896              :         }
    1897            0 :         else if((*i).find('/') == std::string::npos) {
    1898            0 :           throw FailedLoadFile("include", *i, "inclusion of files with file-related local pathnames (like \"bar\") is not supported by repository files; include files relative to repository root (like \"foo/bar\")");
    1899              :         }
    1900              :       }
    1901              : 
    1902          317 :       try {
    1903          317 :         k_load_file(*i, false, &f, pipeline);
    1904              :       }
    1905            0 :       catch (exception & e) {
    1906            0 :         throw FailedLoadFile("include", *i, e);
    1907            0 :       }
    1908            0 :       catch (std::exception & e) {
    1909            0 :         throw FailedLoadFile("include", *i, e.what());
    1910            0 :       }
    1911              :     }
    1912              :     else {
    1913            0 :       throw FailedLoadFile("include", *i, "empty filename");
    1914              :     }
    1915              :   }
    1916          283 : }
    1917              : 
    1918              : void
    1919            0 : OksKernel::get_includes(const std::string& file_name, std::set< std::string >& includes, bool use_repository_name)
    1920              : {
    1921            0 :   try {
    1922            0 :     std::shared_ptr<std::ifstream> f(new std::ifstream(file_name.c_str()));
    1923              : 
    1924            0 :     if(!f->good()) {
    1925            0 :       throw std::runtime_error("get_includes(): cannot open file");
    1926              :     }
    1927              : 
    1928            0 :     std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    1929            0 :     OksFile fp(xmls, file_name, file_name, this);
    1930              : 
    1931            0 :     if(fp.p_list_of_include_files.size()) {
    1932            0 :       for(std::list<std::string>::iterator i = fp.p_list_of_include_files.begin(); i != fp.p_list_of_include_files.end(); ++i) {
    1933            0 :         includes.insert(use_repository_name ? get_file_path(*i, &fp).substr(get_user_repository_root().size()+1) : get_file_path(*i, &fp));
    1934              :       }
    1935              :     }
    1936              : 
    1937            0 :     f->close();
    1938            0 :   }
    1939            0 :   catch (exception & e) {
    1940            0 :     throw (FailedLoadFile("file", file_name, e));
    1941            0 :   }
    1942            0 :   catch (std::exception & e) {
    1943            0 :     throw (FailedLoadFile("file", file_name, e.what()));
    1944            0 :   }
    1945            0 : }
    1946              : 
    1947              : bool
    1948            0 : OksKernel::test_parent(OksFile * file, OksFile::IMap::iterator& i)
    1949              : {
    1950            0 :   OksFile * parent(i->first);
    1951            0 :   OksFile::Set& includes(i->second);
    1952              : 
    1953            0 :   if(includes.find(file) != includes.end()) {
    1954            0 :     if(file->p_included_by != parent) {
    1955            0 :       TLOG_DEBUG( 1 ) << "new parent of file " << file->get_full_file_name() << " is " << parent->get_full_file_name() ;
    1956            0 :       file->p_included_by = parent;
    1957              :     }
    1958              : 
    1959            0 :     return true;
    1960              :   }
    1961              : 
    1962              :   return false;
    1963              : }
    1964              : 
    1965              : void
    1966            0 : OksKernel::k_close_dangling_includes()
    1967              : {
    1968              :     // build inclusion graph
    1969              : 
    1970            0 :   OksFile::IMap igraph;
    1971              : 
    1972            0 :   for(OksFile::Map::iterator i = p_schema_files.begin(); i != p_schema_files.end(); ++i) {
    1973            0 :     for(std::list<std::string>::const_iterator x = i->second->p_list_of_include_files.begin(); x != i->second->p_list_of_include_files.end(); ++x) {
    1974            0 :       std::string f = get_file_path(*x, i->second);
    1975            0 :       OksFile::Map::const_iterator it = p_schema_files.find(&f);
    1976            0 :       if(it != p_schema_files.end()) {
    1977            0 :         igraph[i->second].insert(it->second);
    1978              :       }
    1979              :       else {
    1980            0 :         std::cerr << "cannot find schema " << *x << " included by " << i->second->get_full_file_name() << std::endl;
    1981              :       }
    1982            0 :     }
    1983              :   }
    1984              : 
    1985            0 :   for(OksFile::Map::iterator i = p_data_files.begin(); i != p_data_files.end(); ++i) {
    1986            0 :     for(std::list<std::string>::const_iterator x = i->second->p_list_of_include_files.begin(); x != i->second->p_list_of_include_files.end(); ++x) {
    1987            0 :       std::string f = get_file_path(*x, i->second);
    1988            0 :       OksFile::Map::const_iterator it = p_data_files.find(&f);
    1989            0 :       if(it != p_data_files.end()) {
    1990            0 :         igraph[i->second].insert(it->second);
    1991              :       }
    1992              :       else {
    1993            0 :         it = p_schema_files.find(&f);
    1994              :         
    1995            0 :         if(it != p_schema_files.end()) {
    1996            0 :           igraph[i->second].insert(it->second);
    1997              :         }
    1998              :         else {
    1999            0 :           std::cerr << "cannot find file " << *x << " included by " << i->second->get_full_file_name() << std::endl;
    2000              :         }
    2001              :       }
    2002            0 :     }
    2003              :   }
    2004              : 
    2005              : 
    2006            0 :   const size_t num_of_schema_files(schema_files().size());
    2007              : 
    2008              : 
    2009              :     // calculate files to be closed
    2010              :     
    2011            0 :   while(true) {
    2012            0 :     std::list<OksFile *> schema_files, data_files;  // files to be closed
    2013              :     
    2014            0 :     OksFile::Map * files[2] = {&p_schema_files, &p_data_files};
    2015            0 :     std::list<OksFile *> to_be_closed[2];
    2016              : 
    2017            0 :     for(int c = 0; c < 2; ++c) {
    2018            0 :       for(OksFile::Map::iterator i = files[c]->begin(); i != files[c]->end(); ++i) {
    2019            0 :         if(OksFile * p = const_cast<OksFile *>(i->second->p_included_by)) {
    2020            0 :           bool found_parent = false;
    2021              : 
    2022              :             // check, the parent is valid
    2023              : 
    2024            0 :           if(igraph.find(p) != igraph.end()) {
    2025            0 :             OksFile::IMap::iterator j = igraph.find(p);
    2026            0 :             if(test_parent(i->second, j)) {
    2027            0 :               continue;
    2028              :             }
    2029              :           }
    2030              : 
    2031            0 :           TLOG_DEBUG( 1 ) << "the parent of file " << i->second->get_full_file_name() << " is not valid" ;
    2032              : 
    2033              : 
    2034              :             // try to find new parent
    2035              : 
    2036            0 :           for(OksFile::IMap::iterator j = igraph.begin(); j != igraph.end(); ++j) {
    2037            0 :             if(test_parent(i->second, j)) {
    2038              :               found_parent = true;
    2039              :               break;
    2040              :             }
    2041              :           }
    2042              : 
    2043            0 :           if(found_parent == false) {
    2044            0 :             TLOG_DEBUG( 1 ) << "the file " << i->second->get_full_file_name() << " is not included by any other file and will be closed" ;
    2045            0 :             to_be_closed[c].push_back(i->second);
    2046              :           }
    2047              :         }
    2048              :       }
    2049              :     }
    2050              : 
    2051            0 :     int num = 0;
    2052              : 
    2053            0 :     for(std::list<OksFile *>::const_iterator i = to_be_closed[1].begin(); i != to_be_closed[1].end(); ++i) {
    2054            0 :       num += (*i)->p_list_of_include_files.size();
    2055            0 :       k_close_data(*i, true);
    2056            0 :       igraph.erase(*i);
    2057              :     }
    2058              : 
    2059            0 :     for(std::list<OksFile *>::const_iterator i = to_be_closed[0].begin(); i != to_be_closed[0].end(); ++i) {
    2060            0 :       num += (*i)->p_list_of_include_files.size();
    2061            0 :       k_close_schema(*i);
    2062            0 :       igraph.erase(*i);
    2063              :     }
    2064              : 
    2065            0 :     if(num > 0) {
    2066            0 :       TLOG_DEBUG( 1 ) << "go into recursive call, number of potentially closed includes is " << num ;
    2067              :     }
    2068              :     else {
    2069            0 :       TLOG_DEBUG( 1 ) << "break loop";
    2070            0 :       break;
    2071              :     }
    2072            0 :   }
    2073              :   
    2074            0 :   if(num_of_schema_files != schema_files().size()) {
    2075            0 :     TLOG_DEBUG( 1 ) << "rebuild classes since number of schema files has been changed from " << num_of_schema_files << " to " << schema_files().size() ;
    2076            0 :     registrate_all_classes();
    2077              :   }
    2078            0 : }
    2079              : 
    2080              : 
    2081              : bool
    2082            0 : OksKernel::k_preload_includes(OksFile * fp, std::set<OksFile *>& new_files_h, bool allow_schema_extension)
    2083              : {
    2084            0 :   bool found_include_changes(false);
    2085              : 
    2086            0 :   try {
    2087            0 :     std::shared_ptr<std::ifstream> file(new std::ifstream(fp->get_full_file_name().c_str()));
    2088              : 
    2089            0 :     if(!file->good()) {
    2090            0 :       throw std::runtime_error(std::string("k_preload_includes(): cannot open file \"") + fp->get_full_file_name() + '\"');
    2091              :     }
    2092              : 
    2093              :       // keep included files
    2094              : 
    2095            0 :     std::set<std::string> included;
    2096              : 
    2097            0 :     if(fp->p_list_of_include_files.size()) {
    2098            0 :       for(std::list<std::string>::iterator i = fp->p_list_of_include_files.begin(); i != fp->p_list_of_include_files.end(); ++i) {
    2099            0 :         included.insert(*i);
    2100              :       }
    2101              :     }
    2102              : 
    2103              :       // get size of file and check that it is not empty
    2104              : 
    2105            0 :     file->seekg(0, std::ios::end);
    2106              : 
    2107            0 :     long file_length = static_cast<std::streamoff>(file->tellg());
    2108              : 
    2109            0 :     if(file_length == 0) {
    2110            0 :       throw std::runtime_error(std::string("k_preload_includes(): file \"") + fp->get_full_file_name() + "\" is empty");
    2111              :     }
    2112              : 
    2113            0 :     file->seekg(0, std::ios::beg);
    2114              : 
    2115            0 :     std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(file));
    2116              : 
    2117            0 :     {
    2118            0 :       OksFile fp2(xmls, fp->get_short_file_name(), fp->get_full_file_name(), this);
    2119            0 :       fp2.p_included_by = fp->p_included_by;
    2120            0 :       p_preload_file_info[fp] = new OksFile(*fp);
    2121            0 :       *fp = fp2;
    2122              : 
    2123            0 :       if(fp->p_oks_format.empty()) {
    2124            0 :         throw std::runtime_error(std::string("k_preload_includes(): failed to read header of file \"") + fp->get_full_file_name() + '\"');
    2125              :       }
    2126            0 :       else if(fp->p_oks_format == "schema") {
    2127            0 :         TLOG_DEBUG(2) << "skip reload of schema file \'" << fp->get_full_file_name() << '\'';
    2128            0 :         return false;
    2129              :       }
    2130            0 :       else if(fp->p_oks_format != "data" && fp->p_oks_format != "extended" && fp->p_oks_format != "compact") {
    2131            0 :         throw std::runtime_error(std::string("k_preload_includes(): file \"") + fp->get_full_file_name() + "\" is not valid oks file");
    2132              :       }
    2133            0 :     }
    2134              : 
    2135            0 :     if(fp->p_list_of_include_files.size()) {
    2136            0 :       TLOG_DEBUG(3) << "check \'include\' of the file \'" << fp->get_full_file_name() << '\'';
    2137              : 
    2138            0 :       if(included.size() != fp->p_list_of_include_files.size()) found_include_changes = true;
    2139              : 
    2140            0 :       for(std::list<std::string>::iterator i = fp->p_list_of_include_files.begin(); i != fp->p_list_of_include_files.end(); ++i) {
    2141            0 :         std::set<std::string>::const_iterator x = included.find(*i);
    2142            0 :         if(x != included.end()) {
    2143            0 :           TLOG_DEBUG(3) << "include \'" << *i << "\' already exists, skip...";
    2144              :         }
    2145              :         else {
    2146            0 :           TLOG_DEBUG(3) << "the file \'" << *i << "\' was not previously included by \'" << fp->get_full_file_name() << '\'';
    2147              : 
    2148            0 :           found_include_changes = true;
    2149              : 
    2150            0 :           std::string full_file_name;
    2151              : 
    2152            0 :           try {
    2153            0 :             full_file_name = get_file_path(*i, fp);
    2154              :           }
    2155            0 :           catch (std::exception & e) {
    2156            0 :             throw CanNotOpenFile("k_preload_includes", *i, e.what());
    2157            0 :           }
    2158              : 
    2159            0 :           OksFile::Map::const_iterator j = p_schema_files.find(&full_file_name);
    2160            0 :           if(j != p_schema_files.end()) {
    2161            0 :             TLOG_DEBUG(3) << "the include \'" << *i << "\' is already loaded schema file \'" << j->first << '\'';
    2162            0 :             continue;
    2163            0 :           }
    2164              : 
    2165            0 :           j = p_data_files.find(&full_file_name);
    2166            0 :           if(j != p_data_files.end()) {
    2167            0 :             TLOG_DEBUG(3) << "the include \'" << *i << "\' is already loaded data file \'" << j->first << '\'';
    2168            0 :             continue;
    2169            0 :           }
    2170              : 
    2171            0 :           if(OksFile * f = create_file_info(*i, full_file_name)) {
    2172            0 :             if(f->p_oks_format == "schema") {
    2173            0 :               std::string new_schema_full_file_name = f->get_full_file_name();
    2174            0 :               delete f;
    2175            0 :               if(p_schema_files.find(&new_schema_full_file_name) != p_schema_files.end()) {
    2176            0 :                 TLOG_DEBUG(3) << "the include \'" << *i << "\' is a schema file, that was already loaded";
    2177            0 :                 continue;
    2178            0 :               }
    2179              :               else {
    2180            0 :                 if(allow_schema_extension) {
    2181            0 :                   TLOG_DEBUG(3) << "the include \'" << *i << "\' is new schema file, loading...";
    2182            0 :                   k_load_schema(*i, fp);
    2183            0 :                   continue;
    2184            0 :                 }
    2185              :                 else {
    2186            0 :                   std::ostringstream text;
    2187            0 :                   text << "k_preload_includes(): include of new schema file (\'" << *i << "\') is not allowed on data reload";
    2188            0 :                   throw std::runtime_error(text.str().c_str());
    2189            0 :                 }
    2190              :               }
    2191            0 :             }
    2192            0 :             else if(f->p_oks_format == "data" || f->p_oks_format == "extended" || f->p_oks_format == "compact") {
    2193            0 :               TLOG_DEBUG(3) << "the include \'" << *i << "\' is new data file, pre-loading...";
    2194            0 :               add_data_file(f);
    2195            0 :               p_preload_added_files.push_back(f);
    2196            0 :               new_files_h.insert(f);
    2197            0 :               f->p_list_of_include_files.clear();
    2198            0 :               if(k_preload_includes(f, new_files_h, allow_schema_extension)) found_include_changes = true;
    2199            0 :               f->p_included_by = fp;
    2200            0 :               f->update_status_of_file();
    2201              :             }
    2202              :             else {
    2203            0 :               delete f;
    2204            0 :               std::ostringstream text;
    2205            0 :               text << "k_preload_includes(): failed to parse header of included \'" << full_file_name << "\' file";
    2206            0 :               throw std::runtime_error(text.str().c_str());
    2207            0 :             }
    2208              :           }
    2209              :           else {
    2210            0 :             throw std::runtime_error("k_load_file(): cannot open file");
    2211              :           }
    2212            0 :         }
    2213              :       }
    2214              :     }
    2215            0 :   }
    2216            0 :   catch (exception & e) {
    2217            0 :     throw FailedLoadFile("data file", fp->get_full_file_name(), e);
    2218            0 :   }
    2219            0 :   catch (std::exception & e) {
    2220            0 :     throw FailedLoadFile("data file", fp->get_full_file_name(), e.what());
    2221            0 :   }
    2222              :   
    2223            0 :   return found_include_changes;
    2224              : }
    2225              : 
    2226              : 
    2227              : /******************************************************************************/
    2228              : 
    2229              : std::string
    2230            0 : OksKernel::create_user_repository_dir()
    2231              : {
    2232            0 :   if (const char * path = getenv("TDAQ_DB_USER_REPOSITORY_PATH"))
    2233            0 :     return path;
    2234              : 
    2235              :   // create user repository directory if necessary
    2236            0 :   std::string user_repo;
    2237              : 
    2238            0 :   if (const char * user_repo_base = getenv("TDAQ_DB_USER_REPOSITORY_ROOT"))
    2239            0 :     user_repo = user_repo_base;
    2240              :   else
    2241            0 :     user_repo = get_temporary_dir();
    2242              : 
    2243            0 :   user_repo.push_back('/');
    2244            0 :   if (const char * user_repo_pattern = getenv("TDAQ_DB_USER_REPOSITORY_PATTERN"))
    2245            0 :     user_repo.append(user_repo_pattern);
    2246              :   else
    2247            0 :     user_repo.append("oks.XXXXXX");
    2248              : 
    2249            0 :   std::unique_ptr<char[]> dir_template(new char[user_repo.size() + 1]);
    2250            0 :   strcpy(dir_template.get(), user_repo.c_str());
    2251              : 
    2252            0 :   if (char * tmp_dirname = mkdtemp(dir_template.get()))
    2253              :     {
    2254            0 :       return tmp_dirname;
    2255              :     }
    2256              : 
    2257            0 :   throw CanNotCreateRepositoryDir("make_user_repository_dir", user_repo);
    2258            0 : }
    2259              : 
    2260              : 
    2261              : OksFile *
    2262           32 : OksKernel::find_file(const std::string &s, const OksFile::Map& files) const
    2263              : {
    2264           32 :   try {
    2265           32 :     std::string at = get_file_path(s, nullptr);
    2266           32 :     OksFile::Map::const_iterator i = files.find(&at);
    2267           32 :     if(i != files.end()) return (*i).second;
    2268           32 :   }
    2269            0 :   catch (...) {
    2270              :     // return 0;
    2271            0 :   }
    2272              : 
    2273              :   // search files included as relative to parent
    2274            5 :   for(const auto& f : files)
    2275              :     {
    2276            0 :       if (s == f.second->get_short_file_name())
    2277              :         {
    2278            0 :           return f.second;
    2279              :         }
    2280              :     }
    2281              : 
    2282            5 :   return nullptr;
    2283              : }
    2284              : 
    2285              : OksFile *
    2286            0 : OksKernel::find_schema_file(const std::string &s) const
    2287              : {
    2288            0 :   return find_file(s, p_schema_files);
    2289              : }
    2290              : 
    2291              : OksFile *
    2292           32 : OksKernel::find_data_file(const std::string &s) const
    2293              : {
    2294           32 :   return find_file(s, p_data_files);
    2295              : }
    2296              : 
    2297              : /******************************************************************************/
    2298              : 
    2299              :   // user-allowed method
    2300              : 
    2301              : OksFile *
    2302            0 : OksKernel::load_schema(const std::string& short_file_name, const OksFile * parent_h)
    2303              : {
    2304            0 :   std::unique_lock lock(p_kernel_mutex);
    2305            0 :   return k_load_schema(short_file_name, parent_h);
    2306            0 : }
    2307              : 
    2308              :   // kernel method
    2309              : 
    2310              : OksFile *
    2311            0 : OksKernel::k_load_schema(const std::string& short_file_name, const OksFile * parent_h)
    2312              : {
    2313            0 :   const char _fname[] = "k_load_schema";
    2314            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, short_file_name, nullptr, &parent_h);
    2315              : 
    2316            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    2317              : 
    2318            0 :   std::string full_file_name;
    2319              : 
    2320            0 :   try {
    2321            0 :     full_file_name = get_file_path(short_file_name, parent_h);
    2322              :   }
    2323            0 :   catch (std::exception & e) {
    2324            0 :     throw CanNotOpenFile("k_load_schema", short_file_name, e.what());
    2325            0 :   }
    2326              : 
    2327            0 :   try {
    2328            0 :     OksFile * fp = find_schema_file(full_file_name);
    2329              : 
    2330            0 :     if(fp != 0) {
    2331            0 :       if(p_verbose) {
    2332            0 :         std::lock_guard lock(p_parallel_out_mutex);
    2333            0 :         Oks::warning_msg(fname) << "  The file was already loaded\n";
    2334            0 :       }
    2335            0 :       return fp->check_parent(parent_h);
    2336              :     }
    2337              : 
    2338            0 :     {
    2339            0 :       std::shared_ptr<std::ifstream> f(new std::ifstream(full_file_name.c_str()));
    2340              : 
    2341            0 :       if(!f->good()) {
    2342            0 :         throw std::runtime_error("k_load_schema(): cannot open file");
    2343              :       }
    2344              : 
    2345            0 :       std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    2346              : 
    2347            0 :       fp = new OksFile(xmls, short_file_name, full_file_name, this);
    2348              : 
    2349            0 :       if(fp->p_oks_format.empty()) {
    2350            0 :         throw std::runtime_error("k_load_schema(): failed to read header of file");
    2351              :       }
    2352            0 :       else if(fp->p_oks_format != "schema") {
    2353            0 :         throw std::runtime_error("k_load_schema(): file is not oks schema file");
    2354              :       }
    2355              : 
    2356            0 :       k_load_schema(fp, xmls, parent_h);
    2357              : 
    2358            0 :       OSK_VERBOSE_REPORT("LEAVE " << fname)
    2359              : 
    2360            0 :       return fp;
    2361            0 :     }
    2362              :   }
    2363            0 :   catch (FailedLoadFile &) {
    2364            0 :     throw; //forward
    2365            0 :   }
    2366            0 :   catch (exception & e) {
    2367            0 :     throw FailedLoadFile("schema file", full_file_name, e);
    2368            0 :   }
    2369            0 :   catch (std::exception & e) {
    2370            0 :     throw FailedLoadFile("schema file", full_file_name, e.what());
    2371            0 :   }
    2372            0 :   catch (...) {
    2373            0 :     throw FailedLoadFile("schema file", full_file_name, "caught unknown exception");
    2374            0 :   }
    2375            0 : }
    2376              : 
    2377              : 
    2378              : void
    2379          158 : OksKernel::k_load_schema(OksFile * fp, std::shared_ptr<OksXmlInputStream> xmls, const OksFile * parent_h)
    2380              : {
    2381          158 :   OSK_PROFILING(OksProfiler::KernelLoadSchema, this)
    2382              : 
    2383          158 :   fp->p_included_by = parent_h;
    2384          158 :   check_read_only(fp);
    2385              : 
    2386          158 :   try {
    2387          158 :     if(!p_silence) {
    2388            0 :       std::lock_guard lock(p_parallel_out_mutex);
    2389            0 :       std::cout << (parent_h ? " * loading " : "Loading ") << fp->p_number_of_items << " classes from file \"" << fp->get_full_file_name() << "\"...\n";
    2390            0 :       if(parent_h == 0 && fp->get_full_file_name() != fp->get_short_file_name()) {
    2391            0 :         std::cout << "(non-fully-qualified filename was \"" << fp->get_short_file_name() << "\")\n";
    2392              :       }
    2393            0 :     }
    2394              : 
    2395          158 :     k_load_includes(*fp, 0);
    2396              : 
    2397          158 :     add_schema_file(fp);
    2398              : 
    2399          158 :     std::list<OksClass *> set;
    2400              : 
    2401        13194 :     while(true) {
    2402         6676 :       OksClass *c = 0;
    2403              : 
    2404         6676 :       try {
    2405         6676 :         c = new OksClass(*xmls, this);
    2406              :       }
    2407          158 :       catch(EndOfXmlStream &) {
    2408          158 :         delete c;
    2409          158 :         break;
    2410          158 :       }
    2411              : 
    2412         6518 :       if(c->get_name().empty()) {
    2413            0 :         throw std::runtime_error("k_load_schema(): failed to read a class");
    2414              :       }
    2415              : 
    2416         6518 :       OksClass::Map::const_iterator ic = p_classes.find(c->get_name().c_str());
    2417         6518 :       if(ic != p_classes.end()) {
    2418            0 :         bool are_different = (*ic->second != *c);
    2419              : 
    2420            0 :         c->p_transient = true;
    2421            0 :         delete c;
    2422            0 :         c = ic->second;
    2423            0 :         if(p_allow_duplicated_classes && !are_different) {
    2424            0 :           static bool ers_report = (getenv("OKS_KERNEL_ERS_REPORT_DUPLICATED_CLASSES") != nullptr);
    2425            0 :           if(ers_report) {
    2426            0 :             ers::warning(kernel::ClassAlreadyDefined(ERS_HERE,c->get_name(),fp->get_full_file_name(),c->p_file->get_full_file_name()));
    2427              :           }
    2428              :           else {
    2429            0 :             const char _fname[] = "k_load_schema";
    2430            0 :             std::lock_guard lock(p_parallel_out_mutex);
    2431            0 :             Oks::warning_msg(make_fname(_fname, sizeof(_fname)-1, fp->get_full_file_name(), nullptr, &parent_h))
    2432            0 :               << "  Class \"" << c->get_name() << "\" was already loaded from file \'" << c->get_file()->get_full_file_name() << "\'\n";
    2433            0 :           }
    2434              :         }
    2435              :         else {
    2436            0 :           std::stringstream text;
    2437            0 :           text << (are_different ? "different " : "") << "class \"" << c->get_name() << "\" was already loaded from file \'" << c->get_file()->get_full_file_name() << '\'';
    2438            0 :           throw std::runtime_error(text.str().c_str());
    2439            0 :         }
    2440              :       }
    2441              :       else {
    2442         6518 :         {
    2443         6518 :           std::unique_lock lock(p_schema_mutex);  // protect schema and all objects from changes
    2444         6518 :           p_classes[c->get_name().c_str()] = c;
    2445         6518 :         }
    2446         6518 :         c->p_file = fp;
    2447         6518 :         if(OksClass::create_notify_fn) set.push_back(c);
    2448              :       }
    2449         6518 :     }
    2450              : 
    2451          158 :     fp->p_size = xmls->get_position();
    2452              : 
    2453          158 :     registrate_all_classes(true);
    2454              : 
    2455          158 :     if(OksClass::create_notify_fn)
    2456            0 :       for(std::list<OksClass *>::iterator i2 = set.begin(); i2 != set.end(); ++i2)
    2457            0 :         (*OksClass::create_notify_fn)(*i2);
    2458              : 
    2459          158 :     if(OksClass::change_notify_fn) {
    2460            0 :       std::set<OksClass *> set2;
    2461              : 
    2462            0 :       for(std::list<OksClass *>::iterator i2 = set.begin(); i2 != set.end(); ++i2) {
    2463            0 :         OksClass * c = *i2;
    2464            0 :         if(c->p_all_sub_classes && !c->p_all_sub_classes->empty()) {
    2465            0 :           for(OksClass::FList::iterator i3 = c->p_all_sub_classes->begin(); i3 != c->p_all_sub_classes->end(); ++i3) {
    2466            0 :             if(set2.find(*i3) == set2.end()) {
    2467            0 :               (*OksClass::change_notify_fn)(*i3, OksClass::ChangeSuperClassesList, (const void *)(&(c->p_name)));
    2468            0 :               set2.insert(*i3);
    2469              :             }
    2470              :           }
    2471              :         }
    2472              :       }
    2473            0 :     }
    2474              : 
    2475          158 :     fp->update_status_of_file();
    2476          158 :   }
    2477            0 :   catch (exception & e) {
    2478            0 :     throw FailedLoadFile("schema file", fp->get_full_file_name(), e);
    2479            0 :   }
    2480            0 :   catch (std::exception & e) {
    2481            0 :     throw FailedLoadFile("schema file", fp->get_full_file_name(), e.what());
    2482            0 :   }
    2483            0 :   catch (...) {
    2484            0 :     throw FailedLoadFile("schema file", fp->get_full_file_name(), "caught unknown exception");
    2485            0 :   }
    2486          158 : }
    2487              : 
    2488              : 
    2489              : OksFile *
    2490            0 : OksKernel::new_schema(const std::string& s)
    2491              : {
    2492            0 :   const char _fname[] = "new_schema";
    2493            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, s, nullptr, nullptr);
    2494            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    2495              : 
    2496            0 :   if(!s.length()) {
    2497            0 :     throw CanNotOpenFile("new_schema", s, "file name is empty");
    2498              :   }
    2499              : 
    2500            0 :   std::string file_name(s);
    2501              : 
    2502            0 :   try {
    2503              : 
    2504            0 :     Oks::substitute_variables(file_name);
    2505              : 
    2506            0 :     test_file_existence(file_name, p_silence, fname, "schema");
    2507              : 
    2508            0 :     file_name = get_file_path(s, nullptr, false);
    2509              : 
    2510            0 :     std::unique_lock lock(p_kernel_mutex);
    2511              : 
    2512            0 :     if(find_schema_file(file_name) != 0) {
    2513            0 :       throw std::runtime_error("the file is already loaded");
    2514              :     }
    2515              : 
    2516            0 :     OksFile * file_h = new OksFile(file_name, "", "", "schema", this);
    2517              : 
    2518            0 :     file_h->p_short_name = s;
    2519              : 
    2520            0 :     k_set_active_schema(file_h);
    2521              : 
    2522            0 :     add_schema_file(p_active_schema);
    2523              : 
    2524            0 :     registrate_all_classes(true);
    2525              : 
    2526            0 :   }
    2527            0 :   catch (std::exception & e) {
    2528            0 :     throw CanNotCreateFile("new_schema", "schema file", file_name, e.what());
    2529            0 :   }
    2530            0 :   catch (...) {
    2531            0 :     throw CanNotCreateFile("new_schema", "schema file", file_name, "caught unknown exception");
    2532            0 :   }
    2533              : 
    2534            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    2535              : 
    2536            0 :   return p_active_schema;
    2537            0 : }
    2538              : 
    2539              : 
    2540              :   // user-allowed method
    2541              : 
    2542              : void
    2543            0 : OksKernel::save_schema(OksFile * pf, bool force, OksFile * fh)
    2544              : {
    2545            0 :   std::shared_lock lock(p_kernel_mutex);
    2546            0 :   k_save_schema(pf, force, fh);
    2547            0 : }
    2548              : 
    2549              : 
    2550              : void
    2551            0 : OksKernel::save_schema(OksFile * file_h, bool force, const OksClass::Map & classes)
    2552              : {
    2553            0 :   std::shared_lock lock(p_kernel_mutex);
    2554            0 :   k_save_schema(file_h, force, 0, &classes);
    2555            0 : }
    2556              : 
    2557              : 
    2558              : void
    2559            0 : OksKernel::backup_schema(OksFile * pf, const char * suffix)
    2560              : {
    2561            0 :   std::shared_lock lock(p_kernel_mutex);
    2562              : 
    2563            0 :   OksFile f(
    2564            0 :     pf->get_full_file_name() + suffix,
    2565              :     pf->get_logical_name(),
    2566              :     pf->get_type(),
    2567              :     pf->get_oks_format(),
    2568              :     this
    2569            0 :   );
    2570              : 
    2571            0 :   f.p_created_by = pf->p_created_by;
    2572            0 :   f.p_creation_time = pf->p_creation_time;
    2573            0 :   f.p_created_on = pf->p_created_on;
    2574            0 :   f.p_list_of_include_files = pf->p_list_of_include_files;
    2575              : 
    2576            0 :   if(!p_silence) {
    2577            0 :     std::cout << "Making backup of schema file \"" << pf->p_full_name << "\"...\n";
    2578              :   }
    2579              : 
    2580            0 :   bool silence = p_silence;
    2581              : 
    2582            0 :   p_silence = true;
    2583              : 
    2584            0 :   try {
    2585            0 :     k_save_schema(&f, true, pf);
    2586              :   }
    2587            0 :   catch(exception& ex) {
    2588            0 :     p_silence = silence;
    2589            0 :     throw CanNotBackupFile(pf->p_full_name, ex);
    2590            0 :   }
    2591              : 
    2592            0 :   p_silence = silence;
    2593            0 : }
    2594              : 
    2595              :   // kernel method
    2596              : 
    2597              : void
    2598            0 : OksKernel::k_save_schema(OksFile * pf, bool force, OksFile * fh, const OksClass::Map * classes)
    2599              : {
    2600            0 :   const char _fname[] = "k_save_schema";
    2601            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, pf->p_full_name, nullptr, nullptr);
    2602              : 
    2603            0 :   OSK_PROFILING(OksProfiler::KernelSaveSchema, this)
    2604            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    2605              : 
    2606            0 :   std::string tmp_file_name;
    2607              : 
    2608            0 :   if(!fh) fh = pf;
    2609              : 
    2610            0 :   try {
    2611              : 
    2612              :       // lock the file, if it is not locked already
    2613              : 
    2614            0 :     if(pf->is_locked() == false) {
    2615            0 :       pf->lock();
    2616              :     }
    2617              : 
    2618              : 
    2619              :       // calculate number of classes, going into the schema file
    2620              : 
    2621            0 :     size_t numberOfClasses = 0;
    2622              : 
    2623            0 :     if(classes) {
    2624            0 :       numberOfClasses = classes->size();
    2625              :     }
    2626            0 :     else if(!p_classes.empty()) {
    2627            0 :       for(OksClass::Map::iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    2628            0 :         if(i->second->p_file == fh) numberOfClasses++;
    2629              :       }
    2630              :     }
    2631              : 
    2632              : 
    2633              :       // create temporal file to store the schema
    2634              : 
    2635            0 :     tmp_file_name = get_tmp_file(pf->p_full_name);
    2636              : 
    2637            0 :     {
    2638            0 :       std::ofstream f(tmp_file_name.c_str());
    2639            0 :       f.exceptions ( std::ostream::failbit | std::ostream::badbit );
    2640              : 
    2641            0 :       if(!f) {
    2642            0 :         std::ostringstream text;
    2643            0 :         text << "cannot create temporal file \'" << tmp_file_name << "\' to save schema";
    2644            0 :         throw std::runtime_error(text.str().c_str());
    2645            0 :       }
    2646              :       else {
    2647            0 :         if(!p_silence)
    2648            0 :           std::cout << "Saving " << numberOfClasses << " classes to schema file \"" << pf->p_full_name << "\"...\n";
    2649              :       }
    2650              : 
    2651              : 
    2652            0 :       OksXmlOutputStream xmls(f);
    2653              : 
    2654              : 
    2655              :         // write oks xml file header
    2656              : 
    2657            0 :       pf->p_number_of_items = numberOfClasses;
    2658            0 :       pf->p_oks_format = "schema";
    2659              : 
    2660            0 :       pf->write(xmls);
    2661              : 
    2662              : 
    2663              :         // write oks classes
    2664              : 
    2665            0 :       std::ostringstream errors;
    2666            0 :       bool found_errors = false;
    2667              : 
    2668            0 :       if (classes)
    2669              :         {
    2670            0 :           for (auto & i : *classes)
    2671              :             {
    2672            0 :               found_errors |= i.second->check_relationships(errors, false);
    2673            0 :               i.second->save(xmls);
    2674              :             }
    2675              :         }
    2676              :       else
    2677              :         {
    2678            0 :           for (auto & i : p_classes)
    2679              :             {
    2680            0 :               if (i.second->p_file == fh)
    2681              :                 {
    2682            0 :                   found_errors |= i.second->check_relationships(errors, false);
    2683            0 :                   i.second->save(xmls);
    2684              :                 }
    2685              :             }
    2686              :         }
    2687              : 
    2688            0 :       if(found_errors)
    2689              :         {
    2690            0 :           kernel::BindError ex(ERS_HERE, errors.str());
    2691              : 
    2692            0 :           if(force == false)
    2693              :             {
    2694            0 :               throw std::runtime_error(ex.what());
    2695              :             }
    2696            0 :           else if(p_silence == false)
    2697              :             {
    2698            0 :               ers::warning(ex);
    2699              :             }
    2700            0 :         }
    2701              : 
    2702              :         // close oks xml file
    2703              : 
    2704            0 :       xmls.put_last_tag("oks-schema", sizeof("oks-schema")-1);
    2705              : 
    2706              : 
    2707              :         // flush the buffers
    2708              : 
    2709            0 :       f.close();
    2710            0 :     }
    2711              : 
    2712            0 :     if(rename(tmp_file_name.c_str(), pf->p_full_name.c_str())) {
    2713            0 :       std::ostringstream text;
    2714            0 :       text << "cannot rename \'" << tmp_file_name << "\' to \'" << pf->p_full_name << '\'';
    2715            0 :       throw std::runtime_error(text.str().c_str());
    2716            0 :     }
    2717              : 
    2718            0 :     tmp_file_name.erase(0);
    2719              : 
    2720            0 :     if(pf != p_active_schema) {
    2721            0 :       try {
    2722            0 :         pf->unlock();
    2723              :       }
    2724            0 :       catch(exception& ex) {
    2725            0 :         throw std::runtime_error(ex.what());
    2726            0 :       }
    2727              :     }
    2728            0 :     pf->p_is_updated = false;
    2729            0 :     pf->update_status_of_file();
    2730              : 
    2731              :   }
    2732            0 :   catch (exception & ex) {
    2733            0 :     if(pf != p_active_schema) { try { pf->unlock();} catch(...) {} }
    2734            0 :     if(!tmp_file_name.empty()) { unlink(tmp_file_name.c_str()); }
    2735            0 :     throw CanNotWriteToFile("k_save_schema", "schema file", pf->p_full_name, ex);
    2736            0 :   }
    2737            0 :   catch (std::exception & ex) {
    2738            0 :     if(pf != p_active_schema) { try { pf->unlock();} catch(...) {} }
    2739            0 :     if(!tmp_file_name.empty()) { unlink(tmp_file_name.c_str()); }
    2740            0 :     throw CanNotWriteToFile("k_save_schema", "schema file", pf->p_full_name, ex.what());
    2741            0 :   }
    2742              : 
    2743            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    2744            0 : }
    2745              : 
    2746              : 
    2747              :   // note: the file name is used as a key in the map
    2748              :   // to rename a file it is necessary to remove file from map, change name and insert it back
    2749              : 
    2750              : void
    2751            0 : OksKernel::k_rename_schema(OksFile * pf, const std::string& short_name, const std::string& long_name)
    2752              : {
    2753            0 :   remove_schema_file(pf);
    2754            0 :   pf->rename(short_name, long_name);
    2755            0 :   add_schema_file(pf);
    2756            0 : }
    2757              : 
    2758              : 
    2759              : void
    2760            0 : OksKernel::save_as_schema(const std::string& new_name, OksFile * pf)
    2761              : {
    2762            0 :   const char _fname[] = "save_as_schema";
    2763            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, new_name, nullptr, &pf);
    2764            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    2765              : 
    2766            0 :   try {
    2767              : 
    2768            0 :     if(!new_name.length()) {
    2769            0 :       throw std::runtime_error("the new filename is empty");
    2770              :     }
    2771              : 
    2772            0 :     std::string old_short_name = pf->p_short_name;
    2773            0 :     std::string old_full_name  = pf->p_full_name;
    2774              : 
    2775            0 :     std::unique_lock lock(p_kernel_mutex);
    2776              : 
    2777            0 :     k_rename_schema(pf, new_name, new_name);
    2778              : 
    2779            0 :     try {
    2780            0 :       k_save_schema(pf);
    2781              :     }
    2782            0 :     catch (...) {
    2783            0 :       k_rename_schema(pf, old_short_name, old_full_name);
    2784            0 :       throw;
    2785            0 :     }
    2786              : 
    2787            0 :   }
    2788            0 :   catch (exception & ex) {
    2789            0 :     throw CanNotWriteToFile("k_save_as_schema", "schema file", pf->p_full_name, ex);
    2790            0 :   }
    2791            0 :   catch (std::exception & ex) {
    2792            0 :     throw CanNotWriteToFile("k_save_as_schema", "schema file", pf->p_full_name, ex.what());
    2793            0 :   }
    2794              : 
    2795            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    2796            0 : }
    2797              : 
    2798              : void
    2799            0 : OksKernel::save_all_schema()
    2800              : {
    2801            0 :   OSK_VERBOSE_REPORT("ENTER OksKernel::save_all_schema()")
    2802              : 
    2803            0 :   {
    2804            0 :     std::shared_lock lock(p_kernel_mutex);
    2805              : 
    2806            0 :     for(OksFile::Map::iterator i = p_schema_files.begin(); i != p_schema_files.end(); ++i) {
    2807            0 :       if(check_read_only(i->second) == false) {
    2808            0 :         k_save_schema(i->second);
    2809              :       }
    2810              :       else {
    2811            0 :         TLOG_DEBUG(2) << "skip read-only schema file \'" << *(i->first) << '\'';
    2812              :       }
    2813              : 
    2814              :     }
    2815              : 
    2816            0 :   }
    2817              : 
    2818            0 :   OSK_VERBOSE_REPORT("LEAVE OksKernel::save_all_schema()")
    2819            0 : }
    2820              : 
    2821              : 
    2822              :   // user-allowed method
    2823              : 
    2824              : void
    2825            0 : OksKernel::close_schema(OksFile * pf)
    2826              : {
    2827            0 :   std::unique_lock lock(p_kernel_mutex);
    2828            0 :   k_close_schema(pf);
    2829            0 : }
    2830              : 
    2831              :   // kernel method
    2832              : 
    2833              : void
    2834          158 : OksKernel::k_close_schema(OksFile * pf)
    2835              : {
    2836          158 :   OSK_PROFILING(OksProfiler::KernelCloseSchema, this)
    2837              : 
    2838          158 :   if(!pf) {
    2839            0 :     TLOG_DEBUG(1) << "enter for file (null)";
    2840            0 :     return;
    2841              :   }
    2842              :   else {
    2843          158 :     TLOG_DEBUG(2) << "enter for file " << pf->p_full_name;
    2844              :   }
    2845              : 
    2846          158 :   if(p_active_schema == pf) p_active_schema = 0;
    2847              : 
    2848          158 :   try {
    2849          158 :     pf->unlock();
    2850              :   }
    2851            0 :   catch(exception& ex) {
    2852            0 :     Oks::error_msg("OksKernel::k_close_schema()") << ex.what() << std::endl;
    2853            0 :   }
    2854              : 
    2855          158 :   if(!p_silence)
    2856            0 :     std::cout << (pf->p_included_by ? " * c" : "C") << "lose OKS schema \"" << pf->p_full_name << "\"..." << std::endl;
    2857              : 
    2858          158 :   if(!p_classes.empty()) {
    2859              : 
    2860              :       //
    2861              :       // The fastest way to delete classes is delete
    2862              :       // them in order of superclasses descreasing
    2863              :       // because this reduces amount of work to restructure
    2864              :       // child classes when their parent was deleted and
    2865              :       // there will be no dangling classes
    2866              :       //
    2867              : 
    2868          158 :     std::set<OksClass *> sorted;
    2869              : 
    2870        10839 :     for(OksClass::Map::iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    2871        10681 :       OksClass *c = i->second;
    2872        10681 :       if(pf == c->p_file) sorted.insert(c);
    2873        10681 :       c->p_to_be_deleted = true;
    2874              :     }
    2875              : 
    2876         6676 :     for(std::set<OksClass *>::iterator j = sorted.begin(); j != sorted.end(); ++j) {
    2877         6518 :       delete *j;
    2878              :     }
    2879          158 :   }
    2880              : 
    2881          158 :   remove_schema_file(pf);
    2882          158 :   delete pf;
    2883              : 
    2884          158 :   TLOG_DEBUG(4) << "exit for file " << (void *)pf;
    2885          158 : }
    2886              : 
    2887              : void
    2888          174 : OksKernel::close_all_schema()
    2889              : {
    2890          174 :   TLOG_DEBUG(4) << "enter";
    2891              : 
    2892          174 :   {
    2893          174 :     std::unique_lock lock(p_kernel_mutex);
    2894              : 
    2895         6692 :     for(OksClass::Map::iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    2896         6518 :       i->second->p_to_be_deleted = true;
    2897              :     }
    2898              : 
    2899          332 :     while(!p_schema_files.empty()) {
    2900          158 :       k_close_schema(p_schema_files.begin()->second);
    2901              :     }
    2902          174 :   }
    2903              : 
    2904          174 :   TLOG_DEBUG(4) << "exit";
    2905          174 : }
    2906              : 
    2907              : void
    2908            0 : OksKernel::set_active_schema(OksFile * f)
    2909              : {
    2910            0 :   std::unique_lock lock(p_kernel_mutex);
    2911            0 :   k_set_active_schema(f);
    2912            0 : }
    2913              : 
    2914              : void
    2915            0 : OksKernel::k_set_active_schema(OksFile * f)
    2916              : {
    2917            0 :   TLOG_DEBUG(4) << "enter for file " << (void *)f;
    2918              : 
    2919              :     // check if active schema is different from given file
    2920              : 
    2921            0 :   if(p_active_schema == f) return;
    2922              : 
    2923              : 
    2924              :     // unlock current active schema, if it was saved
    2925              : 
    2926            0 :   if(p_active_schema && p_active_schema->is_updated() == false) {
    2927            0 :     try {
    2928            0 :       p_active_schema->unlock();
    2929              :     }
    2930            0 :     catch(exception& ex) {
    2931            0 :       throw CanNotSetActiveFile("schema", f->get_full_file_name(), ex);
    2932            0 :     }
    2933              :   }
    2934              : 
    2935              : 
    2936              :     // exit, if file is (null)
    2937              : 
    2938            0 :   if(!f) {
    2939            0 :     p_active_schema = 0;
    2940            0 :     return;    
    2941              :   }
    2942              : 
    2943            0 :   try {
    2944            0 :     f->lock();
    2945            0 :     p_active_schema = f;
    2946              :   }
    2947            0 :   catch(exception& ex) {
    2948            0 :     throw CanNotSetActiveFile("schema", f->get_full_file_name(), ex);
    2949            0 :   }
    2950              : 
    2951            0 :   TLOG_DEBUG(4) << "exit for file " << (void *)f;
    2952              : }
    2953              : 
    2954              : std::list<OksClass *> *
    2955            0 : OksKernel::create_list_of_schema_classes(OksFile * pf) const
    2956              : {
    2957            0 :   std::string fname("OksKernel::create_list_of_schema_classes(");
    2958            0 :   fname.append(pf->get_full_file_name());
    2959            0 :   fname.push_back('\'');
    2960              : 
    2961            0 :   OSK_PROFILING(OksProfiler::KernelCreateSchemaClassList, this)
    2962            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    2963              : 
    2964            0 :   std::list<OksClass *> * clist = nullptr;
    2965              : 
    2966            0 :   if(!p_classes.empty()) {
    2967            0 :     for(OksClass::Map::const_iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    2968            0 :       if(pf == i->second->p_file) {
    2969            0 :         if(!clist && !(clist = new std::list<OksClass *>())) {
    2970              :           return 0;
    2971              :         }
    2972              : 
    2973            0 :         clist->push_back(i->second);
    2974              :       }
    2975              :     }
    2976              :   }
    2977              : 
    2978            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    2979              : 
    2980            0 :   return clist;
    2981            0 : }
    2982              : 
    2983              : /******************************************************************************/
    2984              : 
    2985              : static void
    2986            6 : create_updated_lists(const OksFile::Map& files, std::list<OksFile *> ** ufs, std::list<OksFile *> ** rfs, OksFile::FileStatus wu, OksFile::FileStatus wr)
    2987              : {
    2988            6 :   *ufs = 0;  // updated files
    2989            6 :   *rfs = 0;  // removed files
    2990              : 
    2991           12 :   for(OksFile::Map::const_iterator i = files.begin(); i != files.end(); ++i) {
    2992            6 :     OksFile::FileStatus fs = i->second->get_status_of_file();
    2993              : 
    2994            6 :     if(fs == wu /* i.e. Which Updated */ ) {
    2995            0 :       if(*ufs == 0) { *ufs = new std::list<OksFile *>(); }
    2996            0 :       (*ufs)->push_back(i->second);
    2997              :     }
    2998            6 :     else if(fs == wr /* i.e. Which Removed */ ) {
    2999            0 :       if(*rfs == 0) { *rfs = new std::list<OksFile *>(); }
    3000            0 :       (*rfs)->push_back(i->second);
    3001              :     }
    3002              :   }
    3003            6 : }
    3004              : 
    3005              : void
    3006            3 : OksKernel::create_lists_of_updated_schema_files(std::list<OksFile *> ** ufs, std::list<OksFile *> ** rfs) const
    3007              : {
    3008            3 :   std::shared_lock lock(p_kernel_mutex);
    3009              : 
    3010            3 :   create_updated_lists(p_schema_files, ufs, rfs, OksFile::FileModified, OksFile::FileRemoved);
    3011            3 : }
    3012              : 
    3013              : void
    3014            3 : OksKernel::create_lists_of_updated_data_files(std::list<OksFile *> ** ufs, std::list<OksFile *> ** rfs) const
    3015              : {
    3016            3 :   std::shared_lock lock(p_kernel_mutex);
    3017              : 
    3018            3 :   create_updated_lists(p_data_files, ufs, rfs, OksFile::FileModified, OksFile::FileRemoved);
    3019            3 : }
    3020              : 
    3021              : void
    3022            3 : OksKernel::get_modified_files(std::set<OksFile *>& mfs, std::set<OksFile *>& rfs, const std::string& version)
    3023              : {
    3024            3 :   std::list<OksFile *> * files[] =
    3025              :     { nullptr, nullptr, nullptr, nullptr };
    3026              : 
    3027            3 :   std::set<OksFile *> * sets[] =
    3028            3 :     { &mfs, &rfs };
    3029              : 
    3030            3 :   create_lists_of_updated_data_files(&files[0], &files[1]);
    3031            3 :   create_lists_of_updated_schema_files(&files[2], &files[3]);
    3032              : 
    3033           15 :   for (int i = 0; i < 4; ++i)
    3034           12 :     if (std::list<OksFile *> * f = files[i])
    3035              :       {
    3036            0 :         while (!f->empty())
    3037              :           {
    3038            0 :             sets[i % 2]->insert(f->front());
    3039            0 :             f->pop_front();
    3040              :           }
    3041            0 :         delete f;
    3042              :       }
    3043              : 
    3044            3 :   if (!get_user_repository_root().empty() && !version.empty())
    3045            0 :     for (const auto& file_name : get_repository_versions_diff(get_repository_version(), version))
    3046              :       {
    3047            0 :         if (OksFile * f = find_data_file(file_name))
    3048            0 :           sets[0]->insert(f);
    3049            0 :         else if (OksFile * f = find_schema_file(file_name))
    3050            0 :           sets[0]->insert(f);
    3051            0 :       }
    3052            3 : }
    3053              : 
    3054              : /******************************************************************************/
    3055              : 
    3056              : 
    3057            0 :   void LoadErrors::add_parents(std::string& text, const OksFile * file, std::set<const OksFile *>& parents)
    3058              :   {
    3059            0 :     if(file) {
    3060            0 :       if(parents.insert(file).second == false) {
    3061            0 :         text += "(ignoring circular dependency between included files...)\n";
    3062              :       }
    3063              :       else {
    3064            0 :         add_parents(text, file->get_parent(), parents);
    3065            0 :         text += "file \'";
    3066            0 :         text += file->get_full_file_name();
    3067            0 :         text += "\' includes:\n";
    3068              :       }
    3069              :     }
    3070            0 :   }
    3071              : 
    3072            0 :   void LoadErrors::add_error(const OksFile& file, std::exception& ex)
    3073              :   {
    3074            0 :     std::string text;
    3075            0 :     std::set<const OksFile *> parents;
    3076            0 :     add_parents(text, file.get_parent(), parents);
    3077              : 
    3078            0 :     bool has_no_parents(text.empty());
    3079              : 
    3080            0 :     text += "file \'";
    3081            0 :     text += file.get_full_file_name();
    3082            0 :     text += (has_no_parents ? "\' has problem:\n" : "\' that has problem:\n");
    3083            0 :     text += ex.what();
    3084              : 
    3085            0 :     std::lock_guard lock(p_mutex);
    3086            0 :     m_errors.push_back(text);
    3087            0 :   }
    3088              : 
    3089            0 :   std::string LoadErrors::get_text()
    3090              :   {
    3091            0 :     std::lock_guard lock(p_mutex);
    3092              : 
    3093            0 :     {
    3094            0 :       std::ostringstream s;
    3095              : 
    3096            0 :       if(m_errors.size() == 1) {
    3097            0 :         s << "Found 1 error parsing OKS data:\n" << *m_errors.begin();
    3098              :       }
    3099              :       else {
    3100            0 :         s << "Found " << m_errors.size() << " errors parsing OKS data:";
    3101            0 :         int j = 1;
    3102            0 :         for(std::list<std::string>::const_iterator i = m_errors.begin(); i != m_errors.end(); ++i) {
    3103            0 :           s << "\nERROR [" << j++ << "] ***: " << *i; 
    3104              :         }
    3105              :       }
    3106              : 
    3107            0 :       m_error_string = s.str();
    3108            0 :     }
    3109              : 
    3110            0 :     return m_error_string;
    3111            0 :   }
    3112              : 
    3113              : 
    3114              : 
    3115              : struct OksLoadObjectsJob : public OksJob
    3116              : {
    3117              :   public:
    3118              : 
    3119          125 :     OksLoadObjectsJob( OksKernel * kernel, OksFile * fp, std::shared_ptr<OksXmlInputStream> xmls, char format)
    3120          125 :       : m_kernel (kernel),
    3121          125 :         m_fp     (fp),
    3122          125 :         m_xmls   (xmls),
    3123          125 :         m_format (format)
    3124          125 :     { ; }       
    3125              : 
    3126              : 
    3127          125 :     void run()
    3128              :     {
    3129          125 :       try {
    3130          125 :         OksAliasTable alias_table;
    3131          125 :         ReadFileParams read_params( m_fp, *m_xmls, ((m_format == 'X') ? 0 : &alias_table), m_kernel, m_format, 0 );
    3132              : 
    3133          125 :         m_fp->p_number_of_items = 0;
    3134              : 
    3135          125 :         try {
    3136         5073 :           while(OksObject::read(read_params)) {
    3137         4948 :             m_fp->p_number_of_items++;
    3138              :           }
    3139              :         }
    3140            0 :         catch(FailedCreateObject & ex) {
    3141            0 :           m_kernel->p_load_errors.add_error(*m_fp, ex);
    3142            0 :           return;
    3143            0 :         }
    3144              : 
    3145          125 :         m_fp->p_size = m_xmls->get_position();
    3146          125 :       }
    3147            0 :       catch (std::exception& ex) {
    3148            0 :         m_kernel->p_load_errors.add_error(*m_fp, ex);
    3149            0 :       }
    3150              :     }
    3151              : 
    3152              : 
    3153              :   private:
    3154              : 
    3155              :     OksKernel * m_kernel;
    3156              :     OksFile * m_fp;
    3157              :     std::shared_ptr<OksXmlInputStream> m_xmls;
    3158              :     char m_format;
    3159              : 
    3160              : 
    3161              :       // protect usage of copy constructor and assignment operator
    3162              : 
    3163              :   private:
    3164              : 
    3165              :     OksLoadObjectsJob(const OksLoadObjectsJob&);
    3166              :     OksLoadObjectsJob& operator=(const OksLoadObjectsJob &);
    3167              : 
    3168              : };
    3169              : 
    3170              : /******************************************************************************/
    3171              : 
    3172            0 : static bool _find_file(const OksFile::Map & files, const OksFile * f)
    3173              : {
    3174            0 :   for(OksFile::Map::const_iterator i = files.begin(); i != files.end(); ++i) {
    3175            0 :     if(i->second == f) return true;
    3176              :   }
    3177            0 :   return false;
    3178              : }
    3179              : 
    3180              : void
    3181            0 : ReloadObjects::put(OksObject * o)
    3182              : {
    3183            0 :   map_str_t<OksObject *> *& c = data[o->uid.class_id];
    3184            0 :   if(!c) c = new map_str_t<OksObject *>();
    3185            0 :   (*c)[o->GetId()] = o;
    3186            0 : }
    3187              : 
    3188              : OksObject *
    3189            0 : ReloadObjects::pop(const OksClass* c, const std::string& id)
    3190              : {
    3191            0 :   std::map< const OksClass *, map_str_t<OksObject *> * >::iterator i = data.find(c);
    3192            0 :   if(i != data.end()) {
    3193            0 :     map_str_t<OksObject *>::iterator j = i->second->find(id);
    3194            0 :     if(j != i->second->end()) {
    3195            0 :       OksObject * o = j->second;
    3196            0 :       i->second->erase(j);
    3197            0 :       if(i->second->empty()) {
    3198            0 :         delete i->second;
    3199            0 :         data.erase(i);
    3200              :       }
    3201            0 :       return o;
    3202              :     }
    3203              :   }
    3204              : 
    3205              :   return 0;
    3206              : }
    3207              : 
    3208            0 : ReloadObjects::~ReloadObjects()
    3209              : {
    3210            0 :   for(std::map< const OksClass *, map_str_t<OksObject *> * >::iterator i = data.begin(); i != data.end(); ++i) {
    3211            0 :     delete i->second;
    3212              :   }
    3213            0 : }
    3214              : 
    3215              : void
    3216            0 : OksKernel::reload_data(std::set<OksFile *>& files_h, bool allow_schema_extension)
    3217              : {
    3218            0 :   std::map<OksFile *, std::vector<std::string> > included;
    3219              : 
    3220            0 :   std::set<OksFile *>::const_iterator i;
    3221              : 
    3222            0 :   bool check_includes(false);
    3223            0 :   bool found_schema_files(false);
    3224            0 :   std::string file_names;
    3225              : 
    3226            0 :   std::unique_lock lock(p_kernel_mutex);
    3227              : 
    3228            0 :   for(std::set<OksFile *>::const_iterator fi = files_h.begin(); fi != files_h.end();) {
    3229            0 :     if(_find_file(p_schema_files, *fi)) {
    3230              :       found_schema_files = true;
    3231              :     }
    3232            0 :     else if(!_find_file(p_data_files, *fi)) {
    3233            0 :       Oks::error_msg("OksKernel::reload_data") << "file " << (void *)(*fi) << " is not OKS data or schema file, skip..." << std::endl;
    3234            0 :       files_h.erase(fi++);
    3235            0 :       continue;
    3236              :     }
    3237              : 
    3238            0 :     if(fi != files_h.begin()) file_names.append(", ");
    3239            0 :     file_names.push_back('\"');
    3240            0 :     file_names.append((*fi)->get_full_file_name());
    3241            0 :     file_names.push_back('\"');
    3242            0 :     ++fi;
    3243              :   }
    3244              : 
    3245            0 :   try {
    3246              : 
    3247              :       // throw exception on schema_files
    3248              : 
    3249            0 :     if(found_schema_files) {
    3250            0 :       throw std::runtime_error("Reload of modified schema files is not supported");
    3251              :     }
    3252              : 
    3253              :       // exit, if there are no files to reload (e.g. dangling refs.)
    3254              : 
    3255            0 :     if(files_h.empty()) return;
    3256              : 
    3257              : 
    3258              :       // unlock any locked file
    3259              :       // build container of objects which can be updated (and removed, if not reloaded)
    3260              : 
    3261            0 :     ReloadObjects reload_objects;
    3262              : 
    3263            0 :     for(i = files_h.begin(); i != files_h.end(); ++i) {
    3264            0 :       if((*i)->is_locked()) {
    3265            0 :         if(p_active_data == (*i)) { p_active_data = 0; }
    3266            0 :         (*i)->unlock();
    3267              :       }
    3268              : 
    3269            0 :       for(OksObject::Set::const_iterator oi = p_objects.begin(); oi != p_objects.end(); ++oi) {
    3270            0 :         if((*oi)->file == *i) reload_objects.put(*oi);
    3271              :       }
    3272              :     }
    3273              : 
    3274              : 
    3275              :       // preload includes of modified files
    3276              : 
    3277            0 :     {
    3278            0 :       std::set<OksFile *> new_files;
    3279              : 
    3280            0 :       for(i = files_h.begin(); i != files_h.end(); ++i) {
    3281            0 :         try {
    3282            0 :           check_includes |= k_preload_includes(*i, new_files, allow_schema_extension);
    3283              :         }
    3284            0 :         catch(...) {
    3285            0 :           restore_preload_file_info();
    3286            0 :           throw;
    3287            0 :         }
    3288              :       }
    3289              : 
    3290            0 :       clear_preload_file_info();
    3291              : 
    3292            0 :       if(!new_files.empty()) {
    3293            0 :         TLOG_DEBUG(2) << new_files.size() << " new files will be loaded";
    3294              :       }
    3295              : 
    3296            0 :       for(i = new_files.begin(); i != new_files.end(); ++i) {
    3297            0 :         files_h.insert(*i);
    3298              :       }
    3299            0 :     }
    3300              : 
    3301              :       // build list of files to be closed:
    3302              :       // close files which are no more referenced by others
    3303              :       // this may happen if there are changes in the list of includes
    3304              : 
    3305            0 :     std::set<OksFile *> files_to_be_closed;
    3306              : 
    3307            0 :     if(check_includes) {
    3308              :       size_t num_of_closing_files = 0;
    3309              : 
    3310            0 :       while(true) {
    3311              : 
    3312              :           // build list of good (i.e. "included") files
    3313              :           // rebuild the list, if at least one file was excluded
    3314              : 
    3315            0 :         std::map<std::string, OksFile *> good_files;
    3316              :     
    3317            0 :         for(OksFile::Map::iterator j = p_data_files.begin(); j != p_data_files.end(); ++j) {
    3318            0 :           if(files_to_be_closed.find(j->second) == files_to_be_closed.end()) {
    3319            0 :             for(std::list<std::string>::iterator l = j->second->p_list_of_include_files.begin(); l != j->second->p_list_of_include_files.end(); ++l) {
    3320            0 :               try {
    3321            0 :                 good_files[get_file_path(*l, j->second)] = j->second;
    3322              :               }
    3323            0 :               catch (...) {
    3324            0 :               }
    3325              :             }
    3326              :           }
    3327              :         }
    3328              : 
    3329            0 :         for(OksFile::Map::iterator i = p_data_files.begin(); i != p_data_files.end(); ) {
    3330            0 :           if(i->second->p_included_by && files_to_be_closed.find(i->second) == files_to_be_closed.end()) {
    3331            0 :             TLOG_DEBUG(3) << "check the file \'" << i->second->get_full_file_name() << "\' is included";
    3332            0 :             const std::string& s = i->second->get_full_file_name();
    3333            0 :             OksFile * f2 = i->second;
    3334            0 :             ++i;
    3335              : 
    3336            0 :             f2->p_included_by = 0;
    3337              : 
    3338              :               // search for a file which could include given one
    3339              : 
    3340            0 :             std::map<std::string, OksFile *>::const_iterator j = good_files.find(s);
    3341              : 
    3342            0 :             if(j != good_files.end()) {
    3343            0 :               f2->p_included_by = j->second;
    3344              :             }
    3345              :             else {
    3346            0 :               files_to_be_closed.insert(f2);
    3347              : 
    3348            0 :               for(OksObject::Set::const_iterator oi = p_objects.begin(); oi != p_objects.end(); ++oi) {
    3349            0 :                 if((*oi)->file == f2) {
    3350            0 :                   reload_objects.put(*oi); 
    3351              :                 }
    3352              :               }
    3353              : 
    3354            0 :               if (files_h.erase(f2)) {
    3355            0 :                 TLOG_DEBUG(2) << "skip reload of updated file \'" << f2->get_full_file_name() << " since it will be closed";
    3356              :               }
    3357              : 
    3358            0 :               TLOG_DEBUG(3) << "file \'" << f2->get_full_file_name() << " will be closed";
    3359              :             }
    3360              :           }
    3361              :           else {
    3362            0 :             ++i;
    3363              :           }
    3364              :         }
    3365              : 
    3366            0 :         if(num_of_closing_files == files_to_be_closed.size()) {
    3367              :           break;
    3368              :         }
    3369              :         else {
    3370            0 :           num_of_closing_files = files_to_be_closed.size();
    3371              :         }
    3372            0 :       }
    3373              :     }
    3374              :     else {
    3375            0 :       TLOG_DEBUG(2) << "no changes in the list of includes";
    3376              :     }
    3377              : 
    3378              :       // remove exclusive RCRs (will be restored when read, if object was not changed)
    3379              : 
    3380            0 :     {
    3381            0 :       for(std::map< const OksClass *, map_str_t<OksObject *> * >::const_iterator cx = reload_objects.data.begin(); cx != reload_objects.data.end(); ++cx) {
    3382            0 :         const OksClass * c(cx->first);
    3383            0 :         if(c->p_all_relationships && !c->p_all_relationships->empty()) {
    3384            0 :           const unsigned int atts_num(c->number_of_all_attributes());
    3385            0 :           for(map_str_t<OksObject *>::const_iterator j = cx->second->begin(); j != cx->second->end(); ++j) {
    3386            0 :             OksObject * obj = j->second;
    3387            0 :             OksData * d(obj->data + atts_num);
    3388              : 
    3389            0 :             for(std::list<OksRelationship *>::iterator i = c->p_all_relationships->begin(); i != c->p_all_relationships->end(); ++i, ++d) {
    3390            0 :               OksRelationship * r = *i;
    3391            0 :               if(r->get_is_composite() && r->get_is_exclusive()) {
    3392            0 :                 if(d->type == OksData::object_type && d->data.OBJECT) {
    3393            0 :                   if(!is_dangling(d->data.OBJECT)) {
    3394            0 :                     d->data.OBJECT->remove_RCR(obj, r);
    3395              :                   }
    3396              :                 }
    3397            0 :                 else if(d->type == OksData::list_type && d->data.LIST) {
    3398            0 :                   for(OksData::List::iterator i2 = d->data.LIST->begin(); i2 != d->data.LIST->end(); ++i2) {
    3399            0 :                     OksData *d2(*i2);
    3400            0 :                     if(d2->type == OksData::object_type && d2->data.OBJECT) {
    3401            0 :                       if(!is_dangling(d2->data.OBJECT)) {
    3402            0 :                         d2->data.OBJECT->remove_RCR(obj, r);
    3403              :                       }
    3404              :                     }
    3405              :                   }
    3406              :                 }
    3407              :               }
    3408              :             }       
    3409              :           }
    3410              :         }
    3411              :       }
    3412              :     }
    3413              : 
    3414              :       // need to allow "duplicated_objects_via_inheritance_mode", since the objects with the same ID can be created and removed
    3415              : 
    3416            0 :     bool duplicated_objs_mode = get_test_duplicated_objects_via_inheritance_mode();
    3417            0 :     set_test_duplicated_objects_via_inheritance_mode(false);
    3418              : 
    3419              : 
    3420              :       // read objects
    3421              : 
    3422            0 :     for(i = files_h.begin(); i != files_h.end(); ++i) {
    3423            0 :       std::shared_ptr<std::ifstream> f(new std::ifstream((*i)->get_full_file_name().c_str()));
    3424              : 
    3425            0 :       std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    3426              : 
    3427            0 :       OksFile fp(xmls, (*i)->get_short_file_name(), (*i)->get_full_file_name(), this);
    3428            0 :       char format = (fp.p_oks_format == "data" ? 'n' : ((fp.p_oks_format == "extended") ? 'X': 'c'));
    3429              : 
    3430            0 :       if(!p_silence) {
    3431            0 :         std::lock_guard lock(p_parallel_out_mutex);
    3432            0 :         std::cout << " * reading data file \"" << (*i)->get_full_file_name() << "\"..." << std::endl;
    3433            0 :       }
    3434              : 
    3435            0 :       {
    3436            0 :         OksAliasTable alias_table;
    3437            0 :         ReadFileParams read_params( *i, *xmls, ((format == 'X') ? 0 : &alias_table), this, format, &reload_objects );
    3438              : 
    3439              :         try {
    3440            0 :           while(OksObject::read(read_params)) { ; }
    3441              :         }
    3442            0 :         catch(FailedCreateObject & ex) {
    3443            0 :           set_test_duplicated_objects_via_inheritance_mode(duplicated_objs_mode);
    3444            0 :           throw ex;
    3445            0 :         }
    3446            0 :       }
    3447              : 
    3448            0 :       (*i)->update_status_of_file();
    3449            0 :       (*i)->p_is_updated = false;
    3450            0 :     }
    3451              : 
    3452            0 :     set_test_duplicated_objects_via_inheritance_mode(duplicated_objs_mode);
    3453              : 
    3454              : 
    3455              :       // remove objects which were not re-read
    3456              : 
    3457            0 :     OksObject::FSet oset;
    3458              : 
    3459            0 :     {
    3460            0 :       for(std::map< const OksClass *, map_str_t<OksObject *> * >::const_iterator cx = reload_objects.data.begin(); cx != reload_objects.data.end(); ++cx) {
    3461            0 :         for(map_str_t<OksObject *>::const_iterator ox = cx->second->begin(); ox != cx->second->end(); ++ox) {
    3462            0 :           oset.insert(ox->second);
    3463              :         }
    3464              :       }
    3465              : 
    3466              : #ifndef ERS_NO_DEBUG
    3467            0 :       if(ers::debug_level() >= 3) {
    3468            0 :         std::ostringstream text;
    3469            0 :         text << "there are " << oset.size() << " removed objects:\n";
    3470              : 
    3471            0 :         for(OksObject::FSet::iterator x = oset.begin(); x != oset.end(); ++x) {
    3472            0 :           text << " - object " << *x << std::endl;
    3473            0 :           TLOG_DEBUG(3) << text.str();
    3474              :         }
    3475            0 :       }
    3476              : #endif
    3477              : 
    3478            0 :       {
    3479            0 :         OksObject::FSet refs;
    3480            0 :         unbind_all_rels(oset, refs);
    3481            0 :         if(p_change_object_notify_fn) {
    3482            0 :           for(OksObject::FSet::const_iterator x2 = refs.begin(); x2 != refs.end(); ++x2) {
    3483            0 :             TLOG_DEBUG(3) << "*** add object " << *x2 << " to the list of updated *** ";
    3484            0 :             (*p_change_object_notify_fn)(*x2, p_change_object_notify_param);
    3485              :           }
    3486              :         }
    3487            0 :       }
    3488              :     }
    3489              : 
    3490            0 :     for(OksObject::FSet::iterator ox = oset.begin(); ox != oset.end(); ++ox) {
    3491            0 :       OksObject * o = *ox;
    3492              : 
    3493            0 :       if(is_dangling(o)) {
    3494            0 :         TLOG_DEBUG(4) << "skip dangling object " << (void *)o;
    3495            0 :         continue;
    3496            0 :       }
    3497              : 
    3498            0 :       TLOG_DEBUG(3) << "*** remove non-reloaded object " << o << " => " << (void *)o << " ***";
    3499              : 
    3500            0 :       delete o;
    3501              :     }
    3502              : 
    3503              : 
    3504            0 :     for(std::set<OksFile *>::const_iterator x = files_to_be_closed.begin(); x != files_to_be_closed.end(); ++x) {
    3505            0 :       k_close_data(*x, true);
    3506              :     }
    3507              : 
    3508            0 :     k_bind_objects();
    3509              : 
    3510              : 
    3511              :     // check that created objects do not have duplicated IDs within inheritance hierarchy
    3512              : 
    3513            0 :     if (duplicated_objs_mode == true)
    3514              :       {
    3515            0 :         for (auto& o : reload_objects.created)
    3516              :           {
    3517            0 :             o->check_ids();
    3518              :           }
    3519              :       }
    3520            0 :   }
    3521            0 :   catch (exception & e) {
    3522            0 :     throw FailedReloadFile(file_names, e);
    3523            0 :   }
    3524            0 :   catch (std::exception & e) {
    3525            0 :     throw FailedReloadFile(file_names, e.what());
    3526            0 :   }
    3527            0 : }
    3528              : 
    3529              : void
    3530            0 : OksKernel::clear_preload_file_info()
    3531              : {
    3532            0 :   for(std::map<const OksFile *, OksFile *>::iterator i = p_preload_file_info.begin(); i != p_preload_file_info.end(); ++i) {
    3533            0 :     delete i->second;
    3534              :   }
    3535              : 
    3536            0 :   p_preload_file_info.clear();
    3537            0 :   p_preload_added_files.clear();
    3538            0 : }
    3539              : 
    3540              : void
    3541            0 : OksKernel::restore_preload_file_info()
    3542              : {
    3543            0 :   for(std::vector<OksFile *>::iterator j = p_preload_added_files.begin(); j != p_preload_added_files.end(); ++j) {
    3544            0 :     TLOG_DEBUG( 1 ) << "remove file " << (*j)->get_full_file_name() ;
    3545            0 :     remove_data_file(*j);
    3546            0 :     delete *j;
    3547              :   }
    3548              : 
    3549            0 :   for(OksFile::Map::iterator i = p_data_files.begin(); i != p_data_files.end(); ++i) {
    3550            0 :     std::map<const OksFile *, OksFile *>::iterator j = p_preload_file_info.find(i->second);
    3551            0 :     if(j != p_preload_file_info.end()) {
    3552            0 :       TLOG_DEBUG( 1 ) << "restore file " << i->second->get_full_file_name() ;
    3553            0 :       (*i->second) = (*j->second);
    3554              :     }
    3555              :   }
    3556              : 
    3557            0 :   clear_preload_file_info();
    3558            0 : }
    3559              : 
    3560              : 
    3561              :   // user-allowed method
    3562              : 
    3563              : OksFile *
    3564            0 : OksKernel::load_data(const std::string& short_file_name, bool bind)
    3565              : {
    3566            0 :   std::unique_lock lock(p_kernel_mutex);
    3567            0 :   return k_load_data(short_file_name, bind, 0, 0);
    3568            0 : }
    3569              : 
    3570              : 
    3571              :   // kernel method
    3572              : 
    3573              : OksFile *
    3574            0 : OksKernel::k_load_data(const std::string& short_file_name, bool bind, const OksFile * parent_h, OksPipeline * pipeline)
    3575              : {
    3576            0 :   const char _fname[] = "k_load_data";
    3577            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, short_file_name, &bind, &parent_h);
    3578              : 
    3579            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    3580              : 
    3581            0 :   std::string full_file_name;
    3582              : 
    3583            0 :   try {
    3584            0 :     full_file_name = get_file_path(short_file_name, parent_h);
    3585              :   }
    3586            0 :   catch (std::exception & e) {
    3587            0 :     throw CanNotOpenFile("k_load_data", short_file_name, e.what());
    3588            0 :   }
    3589              : 
    3590            0 :   try {
    3591              : 
    3592            0 :     OksFile *fp = find_data_file(full_file_name);
    3593              : 
    3594            0 :     if(fp != 0) {
    3595            0 :       if(p_verbose) {
    3596            0 :         std::lock_guard lock(p_parallel_out_mutex);
    3597            0 :         Oks::warning_msg(fname) << "  The file \'" << full_file_name << "\' was already loaded";
    3598            0 :       }
    3599            0 :       return fp->check_parent(parent_h);
    3600              :     }
    3601              : 
    3602            0 :     {
    3603            0 :       std::shared_ptr<std::ifstream> f(new std::ifstream(full_file_name.c_str()));
    3604              : 
    3605            0 :       if(!f->good()) {
    3606            0 :         throw std::runtime_error("k_load_data(): cannot open file");
    3607              :       }
    3608              : 
    3609            0 :       long file_length(get_file_length(*f));
    3610              :       
    3611            0 :       if(!file_length) {
    3612            0 :         throw std::runtime_error("k_load_data(): file is empty");
    3613              :       }
    3614              : 
    3615            0 :       std::shared_ptr<OksXmlInputStream> xmls(new OksXmlInputStream(f));
    3616              : 
    3617            0 :       fp = new OksFile(xmls, short_file_name, full_file_name, this);
    3618              : 
    3619            0 :       if(fp->p_oks_format.empty()) {
    3620            0 :         throw std::runtime_error("k_load_data(): failed to read header of file");
    3621              :       }
    3622              : 
    3623            0 :       char format;
    3624              : 
    3625            0 :       if(fp->p_oks_format.size() == 4 && cmp_str4n(fp->p_oks_format.c_str(), "data"))
    3626              :         format = 'n';
    3627            0 :       else if(fp->p_oks_format.size() == 8 && cmp_str8n(fp->p_oks_format.c_str(), "extended"))
    3628              :         format = 'X';
    3629            0 :       else if(fp->p_oks_format.size() == 7 && cmp_str7n(fp->p_oks_format.c_str(), "compact"))
    3630              :         format = 'c';
    3631              :       else {
    3632            0 :         throw std::runtime_error("k_load_data(): file is not an oks data file");
    3633              :       }
    3634              : 
    3635            0 :       k_load_data(fp, format, xmls, file_length, bind, parent_h, pipeline);
    3636              : 
    3637            0 :       OSK_VERBOSE_REPORT("LEAVE " << fname)
    3638              : 
    3639            0 :       return fp;
    3640            0 :     }
    3641              :   }
    3642            0 :   catch (FailedLoadFile&) {
    3643            0 :     throw;
    3644            0 :   }
    3645            0 :   catch (exception & e) {
    3646            0 :     throw (FailedLoadFile("data file", full_file_name, e));
    3647            0 :   }
    3648            0 :   catch (std::exception & e) {
    3649            0 :     throw (FailedLoadFile("data file", full_file_name, e.what()));
    3650            0 :   }
    3651            0 : }
    3652              : 
    3653              : 
    3654              : void
    3655          125 : OksKernel::k_load_data(OksFile * fp, char format, std::shared_ptr<OksXmlInputStream> xmls, long file_length, bool bind, const OksFile * parent_h, OksPipeline * pipeline)
    3656              : {
    3657          125 :   OSK_PROFILING(OksProfiler::KernelLoadData, this)
    3658              : 
    3659          125 :   fp->p_included_by = parent_h;
    3660          125 :   check_read_only(fp);
    3661              : 
    3662          125 :   try {
    3663          125 :     if(!p_silence) {
    3664            0 :       std::lock_guard lock(p_parallel_out_mutex);
    3665            0 :       std::cout << (parent_h ? " * r" : "R") << "eading data file \"" << fp->get_full_file_name()
    3666            0 :                 << "\" in " << (format == 'n' ? "normal" : (format == 'X' ? "extended" : "compact")) << " format (" << file_length << " bytes)...\n";
    3667            0 :       if(parent_h == 0 && fp->get_full_file_name() != fp->get_short_file_name()) {
    3668            0 :         std::cout << "(non-fully-qualified filename was \"" << fp->get_short_file_name() << "\")\n";
    3669              :       }
    3670            0 :     }
    3671              : 
    3672          125 :     fp->update_status_of_file();
    3673          125 :     add_data_file(fp);
    3674              : 
    3675          125 :     {
    3676          125 :       std::unique_ptr<OksPipeline> pipeline_guard(pipeline ? 0 : new OksPipeline(p_threads_pool_size));
    3677              : 
    3678          125 :       OksPipeline * m_pipeline;
    3679              : 
    3680          125 :       if(pipeline) {
    3681              :         m_pipeline = pipeline;
    3682              :       }
    3683              :       else {
    3684           82 :         m_pipeline = pipeline_guard.get();
    3685           82 :         p_load_errors.clear();
    3686              :       }
    3687              : 
    3688          125 :       k_load_includes(*fp, m_pipeline);
    3689              : 
    3690              : 
    3691          125 :       if(p_threads_pool_size > 1) {
    3692          125 :         m_pipeline->addJob( new OksLoadObjectsJob( this, fp, xmls, format) );
    3693              :       }
    3694              :       else {
    3695            0 :         OksLoadObjectsJob job(this, fp, xmls, format);
    3696            0 :         job.run();
    3697            0 :       }
    3698          125 :     }
    3699              : 
    3700          125 :     if(!pipeline) {
    3701           82 :       if(!p_load_errors.is_empty()) {
    3702            0 :         throw (FailedLoadFile("data file", fp->get_full_file_name(), p_load_errors.get_text()));
    3703              :       }
    3704              : 
    3705           82 :       if(bind) {
    3706           82 :         k_bind_objects();
    3707              :       }
    3708              :     }
    3709              :   }
    3710            0 :   catch (FailedLoadFile&) {
    3711            0 :     throw;
    3712            0 :   }
    3713            0 :   catch (exception& e) {
    3714            0 :     throw (FailedLoadFile("data file", fp->get_full_file_name(), e));
    3715            0 :   }
    3716            0 :   catch (std::exception& e) {
    3717            0 :     throw (FailedLoadFile("data file", fp->get_full_file_name(), e.what()));
    3718            0 :   }
    3719          125 : }
    3720              : 
    3721              : 
    3722              : OksFile *
    3723            5 : OksKernel::new_data(const std::string& s, const std::string& logical_name, const std::string& type)
    3724              : {
    3725            5 :   const char _fname[] = "new_data";
    3726            5 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, s, nullptr, nullptr);
    3727            5 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    3728              : 
    3729            5 :   if(!s.length()) {
    3730            0 :     throw CanNotOpenFile("new_data", s, "file name is empty");
    3731              :   }
    3732              : 
    3733            5 :   std::string file_name(s);
    3734              : 
    3735            5 :   try {
    3736              : 
    3737            5 :     Oks::substitute_variables(file_name);
    3738              : 
    3739            5 :     test_file_existence(file_name, p_silence, fname, "data");
    3740              : 
    3741            5 :     file_name = get_file_path(s, nullptr, false);
    3742              : 
    3743            5 :     std::unique_lock lock(p_kernel_mutex);
    3744              : 
    3745            5 :     if(find_data_file(file_name) != 0) {
    3746            0 :       throw std::runtime_error("the file is already loaded");
    3747              :     }
    3748              : 
    3749            5 :     OksFile * file_h = new OksFile(file_name, logical_name, type, "data", this);
    3750              : 
    3751            5 :     file_h->p_short_name = s;
    3752              : 
    3753            5 :     k_set_active_data(file_h);
    3754              : 
    3755            5 :     add_data_file(p_active_data);
    3756              : 
    3757            5 :   }
    3758            0 :   catch (exception & e) {
    3759            0 :     throw CanNotCreateFile("new_data", "data file", file_name, e);
    3760            0 :   }
    3761            0 :   catch (std::exception & e) {
    3762            0 :     throw CanNotCreateFile("new_data", "data file", file_name, e.what());
    3763            0 :   }
    3764              : 
    3765            5 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    3766              : 
    3767            5 :   return p_active_data;
    3768            5 : }
    3769              : 
    3770              : 
    3771              : void
    3772          130 : OksKernel::add_data_file(OksFile * f)
    3773              : {
    3774          130 :   p_data_files[&f->p_full_name] = f;
    3775          130 : }
    3776              : 
    3777              : void
    3778          158 : OksKernel::add_schema_file(OksFile * f)
    3779              : {
    3780          158 :   p_schema_files[&f->p_full_name] = f;
    3781          158 : }
    3782              : 
    3783              : void
    3784          130 : OksKernel::remove_data_file(OksFile * f)
    3785              : {
    3786          130 :   p_data_files.erase(&f->p_full_name);
    3787          130 : }
    3788              : 
    3789              : void
    3790          158 : OksKernel::remove_schema_file(OksFile * f)
    3791              : {
    3792          158 :   p_schema_files.erase(&f->p_full_name);
    3793          158 : }
    3794              : 
    3795              : 
    3796              :   // user-allowed method
    3797              : 
    3798              : void
    3799            0 : OksKernel::save_data(OksFile * pf, bool ignoreBadObjects, OksFile * true_file_h, bool force_defaults)
    3800              : {
    3801            0 :   std::shared_lock lock(p_kernel_mutex);
    3802            0 :   k_save_data(pf, ignoreBadObjects, true_file_h, nullptr, force_defaults);
    3803            0 : }
    3804              : 
    3805              : void
    3806            0 : OksKernel::save_data(OksFile * file_h, const OksObject::FSet& objects)
    3807              : {
    3808            0 :   std::shared_lock lock(p_kernel_mutex);
    3809            0 :   k_save_data(file_h, false, 0, &objects);
    3810            0 : }
    3811              : 
    3812              : void
    3813            0 : OksKernel::backup_data(OksFile * pf, const char * suffix)
    3814              : {
    3815            0 :   std::shared_lock lock(p_kernel_mutex);
    3816              : 
    3817            0 :   OksFile f(
    3818            0 :     pf->get_full_file_name() + suffix,
    3819              :     pf->get_logical_name(),
    3820              :     pf->get_type(),
    3821              :     pf->get_oks_format(),
    3822              :     this
    3823            0 :   );
    3824              : 
    3825            0 :   f.p_created_by = pf->p_created_by;
    3826            0 :   f.p_creation_time = pf->p_creation_time;
    3827            0 :   f.p_created_on = pf->p_created_on;
    3828            0 :   f.p_list_of_include_files = pf->p_list_of_include_files;
    3829              : 
    3830            0 :   if(!p_silence) {
    3831            0 :     std::lock_guard lock(p_parallel_out_mutex);
    3832            0 :     std::cout << "Making backup of data file \"" << pf->p_full_name << "\"...\n";
    3833            0 :   }
    3834              : 
    3835            0 :   bool silence = p_silence;
    3836              : 
    3837            0 :   p_silence = true;
    3838              : 
    3839            0 :   try {
    3840            0 :     k_save_data(&f, true, pf);
    3841              :   }
    3842            0 :   catch(exception& ex) {
    3843            0 :     p_silence = silence;
    3844            0 :     throw CanNotBackupFile(pf->p_full_name, ex);
    3845            0 :   }
    3846              : 
    3847            0 :   p_silence = silence;
    3848            0 : }
    3849              : 
    3850              : 
    3851              :   // kernel method
    3852              : 
    3853              : void
    3854            0 : OksKernel::k_save_data(OksFile * pf, bool ignoreBadObjects, OksFile * fh, const OksObject::FSet * objects, bool force_defaults)
    3855              : {
    3856            0 :   const char _fname[] = "k_save_data";
    3857            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, pf->p_full_name, nullptr, nullptr);
    3858              : 
    3859            0 :   OSK_PROFILING(OksProfiler::KernelSaveData, this)
    3860            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    3861              : 
    3862            0 :   std::string tmp_file_name;
    3863              :   
    3864            0 :   if(!fh) fh = pf;
    3865              : 
    3866            0 :   try {
    3867              : 
    3868              :       // calculate number of objects in file and check objects
    3869              : 
    3870            0 :     size_t numberOfObjects = 0;
    3871              : 
    3872            0 :     if(objects) {
    3873            0 :       numberOfObjects = objects->size();
    3874              : 
    3875            0 :       if(!ignoreBadObjects) {
    3876            0 :         std::string errors;
    3877              : 
    3878            0 :         for(OksObject::FSet::const_iterator i = objects->begin(); i != objects->end(); ++i) {
    3879            0 :           errors += (*i)->report_dangling_references();
    3880              :         }
    3881              : 
    3882            0 :         if(!errors.empty()) {
    3883            0 :           std::ostringstream text;
    3884            0 :           text << "the file contains objects with dangling references:\n" << errors;
    3885            0 :           throw std::runtime_error(text.str().c_str());
    3886            0 :         }
    3887            0 :       }
    3888              :     }
    3889              :     else {
    3890              :         // get list of all includes
    3891              : 
    3892            0 :       std::set<OksFile *> includes;
    3893            0 :       pf->get_all_include_files(this, includes);
    3894              : 
    3895            0 :       OSK_VERBOSE_REPORT("Test consistency of objects in file \"" << pf->p_full_name << '\"')
    3896              : 
    3897            0 :       bool found_bad_object = false;
    3898              : 
    3899            0 :       for(OksObject::Set::iterator i = p_objects.begin(); i != p_objects.end(); ++i) {
    3900            0 :         if((*i)->file == fh) {
    3901            0 :           numberOfObjects++;
    3902            0 :           if(!ignoreBadObjects || !p_silence) {
    3903            0 :             if((*i)->is_consistent(includes, "WARNING") == false) {
    3904            0 :               found_bad_object = true;
    3905              :             }
    3906            0 :             if((*i)->is_duplicated() == true) {
    3907            0 :               if(!p_silence) {
    3908            0 :                 Oks::error_msg(fname) << "  The file contains duplicated object " << *i << std::endl;
    3909              :               }
    3910              :               found_bad_object = true;
    3911              :             }
    3912              :           }
    3913              :         }
    3914              :       }
    3915              : 
    3916            0 :       if(found_bad_object && ignoreBadObjects == false) {
    3917            0 :         throw std::runtime_error("the file contains inconsistent/duplicated objects or misses includes");
    3918              :       }
    3919            0 :     }
    3920              : 
    3921              : 
    3922              :       // lock the file, if it is not locked already
    3923              : 
    3924            0 :     if(pf->is_locked() == false) {
    3925            0 :       pf->lock();
    3926              :     }
    3927              : 
    3928              : 
    3929              :       // check if it possible to open the non-existent file in write mode
    3930              : 
    3931            0 :     {
    3932              :         // check first if file already exists
    3933              : 
    3934            0 :       std::fstream f(pf->p_full_name.c_str(), std::ios::in);
    3935              : 
    3936            0 :       if(!f) {
    3937              : 
    3938              :           // no check for non-existent file
    3939              : 
    3940            0 :         std::fstream f2(pf->p_full_name.c_str(), std::ios::out);
    3941              : 
    3942            0 :         if(!f2) {
    3943            0 :           std::ostringstream text;
    3944            0 :           text << "cannot open file \'" << pf->p_full_name << "\' for writing";
    3945            0 :           throw std::runtime_error(text.str().c_str());
    3946            0 :         }
    3947            0 :       }
    3948            0 :     }
    3949              : 
    3950              : 
    3951            0 :     tmp_file_name = get_tmp_file(pf->p_full_name);
    3952              : 
    3953            0 :     long file_len = 0;
    3954              : 
    3955            0 :     {
    3956            0 :       std::ofstream f(tmp_file_name.c_str());
    3957              : 
    3958            0 :       f.exceptions ( std::ostream::failbit | std::ostream::badbit );
    3959              : 
    3960            0 :       if(!f) {
    3961            0 :         std::ostringstream text;
    3962            0 :         text << "cannot create temporal file \'" << tmp_file_name << "\' to save data";
    3963            0 :         throw std::runtime_error(text.str().c_str());
    3964            0 :       }
    3965              :       else {
    3966            0 :         if(!p_silence) {
    3967            0 :           std::lock_guard lock(p_parallel_out_mutex);
    3968            0 :           std::cout << "Saving " << numberOfObjects << " objects " << (force_defaults ? "with enforced default values " : "") << "to data file \"" << pf->p_full_name << "\"...\n";
    3969            0 :         }
    3970              :       }
    3971              : 
    3972              : 
    3973              :         // set header parameters
    3974              : 
    3975            0 :       OksXmlOutputStream xmls(f);
    3976              : 
    3977            0 :       pf->p_number_of_items = numberOfObjects;
    3978            0 :       pf->p_oks_format = "data";
    3979              : 
    3980            0 :       pf->write(xmls);
    3981              : 
    3982            0 :       if(!p_objects.empty()) {
    3983            0 :         for(OksClass::Map::const_iterator i = p_classes.begin(); i != p_classes.end() && f.good(); ++i) {
    3984            0 :           OksObject::SMap sorted;
    3985              : 
    3986            0 :           for(OksObject::Map::const_iterator j = i->second->p_objects->begin(); j != i->second->p_objects->end(); ++j) {
    3987            0 :             if(j->second->file == fh || (objects && (objects->find(j->second) != objects->end()))) {
    3988            0 :               sorted[j->first] = j->second;
    3989              :             }
    3990              :           }
    3991              : 
    3992            0 :           for(OksObject::SMap::iterator j = sorted.begin(); j != sorted.end(); ++j) {
    3993            0 :             j->second->put(xmls, force_defaults);
    3994            0 :             xmls.put_raw('\n');
    3995              :           }
    3996            0 :         }
    3997              :       }
    3998              : 
    3999            0 :       xmls.put_last_tag("oks-data", sizeof("oks-data")-1);
    4000            0 :       file_len = f.tellp();
    4001              : 
    4002            0 :       f.close();
    4003            0 :     }
    4004              : 
    4005              : 
    4006              :         // check that the written file is OK
    4007              :         // FIXME: can be removed later, if exceptions work well enough
    4008              : 
    4009            0 :     {
    4010            0 :       long written_len = 0;
    4011              : 
    4012            0 :       std::shared_ptr<std::ifstream> f(new std::ifstream(tmp_file_name.c_str()));
    4013              : 
    4014            0 :       if(*f) {
    4015            0 :         f->seekg(0, std::ios::end);
    4016            0 :         written_len = static_cast<std::streamoff>(f->tellg());
    4017              :       }
    4018              : 
    4019            0 :       if(written_len != file_len) {
    4020            0 :         unlink(tmp_file_name.c_str());
    4021            0 :         std::ostringstream text;
    4022            0 :         text << "write error in file \'" << tmp_file_name << "\': " << written_len << " bytes been written instead of " << file_len;
    4023            0 :         throw std::runtime_error(text.str().c_str());
    4024            0 :       }
    4025            0 :     }
    4026              : 
    4027              : 
    4028              :       // remember file's mode
    4029              : 
    4030            0 :     struct stat buf;
    4031            0 :     if(int code = stat(pf->p_full_name.c_str(), &buf)) {
    4032            0 :       std::ostringstream text;
    4033            0 :       text << "cannot get information about file \'" << pf->p_full_name << "\': stat() failed with code " << code << ", reason = \'" << strerror(errno) << '\'';
    4034            0 :       throw std::runtime_error(text.str().c_str());
    4035            0 :     }
    4036              : 
    4037              : 
    4038              :       // rename temporal file
    4039              : 
    4040            0 :     if(int code = rename(tmp_file_name.c_str(), pf->p_full_name.c_str())) {
    4041            0 :       std::ostringstream text;
    4042            0 :       text << "cannot rename file \'" << tmp_file_name << "\' to \'" << pf->p_full_name << "\': rename() failed with code " << code << ", reason = \'" << strerror(errno) << '\'';
    4043            0 :       throw std::runtime_error(text.str().c_str());
    4044            0 :     }
    4045              : 
    4046            0 :     tmp_file_name.erase(0);
    4047              : 
    4048              : 
    4049            0 :     if(pf != p_active_data) {
    4050            0 :       try {
    4051            0 :         pf->unlock();
    4052              :       }
    4053            0 :       catch(exception& ex) {
    4054            0 :         throw std::runtime_error(ex.what());
    4055            0 :       }
    4056              :     }
    4057            0 :     pf->p_is_updated = false;
    4058            0 :     pf->update_status_of_file();
    4059              : 
    4060              : 
    4061              :       // get mode for new file
    4062              : 
    4063            0 :     struct stat buf2;
    4064            0 :     if(int code = stat(pf->p_full_name.c_str(), &buf2)) {
    4065            0 :       std::ostringstream text;
    4066            0 :       text << "cannot get information about file \'" << pf->p_full_name << "\': stat() failed with code " << code << ", reason = \'" << strerror(errno) << '\'';
    4067            0 :       throw std::runtime_error(text.str().c_str());
    4068            0 :     }
    4069              : 
    4070              : 
    4071              :       // set file's mode if needed
    4072              : 
    4073            0 :     if(buf.st_mode != buf2.st_mode) {
    4074            0 :       if(int code = chmod(pf->p_full_name.c_str(), buf.st_mode) != 0) {
    4075            0 :         std::ostringstream text;
    4076            0 :         text << "cannot set protection mode for file \'" << pf->p_full_name << "\': chmod() failed with code " << code << ", reason = \'" << strerror(errno) << '\'';
    4077            0 :         throw std::runtime_error(text.str().c_str());
    4078            0 :       }
    4079              :     }
    4080              : 
    4081              :       // set file's group if needed (in case of problems report error, but do not throw exception)
    4082              : 
    4083            0 :     if(buf.st_gid != buf2.st_gid) {
    4084            0 :       if(int code = chown(pf->p_full_name.c_str(), (gid_t)(-1), buf.st_gid) != 0) {
    4085            0 :         ers::warning(kernel::SetGroupIdFailed(ERS_HERE, buf.st_gid, pf->p_full_name.c_str(), code, strerror(errno)));
    4086              :       }
    4087              :     }
    4088              : 
    4089              :   }
    4090              : 
    4091            0 :   catch (exception & e) {
    4092            0 :     if(pf != p_active_data) { try { pf->unlock();} catch(...) {} }
    4093            0 :     if(!tmp_file_name.empty()) { unlink(tmp_file_name.c_str()); }
    4094            0 :     throw CanNotWriteToFile("k_save_data", "data file", pf->p_full_name, e);
    4095            0 :   }
    4096            0 :   catch (std::exception & e) {
    4097            0 :     if(pf != p_active_data) { try { pf->unlock();} catch(...) {} }
    4098            0 :     if(!tmp_file_name.empty()) { unlink(tmp_file_name.c_str()); }
    4099            0 :     throw CanNotWriteToFile("k_save_data", "data file", pf->p_full_name, e.what());
    4100            0 :   }
    4101            0 :   catch (...) {
    4102            0 :     if(pf != p_active_data) { try { pf->unlock();} catch(...) {} }
    4103            0 :     if(!tmp_file_name.empty()) { unlink(tmp_file_name.c_str()); }
    4104            0 :     throw CanNotWriteToFile("k_save_data", "data file", pf->p_full_name, "unknown");
    4105            0 :   }
    4106              : 
    4107            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    4108            0 : }
    4109              : 
    4110              : 
    4111              :   // note: the file name is used as a key in the map
    4112              :   // to rename a file it is necessary to remove file from map, change name and insert it back
    4113              : 
    4114              : void
    4115            0 : OksKernel::k_rename_data(OksFile * pf, const std::string& short_name, const std::string& long_name)
    4116              : {
    4117            0 :   remove_data_file(pf);
    4118            0 :   pf->rename(short_name, long_name);
    4119            0 :   add_data_file(pf);
    4120            0 : }
    4121              : 
    4122              : void
    4123            0 : OksKernel::save_as_data(const std::string& new_name, OksFile * pf)
    4124              : {
    4125            0 :   const char _fname[] = "save_as_data";
    4126            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, new_name, nullptr, &pf);
    4127            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    4128              : 
    4129            0 :   try {
    4130              : 
    4131            0 :     if(!new_name.length()) {
    4132            0 :       throw std::runtime_error("the new filename is empty");
    4133              :     }
    4134              : 
    4135            0 :     std::unique_lock lock(p_kernel_mutex);
    4136              : 
    4137            0 :     std::string old_short_name = pf->p_short_name;
    4138            0 :     std::string old_full_name  = pf->p_full_name;
    4139            0 :     std::string old_format     = pf->p_oks_format;
    4140              : 
    4141            0 :     k_rename_data(pf, new_name, new_name);
    4142              : 
    4143            0 :     try {
    4144            0 :       k_save_data(pf);
    4145              :     }
    4146            0 :     catch (...) {
    4147            0 :       k_rename_data(pf, old_short_name, old_full_name);
    4148            0 :       pf->p_oks_format = old_format;
    4149            0 :       throw;
    4150            0 :     }
    4151              : 
    4152            0 :   }
    4153            0 :   catch (exception & ex) {
    4154            0 :     throw CanNotWriteToFile("k_save_as_data", "data file", new_name, ex);
    4155            0 :   }
    4156            0 :   catch (std::exception & ex) {
    4157            0 :     throw CanNotWriteToFile("k_save_as_data", "data file", new_name, ex.what());
    4158            0 :   }
    4159              : 
    4160            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    4161            0 : }
    4162              : 
    4163              : 
    4164              : void
    4165            0 : OksKernel::save_all_data(bool force_defaults)
    4166              : {
    4167            0 :   TLOG_DEBUG(4) << "enter";
    4168              : 
    4169            0 :   {
    4170            0 :     std::shared_lock lock(p_kernel_mutex);
    4171              : 
    4172            0 :     for(OksFile::Map::iterator i = p_data_files.begin(); i != p_data_files.end(); ++i) {
    4173            0 :       if(check_read_only(i->second) == false) {
    4174            0 :         k_save_data(i->second, false, nullptr, nullptr, force_defaults);
    4175              :       }
    4176              :       else {
    4177            0 :         TLOG_DEBUG(2) << "skip read-only data file \'" << *(i->first) << '\'';
    4178              :       }
    4179              :     }
    4180            0 :   }
    4181              : 
    4182            0 :   TLOG_DEBUG(4) << "exit";
    4183            0 : }
    4184              : 
    4185              :   // user-allowed method
    4186              : 
    4187              : void
    4188            0 : OksKernel::close_data(OksFile * fp, bool unbind)
    4189              : {
    4190            0 :   std::unique_lock lock(p_kernel_mutex);
    4191            0 :   k_close_data(fp, unbind);
    4192            0 : }
    4193              : 
    4194              :   // kernel method
    4195              : 
    4196              : void
    4197          130 : OksKernel::k_close_data(OksFile * fp, bool unbind)
    4198              : {
    4199          130 :   const char _fname[] = "k_close_data";
    4200          130 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, fp->p_full_name, &unbind, nullptr);
    4201              : 
    4202          130 :   OSK_PROFILING(OksProfiler::KernelCloseData, this)
    4203          130 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    4204              : 
    4205          130 :   try {
    4206          130 :     fp->unlock();
    4207              :   }
    4208            0 :   catch(exception& ex) {
    4209            0 :     Oks::error_msg(fname) << ex.what() << std::endl;
    4210            0 :   }
    4211              : 
    4212          130 :   if(!p_silence) {
    4213            0 :     std::lock_guard lock(p_parallel_out_mutex);
    4214            0 :     std::cout << (fp->p_included_by ? " * c" : "C") << "lose OKS data \"" << fp->p_full_name << "\"..." << std::endl;
    4215            0 :   }
    4216              : 
    4217          130 :   if(unbind) {
    4218            0 :     for(OksObject::Set::const_iterator i = p_objects.begin(); i != p_objects.end(); ++i) {
    4219            0 :       OksObject *o = *i;
    4220            0 :       if(o->file != fp) o->unbind_file(fp);
    4221              :     }
    4222              :   }
    4223              : 
    4224          130 :   if(p_close_all == false) {
    4225            0 :     std::list<OksObject *> * olist = create_list_of_data_objects(fp);
    4226              : 
    4227            0 :     if(olist) {
    4228            0 :       while(!olist->empty()) {
    4229            0 :         OksObject *o = olist->front();
    4230            0 :         olist->pop_front();
    4231            0 :         if(!is_dangling(o)) delete o;
    4232              :       }
    4233              : 
    4234            0 :       delete olist;
    4235              :     }
    4236              :   }
    4237              : 
    4238          130 :   remove_data_file(fp);
    4239          130 :   delete fp;
    4240              : 
    4241          130 :   if(p_active_data == fp) p_active_data = 0;
    4242              : 
    4243          130 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    4244          130 : }
    4245              : 
    4246              : 
    4247              : void
    4248          174 : OksKernel::close_all_data()
    4249              : {
    4250          174 :   TLOG_DEBUG(4) << "enter";
    4251              : 
    4252          174 :   {
    4253          174 :     std::unique_lock lock(p_kernel_mutex);
    4254              : 
    4255          174 :     p_close_all = true;
    4256              : 
    4257          304 :     while(!p_data_files.empty()) {
    4258          130 :       k_close_data(p_data_files.begin()->second, false);
    4259              :     }
    4260              : 
    4261          174 :     if(!p_objects.empty()) {
    4262         5062 :       for(OksObject::Set::iterator i = p_objects.begin(); i != p_objects.end(); ++i) {
    4263         4975 :         delete *i;
    4264              :       }
    4265              : 
    4266           87 :       p_objects.clear();
    4267              : 
    4268         6605 :       for(OksClass::Map::const_iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    4269         6518 :         if(i->second->p_objects) {
    4270         6518 :           delete i->second->p_objects;
    4271         6518 :           i->second->p_objects = 0;
    4272              :         }
    4273              :       }
    4274              :     }
    4275              : 
    4276          174 :     p_close_all = false;
    4277          174 :   }
    4278              : 
    4279          174 :   TLOG_DEBUG(4) << "exit";
    4280          174 : }
    4281              : 
    4282              : void
    4283           27 : OksKernel::set_active_data(OksFile * fp)
    4284              : {
    4285           27 :   std::unique_lock lock(p_kernel_mutex);
    4286           27 :   k_set_active_data(fp);
    4287           27 : }
    4288              : 
    4289              : void
    4290           32 : OksKernel::k_set_active_data(OksFile * fp)
    4291              : {
    4292           32 :   TLOG_DEBUG(4) << "enter for file " << (void *)fp;
    4293              : 
    4294              : 
    4295              :     // check if active data is different from given file
    4296              : 
    4297           32 :   if(p_active_data == fp) return;
    4298              : 
    4299              : 
    4300              :     // first unlock current active data
    4301              : 
    4302            5 :   if(p_active_data && p_active_data->is_updated() == false) {
    4303            0 :     try {
    4304            0 :       p_active_data->unlock();
    4305              :     }
    4306            0 :     catch(exception& ex) {
    4307            0 :       throw CanNotSetActiveFile("data", fp->get_full_file_name(), ex);
    4308            0 :     }
    4309              :   }
    4310              : 
    4311              : 
    4312              :     // exit, if file is (null)
    4313              : 
    4314            5 :   if(!fp) {
    4315            0 :     p_active_data = 0;
    4316            0 :     return;    
    4317              :   }
    4318              : 
    4319            5 :   try {
    4320            5 :     fp->lock();
    4321            5 :     p_active_data = fp;
    4322              :   }
    4323            0 :   catch(exception& ex) {
    4324            0 :     throw CanNotSetActiveFile("data", fp->get_full_file_name(), ex);
    4325            0 :   }
    4326              : 
    4327            5 :   TLOG_DEBUG(4) << "leave for file " << (void *)fp;
    4328              : }
    4329              : 
    4330              : 
    4331              : std::list<OksObject *> *
    4332            0 : OksKernel::create_list_of_data_objects(OksFile * fp) const
    4333              : {
    4334            0 :   const char _fname[] = "create_list_of_data_objects";
    4335            0 :   std::string fname = make_fname(_fname, sizeof(_fname)-1, fp->get_full_file_name(), nullptr, nullptr);
    4336              : 
    4337            0 :   OSK_PROFILING(OksProfiler::KernelCreateDataObjectList, this)
    4338            0 :   OSK_VERBOSE_REPORT("ENTER " << fname)
    4339              : 
    4340              : 
    4341            0 :   std::list<OksObject *> * olist = new std::list<OksObject *>();
    4342              : 
    4343            0 :   if(!p_objects.empty()) {
    4344            0 :     for(OksObject::Set::const_iterator i = p_objects.begin(); i != p_objects.end(); ++i) {
    4345            0 :       if((*i)->file == fp) olist->push_back(*i);
    4346              :     }
    4347              :   }
    4348              : 
    4349            0 :   if(olist->empty()) {
    4350            0 :     delete olist;
    4351            0 :     olist = 0;
    4352              :   }
    4353              : 
    4354              : 
    4355            0 :   OSK_VERBOSE_REPORT("LEAVE " << fname)
    4356              : 
    4357            0 :   return olist;
    4358            0 : }
    4359              : 
    4360              : 
    4361              : /******************************************************************************/
    4362              : 
    4363              :   // user-allowed method
    4364              : 
    4365              : void
    4366            5 : OksKernel::bind_objects()
    4367              : {
    4368            5 :   std::unique_lock lock(p_kernel_mutex);
    4369            5 :   k_bind_objects();
    4370            5 : }
    4371              : 
    4372              : void
    4373           87 : OksKernel::k_bind_objects()
    4374              : {
    4375           87 :   TLOG_DEBUG(4) << "enter";
    4376              : 
    4377           87 :   p_bind_objects_status.clear();
    4378              : 
    4379           87 :   if(!p_objects.empty()) {
    4380         5030 :     for(OksObject::Set::iterator i = p_objects.begin(); i != p_objects.end(); ++i) {
    4381         4948 :       try {
    4382         4948 :         (*i)->bind_objects();
    4383              :       }
    4384           18 :       catch(ObjectBindError& ex) {
    4385           18 :         if(ex.p_is_error) {
    4386            0 :           throw;
    4387              :         }
    4388              :         else {
    4389           18 :           const std::string error_text(strchr(ex.what(), '\n')+1);
    4390           18 :           if(!p_bind_objects_status.empty()) p_bind_objects_status.push_back('\n');
    4391           18 :             p_bind_objects_status.append(error_text);
    4392              : 
    4393           18 :             TLOG_DEBUG(1) << error_text;
    4394           18 :         }
    4395           18 :       }
    4396              :     }
    4397              :   }
    4398              : 
    4399           87 :   if(!p_silence && !p_bind_objects_status.empty()) {
    4400            0 :     ers::warning(kernel::BindError(ERS_HERE, p_bind_objects_status));
    4401              :   }
    4402              : 
    4403           87 :   TLOG_DEBUG(4) << "exit with status:\n" << p_bind_objects_status;
    4404           87 : }
    4405              : 
    4406              : 
    4407              : void
    4408            0 : OksKernel::unbind_all_rels(const OksObject::FSet& rm_objs, OksObject::FSet& updated) const
    4409              : {
    4410            0 :   const OksClass::Map& all_classes(classes());
    4411              : 
    4412            0 :   for(OksClass::Map::const_iterator i = all_classes.begin(); i != all_classes.end(); ++i) {
    4413            0 :     OksClass * c(i->second);
    4414            0 :     if(const OksObject::Map * objs = i->second->objects()) {
    4415            0 :       for(OksObject::Map::const_iterator j = objs->begin(); j != objs->end(); ++j) {
    4416            0 :         OksObject *o(j->second);
    4417            0 :         unsigned short l1 = c->number_of_all_attributes();
    4418            0 :         unsigned short l2 = l1 + c->number_of_all_relationships();
    4419              : 
    4420            0 :         while(l1 < l2) {
    4421            0 :           OksDataInfo odi(l1, (OksRelationship *)0);
    4422            0 :           OksData * d(o->GetRelationshipValue(&odi));
    4423              : 
    4424            0 :           if(d->type == OksData::object_type) {
    4425            0 :             if(rm_objs.find(d->data.OBJECT) != rm_objs.end()) {
    4426            0 :               updated.insert(o);
    4427            0 :               const OksClass * __c(d->data.OBJECT->GetClass());
    4428            0 :               const OksString& __id(d->data.OBJECT->GetId());
    4429            0 :               d->Set(__c,__id);
    4430            0 :               TLOG_DEBUG(5) << "set relationship of " << o << ": " << *d;
    4431            0 :             }
    4432              :           }
    4433            0 :           else if(d->type == OksData::list_type) {
    4434            0 :             for(OksData::List::const_iterator li = d->data.LIST->begin(); li != d->data.LIST->end(); ++li) {
    4435            0 :               OksData * lid(*li);
    4436            0 :               if(lid->type == OksData::object_type) {
    4437            0 :                 if(rm_objs.find(lid->data.OBJECT) != rm_objs.end()) {
    4438            0 :                   updated.insert(o);
    4439            0 :                   const OksClass * __c(lid->data.OBJECT->GetClass());
    4440            0 :                   const OksString& __id(lid->data.OBJECT->GetId());
    4441            0 :                   lid->Set(__c,__id);
    4442            0 :                   TLOG_DEBUG(5) << "set relationship of " << o << ": " << *d;
    4443            0 :                 }
    4444              :               }
    4445              :             }
    4446              :           }
    4447            0 :           ++l1;
    4448              :         }
    4449              :       }
    4450              :     }
    4451              :   }
    4452            0 : }
    4453              : 
    4454              : 
    4455              : OksClass *
    4456        30994 : OksKernel::find_class(const char * name) const
    4457              : {
    4458        30994 :   OksClass::Map::const_iterator i = p_classes.find(name);
    4459        30994 :   return (i != p_classes.end() ? i->second : 0);
    4460              : }
    4461              : 
    4462              : 
    4463              : void
    4464            0 : OksKernel::k_add(OksClass *c)
    4465              : {
    4466            0 :   TLOG_DEBUG(4) << "enter for class \"" << c->get_name() << '\"';
    4467              : 
    4468            0 :   if(p_active_schema == 0) {
    4469            0 :     throw CannotAddClass(*c, "no active schema");
    4470              :   }
    4471              : 
    4472            0 :   if(p_classes.find(c->get_name().c_str()) != p_classes.end()) {
    4473            0 :     throw CannotAddClass(*c, "class already exists");
    4474              :   }
    4475              : 
    4476            0 :   c->p_kernel = this;
    4477            0 :   c->p_file = p_active_schema;
    4478            0 :   c->p_file->p_is_updated = true;
    4479              : 
    4480            0 :   p_classes[c->get_name().c_str()] = c;
    4481              : 
    4482            0 :   try {
    4483            0 :     registrate_all_classes(false);
    4484              :   }
    4485            0 :   catch(exception& ex) {
    4486            0 :     throw CannotAddClass(*c, ex);
    4487            0 :   }
    4488              : 
    4489            0 :   if(OksClass::create_notify_fn) (*OksClass::create_notify_fn)(c);
    4490            0 : }
    4491              : 
    4492              : void
    4493         6518 : OksKernel::k_remove(OksClass *c)
    4494              : {
    4495         6518 :   TLOG_DEBUG(4) << "enter for class \"" << c->get_name() << '\"';
    4496              : 
    4497         6518 :   if(OksClass::delete_notify_fn) (*OksClass::delete_notify_fn)(c);
    4498              : 
    4499         6518 :   p_classes.erase(c->get_name().c_str());
    4500         6518 : }
    4501              : 
    4502              : 
    4503              : void
    4504          163 : OksKernel::registrate_all_classes(bool skip_registered)
    4505              : {
    4506          163 :   std::unique_lock lock(p_schema_mutex);  // protect schema and all objects from changes
    4507              : 
    4508          163 :   if(size_t num_of_classes = p_classes.size()) {
    4509          163 :     OksClass ** table = new OksClass * [num_of_classes];
    4510          163 :     size_t array_size = num_of_classes * sizeof(OksClass*) / sizeof(wchar_t);  // is used by wmemset() to init above array with NULLs
    4511              : 
    4512          163 :     OksClass::Map::iterator i = p_classes.begin();
    4513          163 :     unsigned long idx(0);
    4514              : 
    4515        11858 :     for(; i != p_classes.end(); ++i) i->second->registrate_class(skip_registered);
    4516              : 
    4517              :       // create lists of sub-classes
    4518              :       // note: do not use unscalable OksClass::create_sub_classes()
    4519        11858 :     for(i = p_classes.begin(); i != p_classes.end(); ++i) {
    4520        11695 :       OksClass * c(i->second);
    4521              : 
    4522        11695 :       if(!c->p_all_sub_classes) c->p_all_sub_classes = new OksClass::FList();
    4523         5177 :       else c->p_all_sub_classes->clear();
    4524              : 
    4525        11695 :       c->p_id = idx++;
    4526              :     }
    4527              : 
    4528        11858 :     for(i = p_classes.begin(); i != p_classes.end(); ++i) {
    4529        11695 :       OksClass * c(i->second);
    4530        11695 :       if(const OksClass::FList * scl = c->p_all_super_classes) {
    4531        22633 :         for(OksClass::FList::const_iterator j = scl->begin(); j != scl->end(); ++j) {
    4532        10938 :           (*j)->p_all_sub_classes->push_back(c);
    4533              :         }
    4534              :       }
    4535              :     }
    4536              : 
    4537          163 :     if(get_test_duplicated_objects_via_inheritance_mode() && !get_allow_duplicated_objects_mode()) {
    4538          295 :       for(i = p_classes.begin(); i != p_classes.end(); ++i) {
    4539          290 :         OksClass *c(i->second);
    4540          290 :         if(!c->get_is_abstract()) {
    4541          215 :           if(const OksClass::FList * spc = c->all_super_classes()) {
    4542          215 :             if(!spc->empty()) {
    4543          130 :               wmemset(reinterpret_cast<wchar_t *>(table), 0, array_size);  // [re-]set table by NULLs
    4544          330 :               for(OksClass::FList::const_iterator j1 = spc->begin(); j1 != spc->end(); ++j1) {
    4545          200 :                 if(const OksClass::FList * sbc = (*j1)->all_sub_classes()) {
    4546         1640 :                   for(OksClass::FList::const_iterator j2 = sbc->begin(); j2 != sbc->end(); ++j2) {
    4547         1440 :                     OksClass *c2(*j2);
    4548         1440 :                     if((c2 != c) && !c2->get_is_abstract()) {
    4549          800 :                       table[c2->p_id] = c2;
    4550              :                     }
    4551              :                   }
    4552              :                 }
    4553              :               }
    4554              :               
    4555          130 :               unsigned int count(0);
    4556         7670 :               for(unsigned int x = 0; x < num_of_classes; ++x) {
    4557         7540 :                 if(table[x]) count++;
    4558              :               }
    4559              : 
    4560          130 :               if(count) {
    4561          120 :                 std::vector<OksClass *> * cih;
    4562          120 :                 if(!c->p_inheritance_hierarchy) {
    4563          120 :                   cih = c->p_inheritance_hierarchy = new std::vector<OksClass *>();
    4564              :                 }
    4565              :                 else {
    4566            0 :                   cih = c->p_inheritance_hierarchy;
    4567            0 :                   cih->clear();
    4568              :                 }
    4569              : 
    4570          120 :                 cih->reserve(count);
    4571              : 
    4572         7080 :                 for(unsigned int x = 0; x < num_of_classes; ++x) {
    4573         6960 :                   if(table[x]) cih->push_back(table[x]);
    4574              :                 }
    4575              :               }
    4576              :             }
    4577              :           }
    4578              :         }
    4579              :       }
    4580              : 
    4581              : #ifndef ERS_NO_DEBUG
    4582            5 :       if(ers::debug_level() >= 2) {
    4583            3 :         std::ostringstream s;
    4584              : 
    4585          177 :         for(i = p_classes.begin(); i != p_classes.end(); ++i) {
    4586          174 :           if(std::vector<OksClass *> * cis = i->second->p_inheritance_hierarchy) {
    4587           72 :             s << " - class \'" << i->second->get_name() << "\' shares IDs with " << cis->size() << " classes: ";
    4588           72 :             OksClass::Set sorted;
    4589          486 :             for(std::vector<OksClass *>::const_iterator j = cis->begin(); j != cis->end(); ++j) {
    4590          414 :               sorted.insert(*j);
    4591              :             }
    4592          486 :             for(OksClass::Set::const_iterator j = sorted.begin(); j != sorted.end(); ++j) {
    4593          414 :               if(j != sorted.begin()) s << ", ";
    4594          414 :               s << '\'' << (*j)->get_name() << '\'';
    4595              :             }
    4596           72 :             s << std::endl;
    4597           72 :           }
    4598              :         }
    4599              : 
    4600            3 :         TLOG_DEBUG(2) << "Schema inheritance hierarchy used to test objects with equal IDs:\n" << s.str();
    4601            3 :       }
    4602              : #endif
    4603              :     }
    4604              : 
    4605          163 :     delete [] table;
    4606              : 
    4607          163 :     k_check_bind_classes_status();
    4608              :   }
    4609          163 : }
    4610              : 
    4611              : bool
    4612            0 : OksKernel::is_dangling(OksObject *o) const
    4613              : {
    4614            0 :   OSK_PROFILING(OksProfiler::KernelIsDanglingObject, this)
    4615            0 :   OSK_VERBOSE_REPORT("Enter OksKernel::is_dangling(OksObject *)")
    4616              : 
    4617            0 :   bool not_found;
    4618              : 
    4619            0 :   {
    4620            0 :     std::lock_guard lock(p_objects_mutex);
    4621            0 :     not_found = (p_objects.find(o) == p_objects.end());
    4622            0 :   }
    4623              : 
    4624            0 :   if(p_verbose) {
    4625            0 :     std::string fname("OksKernel::is_dangling(");
    4626              : 
    4627            0 :     if(not_found)
    4628            0 :       fname += "?object?) returns true";
    4629              :     else {
    4630            0 :       fname += '\"';
    4631            0 :       fname += o->GetId();
    4632            0 :       fname += "\") returns false";
    4633              :     }
    4634              : 
    4635            0 :     OSK_VERBOSE_REPORT("LEAVE " << fname.c_str())
    4636            0 :   }
    4637              : 
    4638            0 :   return not_found;
    4639            0 : }
    4640              : 
    4641              : 
    4642              : bool
    4643        13060 : OksKernel::is_dangling(OksClass *c) const
    4644              : {
    4645        13060 :   OSK_PROFILING(OksProfiler::KernelIsDanglingClass, this)
    4646        13060 :   OSK_VERBOSE_REPORT("Enter OksKernel::is_dangling(OksClass *)")
    4647              : 
    4648        13060 :   bool not_found = true;
    4649              : 
    4650        13060 :   {
    4651        13060 :     if(!p_classes.empty()) {
    4652       414184 :       for(OksClass::Map::const_iterator i = p_classes.begin(); i != p_classes.end(); ++i) {
    4653       407873 :         if(i->second == c) {
    4654              :           not_found = false;
    4655              :           break;
    4656              :         }
    4657              :       }
    4658              :     }
    4659              :   }
    4660              : 
    4661        13060 :   if(p_verbose) {
    4662            0 :     std::string fname("OksKernel::is_dangling(");
    4663              : 
    4664            0 :     if(not_found)
    4665            0 :       fname += "?class?) returns true";
    4666              :     else {
    4667            0 :       fname += '\"';
    4668            0 :       fname += c->get_name();
    4669            0 :       fname += "\") returns false";
    4670              :     }
    4671              : 
    4672            0 :     OSK_VERBOSE_REPORT("LEAVE " << fname.c_str())
    4673            0 :   }
    4674              : 
    4675        13060 :   return not_found;
    4676        13060 : }
    4677              : 
    4678              : 
    4679              : void
    4680            0 : OksKernel::get_all_classes(const std::vector<std::string>& names_in, ClassSet& classes_out) const
    4681              : {
    4682            0 :   for(std::vector<std::string>::const_iterator i = names_in.begin(); i != names_in.end(); ++i) {
    4683            0 :     OksClass * c = find_class(*i);
    4684            0 :     if(c != 0 && classes_out.find(c) == classes_out.end()) {
    4685            0 :       classes_out.insert(c);
    4686            0 :       if(const OksClass::FList * sc = c->all_sub_classes()) {
    4687            0 :         for(OksClass::FList::const_iterator j = sc->begin(); j != sc->end(); ++j) {
    4688            0 :           classes_out.insert(*j);
    4689              :         }
    4690              :       }
    4691              :     }
    4692              :   }
    4693            0 : }
    4694              : 
    4695              : 
    4696              :   // keep information about repository root
    4697              :   // throw exception if TDAQ_DB_REPOSITORY or TDAQ_DB_USER_REPOSITORY are not defined
    4698              : 
    4699              : struct ReposDirs {
    4700              : 
    4701              :   ReposDirs(const char * op, const char * cwd, OksKernel * kernel);
    4702              :   ~ReposDirs();
    4703              : 
    4704              :   const char * p_repository_root;
    4705              :   const char * p_user_repository_root;
    4706              :   size_t p_repos_dir_len;
    4707              :   size_t p_user_dir_len;
    4708              :   const char * p_dir;
    4709              : 
    4710              :   static std::mutex p_mutex;
    4711              : };
    4712              : 
    4713              : 
    4714              : std::mutex ReposDirs::p_mutex;
    4715              : 
    4716              : 
    4717            0 : ReposDirs::ReposDirs(const char * op, const char * cwd, OksKernel * kernel)
    4718              : {
    4719            0 :   p_repository_root = OksKernel::get_repository_root().c_str();
    4720            0 :   if(OksKernel::get_repository_root().empty()) {
    4721            0 :     throw RepositoryOperationFailed(op, "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    4722              :   }
    4723              :   else {
    4724            0 :     p_repos_dir_len = strlen(p_repository_root);
    4725              :   }
    4726              : 
    4727            0 :   p_user_repository_root = kernel->get_user_repository_root().c_str();
    4728            0 :   if(!*p_user_repository_root) {
    4729            0 :     throw RepositoryOperationFailed(op, "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    4730              :   }
    4731              :   else {
    4732            0 :     p_user_dir_len = strlen(p_user_repository_root);
    4733              :   }
    4734              : 
    4735            0 :   p_mutex.lock();
    4736              : 
    4737            0 :   if(strcmp(cwd, p_user_repository_root)) {
    4738            0 :     if(int result = chdir(p_user_repository_root)) {
    4739            0 :       p_mutex.unlock();
    4740            0 :       std::ostringstream text;
    4741            0 :       text << "chdir (\'" << p_user_repository_root << "\') failed with code " << result << ": " << strerror(errno);
    4742            0 :       throw RepositoryOperationFailed(op, text.str());
    4743            0 :     }
    4744            0 :     p_dir = cwd;
    4745            0 :     TLOG_DEBUG( 2 ) << "change cwd: \"" << p_user_repository_root << '\"' ;
    4746              :   }
    4747              :   else {
    4748            0 :     p_dir = 0;
    4749            0 :     TLOG_DEBUG( 2 ) << "cwd: \"" << p_user_repository_root << "\" is equal to target dir" ;
    4750              :   }
    4751            0 : }
    4752              : 
    4753            0 : ReposDirs::~ReposDirs()
    4754              : {
    4755            0 :   if(p_dir) {
    4756            0 :     if(int result = chdir(p_dir)) {
    4757            0 :       Oks::error_msg("ReposDirs::~ReposDirs()")
    4758            0 :         << "chdir (\'" << p_dir << "\') failed with code " << result << ": " << strerror(errno) << std::endl;
    4759              :     }
    4760            0 :     TLOG_DEBUG( 2 ) << "restore cwd: \"" << p_dir  << '\"' ;
    4761              :   }
    4762              : 
    4763            0 :   p_mutex.unlock();
    4764            0 : }
    4765              : 
    4766              : 
    4767              : 
    4768              :   // keep information and delete output file on exit
    4769              : 
    4770              : struct CommandOutput {
    4771              : 
    4772              :   CommandOutput(const char * command_name, const OksKernel * k, std::string& cmd);
    4773              :   ~CommandOutput();
    4774              : 
    4775              :   const std::string& file_name() const {return p_file_name;}
    4776              :   std::string cat2str() const;
    4777              :   std::string last_str() const;
    4778              : 
    4779              :   void check_command_status(int status);
    4780              : 
    4781              :   std::string p_file_name;
    4782              :   std::string& p_command;
    4783              :   const char * p_command_name;
    4784              : 
    4785              : };
    4786              : 
    4787            0 : CommandOutput::CommandOutput(const char *command_name, const OksKernel *k, std::string &cmd) :
    4788            0 : p_command(cmd), p_command_name(command_name)
    4789              : {
    4790            0 :   p_file_name = get_temporary_dir() + '/' + command_name + '.' + std::to_string(getpid()) + ':' +  std::to_string(reinterpret_cast<std::uintptr_t>(k)) + ".txt";
    4791              : 
    4792            0 :   p_command.append(" &>");
    4793            0 :   p_command.append(p_file_name);
    4794            0 : }
    4795              : 
    4796            0 : CommandOutput::~CommandOutput()
    4797              : {
    4798            0 :   unlink(p_file_name.c_str());
    4799            0 : }
    4800              : 
    4801              : std::string
    4802            0 : CommandOutput::cat2str() const
    4803              : {
    4804            0 :   std::ifstream f(p_file_name.c_str());
    4805            0 :   std::string out;
    4806              : 
    4807            0 :   if(f) {
    4808            0 :     std::filebuf * buf = f.rdbuf();
    4809            0 :     while(true) {
    4810            0 :       char c = buf->sbumpc();
    4811            0 :       if(c == EOF) break;
    4812            0 :       else out += c;
    4813              :     }
    4814              :   }
    4815              : 
    4816            0 :   return out;
    4817            0 : }
    4818              : 
    4819              : std::string
    4820            0 : CommandOutput::last_str() const
    4821              : {
    4822            0 :   std::ifstream f(p_file_name.c_str());
    4823            0 :   std::string lastline;
    4824              : 
    4825            0 :   if (f.is_open())
    4826              :   {
    4827            0 :     f.seekg(-1, std::ios_base::end);
    4828            0 :     if (f.peek() == '\n')
    4829              :       {
    4830            0 :         f.seekg(-1, std::ios_base::cur);
    4831            0 :         for (int i = f.tellg(); i >= 0; i--)
    4832              :           {
    4833            0 :             if (f.peek() == '\n')
    4834              :               {
    4835            0 :                 f.get();
    4836              :                 break;
    4837              :               }
    4838            0 :             f.seekg(i, std::ios_base::beg);
    4839              :           }
    4840              :       }
    4841              : 
    4842            0 :     getline(f, lastline);
    4843              :   }
    4844            0 :   return lastline;
    4845            0 : }
    4846              : 
    4847              : 
    4848              : void
    4849            0 : CommandOutput::check_command_status(int status)
    4850              : {
    4851            0 :   if (status == -1)
    4852              :     {
    4853            0 :       std::ostringstream text;
    4854            0 :       text << "cannot execute command \'" << p_command << "\': " << strerror(errno);
    4855            0 :       throw RepositoryOperationFailed(p_command_name, text.str());
    4856            0 :     }
    4857            0 :   else if (int error_code = WEXITSTATUS(status))
    4858              :     {
    4859            0 :       std::ostringstream text;
    4860            0 :       text << p_command.substr(0, p_command.find_first_of(' ')) << " exit with error code " << error_code << ", output:\n" << cat2str();
    4861            0 :       throw RepositoryOperationFailed(p_command_name, text.str());
    4862            0 :     }
    4863            0 : }
    4864              : 
    4865              : 
    4866              : void
    4867            0 : OksKernel::k_rename_repository_file(OksFile * file_h, const std::string& new_name)
    4868              : {
    4869            0 :   if (file_h->p_oks_format == "schema")
    4870              :     {
    4871            0 :       remove_schema_file(file_h);
    4872            0 :       file_h->rename(new_name);
    4873            0 :       add_schema_file(file_h);
    4874              :     }
    4875              :   else
    4876              :     {
    4877            0 :       remove_data_file(file_h);
    4878            0 :       file_h->rename(new_name);
    4879            0 :       add_data_file(file_h);
    4880              :     }
    4881            0 : }
    4882              : 
    4883              : 
    4884              : void
    4885            0 : OksKernel::k_checkout_repository(const std::string& param, const std::string& val, const std::string& branch_name)
    4886              : {
    4887            0 :   if (get_repository_root().empty())
    4888            0 :     throw RepositoryOperationFailed("checkout", "the repository root is not set");
    4889              : 
    4890            0 :   ReposDirs reps("checkout", s_cwd, this);
    4891              : 
    4892            0 :   std::string cmd("oks-checkout.sh");
    4893              : 
    4894            0 :   if(get_verbose_mode()) { cmd += " -v"; }
    4895              : 
    4896            0 :   cmd.append(" -u ");
    4897            0 :   cmd.append(get_user_repository_root());
    4898              : 
    4899            0 :   if (!param.empty())
    4900              :     {
    4901            0 :       cmd.append(" --");
    4902            0 :       cmd.append(param);
    4903            0 :       cmd.push_back(' ');
    4904            0 :       cmd.push_back('\"');
    4905            0 :       cmd.append(val);
    4906            0 :       cmd.push_back('\"');
    4907              :     }
    4908              : 
    4909            0 :   if (!branch_name.empty())
    4910              :     {
    4911            0 :       cmd.append(" -b ");
    4912            0 :       cmd.append(branch_name);
    4913              :     }
    4914              : 
    4915            0 :   auto start_usage = std::chrono::steady_clock::now();
    4916              : 
    4917            0 :   if (!p_silence)
    4918              :     {
    4919            0 :       std::lock_guard lock(p_parallel_out_mutex);
    4920            0 :       log_timestamp() << "[OKS checkout] => " << cmd << std::endl;
    4921            0 :     }
    4922              : 
    4923            0 :   CommandOutput cmd_out("oks-checkout", this, cmd);
    4924            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    4925              : 
    4926            0 :   p_repository_checkout_ts = p_repository_update_ts = std::time(0);
    4927              : 
    4928            0 :   if(!p_silence)
    4929              :     {
    4930            0 :       std::lock_guard lock(p_parallel_out_mutex);
    4931            0 :       std::cout << cmd_out.cat2str();
    4932            0 :       log_timestamp() << "[OKS checkout] => done in " << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-start_usage).count() / 1000. << " ms" << std::endl;
    4933            0 :     }
    4934              : 
    4935            0 :   static std::string version_prefix("checkout oks version ");
    4936            0 :   std::string version = cmd_out.last_str();
    4937            0 :   std::string::size_type pos = version.find(version_prefix);
    4938              : 
    4939            0 :   if (pos == 0)
    4940            0 :     p_repository_version = version.substr(version_prefix.size());
    4941              :   else
    4942            0 :     throw RepositoryOperationFailed("checkout", "cannot read oks version");
    4943            0 : }
    4944              : 
    4945              : void
    4946           87 : OksKernel::remove_user_repository_dir()
    4947              : {
    4948           87 :   if (p_allow_repository && p_user_repository_root_created)
    4949              :     {
    4950            0 :       s_git_folders.remove(p_user_repository_root);
    4951            0 :       s_git_folders.erase(p_user_repository_root);
    4952            0 :       p_user_repository_root_created = false;
    4953              :     }
    4954           87 : }
    4955              : 
    4956              : void
    4957            0 : OksKernel::unset_repository_created()
    4958              : {
    4959            0 :   s_git_folders.erase(p_user_repository_root);
    4960            0 :   p_user_repository_root_created = false;
    4961            0 : }
    4962              : 
    4963              : void
    4964            0 : OksKernel::k_copy_repository(const std::string& source, const std::string& destination)
    4965              : {
    4966            0 :   std::string cmd("oks-copy.sh");
    4967              : 
    4968            0 :   if (get_verbose_mode())
    4969            0 :     cmd.append(" -v");
    4970              : 
    4971            0 :   cmd.append(" -s ");
    4972            0 :   cmd.append(source);
    4973              : 
    4974            0 :   cmd.append(" -d ");
    4975            0 :   cmd.append(destination);
    4976              : 
    4977            0 :   cmd.append(" -c ");
    4978            0 :   cmd.append(get_repository_version());
    4979              : 
    4980            0 :   auto start_usage = std::chrono::steady_clock::now();
    4981              : 
    4982            0 :   if(!p_silence) {
    4983            0 :     std::lock_guard lock(p_parallel_out_mutex);
    4984            0 :     log_timestamp() << "[OKS copy] => " << cmd << std::endl;
    4985            0 :   }
    4986              : 
    4987            0 :   CommandOutput cmd_out("oks-copy", this, cmd);
    4988            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    4989              : 
    4990            0 :   if(!p_silence) {
    4991            0 :     std::lock_guard lock(p_parallel_out_mutex);
    4992            0 :     std::cout << cmd_out.cat2str();
    4993            0 :     log_timestamp() << "[OKS copy] => done in " << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-start_usage).count() / 1000. << " ms" << std::endl;
    4994            0 :   }
    4995            0 : }
    4996              : 
    4997              : 
    4998              : void
    4999            0 : OksKernel::update_repository(const std::string& param, const std::string& val, RepositoryUpdateType update_type)
    5000              : {
    5001            0 :   std::unique_lock lock(p_kernel_mutex);
    5002              : 
    5003            0 :   if (OksKernel::get_repository_root().empty())
    5004            0 :     throw RepositoryOperationFailed("update", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5005              : 
    5006            0 :   if (get_user_repository_root().empty())
    5007            0 :     throw RepositoryOperationFailed("update", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5008              : 
    5009            0 :   std::string cmd("oks-update.sh");
    5010              : 
    5011            0 :   if (get_verbose_mode())
    5012            0 :     cmd.append(" -v");
    5013              : 
    5014            0 :   cmd.append(" -u ");
    5015            0 :   cmd.append(get_user_repository_root());
    5016              : 
    5017            0 :   if (update_type == OksKernel::DiscardChanges)
    5018            0 :     cmd.append(" --force");
    5019            0 :   else if (update_type == OksKernel::MergeChanges)
    5020            0 :     cmd.append(" --merge");
    5021              : 
    5022            0 :   if (!param.empty())
    5023              :     {
    5024            0 :       cmd.append(" --");
    5025            0 :       cmd.append(param);
    5026            0 :       cmd.push_back(' ');
    5027            0 :       cmd.push_back('\"');
    5028            0 :       cmd.append(val);
    5029            0 :       cmd.push_back('\"');
    5030              :     }
    5031              : 
    5032            0 :   auto start_usage = std::chrono::steady_clock::now();
    5033              : 
    5034            0 :   if (!p_silence) {
    5035            0 :     std::lock_guard lock(p_parallel_out_mutex);
    5036            0 :     log_timestamp() << "[OKS update] => " << cmd << std::endl;
    5037            0 :   }
    5038              : 
    5039            0 :   CommandOutput cmd_out("oks-update", this, cmd);
    5040            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5041              : 
    5042            0 :   p_repository_update_ts = std::time(0);
    5043              : 
    5044            0 :   static std::string version_prefix("update oks version ");
    5045            0 :   std::string version = cmd_out.last_str();
    5046            0 :   std::string::size_type pos = version.find(version_prefix);
    5047              : 
    5048            0 :   if(pos == 0)
    5049            0 :     p_repository_version = version.substr(version_prefix.size());
    5050              :   else
    5051            0 :     throw RepositoryOperationFailed("commit", "cannot read oks version");
    5052              : 
    5053            0 :   if (!p_silence)
    5054              :     {
    5055            0 :       std::lock_guard lock(p_parallel_out_mutex);
    5056            0 :       std::cout << cmd_out.cat2str();
    5057            0 :       log_timestamp() << "[OKS update] => done in " << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-start_usage).count() / 1000. << " ms" << std::endl;
    5058            0 :     }
    5059            0 : }
    5060              : 
    5061              : void
    5062            0 : OksKernel::commit_repository(const std::string& comments, const std::string& credentials)
    5063              : {
    5064            0 :   std::unique_lock lock(p_kernel_mutex);
    5065              : 
    5066            0 :   if (OksKernel::get_repository_root().empty())
    5067            0 :     throw RepositoryOperationFailed("commit", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5068              : 
    5069            0 :   if (get_user_repository_root().empty())
    5070            0 :     throw RepositoryOperationFailed("commit", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5071              : 
    5072            0 :   std::string cmd("oks-commit.sh");
    5073              : 
    5074            0 :   if (get_verbose_mode())
    5075            0 :     cmd.append(" -v");
    5076              : 
    5077            0 :   cmd.append(" -u ");
    5078            0 :   cmd.append(get_user_repository_root());
    5079              : 
    5080            0 :   if(comments.empty() || std::all_of(comments.begin(), comments.end(), [](char c) { return std::isspace(c); }))
    5081            0 :     throw RepositoryOperationFailed("commit", "the commit message may not be empty");
    5082              : 
    5083            0 :   const std::string log_file_name(get_temporary_dir() + '/' + "oks-commit-msg." + std::to_string(getpid()) + ':' +  std::to_string(reinterpret_cast<std::uintptr_t>(this)) + ".txt");
    5084              : 
    5085            0 :   try
    5086              :     {
    5087            0 :       std::ofstream f(log_file_name);
    5088              : 
    5089            0 :       f.exceptions(std::ostream::failbit | std::ostream::badbit);
    5090              : 
    5091            0 :       if (!f)
    5092            0 :         throw std::runtime_error("create message file failed");
    5093              : 
    5094            0 :       f << comments;
    5095            0 :       f.close();
    5096            0 :     }
    5097            0 :   catch (const std::exception& ex)
    5098              :     {
    5099            0 :       std::ostringstream ss;
    5100            0 :       ss << "cannot write to file \'" << log_file_name << "\' to save commit message: " << ex.what();
    5101            0 :       throw RepositoryOperationFailed("commit", ss.str());
    5102            0 :     }
    5103              : 
    5104            0 :   cmd.append(" -f \'");
    5105            0 :   cmd.append(log_file_name);
    5106            0 :   cmd.push_back('\'');
    5107              : 
    5108              :   // if (!credentials.empty())
    5109              :   //   {
    5110              :   //     try
    5111              :   //       {
    5112              :   //         auto token = daq::tokens::verify(credentials);
    5113              : 
    5114              :   //         const std::string author = token.get_subject();
    5115              : 
    5116              :   //         std::string email;
    5117              : 
    5118              :   //         if (token.has_payload_claim("email"))
    5119              :   //           email = token.get_payload_claim("email").as_string();
    5120              : 
    5121              :   //         if (email.empty())
    5122              :   //           email = author + '@' + get_domain_name();
    5123              : 
    5124              :   //         OksSystem::User user(author);
    5125              : 
    5126              :   //         cmd.append(" -n \'");
    5127              :   //         cmd.append(user.real_name());
    5128              :   //         cmd.append("\' -e \'");
    5129              :   //         cmd.append(email);
    5130              :   //         cmd.push_back('\'');
    5131              : 
    5132              :   //         static std::once_flag flag;
    5133              : 
    5134              :   //         std::call_once(flag, []()
    5135              :   //           {
    5136              :   //             const char * opt = " -o SendEnv=OKS_COMMIT_USER";
    5137              : 
    5138              :   //             std::string val;
    5139              : 
    5140              :   //             if (const char * s = getenv("GIT_SSH_COMMAND"))
    5141              :   //               {
    5142              :   //                 if (strstr(s, opt) == nullptr)
    5143              :   //                   val = s;
    5144              :   //               }
    5145              :   //             else
    5146              :   //               {
    5147              :   //                 val = "ssh";
    5148              :   //               }
    5149              : 
    5150              :   //             if (!val.empty())
    5151              :   //               {
    5152              :   //                 val.append(opt);
    5153              :   //                 setenv("GIT_SSH_COMMAND", val.c_str(), 1);
    5154              :   //               }
    5155              :   //           }
    5156              :   //         );
    5157              : 
    5158              :   //         setenv("OKS_COMMIT_USER", credentials.c_str(), 1);
    5159              :   //       }
    5160              :   //     catch(const ers::Issue& ex)
    5161              :   //       {
    5162              :   //         std::ostringstream text;
    5163              :   //         text << '\t' << ex;
    5164              :   //         throw RepositoryOperationFailed("commit", text.str());
    5165              :   //       }
    5166              :   //   }
    5167              : 
    5168            0 :   auto start_usage = std::chrono::steady_clock::now();
    5169              : 
    5170            0 :   if (!p_silence)
    5171              :     {
    5172            0 :       std::lock_guard lock(p_parallel_out_mutex);
    5173            0 :       log_timestamp() << "[OKS commit] => " << cmd << std::endl;
    5174            0 :     }
    5175              : 
    5176            0 :   CommandOutput cmd_out("oks-commit", this, cmd);
    5177              : 
    5178            0 :   int status = system(cmd.c_str());
    5179              : 
    5180            0 :   unlink(log_file_name.c_str());
    5181              : 
    5182            0 :   if (!credentials.empty())
    5183            0 :     unsetenv("OKS_COMMIT_USER");
    5184              : 
    5185            0 :   cmd_out.check_command_status(status);
    5186              : 
    5187            0 :   p_repository_update_ts = std::time(0);
    5188              : 
    5189            0 :   if (!p_silence)
    5190              :     {
    5191            0 :       std::lock_guard lock(p_parallel_out_mutex);
    5192            0 :       std::cout << cmd_out.cat2str();
    5193            0 :       log_timestamp() << "[OKS commit] => done in " << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-start_usage).count() / 1000. << " ms" << std::endl;
    5194            0 :    }
    5195              : 
    5196            0 :   static std::string version_prefix("commit oks version ");
    5197            0 :   std::string version = cmd_out.last_str();
    5198            0 :   std::string::size_type pos = version.find(version_prefix);
    5199              : 
    5200            0 :   if(pos == 0)
    5201            0 :     p_repository_version = version.substr(version_prefix.size());
    5202              :   else
    5203            0 :     throw RepositoryOperationFailed("commit", "cannot read oks version");
    5204            0 : }
    5205              : 
    5206              : void
    5207            0 : OksKernel::tag_repository(const std::string& tag)
    5208              : {
    5209            0 :   std::unique_lock lock(p_kernel_mutex);
    5210              : 
    5211            0 :   if (OksKernel::get_repository_root().empty())
    5212            0 :     throw RepositoryOperationFailed("tag", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5213              : 
    5214            0 :   if (get_user_repository_root().empty())
    5215            0 :     throw RepositoryOperationFailed("tag", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5216              : 
    5217            0 :   std::string cmd("oks-tag.sh");
    5218              : 
    5219            0 :   if (get_verbose_mode())
    5220            0 :     cmd.append(" -v");
    5221              : 
    5222            0 :   cmd.append(" -u ");
    5223            0 :   cmd.append(get_user_repository_root());
    5224              : 
    5225            0 :   if(tag.empty() || std::all_of(tag.begin(), tag.end(), [](char c) { return std::isspace(c); }))
    5226            0 :     throw RepositoryOperationFailed("tag", "the tag may not be empty");
    5227              : 
    5228            0 :   cmd.append(" -t \'");
    5229            0 :   cmd.append(tag);
    5230            0 :   cmd.append("\' -c \'");
    5231            0 :   cmd.append(get_repository_version());
    5232            0 :   cmd.push_back('\'');
    5233              : 
    5234            0 :   auto start_usage = std::chrono::steady_clock::now();
    5235              : 
    5236            0 :   if (!p_silence)
    5237              :     {
    5238            0 :       std::lock_guard lock(p_parallel_out_mutex);
    5239            0 :       log_timestamp() << "[OKS tag] => " << cmd << std::endl;
    5240            0 :     }
    5241              : 
    5242            0 :   CommandOutput cmd_out("oks-tag", this, cmd);
    5243            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5244              : 
    5245            0 :   if (!p_silence)
    5246              :     {
    5247            0 :       std::lock_guard lock(p_parallel_out_mutex);
    5248            0 :       std::cout << cmd_out.cat2str();
    5249            0 :       log_timestamp() << "[OKS tag] => done in " << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now()-start_usage).count() / 1000. << " ms" << std::endl;
    5250            0 :    }
    5251            0 : }
    5252              : 
    5253              : std::list<std::string>
    5254            0 : OksKernel::get_repository_versions_diff(const std::string& sha1, const std::string& sha2)
    5255              : {
    5256            0 :   std::unique_lock lock(p_kernel_mutex);
    5257              : 
    5258            0 :   if (OksKernel::get_repository_root().empty())
    5259            0 :     throw RepositoryOperationFailed("diff", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5260              : 
    5261            0 :   if (get_user_repository_root().empty())
    5262            0 :     throw RepositoryOperationFailed("diff", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5263              : 
    5264            0 :   std::string cmd("oks-diff.sh");
    5265              : 
    5266            0 :   if (get_verbose_mode())
    5267            0 :     cmd.append(" -v");
    5268              : 
    5269            0 :   cmd.append(" -u ");
    5270            0 :   cmd.append(get_user_repository_root());
    5271              : 
    5272            0 :   if(!sha1.empty() && !sha2.empty())
    5273              :     {
    5274            0 :       cmd.append(" --sha ");
    5275            0 :       cmd.append(sha1);
    5276            0 :       cmd.push_back(' ');
    5277            0 :       cmd.append(sha2);
    5278              :     }
    5279              :   else
    5280              :     {
    5281            0 :       cmd.append(" --unmerged");
    5282              :     }
    5283              : 
    5284            0 :   CommandOutput cmd_out("oks-diff", this, cmd);
    5285            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5286              : 
    5287            0 :   std::string output = cmd_out.cat2str();
    5288              : 
    5289            0 :   if(!p_silence) {
    5290            0 :     std::lock_guard lock(p_parallel_out_mutex);
    5291            0 :     std::cout << output << "[OKS get_diff] => done" << std::endl;
    5292            0 :   }
    5293              : 
    5294            0 :   std::istringstream s(output);
    5295              : 
    5296            0 :   std::string line;
    5297            0 :   bool found = false;
    5298              : 
    5299            0 :   const char * diff_pattern = "git diff --name-only ";
    5300              : 
    5301            0 :   while (std::getline(s, line))
    5302            0 :     if (line.find(diff_pattern) == 0)
    5303              :       {
    5304              :         found = true;
    5305              :         break;
    5306              :       }
    5307              : 
    5308            0 :   if (found == false)
    5309              :     {
    5310            0 :       std::ostringstream text;
    5311            0 :       text << "cannot find \"" << diff_pattern << "\" pattern in output of oks-diff.sh:\n" << output;
    5312            0 :       throw RepositoryOperationFailed("get_diff", text.str());
    5313            0 :     }
    5314              : 
    5315            0 :   std::list<std::string> result;
    5316              : 
    5317            0 :   while (std::getline(s, line))
    5318            0 :     result.push_back(line);
    5319              : 
    5320            0 :   return result;
    5321            0 : }
    5322              : 
    5323              : static bool
    5324            0 : check_relevant(const std::set<std::string>& loaded_files, const OksRepositoryVersion& ver)
    5325              : {
    5326            0 :   for (const auto& x : ver.m_files)
    5327            0 :     if (loaded_files.find(x) != loaded_files.end())
    5328            0 :       return true;
    5329              : 
    5330            0 :   return false;
    5331              : }
    5332              : 
    5333              : std::vector<OksRepositoryVersion>
    5334            0 : OksKernel::get_repository_versions(bool skip_irrelevant, const std::string& command_line)
    5335              : {
    5336            0 :   std::string cmd("oks-log.sh");
    5337              : 
    5338            0 :   if (get_verbose_mode())
    5339            0 :     cmd.append(" -v");
    5340              : 
    5341            0 :   cmd.append(" -u ");
    5342            0 :   cmd.append(get_user_repository_root());
    5343              : 
    5344            0 :   cmd.append(command_line);
    5345              : 
    5346            0 :   CommandOutput cmd_out("oks-log", this, cmd);
    5347            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5348              : 
    5349            0 :   std::string output = cmd_out.cat2str();
    5350              : 
    5351            0 :   std::istringstream s(output);
    5352              : 
    5353            0 :   std::string line;
    5354            0 :   bool found = false;
    5355              : 
    5356            0 :   while (std::getline(s, line))
    5357            0 :     if (line.find("git log ") == 0)
    5358              :       {
    5359              :         found = true;
    5360              :         break;
    5361              :       }
    5362              : 
    5363            0 :   if (found == false)
    5364              :     {
    5365            0 :       std::ostringstream text;
    5366            0 :       text << "cannot find \"git log\" pattern in output of oks-log.sh:\n" << output;
    5367            0 :       throw RepositoryOperationFailed("log", text.str());
    5368            0 :     }
    5369              : 
    5370            0 :   std::set<std::string> loaded_files;
    5371              : 
    5372            0 :   if (skip_irrelevant)
    5373              :     {
    5374            0 :       std::size_t len = get_user_repository_root().size()+1;
    5375              : 
    5376            0 :       for (const auto& x : p_schema_files)
    5377            0 :         loaded_files.emplace(x.first->substr(len));
    5378              : 
    5379            0 :       for (const auto& x : p_data_files)
    5380            0 :         loaded_files.emplace(x.first->substr(len));
    5381              :     }
    5382              : 
    5383            0 :   std::vector<OksRepositoryVersion> vec;
    5384            0 :   OksRepositoryVersion ver;
    5385              : 
    5386            0 :   found = false;
    5387              : 
    5388            0 :   while (std::getline(s, line))
    5389              :     {
    5390            0 :       if (found == false)
    5391              :         {
    5392            0 :           ver.clear();
    5393              : 
    5394            0 :           std::string::size_type idx1 = 0;
    5395            0 :           std::string::size_type idx2 = line.find('|');
    5396              : 
    5397            0 :           if (idx2 != std::string::npos)
    5398              :             {
    5399            0 :               ver.m_commit_hash = line.substr(idx1, idx2);
    5400            0 :               idx1 = idx2+1;
    5401            0 :               idx2 = line.find('|', idx1);
    5402              : 
    5403            0 :               if (idx2 != std::string::npos)
    5404              :                 {
    5405            0 :                   ver.m_user = line.substr(idx1, idx2-idx1);
    5406            0 :                   idx1 = idx2+1;
    5407            0 :                   idx2 = line.find('|', idx1);
    5408              : 
    5409            0 :                   if (idx2 != std::string::npos)
    5410              :                     {
    5411            0 :                       ver.m_date = std::stol(line.substr(idx1, idx2-idx1));
    5412            0 :                       ver.m_comment = line.substr(idx2+1);
    5413              :                     }
    5414              :                 }
    5415              :             }
    5416              : 
    5417              : 
    5418            0 :           if (!ver.m_comment.empty())
    5419              :             found = true;
    5420              :           else
    5421              :             {
    5422            0 :               std::ostringstream text;
    5423            0 :               text << "unexpected line \"" << line << "\" in output of oks-log.sh:\n" << output;
    5424            0 :               throw RepositoryOperationFailed("log", text.str());
    5425            0 :             }
    5426              :         }
    5427              :       else
    5428              :         {
    5429            0 :           if (line.empty())
    5430              :             {
    5431            0 :               found = false;
    5432              : 
    5433            0 :               if (skip_irrelevant && check_relevant(loaded_files, ver) == false)
    5434            0 :                 continue;
    5435              : 
    5436            0 :               vec.emplace_back(ver);
    5437              :             }
    5438              :           else
    5439              :             {
    5440            0 :               ver.m_files.push_back(line);
    5441              :             }
    5442              :         }
    5443              :     }
    5444              : 
    5445            0 :   if (found)
    5446              :     {
    5447            0 :       if (skip_irrelevant == false || check_relevant(loaded_files, ver))
    5448            0 :         vec.emplace_back(ver);
    5449              :     }
    5450              : 
    5451            0 :   return vec;
    5452            0 : }
    5453              : 
    5454              : std::vector<OksRepositoryVersion>
    5455            0 : OksKernel::get_repository_versions_by_hash(bool skip_irrelevant, const std::string& since, const std::string& until)
    5456              : {
    5457            0 :   std::string command_line;
    5458              : 
    5459            0 :   if(!since.empty() && !until.empty())
    5460              :     {
    5461            0 :       command_line.push_back(' ');
    5462            0 :       command_line.append(since);
    5463            0 :       command_line.append("..");
    5464            0 :       command_line.append(until);
    5465              :     }
    5466            0 :   else if(!since.empty())
    5467              :     {
    5468            0 :       command_line.push_back(' ');
    5469            0 :       command_line.append(since);
    5470            0 :       command_line.append("..origin/master");
    5471              :     }
    5472            0 :   else if(!until.empty())
    5473              :     {
    5474            0 :       command_line.append(" ..");
    5475            0 :       command_line.append(until);
    5476              :     }
    5477              : 
    5478            0 :   return get_repository_versions(skip_irrelevant, command_line);
    5479            0 : }
    5480              : 
    5481              : static std::string
    5482            0 : replace_datetime_spaces(const std::string& in)
    5483              : {
    5484            0 :   std::string out(in);
    5485            0 :   std::replace(out.begin(), out.end(), ' ', 'T');
    5486            0 :   return out;
    5487              : }
    5488              : 
    5489              : 
    5490              : std::vector<OksRepositoryVersion>
    5491            0 : OksKernel::get_repository_versions_by_date(bool skip_irrelevant, const std::string& since, const std::string& until)
    5492              : {
    5493            0 :   std::string command_line;
    5494              : 
    5495            0 :   if(!since.empty())
    5496              :     {
    5497            0 :       command_line.append(" --since ");
    5498            0 :       command_line.append(replace_datetime_spaces(since));
    5499              :     }
    5500              : 
    5501            0 :   if(!until.empty())
    5502              :     {
    5503            0 :       command_line.append(" --until ");
    5504            0 :       command_line.append(replace_datetime_spaces(until));
    5505              :     }
    5506              : 
    5507            0 :   command_line.append(" origin/master");
    5508              : 
    5509            0 :   return get_repository_versions(skip_irrelevant, command_line);
    5510            0 : }
    5511              : 
    5512              : 
    5513              : std::string
    5514            0 : OksKernel::read_repository_version()
    5515              : {
    5516            0 :   std::unique_lock lock(p_kernel_mutex);
    5517              : 
    5518            0 :   if (OksKernel::get_repository_root().empty())
    5519            0 :     throw RepositoryOperationFailed("status", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5520              : 
    5521            0 :   if (get_user_repository_root().empty())
    5522            0 :     throw RepositoryOperationFailed("status", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5523              : 
    5524            0 :   std::string cmd("oks-version.sh");
    5525              : 
    5526            0 :   cmd.append(" -u ");
    5527            0 :   cmd.append(get_user_repository_root());
    5528              : 
    5529            0 :   CommandOutput cmd_out("oks-status", this, cmd);
    5530            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5531              : 
    5532            0 :   std::string output = cmd_out.cat2str();
    5533              : 
    5534            0 :   static std::string version_prefix("oks version ");
    5535            0 :   std::string version = cmd_out.last_str();
    5536            0 :   std::string::size_type pos = version.find(version_prefix);
    5537              : 
    5538            0 :   if (pos == 0)
    5539            0 :     p_repository_version = version.substr(version_prefix.size());
    5540              :   else
    5541              :     {
    5542            0 :       std::ostringstream text;
    5543            0 :       text << "cannot read oks version from oks-version.sh output: \"" << output << '\"';
    5544            0 :       throw RepositoryOperationFailed("get version", text.str().c_str());
    5545            0 :     }
    5546              : 
    5547            0 :   return p_repository_version;
    5548            0 : }
    5549              : 
    5550              : 
    5551            0 : void OksKernel::get_updated_repository_files(std::set<std::string>& updated, std::set<std::string>& added, std::set<std::string>& removed)
    5552              : {
    5553            0 :   std::unique_lock lock(p_kernel_mutex);
    5554              : 
    5555            0 :   if (OksKernel::get_repository_root().empty())
    5556            0 :     throw RepositoryOperationFailed("status", "the repository-root is not set (check environment variable TDAQ_DB_REPOSITORY)");
    5557              : 
    5558            0 :   if (get_user_repository_root().empty())
    5559            0 :     throw RepositoryOperationFailed("status", "the user-repository-root is not set (check environment variable TDAQ_DB_USER_REPOSITORY)");
    5560              : 
    5561            0 :   std::string cmd("oks-status.sh");
    5562              : 
    5563            0 :   cmd.append(" -u ");
    5564            0 :   cmd.append(get_user_repository_root());
    5565              : 
    5566            0 :   CommandOutput cmd_out("oks-status", this, cmd);
    5567            0 :   cmd_out.check_command_status(system(cmd.c_str()));
    5568              : 
    5569            0 :   std::string output = cmd_out.cat2str();
    5570              : 
    5571            0 :   if(p_verbose) {
    5572            0 :     std::lock_guard lock(p_parallel_out_mutex);
    5573            0 :     std::cout << output << "[OKS get_status] => done" << std::endl;
    5574            0 :   }
    5575              : 
    5576            0 :   std::istringstream s(output);
    5577              : 
    5578            0 :   std::string line;
    5579            0 :   bool found = false;
    5580              : 
    5581            0 :   const char * diff_pattern = "git status --porcelain";
    5582              : 
    5583            0 :   while (std::getline(s, line))
    5584            0 :     if (line.find(diff_pattern) == 0)
    5585              :       {
    5586              :         found = true;
    5587              :         break;
    5588              :       }
    5589              : 
    5590            0 :   if (found == false)
    5591              :     {
    5592            0 :       std::ostringstream text;
    5593            0 :       text << "cannot find \"" << diff_pattern << "\" pattern in output of oks-status.sh:\n" << output;
    5594            0 :       throw RepositoryOperationFailed("status", text.str());
    5595            0 :     }
    5596              : 
    5597            0 :   std::list<std::string> result;
    5598              : 
    5599            0 :   while (std::getline(s, line))
    5600              :     {
    5601            0 :       if (line.find(" D ") == 0)
    5602            0 :         removed.insert(line.substr(3));
    5603            0 :       else if (line.find(" M ") == 0)
    5604            0 :         updated.insert(line.substr(3));
    5605            0 :       else if (line.find("?? ") == 0)
    5606            0 :         added.insert(line.substr(3));
    5607              :       else
    5608              :         {
    5609            0 :           std::ostringstream text;
    5610            0 :           text << "unexpected output \"" << line << "\" in output of oks-status.sh:\n" << output;
    5611            0 :           throw RepositoryOperationFailed("status", text.str());
    5612            0 :         }
    5613              :     }
    5614            0 : }
    5615              : 
    5616              : 
    5617              : //   /* PAM authentication */
    5618              : 
    5619              : // struct creds_pam_t {
    5620              : //   const char * user;
    5621              : //   const char * pwd;
    5622              : // };
    5623              : 
    5624              : // static int
    5625              : // get_credentials_pam (int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr)
    5626              : // {
    5627              : //   struct creds_pam_t * creds = (struct creds_pam_t *)appdata_ptr;
    5628              : //   struct pam_response * buf = (struct pam_response *)(malloc(num_msg * sizeof (struct pam_response)));    /* released by PAM */
    5629              : 
    5630              : //   for(int k = 0; k < num_msg; ++ k) {
    5631              : //     const size_t STRING_SIZE = 1024;
    5632              : //     char * out;
    5633              : //     int error = 0;
    5634              : 
    5635              : //     buf[k].resp = (char*)malloc(STRING_SIZE);
    5636              : //     out = buf[k].resp;
    5637              : //     out[0] = 0;
    5638              : 
    5639              : //     if(msg[k]->msg) {
    5640              : //       if(!strcmp(msg[k]->msg, "login:") || !strcmp(msg[k]->msg, "login: ")) {
    5641              : //         TLOG_DEBUG( 1 ) << "process \'login\' PAM credential of user " << creds->user ;
    5642              : //      strncpy(out, creds->user, STRING_SIZE);
    5643              : //       }
    5644              : //       else if(!strcmp(msg[k]->msg, "Password: ")  || !strcmp(msg[k]->msg, "LDAP Password: ")) {
    5645              : //         TLOG_DEBUG( 1 ) << "process \'password\' PAM credential of user " << creds->user ;
    5646              : //         strncpy (out, creds->pwd, STRING_SIZE);
    5647              : //       }
    5648              : //       else {
    5649              : //         error = 1;
    5650              : //       }
    5651              : //     }
    5652              : 
    5653              : //     if(error != 0) {
    5654              : //       std::cerr << "ERROR: unexpected request in process PAM credential: " << msg[k]->msg << std::endl;
    5655              : //       for (int j = 0; j <= k; ++ j) {
    5656              : //         free(buf[k].resp);
    5657              : //       }
    5658              : //       free(buf);
    5659              : //       return PAM_CONV_ERR;
    5660              : //     }
    5661              : 
    5662              : //     out[STRING_SIZE - 1] = 0;
    5663              : //     buf[k].resp_retcode = 0;
    5664              : //   }
    5665              : 
    5666              : //   *resp = buf;
    5667              : 
    5668              : //   return PAM_SUCCESS;
    5669              : // }
    5670              : 
    5671              : 
    5672              : // void
    5673              : // OksKernel::validate_credentials(const char * user, const char * passwd)
    5674              : // {
    5675              : //   if(!user || !*user) {
    5676              : //     throw oks::AuthenticationFailure("user name is not given");
    5677              : //   }
    5678              : 
    5679              : //   if(!passwd || !*passwd) {
    5680              : //     throw oks::AuthenticationFailure("user password is not given");
    5681              : //   }
    5682              : 
    5683              : //   struct creds_pam_t creds = {user, passwd};
    5684              : //   struct pam_conv conv = {get_credentials_pam, &creds};
    5685              : 
    5686              : //   const char *service = "system-auth";
    5687              : //   pam_handle_t * pamh = 0;
    5688              : 
    5689              : //   int retval = pam_start(service, 0, &conv, &pamh);
    5690              : //   if (retval != PAM_SUCCESS) {
    5691              : //     std::ostringstream text;
    5692              : //     text << "pam_start() failed for service \'" << service << "\': " << pam_strerror (pamh, retval);
    5693              : //     throw oks::AuthenticationFailure(text.str());
    5694              : //   }
    5695              : 
    5696              : //   retval = pam_authenticate (pamh, 0);
    5697              : //   if (retval == PAM_SUCCESS) {
    5698              : //     TLOG_DEBUG( 1 ) << "user " << user << " was authenticated" ;
    5699              : //   }
    5700              : //   else {
    5701              : //     std::ostringstream text;
    5702              : //     text << "failed to authenticate user " << user << ": " << pam_strerror (pamh, retval);
    5703              : //     throw oks::AuthenticationFailure(text.str());
    5704              : //   }
    5705              : 
    5706              : //   retval = pam_end (pamh,retval);
    5707              : //   if (retval != PAM_SUCCESS) {
    5708              : //      std::ostringstream text;
    5709              : //     text << "pam_end() failed: " << pam_strerror (pamh, retval);
    5710              : //     throw oks::AuthenticationFailure(text.str());
    5711              : //   }
    5712              : // }
    5713              : 
    5714              : void
    5715          163 : OksKernel::k_check_bind_classes_status() const noexcept
    5716              : {
    5717          163 :   std::ostringstream out;
    5718              : 
    5719        11858 :   for (auto & c : p_classes)
    5720        11695 :     c.second->check_relationships(out, true);
    5721              : 
    5722          163 :   p_bind_classes_status = out.str();
    5723          163 : }
    5724              : 
    5725              : 
    5726              : std::ostream&
    5727            0 : log_timestamp(__LogSeverity__ severity)
    5728              : {
    5729            0 :   auto now(std::chrono::system_clock::now());
    5730            0 :   auto time_since_epoch(now.time_since_epoch());
    5731            0 :   auto seconds_since_epoch(std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch));
    5732              : 
    5733            0 :   std::time_t now_t(std::chrono::system_clock::to_time_t(std::chrono::system_clock::time_point(seconds_since_epoch)));
    5734              : 
    5735            0 :   char buff[128];
    5736            0 :   std::size_t len = std::strftime(buff, 128 - 16, "%Y-%b-%d %H:%M:%S.", std::localtime(&now_t));
    5737            0 :   sprintf(buff+len, "%03d ", (int)(std::chrono::duration_cast<std::chrono::milliseconds>(time_since_epoch).count() - seconds_since_epoch.count()*1000));
    5738              : 
    5739            0 :   std::ostream& s (severity <= Warning ? std::cerr : std::cout);
    5740              : 
    5741            0 :   s << buff << (severity == Error ? "ERROR " : severity == Warning ? "WARNING " : severity == Debug ? "DEBUG " : "");
    5742              : 
    5743            0 :   return s;
    5744              : }
    5745              : 
    5746              : } // namespace oks
    5747              : } // namespace dunedaq
        

Generated by: LCOV version 2.0-1