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