LCOV - code coverage report
Current view: top level - oks/src - kernel.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 21.6 % 2972 642
Test Date: 2025-12-21 13:07:08 Functions: 31.5 % 260 82

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

Generated by: LCOV version 2.0-1