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