Line data Source code
1 : // DUNE DAQ modification notice:
2 : // This file has been modified from the original ATLAS oks source for the DUNE DAQ project.
3 : // Fork baseline commit: oks-08-03-04 (2022-04-14).
4 : // Renamed since fork: yes (from bin/oks_dump.cpp to apps/oks_dump.cxx).
5 :
6 : /**
7 : * \file oks_dump.cpp
8 : *
9 : * This file is part of the OKS package.
10 : * Author: <Igor.Soloviev@cern.ch>
11 : *
12 : * This file contains the implementation of the OKS application to dump
13 : * contents of the OKS database files.
14 : *
15 : */
16 :
17 : #include "oks/exceptions.hpp"
18 : #include "oks/kernel.hpp"
19 : #include "oks/query.hpp"
20 :
21 : #include <iostream>
22 : #include <vector>
23 :
24 : #include <stdlib.h>
25 : #include <string.h>
26 :
27 : using namespace dunedaq::oks;
28 :
29 : enum __OksDumpExitStatus__
30 : {
31 : __Success__ = 0,
32 : __BadCommandLine__,
33 : __BadOksFile__,
34 : __BadQuery__,
35 : __NoSuchClass__,
36 : __FoundDanglingReferences__,
37 : __ExceptionCaught__
38 : };
39 :
40 : static void
41 0 : printUsage(std::ostream& s)
42 : {
43 0 : s << "Usage: oks_dump\n"
44 : " [--files-only | --files-stat-only | --schema-files-only | --schema-files-stat-only | --data-files-only | "
45 : "--data-files-stat-only]\n"
46 : " [--class name-of-class [--query query [--print-references recursion-depth [class-name*] [--]] "
47 : "[--print-referenced_by [name] [--]]]]\n"
48 : " [--path object-from object-to query]\n"
49 : " [--allow-duplicated-objects-via-inheritance]\n"
50 : " [--version]\n"
51 : " [--help]\n"
52 : " [--input-from-files] database-file [database-file(s)]\n"
53 : "\n"
54 : "Options:\n"
55 : " -f | --files-only print list of oks files names\n"
56 : " -F | --files-stat-only print list of oks files with statistic details (size, "
57 : "number of items\n"
58 : " -s | --schema-files-only print list of schema oks files names\n"
59 : " -S | --schema-files-stat-only print list of oks schema files with statistic details\n"
60 : " -d | --data-files-only print list of data oks files names\n"
61 : " -D | --data-files-stat-only print list of oks data files with statistic details\n"
62 : " -c | --class class_name dump given class (all objects or matching some query)\n"
63 : " -q | --query query print objects matching query (can only be used with "
64 : "class)\n"
65 : " -r | --print-references N C1 C2 ... CX print objects referenced by found objects (can only be "
66 : "used with query), where:\n"
67 : " * the parameter N defines recursion depth for "
68 : "referenced objects (> 0)\n"
69 : " * the optional set of names {C1 .. CX} defines "
70 : "[sub-]classes for above objects\n"
71 : " -b | --print-referenced_by [name] print objects referencing found objects (can only be "
72 : "used with query), where:\n"
73 : " * the optional parameter name defines name of "
74 : "relationship\n"
75 : " -p | --path obj query print path from object \'obj\' to object of query "
76 : "expression\n"
77 : " -i | --input-from-files read oks files to be loaded from file(s) instead of "
78 : "command line\n"
79 : " (to avoid problems with long command line, when there is "
80 : "huge number of files)\n"
81 : " -a | --allow-duplicated-objects-via-inheritance do not stop if there are duplicated object via "
82 : "inheritance hierarchy\n"
83 : " -v | --version print version\n"
84 : " -h | --help print this text\n"
85 : "\n"
86 : "Description:\n"
87 : " Dumps contents of the OKS database.\n"
88 : "\n"
89 : "Return Status:\n"
90 : " 0 - no problems found\n"
91 : " 1 - bad command line parameter\n"
92 : " 2 - bad oks file(s)\n"
93 : " 3 - bad query passed via -q or -p options\n"
94 : " 4 - cannot find class passed via -c option\n"
95 : " 5 - loaded objects have dangling references\n"
96 : " 6 - caught an exception\n"
97 0 : "\n";
98 0 : }
99 :
100 : static void
101 0 : no_param(const char* s)
102 : {
103 0 : Oks::error_msg("oks_dump") << "no parameter(s) for command line argument \'" << s << "\' provided\n\n";
104 0 : exit(EXIT_FAILURE);
105 : }
106 :
107 : OksObject*
108 0 : find_object(char* s, OksKernel& k)
109 : {
110 0 : char* id = s;
111 :
112 0 : if ((s = strchr(id, '@')) == 0)
113 : return 0;
114 :
115 0 : *s = '\0';
116 0 : s++;
117 :
118 0 : if (OksClass* c = k.find_class(s)) {
119 0 : if (OksObject* o = c->get_object(id)) {
120 : return o;
121 : } else {
122 0 : Oks::error_msg("oks_dump::find_object()") << "cannot find object \"" << id << '@' << s << "\"\n";
123 : }
124 : } else {
125 0 : Oks::error_msg("oks_dump::find_object()") << "cannot find class \"" << s << "\"\n";
126 : }
127 :
128 : return 0;
129 : }
130 :
131 : int
132 0 : main(int argc, char** argv)
133 : {
134 0 : if (argc == 1) {
135 0 : printUsage(std::cerr);
136 0 : return __BadCommandLine__;
137 : }
138 :
139 0 : OksKernel kernel;
140 0 : kernel.set_test_duplicated_objects_via_inheritance_mode(true);
141 :
142 0 : try {
143 :
144 0 : int dump_files_only = 0; // 0 - none, 12 - data, 1 - schema, 2 - schema & data
145 0 : const char* class_name = 0;
146 0 : const char* query = 0;
147 0 : const char* object_from = 0;
148 0 : const char* path_query = 0;
149 0 : long recursion_depth = 0;
150 0 : bool print_referenced_by = false;
151 0 : const char* ref_by_rel_name = "*";
152 0 : std::vector<std::string> ref_classes;
153 0 : bool input_from_files = false;
154 0 : bool print_files_stat = false;
155 :
156 0 : for (int i = 1; i < argc; i++) {
157 0 : const char* cp = argv[i];
158 :
159 0 : if (!strcmp(cp, "-h") || !strcmp(cp, "--help")) {
160 0 : printUsage(std::cout);
161 : return __Success__;
162 0 : } else if (!strcmp(cp, "-v") || !strcmp(cp, "--version")) {
163 0 : std::cout << "OKS kernel version " << OksKernel::GetVersion() << std::endl;
164 : return __Success__;
165 0 : } else if (!strcmp(cp, "-a") || !strcmp(cp, "--allow-duplicated-objects-via-inheritance")) {
166 0 : kernel.set_test_duplicated_objects_via_inheritance_mode(false);
167 0 : } else if (!strcmp(cp, "-f") || !strcmp(cp, "--files-only")) {
168 : dump_files_only = 2;
169 0 : } else if (!strcmp(cp, "-F") || !strcmp(cp, "--files-stat-only")) {
170 : dump_files_only = 2;
171 : print_files_stat = true;
172 0 : } else if (!strcmp(cp, "-s") || !strcmp(cp, "--schema-files-only")) {
173 : dump_files_only = 1;
174 0 : } else if (!strcmp(cp, "-S") || !strcmp(cp, "--schema-files-stat-only")) {
175 : dump_files_only = 1;
176 : print_files_stat = true;
177 0 : } else if (!strcmp(cp, "-d") || !strcmp(cp, "--data-files-only")) {
178 : dump_files_only = 12;
179 0 : } else if (!strcmp(cp, "-D") || !strcmp(cp, "--data-files-stat-only")) {
180 : dump_files_only = 12;
181 : print_files_stat = true;
182 0 : } else if (!strcmp(cp, "-c") || !strcmp(cp, "--class")) {
183 0 : if (++i == argc) {
184 0 : no_param(cp);
185 : } else {
186 0 : class_name = argv[i];
187 : }
188 0 : } else if (!strcmp(cp, "-q") || !strcmp(cp, "--query")) {
189 0 : if (++i == argc) {
190 0 : no_param(cp);
191 : } else {
192 0 : query = argv[i];
193 : }
194 0 : } else if (!strcmp(cp, "-i") || !strcmp(cp, "--input-from-files")) {
195 : input_from_files = true;
196 0 : } else if (!strcmp(cp, "-r") || !strcmp(cp, "--print-references")) {
197 0 : if (++i == argc) {
198 0 : no_param(cp);
199 : } else {
200 0 : recursion_depth = atol(argv[i]);
201 : }
202 0 : int j = 0;
203 0 : for (; j < argc - i - 1; ++j) {
204 0 : if (argv[i + 1 + j][0] != '-') {
205 0 : ref_classes.push_back(argv[i + 1 + j]);
206 : } else {
207 : break;
208 : }
209 : }
210 0 : i += j;
211 0 : } else if (!strcmp(cp, "-b") || !strcmp(cp, "--print-referenced_by")) {
212 0 : print_referenced_by = true;
213 0 : if ((i + 1) < argc && argv[i + 1][0] != '-') {
214 0 : ref_by_rel_name = argv[++i];
215 : }
216 0 : } else if (!strcmp(cp, "-p") || !strcmp(cp, "--path")) {
217 0 : if (++i > argc - 1) {
218 0 : no_param(cp);
219 : } else {
220 0 : object_from = argv[i];
221 0 : path_query = argv[++i];
222 : }
223 0 : } else if (strcmp(cp, "--")) {
224 0 : if (input_from_files) {
225 0 : std::ifstream f(cp);
226 0 : if (f.good()) {
227 0 : while (f.good() && !f.eof()) {
228 0 : std::string file_name;
229 0 : std::getline(f, file_name);
230 0 : if (!file_name.empty() && kernel.load_file(file_name) == 0) {
231 0 : Oks::error_msg("oks_dump") << "\tCan not load file \"" << file_name << "\", exiting...\n";
232 0 : return __BadOksFile__;
233 : }
234 0 : }
235 : } else {
236 0 : Oks::error_msg("oks_dump") << "\tCan not open file \"" << cp << "\" for reading, exiting...\n";
237 : return __BadCommandLine__;
238 : }
239 0 : } else {
240 0 : if (kernel.load_file(cp) == 0) {
241 0 : Oks::error_msg("oks_dump") << "\tCan not load file \"" << cp << "\", exiting...\n";
242 : return __BadOksFile__;
243 : }
244 : }
245 : }
246 : }
247 :
248 0 : if (kernel.schema_files().empty()) {
249 0 : Oks::error_msg("oks_dump") << "\tAt least one oks file have to be provided, exiting...\n";
250 : return __BadCommandLine__;
251 : }
252 :
253 0 : if (query && !class_name) {
254 0 : Oks::error_msg("oks_dump")
255 0 : << "\tQuery can only be executed when class name is provided (use -c option), exiting...\n";
256 : return __BadCommandLine__;
257 : }
258 :
259 0 : if (dump_files_only) {
260 0 : long total_size = 0;
261 0 : long total_items = 0;
262 0 : const OksFile::Map* files[2] = { &kernel.schema_files(), &kernel.data_files() };
263 0 : for (int j = (dump_files_only / 10); j < (dump_files_only % 10); ++j) {
264 0 : if (!files[j]->empty()) {
265 0 : for (OksFile::Map::const_iterator i = files[j]->begin(); i != files[j]->end(); ++i) {
266 0 : if (print_files_stat) {
267 0 : total_size += i->second->get_size();
268 0 : total_items += i->second->get_number_of_items();
269 0 : std::cout << *(i->first) << " (" << i->second->get_number_of_items() << " items, "
270 0 : << i->second->get_size() << " bytes)" << std::endl;
271 : } else {
272 0 : std::cout << *(i->first) << std::endl;
273 : }
274 : }
275 : }
276 : }
277 :
278 0 : if (print_files_stat) {
279 0 : std::cout << "Total number of items: " << total_items
280 : << "\n"
281 0 : "Total size of files: "
282 0 : << total_size << " bytes" << std::endl;
283 : }
284 0 : } else if (class_name && *class_name) {
285 0 : if (OksClass* c = kernel.find_class(class_name)) {
286 0 : if (query && *query) {
287 0 : OksQuery* q = new OksQuery(c, query);
288 0 : if (q->good()) {
289 0 : OksObject::List* objs = c->execute_query(q);
290 0 : size_t num = (objs ? objs->size() : 0);
291 0 : std::cout << "Found " << num << " matching query \"" << query << "\" in class \"" << class_name << "\"";
292 0 : if (num) {
293 0 : std::cout << ':' << std::endl;
294 0 : while (!objs->empty()) {
295 0 : OksObject* o = objs->front();
296 0 : objs->pop_front();
297 :
298 0 : if (recursion_depth > 0 || print_referenced_by) {
299 0 : if (recursion_depth) {
300 0 : ClassSet all_ref_classes;
301 0 : kernel.get_all_classes(ref_classes, all_ref_classes);
302 0 : OksObject::FSet refs;
303 0 : o->references(refs, recursion_depth, false, &all_ref_classes);
304 0 : std::cout << o << " references " << refs.size() << " object(s)" << std::endl;
305 0 : for (OksObject::FSet::const_iterator i = refs.begin(); i != refs.end(); ++i) {
306 0 : std::cout << " - " << *i << std::endl;
307 : }
308 0 : }
309 0 : if (print_referenced_by) {
310 0 : if (OksObject::FList* ref_by_objs = o->get_all_rels(ref_by_rel_name)) {
311 0 : std::cout << o << " is referenced by " << ref_by_objs->size() << " object(s) via relationship \""
312 0 : << ref_by_rel_name << "\":" << std::endl;
313 :
314 0 : for (OksObject::FList::const_iterator i = ref_by_objs->begin(); i != ref_by_objs->end(); ++i) {
315 0 : std::cout << " - " << *i << std::endl;
316 : }
317 :
318 0 : delete ref_by_objs;
319 : } else {
320 0 : std::cout << o << " is not referenced by any object via relationship \"" << ref_by_rel_name
321 0 : << '\"' << std::endl;
322 : }
323 : }
324 : } else {
325 0 : std::cout << *o << std::endl;
326 : }
327 : }
328 0 : delete objs;
329 : } else {
330 0 : std::cout << std::endl;
331 : }
332 : } else {
333 0 : Oks::error_msg("oks_dump") << "\tFailed to parse query \"" << query << "\" in class \"" << class_name
334 0 : << "\"\n";
335 : return __BadQuery__;
336 : }
337 0 : delete q;
338 : } else {
339 0 : std::cout << *c << std::endl;
340 : }
341 : } else {
342 0 : Oks::error_msg("oks_dump") << "\tCan not find class \"" << class_name << "\"\n";
343 : return __NoSuchClass__;
344 : }
345 0 : } else if (object_from && *object_from && path_query && *path_query) {
346 0 : OksObject* obj_from = find_object((char*)object_from, kernel);
347 0 : try {
348 0 : QueryPath q(path_query, kernel);
349 0 : OksObject::List* objs = obj_from->find_path(q);
350 :
351 0 : size_t num = (objs ? objs->size() : 0);
352 0 : std::cout << "Found " << num << " objects in the path \"" << q << "\" from object " << obj_from << ":"
353 0 : << std::endl;
354 :
355 0 : if (num) {
356 0 : while (!objs->empty()) {
357 0 : OksObject* o = objs->front();
358 0 : objs->pop_front();
359 0 : std::cout << *o << std::endl;
360 : }
361 0 : delete objs;
362 : }
363 0 : } catch (bad_query_syntax& e) {
364 0 : Oks::error_msg("oks_dump") << "\tFailed to parse query: " << e.what() << std::endl;
365 0 : return __BadQuery__;
366 0 : }
367 0 : } else {
368 0 : std::cout << kernel;
369 : }
370 :
371 0 : if (!kernel.get_bind_classes_status().empty()) {
372 0 : Oks::error_msg("oks_dump") << "The schema contains dangling references to non-loaded classes:\n"
373 0 : << kernel.get_bind_classes_status();
374 : }
375 :
376 0 : if (!kernel.get_bind_objects_status().empty()) {
377 0 : Oks::error_msg("oks_dump") << "\tThe data contain dangling references to non-loaded objects\n";
378 : }
379 :
380 0 : if (!kernel.get_bind_classes_status().empty() || !kernel.get_bind_objects_status().empty()) {
381 : return __FoundDanglingReferences__;
382 : }
383 0 : } catch (exception& ex) {
384 0 : std::cerr << "Caught oks exception:\n" << ex << std::endl;
385 0 : return __ExceptionCaught__;
386 0 : } catch (std::exception& e) {
387 0 : std::cerr << "Caught standard C++ exception: " << e.what() << std::endl;
388 0 : return __ExceptionCaught__;
389 0 : } catch (...) {
390 0 : std::cerr << "Caught unknown exception" << std::endl;
391 0 : return __ExceptionCaught__;
392 0 : }
393 :
394 0 : return __Success__;
395 0 : }
|