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