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