17#include <initializer_list>
51 mthrow(
"Operation only possible if connected to an online ODB");
56 mthrow(
"Please call cm_connect_experiment() before accessing the ODB");
92 std::cout <<
"Delete key " +
name <<
" not found in ODB" << std::endl;
96 std::cout <<
"Delete ODB key " +
name << std::endl;
101 void odb::load(
const std::string &filename,
const std::string &odb_path) {
104 mthrow(
"Cannot connect to ODB");
112 mthrow(
"ODB path " + odb_path +
" not found in ODB");
117 mthrow(
"ODB path " + odb_path +
" does not point to a directory");
125 if (po->
m_data ==
nullptr)
126 mthrow(
"Callback received for a midas::odb object which went out of scope");
128 if (poh ==
nullptr) {
130 mthrow(
"New key \"" +
s +
"\" has been created in ODB after calling watch()");
145 mthrow(
"Cannot create key " + std::string(
name) +
", db_create_key() status = " + std::to_string(
status));
155 m_data[
i].get_odb().set_flags_recursively(f);
165 mthrow(
"ODB key \"" +
str +
"\" not found in ODB");
168 char *buffer = (
char *)malloc(bsize);
174 buffer = (
char *)realloc(buffer, bsize);
179 mthrow(
"Cannot retrieve XML data, status = " + std::to_string(
status));
182 std::cout <<
"Retrieved XML tree for \"" +
str +
"\"" << std::endl;
184 char error[256] =
"";
185 PMXML_NODE tree = mxml_parse_buffer(buffer, error,
sizeof(error), NULL);
187 std::cout <<
"MXML error, buffer =\n" << buffer << std::endl;
188 mthrow(
"MXML error: " + std::string(error));
195 mxml_free_tree(tree);
199 char error[256] =
"";
200 PMXML_NODE tree = mxml_parse_buffer(
str.c_str(), error,
sizeof(error), NULL);
202 std::cout <<
"MXML error, buffer =\n" <<
str << std::endl;
203 mthrow(
"MXML error: " + std::string(error));
208 root = &tree->child[2];
211 std::stringstream ss(subkey);
212 std::string dir, xpath;
213 while (std::getline(ss, dir,
'/'))
215 xpath +=
"/dir[@name=\"" + dir +
"\"]";
218 root = mxml_find_node(&tree->child[2], xpath.c_str());
219 if (root ==
nullptr) {
221 size_t pos = xpath.rfind(
"dir");
222 if (pos != std::string::npos)
223 xpath.replace(pos, 3,
"key");
224 root = mxml_find_node(&tree->child[2], xpath.c_str());
226 mthrow(
"ODB key \"" + subkey +
"\" not found in ODB");
231 mxml_free_tree(tree);
241 std::vector<std::string>
split(std::string input,
char delimiter =
'/') {
242 std::vector<std::string> result;
245 if (!input.empty() && input.front() ==
'/')
247 if (!input.empty() && input.back() ==
'/')
250 std::stringstream ss(input);
252 while (std::getline(ss, item, delimiter)) {
253 result.push_back(item);
261 MJsonNode* node = MJsonNode::Parse(
str.c_str());
262 if (node->GetType() == MJSON_ERROR)
263 mthrow(
"Error parsing JSON: " + node->GetError());
272 auto dirs =
split(subkey);
277 std::string root_name =
"root";
278 for (std::string subdir : dirs) {
279 const MJsonStringVector* names = node->GetObjectNames();
280 const MJsonNodeVector* nodes = node->GetObjectNodes();
283 for (
i=0;
i<(int)names->size();
i++) {
284 const char *
name = (*names)[
i].c_str();
285 MJsonNode *subnode = (*nodes)[
i];
286 if (strchr(
name,
'/'))
288 if (node->GetType() == MJSON_OBJECT)
289 if (
name == subdir) {
290 auto key = node->FindObjectNode((std::string(
name) +
"/key").c_str());
292 tid =
key->FindObjectNode(
"type")->GetInt();
301 if (
i == (
int)names->size())
302 mthrow(
"Subdirectory \"" + subdir +
"\" not found in JSON");
330 new_array[
i].set_string(
"");
342 void odb::get(std::string &s,
bool quotes,
bool refresh) {
394 d.m_num_values =
s.m_num_values;
396 d.m_watch_callback =
s.m_watch_callback;
398 for (
int i = 0;
i <
d.m_num_values;
i++) {
400 d.m_data[
i].set_parent(&
d);
403 d.m_data[
i].set_string(
s.m_data[
i]);
412 d.m_data[
i] =
s.m_data[
i];
413 d.m_data[
i].set_parent(
this);
437 std::size_t
i =
s.find_last_of(
"/");
454 "\" failed with status " + std::to_string(
status));
466 "\" failed with status " + std::to_string(
status));
468 if (
size > old_size) {
469 for (
int i=old_size ;
i<
size ;
i++)
497 s +=
"\"" +
m_name +
"\": {\n";
534 s +=
"\"" +
m_name +
"\": {\n";
553 s +=
"\"" +
m_name +
"/key\": ";
554 s +=
"{ \"type\": " + std::to_string(
m_tid) +
", ";
574 std::string header =
"{\n";
575 header +=
" \"/MIDAS version\" : \"2.1\",\n";
576 header +=
" \"/filename\" : \"" + filename +
"\",\n";
581 header +=
" \"/ODB path\" : \"" + path +
"\",\n\n";
587 std::ofstream f(filename);
589 mthrow(
"Cannot open file \"" + filename);
591 f << header << buffer;
601 std::string first =
str;
603 if (
str.find(
'/') != std::string::npos) {
604 first =
str.substr(0,
str.find(
'/'));
605 tail =
str.substr(
str.find(
'/') + 1);
631 std::cout <<
"Created ODB key \"" +
m_name +
"\"" << std::endl;
633 std::cout <<
"Created ODB key \"" +
get_full_path() +
"\"" << std::endl;
636 if (
m_name.find_last_of(
'/') != std::string::npos)
639 mthrow(
"Invalid key \"" +
m_name +
"\" does not have subkeys");
645 std::string first =
str;
647 if (
str.find(
'/') != std::string::npos) {
648 first =
str.substr(0,
str.find(
'/'));
649 tail =
str.substr(
str.find(
'/') + 1);
689 mthrow(
"get_sub-keys called with invalid m_hKey for ODB key \"" +
m_name +
"\"");
692 std::vector<HNDLE> hlist;
694 for (
int i = 0;;
i++) {
720 mthrow(
"db_get_key for ODB key \"" + path +
721 "\" failed with status " + std::to_string(
status));
726 "\" has different type than specified");
729 std::cout <<
"Get definition for ODB key \"" +
get_full_path() +
"\"" << std::endl;
753 "\" failed with status " + std::to_string(
status));
767 std::vector<std::string>
name;
804 mthrow(
"ODB key \"" + path +
"\" cannot be created");
807 mthrow(
"ODB key \"" + path +
"\" not found after creation");
810 std::cout <<
"Created ODB key \"" + path +
"\"" << std::endl;
812 std::cout <<
"Created ODB key \"" +
get_full_path() +
"\"" << std::endl;
815 mthrow(
"ODB key \"" + path +
"\" cannot be found");
821 mthrow(
"db_get_key for ODB key \"" + path +
822 "\" failed with status " + std::to_string(
status));
832 mthrow(
"db_delete_key for ODB key \"" + path +
833 "\" failed with status " + std::to_string(
status));
836 mthrow(
"ODB key \"" + path +
"\" cannot be created");
839 mthrow(
"ODB key \"" + path +
"\" not found after creation");
841 std::cout <<
"Re-created ODB key \"" +
get_full_path() <<
"\" with different type" << std::endl;
845 "\" has differnt type than specified");
847 std::cout <<
"Validated ODB key \"" +
get_full_path() +
"\"" << std::endl;
861 mthrow(
"ODB key \"" +
m_name +
"\" cannot be pulled because it has been deleted");
875 mthrow(
"Cannot connect key \"" + path +
"\" to ODB");
889 std::vector<std::string>
name;
924 void *buffer = malloc(
size);
951 m_data[
i].
set(std::string(
static_cast<const char *
>(p)));
953 m_data[
i].
set(std::string(
static_cast<const char *
>(p)));
955 mthrow(
"Invalid type ID " + std::to_string(
m_tid));
964 "\" failed with status " + std::to_string(
status));
971 get(
s,
false,
false);
975 std::to_string(
m_num_values - 1) +
"]\": [\"" +
s +
"\"]" << std::endl;
978 std::to_string(
m_num_values - 1) +
"]\": [" +
s +
"]" << std::endl;
981 std::cout <<
"Get ODB key \"" +
get_full_path() +
"\": \"" +
s +
"\"" << std::endl;
983 std::cout <<
"Get ODB key \"" +
get_full_path() +
"\": " +
s << std::endl;
1014 void *buffer = malloc(
size);
1044 mthrow(
"Invalid type ID " + std::to_string(
m_tid));
1051 "\" failed with status " + std::to_string(
status));
1057 std::to_string(
index) +
"]\": [\"" +
s +
"\"]" << std::endl;
1060 std::to_string(
index) +
"]\": [" +
s +
"]" << std::endl;
1075 mthrow(
"Cannot connect key \"" + path +
"\" to ODB");
1077 }
else if (
m_hKey == 0) {
1082 mthrow(
"Cannot create ODB key \"" + to_create +
"\", status =" + std::to_string(
status));
1085 std::cout <<
"Created ODB key \"" + to_create +
"\"" << std::endl;
1088 if (
m_name.find_last_of(
'/') != std::string::npos)
1091 mthrow(
"Write of un-connected ODB key \"" +
m_name +
"\" not possible");
1107 size =
s.size() + 1;
1110 char *ss = (
char *)malloc(
size+1);
1111 mstrlcpy(ss,
s.c_str(),
size);
1122 std::cout <<
"ODB string size mismatch for \"" <<
get_full_path() <<
1123 "\" (" <<
key.
item_size <<
" vs " << str_size <<
"). ODB key recreated."
1136 std::cout <<
"Set ODB key \"" +
get_full_path() +
"[" + std::to_string(
index) +
"]\" = \"" +
s
1137 +
"\"" << std::endl;
1139 std::cout <<
"Set ODB key \"" +
get_full_path() +
"\" = \"" +
s +
"\""<< std::endl;
1145 BOOL b =
static_cast<bool>(u);
1154 std::cout <<
"Set ODB key \"" +
get_full_path() +
"[" + std::to_string(
index) +
"]\" = " +
s
1157 std::cout <<
"Set ODB key \"" +
get_full_path() +
"\" = " +
s << std::endl;
1162 "\" failed with status " + std::to_string(
status));
1170 mthrow(
"ODB key \"" +
m_name +
"\" cannot be written because it has been deleted");
1182 if (m_tid < 1 || m_tid >=
TID_LAST)
1187 "\" is not possible because of invalid key handle");
1207 mthrow(
"Cannot connect key \"" + path +
"\" to ODB");
1209 }
else if (
m_hKey == 0) {
1214 mthrow(
"Cannot create ODB key \"" + to_create +
"\", status" + std::to_string(
status));
1217 std::cout <<
"Created ODB key \"" + to_create +
"\"" << std::endl;
1220 if (
m_name.find_last_of(
'/') != std::string::npos)
1223 mthrow(
"Write of un-connected ODB key \"" +
m_name +
"\" not possible");
1236 if ((
int)
d.size() + 1 >
size)
1237 size =
d.size() + 1;
1240 size = (((
size - 1) / 32) + 1) * 32;
1257 get(
s,
true,
false);
1259 "[0..." + std::to_string(
m_num_values - 1) +
"]\" = [" +
s +
"]" << std::endl;
1269 std::cout <<
"Set ODB key \"" +
get_full_path() +
"\" = " +
s << std::endl;
1273 uint8_t *buffer = (uint8_t *) malloc(
size);
1274 uint8_t *p = buffer;
1292 get(
s,
false,
false);
1295 "]\" = [" +
s +
"]" << std::endl;
1297 std::cout <<
"Set ODB key \"" +
get_full_path() +
"\" = " +
s << std::endl;
1303 "\" failed with status " + std::to_string(
status));
1312 std::vector<std::string> to_delete;
1314 for (
int i = 0;;
i++) {
1322 std::string full_path = path +
"/" + subKey.
name;
1325 to_delete.push_back(subKey.
name);
1328 std::cout <<
"Deleting " << full_path <<
" as not in list of defaults" << std::endl;
1335 for (
auto name : to_delete) {
1349 retval[path].push_back(
sub.get_name());
1356 if (user_order.find(path) != user_order.end()) {
1357 default_odb.
fix_order(user_order[path]);
1361 if (it.get_tid() ==
TID_KEY) {
1374 std::vector<std::string> curr_order;
1381 if (target_order.size() != curr_order.size() || (
int)target_order.size() !=
m_num_values) {
1386 bool force_order =
false;
1393 if (force_order || curr_order[
i] != target_order[
i]) {
1403 auto curr_it = std::find(curr_order.begin(), curr_order.end(), target_order[
i]);
1405 if (curr_it == curr_order.end()) {
1407 delete[] new_m_data;
1411 int curr_idx = curr_it - curr_order.begin();
1412 new_m_data[
i] =
m_data[curr_idx];
1426 delete[] new_m_data;
1430 void odb::connect(
const std::string &p,
const std::string &
name,
bool write_defaults,
bool delete_keys_not_in_defaults) {
1435 std::string path(p);
1438 mthrow(
"odb::connect() cannot be called with an empty ODB path");
1441 mthrow(
"odb::connect(\"" + path +
"\"): path must start with leading \"/\"");
1443 if (path.back() !=
'/')
1451 bool created =
false;
1453 if (key_exists && delete_keys_not_in_defaults) {
1460 if (!key_exists || write_defaults) {
1461 created =
write_key(path, write_defaults);
1473 }
else if (created || write_defaults) {
1481 void odb::connect(std::string
str,
bool write_defaults,
bool delete_keys_not_in_defaults) {
1484 mthrow(
"odb::connect() cannot be called with an empty ODB path");
1487 mthrow(
"odb::connect(\"" +
str +
"\"): path must start with leading \"/\"");
1490 mthrow(
"odb::connect(\"" +
str +
"\"): root ODB tree is not allowed");
1492 if (
str.back() ==
'/')
1498 name =
str.substr(
str.find_last_of(
'/') + 1);
1499 path =
str.substr(0,
str.find_last_of(
'/') + 1);
1501 connect(path,
name, write_defaults, delete_keys_not_in_defaults);
1513 std::map<std::string, std::vector<std::string> > user_order;
1529 mthrow(
"Cannot modify write protected key \"" +
m_name +
"\"");
1536 "\" returnd error code " + std::to_string(
status));
1539 std::cout <<
"Deleted ODB key \"" +
m_name +
"\"" << std::endl;
1563 "\" returnd error code " + std::to_string(
status));
1566 std::cout <<
"Set mode of ODB key \"" +
get_full_path() +
"\" to " << mode << std::endl;
1578 "\" returnd error code " + std::to_string(
status));
1592 "\" returnd error code " + std::to_string(
status));
1600 "\" which is not connected to ODB");
1640 s = (
s ==
"y" ||
s ==
"1") ?
"1" :
"0";
1655 s = (
s ==
"y" ||
s ==
"1") ?
"1" :
"0";
1720 s = std::string(
m_bool ?
"true" :
"false");
1731 else if (
m_tid == 0)
1734 mthrow(
"Invalid type ID " + std::to_string(
m_tid));
1863 u_odb::operator uint8_t() {
1865 m_parent_odb->set_last_index(-1);
1866 return get<uint8_t>();
1868 u_odb::operator int8_t() {
1870 m_parent_odb->set_last_index(-1);
1871 return get<int8_t>();
1873 u_odb::operator uint16_t() {
1875 m_parent_odb->set_last_index(-1);
1876 return get<uint16_t>();
1878 u_odb::operator int16_t() {
1880 m_parent_odb->set_last_index(-1);
1881 return get<int16_t>();
1883 u_odb::operator uint32_t() {
1885 m_parent_odb->set_last_index(-1);
1886 return get<uint32_t>();
1888 u_odb::operator int32_t() {
1890 m_parent_odb->set_last_index(-1);
1891 return get<int32_t>();
1893 u_odb::operator uint64_t() {
1895 m_parent_odb->set_last_index(-1);
1896 return get<uint64_t>();
1898 u_odb::operator int64_t() {
1900 m_parent_odb->set_last_index(-1);
1901 return get<int64_t>();
1903 u_odb::operator bool() {
1905 m_parent_odb->set_last_index(-1);
1908 u_odb::operator float() {
1910 m_parent_odb->set_last_index(-1);
1911 return get<float>();
1913 u_odb::operator double() {
1915 m_parent_odb->set_last_index(-1);
1916 return get<double>();
1918 u_odb::operator std::string() {
1920 m_parent_odb->set_last_index(-1);
1925 u_odb::operator
const char *() {
1927 m_parent_odb->set_last_index(-1);
1929 mthrow(
"Only ODB string keys can be converted to \"const char *\"");
1930 return m_string->c_str();
1936 mthrow(
"Only ODB directories can be converted to \"midas::odb &\"");
1955 m_float +=
static_cast<float>(inc);
1959 mthrow(
"Invalid arithmetic operation for ODB key \"" +
1984 mthrow(
"Invalid operation for ODB key \"" +
void set_string_size(std::string s, int size)
std::string get_parent_path()
std::string get_full_path()
void set(std::string str)
static bool exists(const std::string &name)
void write(int str_size=0)
void set_auto_refresh_read(bool f)
void set_auto_enlarge_array(bool f)
void set_odb(odb *o, int i)
void deep_copy(odb &d, const odb &s)
bool is_auto_refresh_read() const
static void unwatch_all()
std::function< void(midas::odb &)> m_watch_callback
bool is_auto_create() const
bool is_preserve_string_size() const
static void watch_callback(int hDB, int hKey, int index, void *info)
bool is_auto_refresh_write() const
bool read_key(const std::string &path)
void set_preserve_string_size(bool f)
static thread_local odb_source s_odb_source
void set_trigger_hotlink(bool f)
void set_flags(uint32_t f)
void set_auto_refresh_write(bool f)
void odb_from_xml_remote(const std::string &str)
void set_auto_create(bool f)
static thread_local std::string s_odb_source_str
void odb_from_xml_string(const std::string &str, const std::string &subkey)
void resize_mdata(int size)
odb & get_subkey(std::string str)
void odb_from_json_string(const std::string &str, const std::string &subkey)
void set_flags_recursively(uint32_t f)
unsigned int get_last_written()
midas::odb * odb_from_json(const MJsonNode *node, std::string name, int tid, odb *o)
void set_name(std::string s)
int get_subkeys(std::vector< std::string > &name)
void watch(std::function< void(midas::odb &)> f)
void save(const std::string &filename)
void set_last_index(int i)
static int create(const char *name, int type=TID_KEY)
bool is_subkey(std::string str)
void fix_order(std::vector< std::string > target_subkey_order)
void connect_and_fix_structure(std::string path)
static bool s_connected_odb
bool is_trigger_hotlink() const
bool write_key(std::string &path, bool write_defaults)
static midas::odb * search_hkey(midas::odb *po, int hKey)
static bool is_connected_odb()
static void load(const std::string &filename, const std::string &odb_path)
midas::odb * odb_from_xml(PMXML_NODE node, odb *o)
void set_parent(midas::odb *p)
void set_write_protect(bool f)
bool is_write_protect() const
void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults=false)
uint8_t operator=(uint8_t v)
void mult(double f, bool push=true)
void set_string(std::string s)
void add(double inc, bool push=true)
void set_string_size(std::string s, int size)
void set_string_ptr(std::string *s)
INT cm_get_experiment_database(HNDLE *hDB, HNDLE *hKeyClient)
#define DB_INVALID_HANDLE
BOOL equal_ustring(const char *str1, const char *str2)
INT db_get_data_index(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, INT idx, DWORD type)
INT db_delete_key(HNDLE hDB, HNDLE hKey, BOOL follow_links)
INT db_reorder_key(HNDLE hDB, HNDLE hKey, INT idx)
INT db_get_path(HNDLE hDB, HNDLE hKey, char *path, INT buf_size)
INT db_get_data(HNDLE hDB, HNDLE hKey, void *data, INT *buf_size, DWORD type)
INT db_create_key(HNDLE hDB, HNDLE hKey, const char *key_name, DWORD type)
INT db_copy_xml(HNDLE hDB, HNDLE hKey, char *buffer, int *buffer_size, bool header)
INT db_unwatch(HNDLE hDB, HNDLE hKey)
INT db_set_mode(HNDLE hDB, HNDLE hKey, WORD mode, BOOL recurse)
INT db_get_key(HNDLE hDB, HNDLE hKey, KEY *key)
INT db_load(HNDLE hDB, HNDLE hKeyRoot, const char *filename, BOOL bRemote)
INT db_watch(HNDLE hDB, HNDLE hKey, void(*dispatcher)(INT, INT, INT, void *), void *info)
INT db_set_data(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
INT db_set_data1(HNDLE hDB, HNDLE hKey, const void *data, INT buf_size, INT num_values, DWORD type)
INT db_find_key(HNDLE hDB, HNDLE hKey, const char *key_name, HNDLE *subhKey)
INT db_set_data_index1(HNDLE hDB, HNDLE hKey, const void *data, INT data_size, INT idx, DWORD type, BOOL bNotify)
INT db_enum_key(HNDLE hDB, HNDLE hKey, INT idx, HNDLE *subkey_handle)
INT db_set_num_values(HNDLE hDB, HNDLE hKey, INT num_values)
#define write(n, a, f, d)
static std::string indent(int x, const char *p=" ")
std::vector< std::string > split(std::string input, char delimiter='/')
void recurse_fix_order(midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &user_order)
void recurse_get_defaults_order(std::string path, midas::odb &default_odb, std::map< std::string, std::vector< std::string > > &retval)
std::vector< midas::odb * > g_watchlist
void recurse_del_keys_not_in_defaults(std::string path, HNDLE hDB, HNDLE hKey, midas::odb &default_odb)
static double sub(double a, double b)