MIDAS
Loading...
Searching...
No Matches
odbxx.cxx
Go to the documentation of this file.
1/********************************************************************\
2
3 Name: odbxx.cxx
4 Created by: Stefan Ritt
5
6 Contents: Object oriented interface to ODB implementation file
7
8\********************************************************************/
9
10#include <string>
11#include <iostream>
12#include <fstream>
13#include <sstream>
14#include <map>
15#include <stdexcept>
16#include <algorithm>
17#include <initializer_list>
18#include <cstring>
19#include <bitset>
20#include <functional>
21
22#include "midas.h"
23#include "odbxx.h"
24#include "mexcept.h"
25#include "mstrlcpy.h"
26// #include "mleak.hxx" // un-comment for memory leak debugging
27
28/*------------------------------------------------------------------*/
29
30namespace midas {
31
32 //----------------------------------------------------------------
33
34 // initialize static variables
35 HNDLE odb::s_hDB = 0;
36 bool odb::s_debug = false;
37 bool odb::s_connected_odb = false;
38 std::vector<midas::odb *> g_watchlist = {};
39
40 // static functions ----------------------------------------------
41
42 // initialize s_hDB, internal use only
44 if (s_hDB == 0)
46 if (s_hDB == 0)
47 mthrow("Please call cm_connect_experiment() before accessing the ODB");
48 s_connected_odb = true;
49 }
50
51 // search for a key with a specific hKey, needed for callbacks
53 if (po->m_hKey == hKey)
54 return po;
55 if (po->m_tid == TID_KEY) {
56 for (int i = 0; i < po->m_num_values; i++) {
57 midas::odb *pot = search_hkey(po->m_data[i].get_podb(), hKey);
58 if (pot != nullptr)
59 return pot;
60 }
61 }
62 return nullptr;
63 }
64
65 // check if a key exists in the ODB
66 bool odb::exists(const std::string &name) {
67 init_hdb();
69 return false;
70 HNDLE hkey;
71 return db_find_key(s_hDB, 0, name.c_str(), &hkey) == DB_SUCCESS;
72 }
73
74 // delete a key in the ODB
75 int odb::delete_key(const std::string &name) {
76 init_hdb();
78 return false;
79 HNDLE hkey;
80 auto status = db_find_key(s_hDB, 0, name.c_str(), &hkey);
81 if (status != DB_SUCCESS) {
82 if (s_debug)
83 std::cout << "Delete key " + name << " not found in ODB" << std::endl;
84 return status;
85 }
86 if (s_debug)
87 std::cout << "Delete ODB key " + name << std::endl;
88 return db_delete_key(s_hDB, hkey, false);
89 }
90
91 // load file into ODB
92 void odb::load(const std::string &filename, const std::string &odb_path) {
93 init_hdb();
95 mthrow("Cannot connect to ODB");
96
97 HNDLE hkey;
98 auto status = db_find_key(s_hDB, 0, odb_path.c_str(), &hkey);
99 if (status == DB_NO_KEY)
100 db_create_key(s_hDB, 0, odb_path.c_str(), TID_KEY);
101 status = db_find_key(s_hDB, 0, odb_path.c_str(), &hkey);
102 if (status != DB_SUCCESS)
103 mthrow("ODB path " + odb_path + " not found in ODB");
104
105 KEY key;
107 if (key.type != TID_KEY)
108 mthrow("ODB path " + odb_path + " does not point to a directory");
109
110 db_load(s_hDB, hkey, filename.c_str(), false);
111 }
112
113 // global callback function for db_watch()
114 void odb::watch_callback(int hDB, int hKey, int index, void *info) {
115 midas::odb *po = static_cast<midas::odb *>(info);
116 if (po->m_data == nullptr)
117 mthrow("Callback received for a midas::odb object which went out of scope");
119 if (poh == nullptr) {
120 auto s = db_get_path(hDB, hKey);
121 mthrow("New key \"" + s + "\" has been created in ODB after calling watch()");
122 }
123
124 poh->m_last_index = index;
125 po->m_watch_callback(*poh);
126 poh->m_last_index = -1;
127 }
128
129 // create ODB key
130 int odb::create(const char *name, int type) {
131 init_hdb();
132 int status = -1;
133 if (is_connected_odb())
136 mthrow("Cannot create key " + std::string(name) + ", db_create_key() status = " + std::to_string(status));
137 return status;
138 }
139
140 // private functions ---------------------------------------------
141
143 m_flags = f;
144 if (m_tid == TID_KEY) {
145 for (int i = 0; i < m_num_values; i++)
146 m_data[i].get_odb().set_flags_recursively(f);
147 }
148 }
149
150 void odb::odb_from_xml(const std::string &str) {
151 init_hdb();
152
153 HNDLE hKey;
154 int status = db_find_key(s_hDB, 0, str.c_str(), &hKey);
155 if (status != DB_SUCCESS)
156 mthrow("ODB key \"" + str + "\" not found in ODB");
157
158 int bsize = 1000000;
159 char *buffer = (char *)malloc(bsize);
160 do {
161 int size = bsize;
162 status = db_copy_xml(s_hDB, hKey, buffer, &size, false);
163 if (status == DB_TRUNCATED) {
164 bsize *= 2;
165 buffer = (char *)realloc(buffer, bsize);
166 }
167 } while (status == DB_TRUNCATED);
168
169 if (status != DB_SUCCESS)
170 mthrow("Cannot retrieve XML data, status = " + std::to_string(status));
171
172 if (s_debug)
173 std::cout << "Retrieved XML tree for \"" + str + "\"" << std::endl;
174
175 char error[256] = "";
176 PMXML_NODE tree = mxml_parse_buffer(buffer, error, sizeof(error), NULL);
177 if (error[0]) {
178 std::cout << "MXML error, buffer =\n" << buffer << std::endl;
179 mthrow("MXML error: " + std::string(error));
180 }
181 free(buffer);
182
183 odb_from_xml(&tree->child[2], this);
184 m_hKey = hKey;
185
187 }
188
189 // resize internal m_data array, keeping old values
190 void odb::resize_mdata(int size) {
191 auto new_array = new u_odb[size]{};
192 int i;
193 for (i = 0; i < m_num_values && i < size; i++) {
194 new_array[i] = m_data[i];
195 if (m_tid == TID_KEY)
196 m_data[i].set_odb(nullptr); // move odb*
197 if (m_tid == TID_STRING || m_tid == TID_LINK)
198 m_data[i].set_string_ptr(nullptr); // move std::string*
199 }
200 for (; i < size; i++) {
201 if (m_tid == TID_STRING || m_tid == TID_LINK)
202 new_array[i].set_string(""); // allocates new string
203 }
204 delete[] m_data;
207 for (i = 0; i < m_num_values; i++) {
209 m_data[i].set_parent(this);
210 }
211 }
212
213 // get function for strings
214 void odb::get(std::string &s, bool quotes, bool refresh) {
215 if (refresh && is_auto_refresh_read())
216 read();
217
218 // put value into quotes
219 s = "";
220 std::string sd;
221 for (int i = 0; i < m_num_values; i++) {
222 m_data[i].get(sd);
223 if (quotes)
224 s += "\"";
225 s += sd;
226 if (quotes)
227 s += "\"";
228 if (i < m_num_values - 1)
229 s += ",";
230 }
231 }
232
233 // public functions ----------------------------------------------
234
235 // Deep copy constructor
236 odb::odb(const odb &o) : odb() {
237 m_tid = o.m_tid;
238 m_name = o.m_name;
239 m_num_values = o.m_num_values;
240 m_hKey = o.m_hKey;
241 m_watch_callback = o.m_watch_callback;
243 for (int i = 0; i < m_num_values; i++) {
245 m_data[i].set_parent(this);
246 if (m_tid == TID_STRING || m_tid == TID_LINK) {
247 // set_string() creates a copy of our string
248 m_data[i].set_string(o.m_data[i]);
249 } else if (m_tid == TID_KEY) {
250 // recursive call to create a copy of the odb object
252 midas::odb *pc = new midas::odb(*po);
253 pc->set_parent(this);
254 m_data[i].set(pc);
255 } else {
256 // simply pass basic types
257 m_data[i] = o.m_data[i];
258 m_data[i].set_parent(this);
259 }
260 }
261 }
262
263 void odb::deep_copy(odb &d, const odb &s) {
264 d.m_tid = s.m_tid;
265 d.m_name = s.m_name;
266 d.m_num_values = s.m_num_values;
267 d.m_hKey = s.m_hKey;
268 d.m_watch_callback = s.m_watch_callback;
269 d.m_data = new midas::u_odb[d.m_num_values]{};
270 for (int i = 0; i < d.m_num_values; i++) {
271 d.m_data[i].set_tid(d.m_tid);
272 d.m_data[i].set_parent(&d);
273 if (d.m_tid == TID_STRING || d.m_tid == TID_LINK) {
274 // set_string() creates a copy of our string
275 d.m_data[i].set_string(s.m_data[i]);
276 } else if (d.m_tid == TID_KEY) {
277 // recursive call to create a copy of the odb object
279 midas::odb *pc = new midas::odb(*po);
280 pc->set_parent(&d);
281 d.m_data[i].set(pc);
282 } else {
283 // simply pass basic types
284 d.m_data[i] = s.m_data[i];
285 d.m_data[i].set_parent(this);
286 }
287 }
288 }
289
290 // return full path from ODB
291 std::string odb::get_full_path() {
292 if (m_name[0] == '/')
293 return m_name;
294 if (m_parent)
295 return m_parent->get_full_path() + "/" + m_name;
296
297 if (!is_connected_odb() || m_hKey == -1)
298 return m_name;
299
300 std::string str = db_get_path(s_hDB, m_hKey);
301 if (str == "/") // change "/" to ""
302 str = "";
303 return str;
304 }
305
306 // return parent object
307 std::string odb::get_parent_path() {
308 std::string s = get_full_path();
309 std::size_t i = s.find_last_of("/");
310 s = s.substr(0, i);
311 return s;
312 }
313
314 // return size of ODB key
315 int odb::size() {
316 return m_num_values;
317 }
318
319 // Resize an ODB key
320 void odb::resize(int size) {
322 if (this->is_auto_refresh_write()) {
323 int status = db_set_num_values(s_hDB, m_hKey, size);
324 if (status != DB_SUCCESS)
325 mthrow("db_set_num_values for ODB key \"" + get_full_path() +
326 "\" failed with status " + std::to_string(status));
327 }
328 }
329
330 // Resize an ODB key with default value
331 void odb::resize(int size, bool b) {
334 if (this->is_auto_refresh_write()) {
335 int status = db_set_num_values(s_hDB, m_hKey, size);
336 if (status != DB_SUCCESS)
337 mthrow("db_set_num_values for ODB key \"" + get_full_path() +
338 "\" failed with status " + std::to_string(status));
339 }
340 if (size > old_size) {
341 for (int i=old_size ; i<size ; i++)
342 m_data[i] = b;
343 if (this->is_auto_refresh_write())
344 write();
345 }
346 }
347
348 std::string odb::print() {
349 std::string s;
350 s = "{\n";
351 print(s, 1);
352 s += "\n}";
353 return s;
354 }
355
356 std::string odb::dump() {
357 std::string s;
358 s = "{\n";
359 dump(s, 1);
360 s += "\n}";
361 return s;
362 }
363
364 // print current object with all sub-objects nicely indented
365 void odb::print(std::string &s, int indent) {
366 for (int i = 0; i < indent; i++)
367 s += " ";
368 if (m_tid == TID_KEY) {
369 s += "\"" + m_name + "\": {\n";
370 for (int i = 0; i < m_num_values; i++) {
371 std::string v;
372 // recursive call
373 m_data[i].get_odb().print(v, indent + 1);
374 s += v;
375 if (i < m_num_values - 1)
376 s += ",\n";
377 else
378 s += "\n";
379 }
380 for (int i = 0; i < indent; i++)
381 s += " ";
382 s += "}";
383 } else {
384 s += "\"" + m_name + "\": ";
385 if (m_num_values > 1)
386 s += "[";
387 std::string v;
388 get(v, m_tid == TID_STRING || m_tid == TID_LINK);
389 if (m_tid == TID_LINK)
390 s += " -> ";
391 s += v;
392 if (m_num_values > 1)
393 s += "]";
394 }
395 }
396
397 // dump current object in the same way as odbedit saves as json
398 void odb::dump(std::string &s, int indent) {
399 for (int i = 0; i < indent; i++)
400 s += " ";
401 if (m_tid == TID_KEY) {
402 s += "\"" + m_name + "\": {\n";
403 for (int i = 0; i < m_num_values; i++) {
404 std::string v;
405 m_data[i].get_odb().dump(v, indent + 1);
406 s += v;
407 if (i < m_num_values - 1)
408 s += ",\n";
409 else
410 s += "\n";
411 }
412 for (int i = 0; i < indent; i++)
413 s += " ";
414 s += "}";
415 } else {
416 KEY key;
418 s += "\"" + m_name + "/key\": ";
419 s += "{ \"type\": " + std::to_string(m_tid) + ", ";
420 s += "\"access_mode\": " + std::to_string(key.access_mode) + ", ";
421 s += "\"last_written\": " + std::to_string(key.last_written) + "},\n";
422 for (int i = 0; i < indent; i++)
423 s += " ";
424 s += "\"" + m_name + "\": ";
425 if (m_num_values > 1)
426 s += "[";
427 std::string v;
428 get(v, m_tid == TID_STRING || m_tid == TID_LINK);
429 s += v;
430 if (m_num_values > 1)
431 s += "]";
432 }
433 }
434
435 // save ODB tree into file in JSON format
436 void odb::save(const std::string &filename) {
437 std::string buffer;
438
439 std::string header = "{\n";
440 header += " \"/MIDAS version\" : \"2.1\",\n";
441 header += " \"/filename\" : \"" + filename + "\",\n";
442 header += " \"/ODB path\" : \"" + get_full_path() + "\",\n\n";
443
444 odb::dump(buffer, 1);
445
446 buffer += "\n}\n";
447
448 std::ofstream f(filename);
449 if (!f.is_open())
450 mthrow("Cannot open file \"" + filename);
451
452 f << header << buffer;
453 f.close();
454 }
455
456
457 // check if key contains a certain subkey
458 bool odb::is_subkey(std::string str) {
459 if (m_tid != TID_KEY)
460 return false;
461
462 std::string first = str;
463 std::string tail{};
464 if (str.find('/') != std::string::npos) {
465 first = str.substr(0, str.find('/'));
466 tail = str.substr(str.find('/') + 1);
467 }
468
469 int i;
470 for (i = 0; i < m_num_values; i++)
471 if (m_data[i].get_odb().get_name() == first)
472 break;
473 if (i == m_num_values)
474 return false;
475
476 if (!tail.empty())
477 return m_data[i].get_odb().is_subkey(tail);
478
479 return true;
480 }
481
482 odb &odb::get_subkey(std::string str) {
483 if (m_tid == 0) {
484 if (is_auto_create()) {
485 m_tid = TID_KEY;
486 int status = db_create_key(s_hDB, 0, m_name.c_str(), m_tid);
488 mthrow("Cannot create ODB key \"" + m_name + "\", status" + std::to_string(status));
489 db_find_key(s_hDB, 0, m_name.c_str(), &m_hKey);
490 if (s_debug) {
491 if (m_name[0] == '/')
492 std::cout << "Created ODB key \"" + m_name + "\"" << std::endl;
493 else
494 std::cout << "Created ODB key \"" + get_full_path() + "\"" << std::endl;
495 }
496 // strip path from name
497 if (m_name.find_last_of('/') != std::string::npos)
498 m_name = m_name.substr(m_name.find_last_of('/') + 1);
499 } else
500 mthrow("Invalid key \"" + m_name + "\" does not have subkeys");
501
502 }
503 if (m_tid != TID_KEY)
504 mthrow("ODB key \"" + get_full_path() + "\" does not have subkeys");
505
506 std::string first = str;
507 std::string tail{};
508 if (str.find('/') != std::string::npos) {
509 first = str.substr(0, str.find('/'));
510 tail = str.substr(str.find('/') + 1);
511 }
512
513 int i;
514 for (i = 0; i < m_num_values; i++)
515 if (equal_ustring(first.c_str(), m_data[i].get_odb().get_name().c_str()))
516 break;
517 if (i == m_num_values) {
518 if (is_auto_create()) {
519 if (m_num_values == 0) {
520 m_num_values = 1;
521 m_data = new u_odb[1]{};
522 i = 0;
523 } else {
524 // resize array
526 i = m_num_values - 1;
527 }
528 midas::odb *o = new midas::odb();
530 m_data[i].set_parent(this);
531 o->set_name(get_full_path() + "/" + str);
532 o->set_tid(0); // tid is currently undefined
533 o->set_flags(get_flags());
534 o->set_parent(this);
535 m_data[i].set(o);
536 } else
537 mthrow("ODB key \"" + get_full_path() + "\" does not contain subkey \"" + first + "\"");
538 }
539 if (!tail.empty())
540 return m_data[i].get_odb().get_subkey(tail);
541
542 return *m_data[i].get_podb();
543 }
544
545 // get number of subkeys in ODB, return number and vector of names
546 int odb::get_subkeys(std::vector<std::string> &name) {
547 if (m_tid != TID_KEY)
548 return 0;
549 if (m_hKey == 0 || m_hKey == -1)
550 mthrow("get_sub-keys called with invalid m_hKey for ODB key \"" + m_name + "\"");
551
552 // count number of subkeys in ODB
553 std::vector<HNDLE> hlist;
554 int n = 0;
555 for (int i = 0;; i++) {
556 HNDLE h;
557 int status = db_enum_key(s_hDB, m_hKey, i, &h);
558 if (status != DB_SUCCESS)
559 break;
560 KEY key;
561 db_get_key(s_hDB, h, &key);
562 hlist.push_back(h);
563 name.push_back(key.name);
564 n = i + 1;
565 }
566
567 return n;
568 }
569
570 // obtain key definition from ODB and allocate local data array
571 bool odb::read_key(const std::string &path) {
572 init_hdb();
573
574 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
575 if (status != DB_SUCCESS)
576 return false;
577
578 KEY key;
580 if (status != DB_SUCCESS)
581 mthrow("db_get_key for ODB key \"" + path +
582 "\" failed with status " + std::to_string(status));
583
584 // check for correct type if given as parameter
585 if (m_tid > 0 && m_tid != (int) key.type)
586 mthrow("ODB key \"" + get_full_path() +
587 "\" has different type than specified");
588
589 if (s_debug)
590 std::cout << "Get definition for ODB key \"" + get_full_path() + "\"" << std::endl;
591
592 m_tid = key.type;
593 m_name = key.name;
594 if (m_tid == TID_KEY) {
595
596 // merge ODB keys with local keys
597 for (int i = 0; i < m_num_values; i++) {
598 std::string p(path);
599 if (p.back() != '/')
600 p += "/";
601 p += m_data[i].get_odb().get_name();
602 HNDLE h;
603 status = db_find_key(s_hDB, 0, p.c_str(), &h);
604 if (status != DB_SUCCESS) {
605 // if key does not exist in ODB write it
606 m_data[i].get_odb().write_key(p, true);
607 m_data[i].get_odb().write();
608 } else {
609 // check key type
610 KEY key;
611 status = db_get_key(s_hDB, h, &key);
612 if (status != DB_SUCCESS)
613 mthrow("db_get_key for ODB key \"" + get_full_path() +
614 "\" failed with status " + std::to_string(status));
615 if (m_data[i].get_odb().get_tid() != (int)key.type) {
616 // write key if different
617 m_data[i].get_odb().write_key(p, true);
618 m_data[i].get_odb().write();
619 }
620 if (m_data[i].get_odb().get_tid() == TID_KEY) {
621 // update subkey structure
622 m_data[i].get_odb().read_key(p);
623 }
624 }
625 }
626
627 // read back everything from ODB
628 std::vector<std::string> name;
630 delete[] m_data;
632 for (int i = 0; i < m_num_values; i++) {
633 std::string p(path);
634 if (p.back() != '/')
635 p += "/";
636 p += name[i];
637 midas::odb *o = new midas::odb(p.c_str());
638 o->set_parent(this);
640 m_data[i].set_parent(this);
641 m_data[i].set(o);
642 }
643 } else {
645 delete[] m_data;
647 for (int i = 0; i < m_num_values; i++) {
649 m_data[i].set_parent(this);
650 }
651 }
652
653 return true;
654 }
655
656 // create key in ODB if it does not exist, otherwise check key type
657 bool odb::write_key(std::string &path, bool force_write) {
658 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
659 if (status != DB_SUCCESS) {
660 if (m_tid == 0) // auto-create subdir
661 m_tid = TID_KEY;
662 if (m_tid > 0 && m_tid < TID_LAST) {
663 status = db_create_key(s_hDB, 0, path.c_str(), m_tid);
664 if (status != DB_SUCCESS)
665 mthrow("ODB key \"" + path + "\" cannot be created");
666 status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
667 if (status != DB_SUCCESS)
668 mthrow("ODB key \"" + path + "\" not found after creation");
669 if (s_debug) {
670 if (path[0] == '/')
671 std::cout << "Created ODB key \"" + path + "\"" << std::endl;
672 else
673 std::cout << "Created ODB key \"" + get_full_path() + "\"" << std::endl;
674 }
675 } else
676 mthrow("ODB key \"" + path + "\" cannot be found");
677 return true;
678 } else {
679 KEY key;
681 if (status != DB_SUCCESS)
682 mthrow("db_get_key for ODB key \"" + path +
683 "\" failed with status " + std::to_string(status));
684 if (m_tid == 0)
685 m_tid = key.type;
686
687 // check for correct type
688 if (m_tid > 0 && m_tid != (int) key.type) {
689 if (force_write) {
690 // delete and recreate key
691 status = db_delete_key(s_hDB, m_hKey, false);
692 if (status != DB_SUCCESS)
693 mthrow("db_delete_key for ODB key \"" + path +
694 "\" failed with status " + std::to_string(status));
695 status = db_create_key(s_hDB, 0, path.c_str(), m_tid);
696 if (status != DB_SUCCESS)
697 mthrow("ODB key \"" + path + "\" cannot be created");
698 status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
699 if (status != DB_SUCCESS)
700 mthrow("ODB key \"" + path + "\" not found after creation");
701 if (s_debug)
702 std::cout << "Re-created ODB key \"" + get_full_path() << "\" with different type" << std::endl;
703 } else
704 // abort
705 mthrow("ODB key \"" + get_full_path() +
706 "\" has differnt type than specified");
707 } else if (s_debug)
708 std::cout << "Validated ODB key \"" + get_full_path() + "\"" << std::endl;
709
710 return false;
711 }
712 }
713
714
715 // retrieve data from ODB and assign it to this object
716 void odb::read() {
717 if (!is_connected_odb())
718 return;
719
720 // check if deleted
721 if (is_deleted())
722 mthrow("ODB key \"" + m_name + "\" cannot be pulled because it has been deleted");
723
724 if (m_hKey == 0)
725 return; // needed to print un-connected objects
726
727 if (m_tid == 0)
728 mthrow("Read of invalid ODB key \"" + m_name + "\"");
729
730 if (m_hKey == -1) {
731 // connect un-connected object (crated via XML)
732 std::string path = get_full_path();
733
734 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
735 if (status != DB_SUCCESS)
736 mthrow("Cannot connect key \"" + path + "\" to ODB");
737 }
738
739 int status{};
740 if (m_tid == TID_STRING) {
741 KEY key;
743 char *str = (char *) malloc(key.total_size);
744 int size = key.total_size;
746 for (int i = 0; i < m_num_values; i++)
747 m_data[i].set(str + i * key.item_size);
748 free(str);
749 } else if (m_tid == TID_KEY) {
750 std::vector<std::string> name;
751 int n = get_subkeys(name);
752 if (n != m_num_values) {
753 // if subdirs have changed, rebuild it
754 delete[] m_data;
755 m_num_values = n;
757 for (int i = 0; i < m_num_values; i++) {
758 std::string k(get_full_path());
759 k += "/" + name[i];
760 midas::odb *o = new midas::odb(k.c_str());
761 o->set_parent(this);
763 m_data[i].set_parent(this);
764 m_data[i].set(o);
765 }
766 }
767 for (int i = 0; i < m_num_values; i++)
768 m_data[i].get_odb().read();
770 } else {
771 // resize local array if number of values has changed
772 KEY key;
774 if (key.num_values != m_num_values) {
775 delete[] m_data;
778 for (int i = 0; i < m_num_values; i++) {
780 m_data[i].set_parent(this);
781 }
782 }
783
785 void *buffer = malloc(size);
786 void *p = buffer;
788 for (int i = 0; i < m_num_values; i++) {
789 if (m_tid == TID_UINT8)
790 m_data[i].set(*static_cast<uint8_t *>(p));
791 else if (m_tid == TID_INT8)
792 m_data[i].set(*static_cast<int8_t *>(p));
793 else if (m_tid == TID_UINT16)
794 m_data[i].set(*static_cast<uint16_t *>(p));
795 else if (m_tid == TID_INT16)
796 m_data[i].set(*static_cast<int16_t *>(p));
797 else if (m_tid == TID_UINT32)
798 m_data[i].set(*static_cast<uint32_t *>(p));
799 else if (m_tid == TID_INT32)
800 m_data[i].set(*static_cast<int32_t *>(p));
801 else if (m_tid == TID_UINT64)
802 m_data[i].set(*static_cast<uint64_t *>(p));
803 else if (m_tid == TID_INT64)
804 m_data[i].set(*static_cast<int64_t *>(p));
805 else if (m_tid == TID_BOOL)
806 m_data[i].set(*static_cast<bool *>(p));
807 else if (m_tid == TID_FLOAT)
808 m_data[i].set(*static_cast<float *>(p));
809 else if (m_tid == TID_DOUBLE)
810 m_data[i].set(*static_cast<double *>(p));
811 else if (m_tid == TID_STRING)
812 m_data[i].set(std::string(static_cast<const char *>(p)));
813 else if (m_tid == TID_LINK)
814 m_data[i].set(std::string(static_cast<const char *>(p)));
815 else
816 mthrow("Invalid type ID " + std::to_string(m_tid));
817
818 p = static_cast<char *>(p) + rpc_tid_size(m_tid);
819 }
820 free(buffer);
821 }
822
823 if (status != DB_SUCCESS)
824 mthrow("db_get_data for ODB key \"" + get_full_path() +
825 "\" failed with status " + std::to_string(status));
826 if (s_debug) {
827 if (m_tid == TID_KEY) {
828 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
829 std::to_string(m_num_values - 1) + "]\"" << std::endl;
830 } else {
831 std::string s;
832 get(s, false, false);
833 if (m_num_values > 1) {
834 if (m_tid == TID_STRING || m_tid == TID_LINK)
835 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
836 std::to_string(m_num_values - 1) + "]\": [\"" + s + "\"]" << std::endl;
837 else
838 std::cout << "Get ODB key \"" + get_full_path() + "[0..." +
839 std::to_string(m_num_values - 1) + "]\": [" + s + "]" << std::endl;
840 } else {
841 if (m_tid == TID_STRING || m_tid == TID_LINK)
842 std::cout << "Get ODB key \"" + get_full_path() + "\": \"" + s + "\"" << std::endl;
843 else
844 std::cout << "Get ODB key \"" + get_full_path() + "\": " + s << std::endl;
845 }
846 }
847 }
848 }
849
850 // retrieve individual member of array
851 void odb::read(int index) {
852 if (!is_connected_odb())
853 return;
854
855 if (m_hKey == 0 || m_hKey == -1)
856 return; // needed to print un-connected objects
857
858 if (m_tid == 0)
859 mthrow("Pull of invalid ODB key \"" + m_name + "\"");
860
861 int status{};
862 if (m_tid == TID_STRING || m_tid == TID_LINK) {
863 KEY key;
865 char *str = (char *) malloc(key.item_size);
866 int size = key.item_size;
869 free(str);
870 } else if (m_tid == TID_KEY) {
873 } else {
874 int size = rpc_tid_size(m_tid);
875 void *buffer = malloc(size);
876 void *p = buffer;
878 if (m_tid == TID_UINT8)
879 m_data[index].set(*static_cast<uint8_t *>(p));
880 else if (m_tid == TID_INT8)
881 m_data[index].set(*static_cast<int8_t *>(p));
882 else if (m_tid == TID_UINT16)
883 m_data[index].set(*static_cast<uint16_t *>(p));
884 else if (m_tid == TID_INT16)
885 m_data[index].set(*static_cast<int16_t *>(p));
886 else if (m_tid == TID_UINT32)
887 m_data[index].set(*static_cast<uint32_t *>(p));
888 else if (m_tid == TID_INT32)
889 m_data[index].set(*static_cast<int32_t *>(p));
890 else if (m_tid == TID_UINT64)
891 m_data[index].set(*static_cast<uint64_t *>(p));
892 else if (m_tid == TID_INT64)
893 m_data[index].set(*static_cast<int64_t *>(p));
894 else if (m_tid == TID_BOOL)
895 m_data[index].set(*static_cast<bool *>(p));
896 else if (m_tid == TID_FLOAT)
897 m_data[index].set(*static_cast<float *>(p));
898 else if (m_tid == TID_DOUBLE)
899 m_data[index].set(*static_cast<double *>(p));
900 else if (m_tid == TID_STRING)
901 m_data[index].set(std::string(static_cast<const char *>(p)));
902 else if (m_tid == TID_LINK)
903 m_data[index].set(std::string(static_cast<const char *>(p)));
904 else
905 mthrow("Invalid type ID " + std::to_string(m_tid));
906
907 free(buffer);
908 }
909
910 if (status != DB_SUCCESS)
911 mthrow("db_get_data for ODB key \"" + get_full_path() +
912 "\" failed with status " + std::to_string(status));
913 if (s_debug) {
914 std::string s;
915 m_data[index].get(s);
916 if (m_tid == TID_STRING || m_tid == TID_LINK)
917 std::cout << "Get ODB key \"" + get_full_path() + "[" +
918 std::to_string(index) + "]\": [\"" + s + "\"]" << std::endl;
919 else
920 std::cout << "Get ODB key \"" + get_full_path() + "[" +
921 std::to_string(index) + "]\": [" + s + "]" << std::endl;
922 }
923 }
924
925 // push individual member of an array
926 void odb::write(int index, int str_size) {
927 if (!is_connected_odb())
928 return;
929
930 if (m_hKey == -1) {
931 // connect un-connected object (crated via XML)
932 std::string path = get_full_path();
933
934 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
935 if (status != DB_SUCCESS)
936 mthrow("Cannot connect key \"" + path + "\" to ODB");
937
938 } else if (m_hKey == 0) {
939 if (is_auto_create()) {
940 std::string to_create = m_name[0] == '/' ? m_name : get_full_path();
941 int status = db_create_key(s_hDB, 0, to_create.c_str(), m_tid);
943 mthrow("Cannot create ODB key \"" + to_create + "\", status =" + std::to_string(status));
944 db_find_key(s_hDB, 0, to_create.c_str(), &m_hKey);
945 if (s_debug) {
946 std::cout << "Created ODB key \"" + to_create + "\"" << std::endl;
947 }
948 // strip path from name
949 if (m_name.find_last_of('/') != std::string::npos)
950 m_name = m_name.substr(m_name.find_last_of('/') + 1);
951 } else
952 mthrow("Write of un-connected ODB key \"" + m_name + "\" not possible");
953 }
954
955 // don't write keys
956 if (m_tid == TID_KEY)
957 return;
958
959 int status{};
960 if (m_tid == TID_STRING || m_tid == TID_LINK) {
961 KEY key;
963 std::string s;
964 m_data[index].get(s);
965 if (m_num_values == 1) {
966 int size = key.item_size;
968 size = s.size() + 1;
969 if (str_size > 0)
970 size = str_size;
971 char *ss = (char *)malloc(size+1);
972 mstrlcpy(ss, s.c_str(), size);
973 if (is_trigger_hotlink())
975 else
977 free(ss);
978 } else {
979 if (key.item_size == 0)
980 key.item_size = s.size() + 1;
981 if (str_size > 0) {
982 if (key.item_size > 0 && key.item_size != str_size) {
983 std::cout << "ODB string size mismatch for \"" << get_full_path() <<
984 "\" (" << key.item_size << " vs " << str_size << "). ODB key recreated."
985 << std::endl;
986 if (is_trigger_hotlink())
987 status = db_set_data(s_hDB, m_hKey, s.c_str(), str_size, 1, m_tid);
988 else
989 status = db_set_data1(s_hDB, m_hKey, s.c_str(), str_size, 1, m_tid);
990 }
992 }
994 }
995 if (s_debug) {
996 if (m_num_values > 1)
997 std::cout << "Set ODB key \"" + get_full_path() + "[" + std::to_string(index) + "]\" = \"" + s
998 + "\"" << std::endl;
999 else
1000 std::cout << "Set ODB key \"" + get_full_path() + "\" = \"" + s + "\""<< std::endl;
1001 }
1002 } else {
1003 u_odb u = m_data[index];
1004 if (m_tid == TID_BOOL) {
1005 u.set_parent(nullptr);
1006 BOOL b = static_cast<bool>(u); // "bool" is only 1 Byte, BOOL is 4 Bytes
1008 } else {
1010 }
1011 if (s_debug) {
1012 std::string s;
1013 u.get(s);
1014 if (m_num_values > 1)
1015 std::cout << "Set ODB key \"" + get_full_path() + "[" + std::to_string(index) + "]\" = " + s
1016 << std::endl;
1017 else
1018 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1019 }
1020 }
1021 if (status != DB_SUCCESS)
1022 mthrow("db_set_data_index for ODB key \"" + get_full_path() +
1023 "\" failed with status " + std::to_string(status));
1024 }
1025
1026 // write all members of an array to the ODB
1028
1029 // check if deleted
1030 if (is_deleted())
1031 mthrow("ODB key \"" + m_name + "\" cannot be written because it has been deleted");
1032
1033 // write subkeys
1034 if (m_tid == TID_KEY) {
1035 for (int i = 0; i < m_num_values; i++)
1036 m_data[i].get_odb().write();
1037 return;
1038 }
1039
1040 if (m_tid == 0 && m_data[0].get_tid() != 0)
1041 m_tid = m_data[0].get_tid();
1042
1044 mthrow("Invalid TID for ODB key \"" + get_full_path() + "\"");
1045
1046 if ((m_hKey == 0 || m_hKey == -1) && !is_auto_create())
1047 mthrow("Writing ODB key \"" + m_name +
1048 "\" is not possible because of invalid key handle");
1049
1050 // if index operator [] returned previously a certain index, write only this one
1051 if (m_last_index != -1) {
1053 m_last_index = -1;
1054 return;
1055 }
1056
1057 if (m_num_values == 1) {
1058 write(0, str_size);
1059 return;
1060 }
1061
1062 if (m_hKey == -1) {
1063 // connect un-connected object (crated via XML)
1064 std::string path = get_full_path();
1065
1066 int status = db_find_key(s_hDB, 0, path.c_str(), &m_hKey);
1067 if (status != DB_SUCCESS)
1068 mthrow("Cannot connect key \"" + path + "\" to ODB");
1069
1070 } else if (m_hKey == 0) {
1071 if (is_auto_create()) {
1072 std::string to_create = m_name[0] == '/' ? m_name : get_full_path();
1073 int status = db_create_key(s_hDB, 0, to_create.c_str(), m_tid);
1075 mthrow("Cannot create ODB key \"" + to_create + "\", status" + std::to_string(status));
1076 db_find_key(s_hDB, 0, to_create.c_str(), &m_hKey);
1077 if (s_debug) {
1078 std::cout << "Created ODB key \"" + to_create + "\"" << std::endl;
1079 }
1080 // strip path from name
1081 if (m_name.find_last_of('/') != std::string::npos)
1082 m_name = m_name.substr(m_name.find_last_of('/') + 1);
1083 } else
1084 mthrow("Write of un-connected ODB key \"" + m_name + "\" not possible");
1085 }
1086
1087 int status{};
1088 if (m_tid == TID_STRING || m_tid == TID_LINK) {
1090 KEY key;
1092 if (key.item_size == 0 || key.total_size == 0) {
1093 int size = 1;
1094 for (int i = 0; i < m_num_values; i++) {
1095 std::string d;
1096 m_data[i].get(d);
1097 if ((int) d.size() + 1 > size)
1098 size = d.size() + 1;
1099 }
1100 // round up to multiples of 32
1101 size = (((size - 1) / 32) + 1) * 32;
1102 key.item_size = size;
1104 }
1105 char *str = (char *) malloc(key.item_size * m_num_values);
1106 for (int i = 0; i < m_num_values; i++) {
1107 std::string d;
1108 m_data[i].get(d);
1109 strncpy(str + i * key.item_size, d.c_str(), key.item_size);
1110 }
1111 if (is_trigger_hotlink())
1113 else
1115 free(str);
1116 if (s_debug) {
1117 std::string s;
1118 get(s, true, false);
1119 std::cout << "Set ODB key \"" + get_full_path() +
1120 "[0..." + std::to_string(m_num_values - 1) + "]\" = [" + s + "]" << std::endl;
1121 }
1122 } else {
1123 std::string s;
1124 m_data[0].get(s);
1125 if (is_trigger_hotlink())
1126 status = db_set_data(s_hDB, m_hKey, s.c_str(), s.length() + 1, 1, m_tid);
1127 else
1128 status = db_set_data1(s_hDB, m_hKey, s.c_str(), s.length() + 1, 1, m_tid);
1129 if (s_debug)
1130 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1131 }
1132 } else {
1134 uint8_t *buffer = (uint8_t *) malloc(size);
1135 uint8_t *p = buffer;
1136 for (int i = 0; i < m_num_values; i++) {
1137 if (m_tid == TID_BOOL) {
1138 // bool has 1 Byte, BOOL has 4 Bytes
1139 BOOL b = static_cast<bool>(m_data[i]);
1140 memcpy(p, &b, rpc_tid_size(m_tid));
1141 } else {
1142 memcpy(p, (void*)&m_data[i], rpc_tid_size(m_tid));
1143 }
1144 p += rpc_tid_size(m_tid);
1145 }
1146 if (is_trigger_hotlink())
1148 else
1150 free(buffer);
1151 if (s_debug) {
1152 std::string s;
1153 get(s, false, false);
1154 if (m_num_values > 1)
1155 std::cout << "Set ODB key \"" + get_full_path() + "[0..." + std::to_string(m_num_values - 1) +
1156 "]\" = [" + s + "]" << std::endl;
1157 else
1158 std::cout << "Set ODB key \"" + get_full_path() + "\" = " + s << std::endl;
1159 }
1160 }
1161
1162 if (status != DB_SUCCESS)
1163 mthrow("db_set_data for ODB key \"" + get_full_path() +
1164 "\" failed with status " + std::to_string(status));
1165 }
1166
1168 // Delete any subkeys that are not in the list of defaults.
1169 KEY key;
1170 db_get_key(hDB, hKey, &key);
1171
1172 if (key.type == TID_KEY) {
1173 std::vector<std::string> to_delete;
1174
1175 for (int i = 0;; i++) {
1176 HNDLE hSubKey;
1177 int status = db_enum_key(hDB, hKey, i, &hSubKey);
1178 if (status != DB_SUCCESS)
1179 break;
1180
1181 KEY subKey;
1183 std::string full_path = path + "/" + subKey.name;
1184
1185 if (!default_odb.is_subkey(subKey.name)) {
1186 to_delete.push_back(subKey.name);
1187
1188 if (default_odb.get_debug()) {
1189 std::cout << "Deleting " << full_path << " as not in list of defaults" << std::endl;
1190 }
1191 } else if (key.type == TID_KEY) {
1193 }
1194 }
1195
1196 for (auto name : to_delete) {
1197 HNDLE hSubKey;
1198 db_find_key(hDB, hKey, name.c_str(), &hSubKey);
1200 }
1201 }
1202 }
1203
1204 void recurse_get_defaults_order(std::string path, midas::odb& default_odb, std::map<std::string, std::vector<std::string> >& retval) {
1205 for (midas::odb& sub : default_odb) {
1206 if (sub.get_tid() == TID_KEY) {
1207 recurse_get_defaults_order(path + "/" + sub.get_name(), sub, retval);
1208 }
1209
1210 retval[path].push_back(sub.get_name());
1211 }
1212 }
1213
1214 void recurse_fix_order(midas::odb& default_odb, std::map<std::string, std::vector<std::string> >& user_order) {
1215 std::string path = default_odb.get_full_path();
1216
1217 if (user_order.find(path) != user_order.end()) {
1218 default_odb.fix_order(user_order[path]);
1219 }
1220
1221 for (midas::odb& it : default_odb) {
1222 if (it.get_tid() == TID_KEY) {
1224 }
1225 }
1226 }
1227
1228 void odb::fix_order(std::vector<std::string> target_order) {
1229 // Fix the order of ODB keys to match that specified in target_order.
1230 // The in-ODB representation is simple, as we can just use db_reorder_key()
1231 // on anything that's in the wrong place.
1232 // The in-memory representation is a little trickier, but we just copy raw
1233 // memory into a temporary array, so we don't have to delete/recreate the
1234 // u_odb objects.
1235 std::vector<std::string> curr_order;
1236
1237 if (get_subkeys(curr_order) <= 0) {
1238 // Not a TID_KEY (or no keys)
1239 return;
1240 }
1241
1242 if (target_order.size() != curr_order.size() || (int)target_order.size() != m_num_values) {
1243 return;
1244 }
1245
1246 HNDLE hKey = get_hkey();
1247 bool force_order = false;
1248
1249 // Temporary location where we'll store in-memory u_odb objects in th
1250 // correct order.
1252
1253 for (int i = 0; i < m_num_values; i++) {
1254 if (force_order || curr_order[i] != target_order[i]) {
1255 force_order = true;
1256 HNDLE hSubKey;
1257
1258 // Fix the order in the ODB
1261 }
1262
1263 // Fix the order in memory
1264 auto curr_it = std::find(curr_order.begin(), curr_order.end(), target_order[i]);
1265
1266 if (curr_it == curr_order.end()) {
1267 // Logic error - bail to avoid doing any damage to the in-memory version.
1268 delete[] new_m_data;
1269 return;
1270 }
1271
1272 int curr_idx = curr_it - curr_order.begin();
1274 }
1275
1276 // Final update of the in-memory version so they are in the correct order
1277 for (int i = 0; i < m_num_values; i++) {
1278 m_data[i] = new_m_data[i];
1279
1280 // Nullify pointers that point to the same object in
1281 // m_data and new_m_data, so the underlying object doesn't
1282 // get destroyed when we delete new_m_data.
1283 new_m_data[i].set_string_ptr(nullptr);
1284 new_m_data[i].set_odb(nullptr);
1285 }
1286
1287 delete[] new_m_data;
1288 }
1289
1290 // connect function with separated path and key name
1291 void odb::connect(const std::string &p, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults) {
1292 init_hdb();
1293
1294 if (!name.empty())
1295 m_name = name;
1296 std::string path(p);
1297
1298 if (path.empty())
1299 mthrow("odb::connect() cannot be called with an empty ODB path");
1300
1301 if (path[0] != '/')
1302 mthrow("odb::connect(\"" + path + "\"): path must start with leading \"/\"");
1303
1304 if (path.back() != '/')
1305 path += "/";
1306
1307 path += m_name;
1308
1309 HNDLE hKey;
1310 int status = db_find_key(s_hDB, 0, path.c_str(), &hKey);
1311 bool key_exists = (status == DB_SUCCESS);
1312 bool created = false;
1313
1315 // Recurse down to delete keys as needed.
1316 // We need to do this recursively BEFORE calling read/read_key for the first time
1317 // to ensure that subdirectories get handled correctly.
1319 }
1320
1321 if (!key_exists || write_defaults) {
1323 } else {
1324 read_key(path);
1325 }
1326
1327 // correct wrong parent ODB from initializer_list
1328 for (int i = 0; i < m_num_values; i++)
1329 m_data[i].set_parent(this);
1330
1331 if (m_tid == TID_KEY) {
1332 for (int i = 0; i < m_num_values; i++)
1333 m_data[i].get_odb().connect(get_full_path(), m_data[i].get_odb().get_name(), write_defaults);
1334 } else if (created || write_defaults) {
1335 write();
1336 } else {
1337 read();
1338 }
1339 }
1340
1341 // send key definitions and data with optional subkeys to certain path in ODB
1343
1344 if (str.empty())
1345 mthrow("odb::connect() cannot be called with an empty ODB path");
1346
1347 if (str[0] != '/')
1348 mthrow("odb::connect(\"" + str + "\"): path must start with leading \"/\"");
1349
1350 if (str == "/")
1351 mthrow("odb::connect(\"" + str + "\"): root ODB tree is not allowed");
1352
1353 if (str.back() == '/')
1354 str = str.substr(0, str.size()-1);
1355
1356 // separate ODB path and key nam
1357 std::string name;
1358 std::string path;
1359 name = str.substr(str.find_last_of('/') + 1);
1360 path = str.substr(0, str.find_last_of('/') + 1);
1361
1363 }
1364
1365 // shorthand for the same behavior as db_check_record:
1366 // - keep values of keys that already exist with the correct type
1367 // - add keys that user provided but aren't in ODB already
1368 // - delete keys that are in ODB but not in user's settings
1369 // - re-order ODB keys to match user's order
1370 void odb::connect_and_fix_structure(std::string path) {
1371 // Store the order the user specified.
1372 // Need to do this recursively before calling connect(), as the first
1373 // read() in that function merges user keys and existing keys.
1374 std::map<std::string, std::vector<std::string> > user_order;
1376
1377 // Main connect() that adds/deletes/updates keys as needed.
1378 connect(path, false, true);
1379
1380 // Fix order in ODB (and memory)
1382 }
1383
1385 init_hdb();
1386
1388
1389 if (this->is_write_protect())
1390 mthrow("Cannot modify write protected key \"" + m_name + "\"");
1391
1392
1393 // delete key in ODB
1395 if (status != DB_SUCCESS && status != DB_INVALID_HANDLE)
1396 mthrow("db_delete_key for ODB key \"" + m_name +
1397 "\" returnd error code " + std::to_string(status));
1398
1399 if (s_debug)
1400 std::cout << "Deleted ODB key \"" + m_name + "\"" << std::endl;
1401
1402 // invalidate this object
1403 delete[] m_data;
1404 m_data = nullptr;
1405 m_num_values = 0;
1406 m_tid = 0;
1407 m_hKey = 0;
1408
1409 // set flag that this object has been deleted
1410 set_deleted(true);
1411 }
1412
1414 // set mode of ODB key
1415 // default is MODE_READ | MODE_WRITE | MODE_DELETE
1416
1417 init_hdb();
1418
1419 // set mode in ODB
1421
1423 mthrow("db_set_mode for ODB key \"" + get_full_path() +
1424 "\" returnd error code " + std::to_string(status));
1425
1426 if (s_debug)
1427 std::cout << "Set mode of ODB key \"" + get_full_path() + "\" to " << mode << std::endl;
1428 }
1429
1431 init_hdb();
1432
1433 // set mode in ODB
1434 KEY key;
1435 int status = db_get_key(s_hDB, m_hKey, &key);
1436
1438 mthrow("db_get_key for ODB key \"" + get_full_path() +
1439 "\" returnd error code " + std::to_string(status));
1440
1441 return key.access_mode;
1442 }
1443
1444 unsigned int odb::get_last_written() {
1445 init_hdb();
1446
1447 // set mode in ODB
1448 KEY key;
1449 int status = db_get_key(s_hDB, m_hKey, &key);
1450
1452 mthrow("db_get_key for ODB key \"" + get_full_path() +
1453 "\" returnd error code " + std::to_string(status));
1454
1455 return (unsigned int) (key.last_written);
1456 }
1457
1458 void odb::watch(std::function<void(midas::odb &)> f) {
1459 if (m_hKey == 0 || m_hKey == -1)
1460 mthrow("watch() called for ODB key \"" + m_name +
1461 "\" which is not connected to ODB");
1462
1463 // create a deep copy of current object in case it
1464 // goes out of scope
1465 midas::odb* ow = new midas::odb(*this);
1466
1467 ow->m_watch_callback = f;
1469
1470 // put object into watchlist
1471 g_watchlist.push_back(ow);
1472 }
1473
1475 {
1476 for (int i=0 ; i<(int) g_watchlist.size() ; i++) {
1477 if (g_watchlist[i]->get_hkey() == this->get_hkey()) {
1478 db_unwatch(s_hDB, g_watchlist[i]->get_hkey());
1479 delete g_watchlist[i];
1480 g_watchlist.erase(g_watchlist.begin() + i);
1481 i--;
1482 }
1483 }
1484 }
1485
1487 {
1488 for (int i=0 ; i<(int) g_watchlist.size() ; i++) {
1490 delete g_watchlist[i];
1491 }
1492 g_watchlist.clear();
1493 }
1494
1495 void odb::set(std::string s)
1496 {
1497 if (this->is_write_protect())
1498 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1499
1500 if (m_tid == TID_BOOL)
1501 s = (s == "y" || s == "1") ? "1" : "0";
1502
1503 m_num_values = 1;
1504 m_data = new u_odb[1];
1505 m_data[0].set_parent(this);
1506 m_data[0].set_tid(m_tid);
1507 m_data[0].set(s);
1508 }
1509
1510 void odb::set(std::string s, int i)
1511 {
1512 if (this->is_write_protect())
1513 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1514
1515 if (m_tid == TID_BOOL)
1516 s = (s == "y" || s == "1") ? "1" : "0";
1517
1518 if (m_data == nullptr)
1519 m_data = new u_odb[m_num_values];
1520 m_data[i].set_parent(this);
1522 m_data[i].set(s);
1523 }
1524
1525 void odb::set_string_size(std::string s, int size)
1526 {
1527 if (this->is_write_protect())
1528 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1529
1530 m_num_values = 1;
1531 m_tid = TID_STRING;
1532 m_data = new u_odb[1];
1533 m_data[0].set_parent(this);
1534 m_data[0].set_tid(m_tid);
1537 }
1538
1539 void odb::set_odb(odb *o, int i)
1540 {
1541 if (this->is_write_protect())
1542 mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
1543
1544 if (m_data == nullptr)
1545 m_data = new u_odb[m_num_values];
1546 m_data[i].set_parent(this);
1548 m_data[i].set_odb(o);
1549 }
1550
1551 //-----------------------------------------------
1552
1553 //---- u_odb implementations calling functions from odb
1554
1556 if (m_tid == TID_STRING || m_tid == TID_LINK)
1557 delete m_string;
1558 else if (m_tid == TID_KEY)
1559 delete m_odb;
1560 }
1561
1562 // get function for strings
1563 void u_odb::get(std::string &s) {
1564 if (m_tid == TID_UINT8)
1565 s = std::to_string(m_uint8);
1566 else if (m_tid == TID_INT8)
1567 s = std::to_string(m_int8);
1568 else if (m_tid == TID_UINT16)
1569 s = std::to_string(m_uint16);
1570 else if (m_tid == TID_INT16)
1571 s = std::to_string(m_int16);
1572 else if (m_tid == TID_UINT32)
1573 s = std::to_string(m_uint32);
1574 else if (m_tid == TID_INT32)
1575 s = std::to_string(m_int32);
1576 else if (m_tid == TID_UINT64)
1577 s = std::to_string(m_uint64);
1578 else if (m_tid == TID_INT64)
1579 s = std::to_string(m_int64);
1580 else if (m_tid == TID_BOOL)
1581 s = std::string(m_bool ? "true" : "false");
1582 else if (m_tid == TID_FLOAT)
1583 s = std::to_string(m_float);
1584 else if (m_tid == TID_DOUBLE)
1585 s = std::to_string(m_double);
1586 else if (m_tid == TID_STRING)
1587 s = *m_string;
1588 else if (m_tid == TID_LINK)
1589 s = *m_string;
1590 else if (m_tid == TID_KEY)
1591 m_odb->print(s, 0);
1592 else if (m_tid == 0)
1593 mthrow("Subkey \"" + m_parent_odb->get_name() + "\" not found");
1594 else
1595 mthrow("Invalid type ID " + std::to_string(m_tid));
1596 }
1597
1598 //---- u_odb assignment and arithmetic operators overloads which call odb::write()
1599
1600 // overload assignment operators
1602 if (m_tid == 0)
1603 m_tid = TID_UINT8;
1604 set(v);
1607 return v;
1608 }
1610 if (m_tid == 0)
1611 m_tid = TID_INT8;
1612 set(v);
1615 return v;
1616 }
1618 if (m_tid == 0)
1619 m_tid = TID_UINT16;
1620 set(v);
1623 return v;
1624 }
1626 if (m_tid == 0)
1627 m_tid = TID_INT16;
1628 set(v);
1631 return v;
1632 }
1634 if (m_tid == 0)
1635 m_tid = TID_UINT32;
1636 set(v);
1639 return v;
1640 }
1642 if (m_tid == 0)
1643 m_tid = TID_INT32;
1644 set(v);
1647 return v;
1648 }
1650 if (m_tid == 0)
1651 m_tid = TID_UINT64;
1652 set(v);
1655 return v;
1656 }
1658 if (m_tid == 0)
1659 m_tid = TID_INT64;
1660 set(v);
1663 return v;
1664 }
1665 bool u_odb::operator=(bool v) {
1666 if (m_tid == 0)
1667 m_tid = TID_BOOL;
1668 set(v);
1671 return v;
1672 }
1673 float u_odb::operator=(float v) {
1674 if (m_tid == 0)
1675 m_tid = TID_FLOAT;
1676 set(v);
1679 return v;
1680 }
1681 double u_odb::operator=(double v) {
1682 if (m_tid == 0)
1683 m_tid = TID_DOUBLE;
1684 set(v);
1687 return v;
1688 }
1689 const char * u_odb::operator=(const char * v) {
1690 if (m_tid == 0)
1691 m_tid = TID_STRING;
1692 set(v);
1695 return v;
1696 }
1697
1698 std::string * u_odb::operator=(std::string * v){
1699 if (m_tid == 0)
1700 m_tid = TID_STRING;
1701 set(*v);
1704 return v;
1705 }
1706
1707 std::string u_odb::operator=(std::string v){
1708 if (m_tid == 0)
1709 m_tid = TID_STRING;
1710 set(v);
1713 return v;
1714 }
1715
1716 void u_odb::set_string_size(std::string v, int size) {
1717 m_tid = TID_STRING;
1718 set(v);
1720 m_parent_odb->write(size);
1721 }
1722
1723 // overload all standard conversion operators
1724 u_odb::operator uint8_t() {
1725 if (m_parent_odb)
1726 m_parent_odb->set_last_index(-1);
1727 return get<uint8_t>();
1728 }
1729 u_odb::operator int8_t() {
1730 if (m_parent_odb)
1731 m_parent_odb->set_last_index(-1);
1732 return get<int8_t>();
1733 }
1734 u_odb::operator uint16_t() {
1735 if (m_parent_odb)
1736 m_parent_odb->set_last_index(-1);
1737 return get<uint16_t>();
1738 }
1739 u_odb::operator int16_t() {
1740 if (m_parent_odb)
1741 m_parent_odb->set_last_index(-1);
1742 return get<int16_t>();
1743 }
1744 u_odb::operator uint32_t() {
1745 if (m_parent_odb)
1746 m_parent_odb->set_last_index(-1);
1747 return get<uint32_t>();
1748 }
1749 u_odb::operator int32_t() {
1750 if (m_parent_odb)
1751 m_parent_odb->set_last_index(-1);
1752 return get<int32_t>();
1753 }
1754 u_odb::operator uint64_t() {
1755 if (m_parent_odb)
1756 m_parent_odb->set_last_index(-1);
1757 return get<uint64_t>();
1758 }
1759 u_odb::operator int64_t() {
1760 if (m_parent_odb)
1761 m_parent_odb->set_last_index(-1);
1762 return get<int64_t>();
1763 }
1764 u_odb::operator bool() {
1765 if (m_parent_odb)
1766 m_parent_odb->set_last_index(-1);
1767 return get<bool>();
1768 }
1769 u_odb::operator float() {
1770 if (m_parent_odb)
1771 m_parent_odb->set_last_index(-1);
1772 return get<float>();
1773 }
1774 u_odb::operator double() {
1775 if (m_parent_odb)
1776 m_parent_odb->set_last_index(-1);
1777 return get<double>();
1778 }
1779 u_odb::operator std::string() {
1780 if (m_parent_odb)
1781 m_parent_odb->set_last_index(-1);
1782 std::string s;
1783 get(s);
1784 return s;
1785 }
1786 u_odb::operator const char *() {
1787 if (m_parent_odb)
1788 m_parent_odb->set_last_index(-1);
1789 if (m_tid != TID_STRING && m_tid != TID_LINK)
1790 mthrow("Only ODB string keys can be converted to \"const char *\"");
1791 return m_string->c_str();
1792 }
1793 u_odb::operator midas::odb&() {
1794 if (m_parent_odb)
1795 m_parent_odb->set_last_index(-1);
1796 if (m_tid != TID_KEY)
1797 mthrow("Only ODB directories can be converted to \"midas::odb &\"");
1798 return *m_odb;
1799 }
1800
1801
1802 void u_odb::add(double inc, bool write) {
1803 if (m_tid == TID_UINT8)
1804 m_uint8 += inc;
1805 else if (m_tid == TID_INT8)
1806 m_int8 += inc;
1807 else if (m_tid == TID_UINT16)
1808 m_uint16 += inc;
1809 else if (m_tid == TID_INT16)
1810 m_int16 += inc;
1811 else if (m_tid == TID_UINT32)
1812 m_uint32 += inc;
1813 else if (m_tid == TID_INT32)
1814 m_int32 += inc;
1815 else if (m_tid == TID_FLOAT)
1816 m_float += static_cast<float>(inc);
1817 else if (m_tid == TID_DOUBLE)
1818 m_double += inc;
1819 else
1820 mthrow("Invalid arithmetic operation for ODB key \"" +
1821 m_parent_odb->get_full_path() + "\"");
1824 }
1825
1826 void u_odb::mult(double f, bool write) {
1827 int tid = m_parent_odb->get_tid();
1828 if (tid == TID_UINT8)
1829 m_uint8 *= f;
1830 else if (tid == TID_INT8)
1831 m_int8 *= f;
1832 else if (tid == TID_UINT16)
1833 m_uint16 *= f;
1834 else if (tid == TID_INT16)
1835 m_int16 *= f;
1836 else if (tid == TID_UINT32)
1837 m_uint32 *= f;
1838 else if (tid == TID_INT32)
1839 m_int32 *= f;
1840 else if (tid == TID_FLOAT)
1841 m_float *= f;
1842 else if (tid == TID_DOUBLE)
1843 m_double *= f;
1844 else
1845 mthrow("Invalid operation for ODB key \"" +
1846 m_parent_odb->get_full_path() + "\"");
1849 }
1850
1851}; // namespace midas
#define FALSE
Definition cfortran.h:309
void set_string_size(std::string s, int size)
Definition odbxx.cxx:1525
std::string get_parent_path()
Definition odbxx.cxx:307
std::string get_full_path()
Definition odbxx.cxx:291
void set(std::string str)
Definition odbxx.cxx:1495
int m_num_values
Definition odbxx.h:455
static bool exists(const std::string &name)
Definition odbxx.cxx:66
std::string get_name()
Definition odbxx.h:1278
void write(int str_size=0)
Definition odbxx.cxx:1027
int m_tid
Definition odbxx.h:449
void set_mode(int mode)
Definition odbxx.cxx:1413
void delete_key()
Definition odbxx.cxx:1384
void set_odb(odb *o, int i)
Definition odbxx.cxx:1539
u_odb * m_data
Definition odbxx.h:451
void deep_copy(odb &d, const odb &s)
Definition odbxx.cxx:263
bool is_deleted() const
Definition odbxx.h:516
bool is_auto_refresh_read() const
Definition odbxx.h:1199
static void unwatch_all()
Definition odbxx.cxx:1486
static HNDLE s_hDB
Definition odbxx.h:438
HNDLE get_hkey()
Definition odbxx.h:1273
std::function< void(midas::odb &)> m_watch_callback
Definition odbxx.h:461
bool is_auto_create() const
Definition odbxx.h:1214
bool is_preserve_string_size() const
Definition odbxx.h:1193
static void watch_callback(int hDB, int hKey, int index, void *info)
Definition odbxx.cxx:114
void unwatch()
Definition odbxx.cxx:1474
T get()
Definition odbxx.h:480
int get_tid()
Definition odbxx.h:1276
bool is_auto_refresh_write() const
Definition odbxx.h:1205
bool read_key(const std::string &path)
Definition odbxx.cxx:571
void resize(int size)
Definition odbxx.cxx:320
void set_preserve_string_size(bool f)
Definition odbxx.h:1194
int size()
Definition odbxx.cxx:315
int get_mode()
Definition odbxx.cxx:1430
void read()
Definition odbxx.cxx:716
void resize_mdata(int size)
Definition odbxx.cxx:190
odb & get_subkey(std::string str)
Definition odbxx.cxx:482
void set_flags_recursively(uint32_t f)
Definition odbxx.cxx:142
unsigned int get_last_written()
Definition odbxx.cxx:1444
int get_subkeys(std::vector< std::string > &name)
Definition odbxx.cxx:546
void watch(std::function< void(midas::odb &)> f)
Definition odbxx.cxx:1458
std::string s()
Definition odbxx.h:1281
void save(const std::string &filename)
Definition odbxx.cxx:436
void set_last_index(int i)
Definition odbxx.h:956
static int create(const char *name, int type=TID_KEY)
Definition odbxx.cxx:130
bool is_subkey(std::string str)
Definition odbxx.cxx:458
static bool s_debug
Definition odbxx.h:440
void fix_order(std::vector< std::string > target_subkey_order)
Definition odbxx.cxx:1228
std::string dump()
Definition odbxx.cxx:356
int m_last_index
Definition odbxx.h:457
void connect_and_fix_structure(std::string path)
Definition odbxx.cxx:1370
static bool s_connected_odb
Definition odbxx.h:442
static void init_hdb()
Definition odbxx.cxx:43
uint32_t get_flags()
Definition odbxx.h:514
bool is_trigger_hotlink() const
Definition odbxx.h:1232
bool write_key(std::string &path, bool write_defaults)
Definition odbxx.cxx:657
std::string print()
Definition odbxx.cxx:348
static midas::odb * search_hkey(midas::odb *po, int hKey)
Definition odbxx.cxx:52
static bool is_connected_odb()
Definition odbxx.h:1250
std::bitset< 9 > m_flags
Definition odbxx.h:447
void set_deleted(bool f)
Definition odbxx.h:517
static void load(const std::string &filename, const std::string &odb_path)
Definition odbxx.cxx:92
midas::odb * odb_from_xml(PMXML_NODE node, odb *o)
Definition odbxx.h:1142
void set_parent(midas::odb *p)
Definition odbxx.h:524
HNDLE m_hKey
Definition odbxx.h:459
std::string m_name
Definition odbxx.h:453
bool is_write_protect() const
Definition odbxx.h:1226
void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults=false)
Definition odbxx.cxx:1291
midas::odb * m_parent
Definition odbxx.h:463
uint8_t m_uint8
Definition odbxx.h:50
bool m_bool
Definition odbxx.h:58
uint8_t operator=(uint8_t v)
Definition odbxx.cxx:1601
void set_tid(int tid)
Definition odbxx.h:103
void mult(double f, bool push=true)
Definition odbxx.cxx:1826
void set_string(std::string s)
Definition odbxx.h:170
int8_t m_int8
Definition odbxx.h:51
uint64_t m_uint64
Definition odbxx.h:56
int32_t m_int32
Definition odbxx.h:55
int64_t m_int64
Definition odbxx.h:57
void set(T v)
Definition odbxx.h:140
double m_double
Definition odbxx.h:60
odb * m_parent_odb
Definition odbxx.h:66
void set_odb(odb *v)
Definition odbxx.h:187
int m_tid
Definition odbxx.h:65
void add(double inc, bool push=true)
Definition odbxx.cxx:1802
void set_parent(odb *o)
Definition odbxx.h:100
uint16_t m_uint16
Definition odbxx.h:52
odb * get_podb()
Definition odbxx.h:367
void set_string_size(std::string s, int size)
Definition odbxx.cxx:1716
int16_t m_int16
Definition odbxx.h:53
odb & get_odb()
Definition odbxx.h:373
std::string s()
Definition odbxx.h:359
std::string * m_string
Definition odbxx.h:61
void set_string_ptr(std::string *s)
Definition odbxx.h:177
odb * m_odb
Definition odbxx.h:62
float m_float
Definition odbxx.h:59
uint32_t m_uint32
Definition odbxx.h:54
int get_tid()
Definition odbxx.h:105
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
Definition midas.cxx:3011
#define DB_KEY_EXIST
Definition midas.h:641
#define DB_INVALID_HANDLE
Definition midas.h:635
#define DB_SUCCESS
Definition midas.h:631
#define DB_NO_KEY
Definition midas.h:642
#define DB_CREATED
Definition midas.h:632
#define DB_TRUNCATED
Definition midas.h:644
#define TID_DOUBLE
Definition midas.h:343
#define TID_KEY
Definition midas.h:349
#define TID_BOOL
Definition midas.h:340
#define TID_UINT64
Definition midas.h:352
#define TID_INT64
Definition midas.h:351
#define TID_INT32
Definition midas.h:339
#define TID_UINT8
Definition midas.h:328
#define TID_LINK
Definition midas.h:350
#define TID_STRING
Definition midas.h:346
#define TID_INT8
Definition midas.h:330
#define TID_UINT32
Definition midas.h:337
#define TID_UINT16
Definition midas.h:333
#define TID_INT16
Definition midas.h:335
#define TID_FLOAT
Definition midas.h:341
#define TID_LAST
Definition midas.h:354
BOOL equal_ustring(const char *str1, const char *str2)
Definition odb.cxx:3201
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
Definition odb.cxx:6893
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
Definition odb.cxx:3856
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
Definition odb.cxx:6361
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
Definition odb.cxx:4990
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
Definition odb.cxx:6539
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
Definition odb.cxx:3308
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
Definition odb.cxx:9037
INT db_unwatch(HNDLE hDB, HNDLE hKey)
Definition odb.cxx:13887
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
Definition odb.cxx:8027
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
Definition odb.cxx:6019
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
Definition odb.cxx:8126
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
Definition odb.cxx:13813
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7215
INT db_set_data1(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
Definition odb.cxx:7313
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
Definition odb.cxx:4079
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
Definition odb.cxx:7828
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
Definition odb.cxx:5586
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
Definition odb.cxx:7502
INT rpc_tid_size(INT id)
Definition midas.cxx:11757
void ** info
Definition fesimdaq.cxx:41
HNDLE hKey
DWORD n[4]
Definition mana.cxx:247
INT index
Definition mana.cxx:271
INT type
Definition mana.cxx:269
HNDLE hDB
main ODB handle
Definition mana.cxx:207
KEY key
Definition mdump.cxx:34
INT i
Definition mdump.cxx:32
#define mthrow(arg)
Definition mexcept.h:24
INT HNDLE
Definition midas.h:132
DWORD BOOL
Definition midas.h:105
#define TRUE
Definition midas.h:182
#define write(n, a, f, d)
#define name(x)
Definition midas_macro.h:24
#define set(var, value)
static std::string indent(int x, const char *p=" ")
void recurse_fix_order(midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &user_order)
Definition odbxx.cxx:1214
void recurse_get_defaults_order(std::string path, midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &retval)
Definition odbxx.cxx:1204
std::vector< midas::odb * > g_watchlist
Definition odbxx.cxx:38
void recurse_del_keys_not_in_defaults(std::string path, HNDLE hDB, HNDLE hKey, midas::odb &default_odb)
Definition odbxx.cxx:1167
INT k
Definition odbhist.cxx:40
char str[256]
Definition odbhist.cxx:33
DWORD status
Definition odbhist.cxx:39
TH1X EXPRT * h1_book(const char *name, const char *title, int bins, double min, double max)
Definition rmidas.h:24
Definition midas.h:1026
INT num_values
Definition midas.h:1028
DWORD type
Definition midas.h:1027
INT total_size
Definition midas.h:1031
WORD access_mode
Definition midas.h:1033
INT last_written
Definition midas.h:1037
char name[NAME_LENGTH]
Definition midas.h:1029
INT item_size
Definition midas.h:1032
double d
Definition system.cxx:1311
static double sub(double a, double b)
Definition tinyexpr.c:244