otsdaq  v2_04_01
ConfigurationManagerRW.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h"
2 
3 // backbone includes
4 //#include "otsdaq-core/TablePlugins/ConfigurationAliases.h"
5 //#include "otsdaq-core/TablePlugins/Configurations.h"
6 //#include "otsdaq-core/TablePlugins/DefaultConfigurations.h"
7 //#include "otsdaq-core/TablePlugins/VersionAliases.h"
8 
9 //#include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h"//All configurable
10 // objects are included here
11 
12 //
13 //#include "otsdaq-core/TablePlugins/DetectorTable.h"
14 //#include "otsdaq-core/TablePlugins/MaskTable.h"
15 //#include "otsdaq-core/TablePlugins/DetectorToFETable.h"
16 //
17 
18 //#include "otsdaq-core/ConfigurationInterface/DACStream.h"
19 //#include "otsdaq-core/ConfigurationDataFormats/TableGroupKey.h"
20 //
21 //#include "otsdaq-core/ConfigurationInterface/FileConfigurationInterface.h"
22 //
23 //#include <cassert>
24 
25 #include <dirent.h>
26 
27 using namespace ots;
28 
29 #undef __MF_SUBJECT__
30 #define __MF_SUBJECT__ "ConfigurationManagerRW"
31 
32 #define TABLE_INFO_PATH std::string(__ENV__("TABLE_INFO_PATH")) + "/"
33 #define TABLE_INFO_EXT "Info.xml"
34 
35 #define CORE_TABLE_INFO_FILENAME \
36  ((getenv("SERVICE_DATA_PATH") == NULL) \
37  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData") \
38  : (std::string(__ENV__("SERVICE_DATA_PATH")))) + \
39  "/CoreTableInfoNames.dat"
40 
41 //==============================================================================
42 // ConfigurationManagerRW
43 ConfigurationManagerRW::ConfigurationManagerRW(std::string username)
44  : ConfigurationManager(username) // for use as author of new views
45 {
46  __COUT__ << "Using Config Mgr with Write Access! (for " << username << ")" << __E__;
47 
48  // FIXME only necessarily temporarily while Lore is still using fileSystem xml
49  theInterface_ =
50  ConfigurationInterface::getInstance(false); // false to use artdaq DB
51  // FIXME -- can delete this change of
52  // interface once RW and regular use
53  // same interface instance
54 
55  //=========================
56  // dump names of core tables (so UpdateOTS.sh can copy core tables for user)
57  // only if table does not exist
58  {
59  const std::set<std::string>& contextMemberNames = getContextMemberNames();
60  const std::set<std::string>& backboneMemberNames = getBackboneMemberNames();
61  const std::set<std::string>& iterateMemberNames = getIterateMemberNames();
62 
63  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "r");
64 
65  __COUT__ << "Updating core tables table..." << __E__;
66 
67  if(fp) // check for all core table names in file, and force their presence
68  {
69  std::vector<unsigned int> foundVector;
70  char line[100];
71  for(const auto& name : contextMemberNames)
72  {
73  foundVector.push_back(false);
74  rewind(fp);
75  while(fgets(line, 100, fp))
76  {
77  if(strlen(line) < 1)
78  continue;
79  line[strlen(line) - 1] = '\0'; // remove endline
80  if(strcmp(line, ("ContextGroup/" + name).c_str()) == 0) // is match?
81  {
82  foundVector.back() = true;
83  //__COUTV__(name);
84  break;
85  }
86  }
87  }
88 
89  for(const auto& name : backboneMemberNames)
90  {
91  foundVector.push_back(false);
92  rewind(fp);
93  while(fgets(line, 100, fp))
94  {
95  if(strlen(line) < 1)
96  continue;
97  line[strlen(line) - 1] = '\0'; // remove endline
98  if(strcmp(line, ("BackboneGroup/" + name).c_str()) == 0) // is match?
99  {
100  foundVector.back() = true;
101  //__COUTV__(name);
102  break;
103  }
104  }
105  }
106 
107  for(const auto& name : iterateMemberNames)
108  {
109  foundVector.push_back(false);
110  rewind(fp);
111  while(fgets(line, 100, fp))
112  {
113  if(strlen(line) < 1)
114  continue;
115  line[strlen(line) - 1] = '\0'; // remove endline
116  if(strcmp(line, ("IterateGroup/" + name).c_str()) == 0) // is match?
117  {
118  foundVector.back() = true;
119  //__COUTV__(name);
120  break;
121  }
122  }
123  }
124 
125  fclose(fp);
126 
127  // for(const auto &found:foundVector)
128  // __COUTV__(found);
129 
130  // open file for appending the missing names
131  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
132  if(fp)
133  {
134  unsigned int i = 0;
135  for(const auto& name : contextMemberNames)
136  {
137  if(!foundVector[i])
138  fprintf(fp, "\nContextGroup/%s", name.c_str());
139 
140  ++i;
141  }
142  for(const auto& name : backboneMemberNames)
143  {
144  if(!foundVector[i])
145  fprintf(fp, "\nBackboneGroup/%s", name.c_str());
146 
147  ++i;
148  }
149  for(const auto& name : iterateMemberNames)
150  {
151  if(!foundVector[i])
152  fprintf(fp, "\nIterateGroup/%s", name.c_str());
153 
154  ++i;
155  }
156  fclose(fp);
157  }
158  else
159  {
160  __SS__ << "Failed to open core table info file for appending: "
161  << CORE_TABLE_INFO_FILENAME << __E__;
162  __SS_THROW__;
163  }
164  }
165  else
166  {
167  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "w");
168  if(fp)
169  {
170  for(const auto& name : contextMemberNames)
171  fprintf(fp, "\nContextGroup/%s", name.c_str());
172  for(const auto& name : backboneMemberNames)
173  fprintf(fp, "\nBackboneGroup/%s", name.c_str());
174  for(const auto& name : iterateMemberNames)
175  fprintf(fp, "\nIterateGroup/%s", name.c_str());
176  fclose(fp);
177  }
178  else
179  {
180  __SS__ << "Failed to open core table info file: "
181  << CORE_TABLE_INFO_FILENAME << __E__;
182  __SS_THROW__;
183  }
184  }
185  } // end dump names of core tables
186 } // end constructor
187 
188 //==============================================================================
189 // getAllTableInfo()
190 // Used by ConfigurationGUISupervisor to get all the info for the existing configurations
191 //
192 // if(accumulatedErrors)
193 // this implies allowing column errors and accumulating such errors in given string
194 const std::map<std::string, TableInfo>& ConfigurationManagerRW::getAllTableInfo(
195  bool refresh, std::string* accumulatedErrors, const std::string& errorFilterName)
196 {
197  // allTableInfo_ is container to be returned
198 
199  // if(accumulatedErrors)
200  // *accumulatedErrors = "";
201 
202  if(!refresh)
203  return allTableInfo_;
204 
205  // else refresh!
206  allTableInfo_.clear();
207  allGroupInfo_.clear();
208 
209  TableBase* table;
210 
211  // existing configurations are defined by which infos are in TABLE_INFO_PATH
212  // can test that the class exists based on this
213  // and then which versions
214  __COUT__ << "======================================================== "
215  "getAllTableInfo start"
216  << __E__;
217  __COUT__ << "Refreshing all! Extracting list of tables..." << __E__;
218  DIR* pDIR;
219  struct dirent* entry;
220  std::string path = TABLE_INFO_PATH;
221  char fileExt[] = TABLE_INFO_EXT;
222  const unsigned char MIN_TABLE_NAME_SZ = 3;
223  if((pDIR = opendir(path.c_str())) != 0)
224  {
225  while((entry = readdir(pDIR)) != 0)
226  {
227  // enforce table name length
228  if(strlen(entry->d_name) < strlen(fileExt) + MIN_TABLE_NAME_SZ)
229  continue;
230 
231  // find file names with correct file extenstion
232  if(strcmp(&(entry->d_name[strlen(entry->d_name) - strlen(fileExt)]),
233  fileExt) != 0)
234  continue; // skip different extentions
235 
236  entry->d_name[strlen(entry->d_name) - strlen(fileExt)] =
237  '\0'; // remove file extension to get table name
238 
239  //__COUT__ << entry->d_name << __E__;
240 
241  // 0 will force the creation of new instance (and reload from Info)
242  table = 0;
243 
244  try // only add valid table instances to maps
245  {
246  theInterface_->get(table, entry->d_name, 0, 0,
247  true); // dont fill
248  }
249  catch(cet::exception const&)
250  {
251  if(table)
252  delete table;
253  table = 0;
254 
255  __COUT__ << "Skipping! No valid class found for... " << entry->d_name
256  << "\n";
257  continue;
258  }
259  catch(std::runtime_error& e)
260  {
261  if(table)
262  delete table;
263  table = 0;
264 
265  __COUT__ << "Skipping! No valid class found for... " << entry->d_name
266  << "\n";
267  __COUT__ << "Error: " << e.what() << __E__;
268 
269  // for a runtime_error, it is likely that columns are the problem
270  // the Table Editor needs to still fix these.. so attempt to
271  // proceed.
272  if(accumulatedErrors)
273  {
274  if(errorFilterName == "" || errorFilterName == entry->d_name)
275  {
276  *accumulatedErrors += std::string("\nIn table '") +
277  entry->d_name + "'..." +
278  e.what(); // global accumulate
279 
280  __SS__ << "Attempting to allow illegal columns!" << __E__;
281  *accumulatedErrors += ss.str();
282  }
283 
284  // attempt to recover and build a mock-up
285  __COUT__ << "Attempting to allow illegal columns!" << __E__;
286 
287  std::string returnedAccumulatedErrors;
288  try
289  {
290  // table = new TableBase(entry->d_name,
291  // &returnedAccumulatedErrors);
292  table = new TableBase(entry->d_name, &returnedAccumulatedErrors);
293  }
294  catch(...)
295  {
296  __COUT__
297  << "Skipping! Allowing illegal columns didn't work either... "
298  << entry->d_name << "\n";
299  continue;
300  }
301  __COUT__ << "Error (but allowed): " << returnedAccumulatedErrors
302  << __E__;
303 
304  if(errorFilterName == "" || errorFilterName == entry->d_name)
305  *accumulatedErrors +=
306  std::string("\nIn table '") + entry->d_name + "'..." +
307  returnedAccumulatedErrors; // global accumulate
308  }
309  else
310  continue;
311  }
312 
313  //__COUT__ << "Instance created: " << entry->d_name << "\n"; //found!
314 
315  if(nameToTableMap_[entry->d_name]) // handle if instance existed
316  {
317  // copy the temporary versions! (or else all is lost)
318  std::set<TableVersion> versions =
319  nameToTableMap_[entry->d_name]->getStoredVersions();
320  for(auto& version : versions)
321  if(version.isTemporaryVersion())
322  {
323  //__COUT__ << "copying tmp = " << version << __E__;
324 
325  try // do NOT let TableView::init() throw here
326  {
327  nameToTableMap_[entry->d_name]->setActiveView(version);
328  table->copyView( // this calls TableView::init()
329  nameToTableMap_[entry->d_name]->getView(),
330  version,
331  username_);
332  }
333  catch(...) // do NOT let invalid temporary version throw at this
334  // point
335  {
336  } // just trust configurationBase throws out the failed version
337  }
338  //__COUT__ << "deleting: " << entry->d_name << "\n"; //found!
339  delete nameToTableMap_[entry->d_name];
340  nameToTableMap_[entry->d_name] = 0;
341  }
342 
343  nameToTableMap_[entry->d_name] = table;
344 
345  allTableInfo_[entry->d_name].tablePtr_ = table;
346  allTableInfo_[entry->d_name].versions_ = theInterface_->getVersions(table);
347 
348  // also add any existing temporary versions to all table info
349  // because the interface wont find those versions
350  std::set<TableVersion> versions =
351  nameToTableMap_[entry->d_name]->getStoredVersions();
352  for(auto& version : versions)
353  if(version.isTemporaryVersion())
354  {
355  //__COUT__ << "surviving tmp = " << version << __E__;
356  allTableInfo_[entry->d_name].versions_.emplace(version);
357  }
358  }
359  closedir(pDIR);
360  }
361  __COUT__ << "Extracting list of tables complete. Now initializing..." << __E__;
362 
363  // call init to load active versions by default
364  init(accumulatedErrors);
365 
366  __COUT__
367  << "======================================================== getAllTableInfo end"
368  << __E__;
369 
370  // get Group Info too!
371  try
372  {
373  // build allGroupInfo_ for the ConfigurationManagerRW
374 
375  std::set<std::string /*name*/> tableGroups =
376  theInterface_->getAllTableGroupNames();
377  __COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
378 
379  TableGroupKey key;
380  std::string name;
381  for(const auto& fullName : tableGroups)
382  {
383  TableGroupKey::getGroupNameAndKey(fullName, name, key);
384  cacheGroupKey(name, key);
385  }
386 
387  // for each group get member map & comment, author, time, and type for latest key
388  for(auto& groupInfo : allGroupInfo_)
389  {
390  try
391  {
392  loadTableGroup(groupInfo.first /*groupName*/,
393  groupInfo.second.getLatestKey(),
394  false /*doActivate*/,
395  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
396  0 /*progressBar*/,
397  0 /*accumulateErrors*/,
398  &groupInfo.second.latestKeyGroupComment_,
399  &groupInfo.second.latestKeyGroupAuthor_,
400  &groupInfo.second.latestKeyGroupCreationTime_,
401  true /*doNotLoadMember*/,
402  &groupInfo.second.latestKeyGroupTypeString_);
403  }
404  catch(...)
405  {
406  __COUT_WARN__
407  << "Error occurred loading latest group info into cache for '"
408  << groupInfo.first << "'..." << __E__;
409  groupInfo.second.latestKeyGroupComment_ = "UNKNOWN";
410  groupInfo.second.latestKeyGroupAuthor_ = "UNKNOWN";
411  groupInfo.second.latestKeyGroupCreationTime_ = "0";
412  groupInfo.second.latestKeyGroupTypeString_ = "UNKNOWN";
413  }
414  } // end group info loop
415  } // end get group info
416  catch(const std::runtime_error& e)
417  {
418  __SS__ << "A fatal error occurred reading the info for all table groups. Error: "
419  << e.what() << __E__;
420  __COUT_ERR__ << "\n" << ss.str();
421  if(accumulatedErrors)
422  *accumulatedErrors += ss.str();
423  else
424  throw;
425  }
426  catch(...)
427  {
428  __SS__ << "An unknown fatal error occurred reading the info for all table groups."
429  << __E__;
430  __COUT_ERR__ << "\n" << ss.str();
431  if(accumulatedErrors)
432  *accumulatedErrors += ss.str();
433  else
434  throw;
435  }
436 
437  return allTableInfo_;
438 } // end getAllTableInfo
439 
440 //==============================================================================
441 // getVersionAliases()
442 // get version aliases organized by table, for currently active backbone tables
443 // add scratch versions to the alias map returned by ConfigurationManager
444 std::map<std::string /*table name*/,
445  std::map<std::string /*version alias*/, TableVersion /*aliased version*/> >
446 ConfigurationManagerRW::getVersionAliases(void) const
447 {
448  //__COUT__ << "getVersionAliases()" << __E__;
449  std::map<std::string /*table name*/,
450  std::map<std::string /*version alias*/, TableVersion /*aliased version*/> >
451  retMap = ConfigurationManager::getVersionAliases();
452 
453  // always have scratch alias for each table that has a scratch version
454  // overwrite map entry if necessary
455  if(!ConfigurationInterface::isVersionTrackingEnabled())
456  for(const auto& tableInfo : allTableInfo_)
457  for(const auto& version : tableInfo.second.versions_)
458  if(version.isScratchVersion())
459  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
460  TableVersion(TableVersion::SCRATCH);
461 
462  return retMap;
463 } // end getVersionAliases()
464 
465 //==============================================================================
466 // setActiveGlobalConfiguration
467 // load table group and activate
468 // deactivates previous table group of same type if necessary
469 void ConfigurationManagerRW::activateTableGroup(const std::string& configGroupName,
470  TableGroupKey tableGroupKey,
471  std::string* accumulatedTreeErrors)
472 {
473  loadTableGroup(configGroupName,
474  tableGroupKey,
475  true, // loads and activates
476  0, // no members needed
477  0, // no progress bar
478  accumulatedTreeErrors); // accumulate warnings or not
479 
480  if(accumulatedTreeErrors && *accumulatedTreeErrors != "")
481  {
482  __COUT_ERR__ << "Errors were accumulated so de-activating group: "
483  << configGroupName << " (" << tableGroupKey << ")" << __E__;
484  try // just in case any lingering pieces, lets deactivate
485  {
486  destroyTableGroup(configGroupName, true);
487  }
488  catch(...)
489  {
490  }
491  }
492 
493  __COUT_INFO__ << "Updating persistent active groups to "
494  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
495  __MOUT_INFO__ << "Updating persistent active groups to "
496  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
497 
498  std::string fn = ConfigurationManager::ACTIVE_GROUPS_FILENAME;
499  FILE* fp = fopen(fn.c_str(), "w");
500  if(!fp)
501  {
502  __SS__ << "Fatal Error! Unable to open the file "
503  << ConfigurationManager::ACTIVE_GROUPS_FILENAME
504  << " for editing! Is there a permissions problem?" << __E__;
505  __COUT_ERR__ << ss.str();
506  __SS_THROW__;
507  return;
508  }
509 
510  __MCOUT_INFO__("Active Context table group: "
511  << theContextTableGroup_ << "("
512  << (theContextTableGroupKey_
513  ? theContextTableGroupKey_->toString().c_str()
514  : "-1")
515  << ")" << __E__);
516  __MCOUT_INFO__("Active Backbone table group: "
517  << theBackboneTableGroup_ << "("
518  << (theBackboneTableGroupKey_
519  ? theBackboneTableGroupKey_->toString().c_str()
520  : "-1")
521  << ")" << __E__);
522  __MCOUT_INFO__("Active Iterate table group: "
523  << theIterateTableGroup_ << "("
524  << (theIterateTableGroupKey_
525  ? theIterateTableGroupKey_->toString().c_str()
526  : "-1")
527  << ")" << __E__);
528  __MCOUT_INFO__("Active Configuration table group: "
529  << theConfigurationTableGroup_ << "("
530  << (theConfigurationTableGroupKey_
531  ? theConfigurationTableGroupKey_->toString().c_str()
532  : "-1")
533  << ")" << __E__);
534 
535  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
536  fprintf(
537  fp,
538  "%s\n",
539  theContextTableGroupKey_ ? theContextTableGroupKey_->toString().c_str() : "-1");
540  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
541  fprintf(
542  fp,
543  "%s\n",
544  theBackboneTableGroupKey_ ? theBackboneTableGroupKey_->toString().c_str() : "-1");
545  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
546  fprintf(
547  fp,
548  "%s\n",
549  theIterateTableGroupKey_ ? theIterateTableGroupKey_->toString().c_str() : "-1");
550  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
551  fprintf(fp,
552  "%s\n",
553  theConfigurationTableGroupKey_
554  ? theConfigurationTableGroupKey_->toString().c_str()
555  : "-1");
556  fclose(fp);
557 }
558 
559 //==============================================================================
560 // createTemporaryBackboneView
561 // sourceViewVersion of INVALID is from MockUp, else from valid view version
562 // returns temporary version number (which is always negative)
563 TableVersion ConfigurationManagerRW::createTemporaryBackboneView(
564  TableVersion sourceViewVersion)
565 {
566  __COUT_INFO__ << "Creating temporary backbone view from version " << sourceViewVersion
567  << __E__;
568 
569  // find common available temporary version among backbone members
570  TableVersion tmpVersion =
571  TableVersion::getNextTemporaryVersion(); // get the default temporary version
572  TableVersion retTmpVersion;
573  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
574  for(auto& name : backboneMemberNames)
575  {
576  retTmpVersion =
577  ConfigurationManager::getTableByName(name)->getNextTemporaryVersion();
578  if(retTmpVersion < tmpVersion)
579  tmpVersion = retTmpVersion;
580  }
581 
582  __COUT__ << "Common temporary backbone version found as " << tmpVersion << __E__;
583 
584  // create temporary views from source version to destination temporary version
585  for(auto& name : backboneMemberNames)
586  {
587  retTmpVersion =
588  getTableByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
589  if(retTmpVersion != tmpVersion)
590  {
591  __SS__ << "Failure! Temporary view requested was " << tmpVersion
592  << ". Mismatched temporary view created: " << retTmpVersion << __E__;
593  __COUT_ERR__ << ss.str();
594  __SS_THROW__;
595  }
596  }
597 
598  return tmpVersion;
599 }
600 
601 //==============================================================================
602 TableBase* ConfigurationManagerRW::getTableByName(const std::string& tableName)
603 {
604  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
605  {
606  __SS__ << "Table not found with name: " << tableName << __E__;
607  size_t f;
608  if((f = tableName.find(' ')) != std::string::npos)
609  ss << "There was a space character found in the table name needle at "
610  "position "
611  << f << " in the string (was this intended?). " << __E__;
612  __COUT_ERR__ << "\n" << ss.str();
613  __SS_THROW__;
614  }
615  return nameToTableMap_[tableName];
616 }
617 
618 //==============================================================================
619 // getVersionedTableByName
620 // Used by table GUI to load a particular table-version pair as the active version.
621 // This table instance must already exist and be owned by ConfigurationManager.
622 // return null pointer on failure, on success return table pointer.
623 TableBase* ConfigurationManagerRW::getVersionedTableByName(const std::string& tableName,
624  TableVersion version,
625  bool looseColumnMatching)
626 {
627  auto it = nameToTableMap_.find(tableName);
628  if(it == nameToTableMap_.end())
629  {
630  __SS__ << "\nCan not find table named '" << tableName
631  << "'\n\n\n\nYou need to load the table before it can be used."
632  << "It probably is missing from the member list of the Table "
633  "Group that was loaded?\n\n\n\n\n"
634  << __E__;
635  __SS_THROW__;
636  }
637  TableBase* table = it->second;
638  theInterface_->get(table,
639  tableName,
640  0,
641  0,
642  false, // fill w/version
643  version,
644  false, // do not reset
645  looseColumnMatching);
646  return table;
647 }
648 
649 //==============================================================================
650 // saveNewTable
651 // saves version, makes the new version the active version, and returns new version
652 TableVersion ConfigurationManagerRW::saveNewTable(const std::string& tableName,
653  TableVersion temporaryVersion,
654  bool makeTemporary) //,
655 // bool saveToScratchVersion)
656 {
657  TableVersion newVersion(temporaryVersion);
658 
659  // set author of version
660  TableBase* table = getTableByName(tableName);
661  table->getTemporaryView(temporaryVersion)->setAuthor(username_);
662  // NOTE: author is assigned to permanent versions when saved to DBI
663 
664  if(!makeTemporary) // saveNewVersion makes the new version the active version
665  newVersion = theInterface_->saveNewVersion(table, temporaryVersion);
666  else // make the temporary version active
667  table->setActiveView(newVersion);
668 
669  // if there is a problem, try to recover
670  while(!makeTemporary && !newVersion.isScratchVersion() &&
671  allTableInfo_[tableName].versions_.find(newVersion) !=
672  allTableInfo_[tableName].versions_.end())
673  {
674  __COUT_ERR__ << "What happenened!?? ERROR::: new persistent version v"
675  << newVersion
676  << " already exists!? How is it possible? Retrace your steps and "
677  "tell an admin."
678  << __E__;
679 
680  // create a new temporary version of the target view
681  temporaryVersion = table->createTemporaryView(newVersion);
682 
683  if(newVersion.isTemporaryVersion())
684  newVersion = temporaryVersion;
685  else
686  newVersion = TableVersion::getNextVersion(newVersion);
687 
688  __COUT_WARN__ << "Attempting to recover and use v" << newVersion << __E__;
689 
690  if(!makeTemporary) // saveNewVersion makes the new version the active version
691  newVersion =
692  theInterface_->saveNewVersion(table, temporaryVersion, newVersion);
693  else // make the temporary version active
694  table->setActiveView(newVersion);
695  }
696 
697  if(newVersion.isInvalid())
698  {
699  __SS__ << "Something went wrong saving the new version v" << newVersion
700  << ". What happened?! (duplicates? database error?)" << __E__;
701  __COUT_ERR__ << "\n" << ss.str();
702  __SS_THROW__;
703  }
704 
705  // update allTableInfo_ with the new version
706  allTableInfo_[tableName].versions_.insert(newVersion);
707 
708  __COUT__ << "New version added to info " << newVersion << __E__;
709 
710  // table->getView().print();
711  return newVersion;
712 }
713 
714 //==============================================================================
715 // eraseTemporaryVersion
716 // if version is invalid then erases ALL temporary versions
717 //
718 // maintains allTableInfo_ also while erasing
719 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string& tableName,
720  TableVersion targetVersion)
721 {
722  TableBase* table = getTableByName(tableName);
723 
724  table->trimTemporary(targetVersion);
725 
726  // if allTableInfo_ is not setup, then done
727  if(allTableInfo_.find(tableName) == allTableInfo_.end())
728  return;
729  // else cleanup table info
730 
731  if(targetVersion.isInvalid())
732  {
733  // erase all temporary versions!
734  for(auto it = allTableInfo_[tableName].versions_.begin();
735  it != allTableInfo_[tableName].versions_.end();
736  /*no increment*/)
737  {
738  if(it->isTemporaryVersion())
739  {
740  __COUT__ << "Removing version info: " << *it << __E__;
741  allTableInfo_[tableName].versions_.erase(it++);
742  }
743  else
744  ++it;
745  }
746  }
747  else // erase target version only
748  {
749  __COUT__ << "Removing version info: " << targetVersion << __E__;
750  auto it = allTableInfo_[tableName].versions_.find(targetVersion);
751  if(it == allTableInfo_[tableName].versions_.end())
752  {
753  __COUT__ << "Target version was not found in info versions..." << __E__;
754  return;
755  }
756  allTableInfo_[tableName].versions_.erase(
757  allTableInfo_[tableName].versions_.find(targetVersion));
758  __COUT__ << "Target version was erased from info." << __E__;
759  }
760 }
761 
762 //==============================================================================
763 // clearCachedVersions
764 // clear ALL cached persistent versions (does not erase temporary versions)
765 //
766 // maintains allTableInfo_ also while erasing (trivial, do nothing)
767 void ConfigurationManagerRW::clearCachedVersions(const std::string& tableName)
768 {
769  TableBase* table = getTableByName(tableName);
770 
771  table->trimCache(0);
772 }
773 
774 //==============================================================================
775 // clearAllCachedVersions
776 // clear ALL cached persistent versions (does not erase temporary versions)
777 //
778 // maintains allTableInfo_ also while erasing (trivial, do nothing)
779 void ConfigurationManagerRW::clearAllCachedVersions()
780 {
781  for(auto configInfo : allTableInfo_)
782  configInfo.second.tablePtr_->trimCache(0);
783 }
784 
785 //==============================================================================
786 // copyViewToCurrentColumns
787 TableVersion ConfigurationManagerRW::copyViewToCurrentColumns(
788  const std::string& tableName, TableVersion sourceVersion)
789 {
790  getTableByName(tableName)->reset();
791 
792  // make sure source version is loaded
793  // need to load with loose column rules!
794  TableBase* table =
795  getVersionedTableByName(tableName, TableVersion(sourceVersion), true);
796 
797  // copy from source version to a new temporary version
798  TableVersion newTemporaryVersion =
799  table->copyView(table->getView(), TableVersion(), username_);
800 
801  // update allTableInfo_ with the new version
802  allTableInfo_[tableName].versions_.insert(newTemporaryVersion);
803 
804  return newTemporaryVersion;
805 }
806 
807 //==============================================================================
808 // cacheGroupKey
809 void ConfigurationManagerRW::cacheGroupKey(const std::string& groupName,
810  TableGroupKey key)
811 {
812  allGroupInfo_[groupName].keys_.emplace(key);
813 }
814 
815 //==============================================================================
816 // getGroupInfo
817 // the interface is slow when there are a lot of groups..
818 // so plan is to maintain local cache of recent group info
819 const GroupInfo& ConfigurationManagerRW::getGroupInfo(const std::string& groupName)
820 {
821  // //NOTE: seems like this filter is taking the long amount of time
822  // std::set<std::string /*name*/> fullGroupNames =
823  // theInterface_->getAllTableGroupNames(groupName); //db filter by
824  // group name
825 
826  // so instead caching ourselves...
827  auto it = allGroupInfo_.find(groupName);
828  if(it == allGroupInfo_.end())
829  {
830  __SS__ << "Group name '" << groupName
831  << "' not found in group info! (creating empty info)" << __E__;
832  __COUT_WARN__ << ss.str();
833  //__SS_THROW__;
834  return allGroupInfo_[groupName];
835  }
836  return it->second;
837 }
838 
839 //==============================================================================
840 // findTableGroup
841 // return group with same name and same members and same aliases
842 // else return invalid key
843 //
844 // Note: if aliases, then member alias is matched (not member
845 //
846 // Note: this is taking too long when there are a ton of groups.
847 // Change to going back only a limited number.. (but the order also comes in alpha order
848 // from theInterface_->getAllTableGroupNames which is a problem for choosing
849 // the most recent to check. )
850 TableGroupKey ConfigurationManagerRW::findTableGroup(
851  const std::string& groupName,
852  const std::map<std::string, TableVersion>& groupMemberMap,
853  const std::map<std::string /*name*/, std::string /*alias*/>& groupAliases)
854 {
855  // //NOTE: seems like this filter is taking the long amount of time
856  // std::set<std::string /*name*/> fullGroupNames =
857  // theInterface_->getAllTableGroupNames(groupName); //db filter by
858  // group name
859  const GroupInfo& groupInfo = getGroupInfo(groupName);
860 
861  // std::string name;
862  // TableGroupKey key;
863  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
864  std::map<std::string /*name*/, std::string /*alias*/> compareToGroupAliases;
865  bool isDifferent;
866 
867  const unsigned int MAX_DEPTH_TO_CHECK = 20;
868  unsigned int keyMinToCheck = 0;
869 
870  if(groupInfo.keys_.size())
871  keyMinToCheck = groupInfo.keys_.rbegin()->key();
872  if(keyMinToCheck > MAX_DEPTH_TO_CHECK)
873  {
874  keyMinToCheck -= MAX_DEPTH_TO_CHECK;
875  __COUT__ << "Checking groups back to key... " << keyMinToCheck << __E__;
876  }
877  else
878  {
879  keyMinToCheck = 0;
880  __COUT__ << "Checking all groups." << __E__;
881  }
882 
883  // have min key to check, now loop through and check groups
884  // std::string fullName;
885  for(const auto& key : groupInfo.keys_)
886  {
887  // TableGroupKey::getGroupNameAndKey(fullName,name,key);
888 
889  if(key.key() < keyMinToCheck)
890  continue; // skip keys that are too old
891 
892  // fullName = TableGroupKey::getFullGroupString(groupName,key);
893  //
894  // __COUT__ << "checking group... " << fullName << __E__;
895  //
896  // compareToMemberMap =
897  // theInterface_->getTableGroupMembers(fullName);
898 
899  loadTableGroup(groupName,
900  key,
901  false /*doActivate*/,
902  &compareToMemberMap /*memberMap*/,
903  0,
904  0,
905  0,
906  0,
907  0, /*null pointers*/
908  true /*doNotLoadMember*/,
909  0 /*groupTypeString*/,
910  &compareToGroupAliases);
911 
912  isDifferent = false;
913  for(auto& memberPair : groupMemberMap)
914  {
915  //__COUT__ << memberPair.first << " - " << memberPair.second << __E__;
916 
917  if(groupAliases.find(memberPair.first) != groupAliases.end())
918  {
919  // handle this table as alias, not version
920  if(compareToGroupAliases.find(memberPair.first) ==
921  compareToGroupAliases.end() || // alias is missing
922  groupAliases.at(memberPair.first) !=
923  compareToGroupAliases.at(memberPair.first))
924  { // then different
925  //__COUT__ << "alias mismatch found!" << __E__;
926  isDifferent = true;
927  break;
928  }
929  else
930  continue;
931  } // else check if compareTo group is using an alias for table
932  else if(compareToGroupAliases.find(memberPair.first) !=
933  compareToGroupAliases.end())
934  {
935  // then different
936  //__COUT__ << "alias mismatch found!" << __E__;
937  isDifferent = true;
938  break;
939 
940  } // else handle as table version comparison
941  else if(compareToMemberMap.find(memberPair.first) ==
942  compareToMemberMap.end() || // name is missing
943  memberPair.second !=
944  compareToMemberMap.at(memberPair.first)) // or version mismatch
945  { // then different
946  //__COUT__ << "mismatch found!" << __E__;
947  isDifferent = true;
948  break;
949  }
950  }
951  if(isDifferent)
952  continue;
953 
954  // check member size for exact match
955  if(groupMemberMap.size() != compareToMemberMap.size())
956  continue; // different size, so not same (groupMemberMap is a subset of
957  // memberPairs)
958 
959  __COUT__ << "Found exact match with key: " << key << __E__;
960  // else found an exact match!
961  return key;
962  }
963  __COUT__ << "No match found - this group is new!" << __E__;
964  // if here, then no match found
965  return TableGroupKey(); // return invalid key
966 }
967 
968 //==============================================================================
969 // saveNewTableGroup
970 // saves new group and returns the new group key
971 // if previousVersion is provided, attempts to just bump that version
972 // else, bumps latest version found in db
973 //
974 // Note: groupMembers map will get modified with group metadata table version
975 TableGroupKey ConfigurationManagerRW::saveNewTableGroup(
976  const std::string& groupName,
977  std::map<std::string, TableVersion>& groupMembers,
978  const std::string& groupComment,
979  std::map<std::string /*table*/, std::string /*alias*/>* groupAliases)
980 {
981  // steps:
982  // determine new group key
983  // verify group members
984  // verify groupNameWithKey
985  // verify store
986 
987  if(groupMembers.size() == 0) // do not allow empty groups
988  {
989  __SS__ << "Empty group member list. Can not create a group without members!"
990  << __E__;
991  __SS_THROW__;
992  }
993 
994  // determine new group key
995  TableGroupKey newKey =
996  TableGroupKey::getNextKey(theInterface_->findLatestGroupKey(groupName));
997 
998  __COUT__ << "New Key for group: " << groupName << " found as " << newKey << __E__;
999 
1000  // verify group members
1001  // - use all table info
1002  std::map<std::string, TableInfo> allCfgInfo = getAllTableInfo();
1003  for(auto& memberPair : groupMembers)
1004  {
1005  // check member name
1006  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
1007  {
1008  __COUT_ERR__ << "Group member \"" << memberPair.first
1009  << "\" not found in database!";
1010 
1011  if(groupMetadataTable_.getTableName() == memberPair.first)
1012  {
1013  __COUT_WARN__
1014  << "Looks like this is the groupMetadataTable_ '"
1015  << ConfigurationInterface::GROUP_METADATA_TABLE_NAME
1016  << ".' Note that this table is added to the member map when groups "
1017  "are saved."
1018  << "It should not be part of member map when calling this function."
1019  << __E__;
1020  __COUT__ << "Attempting to recover." << __E__;
1021  groupMembers.erase(groupMembers.find(memberPair.first));
1022  }
1023  else
1024  {
1025  __SS__ << ("Group member not found!") << __E__;
1026  __SS_THROW__;
1027  }
1028  }
1029  // check member version
1030  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
1031  allCfgInfo[memberPair.first].versions_.end())
1032  {
1033  __SS__ << "Group member \"" << memberPair.first << "\" version \""
1034  << memberPair.second << "\" not found in database!";
1035  __SS_THROW__;
1036  }
1037  } // end verify members
1038 
1039  // verify group aliases
1040  if(groupAliases)
1041  {
1042  for(auto& aliasPair : *groupAliases)
1043  {
1044  // check for alias table in member names
1045  if(groupMembers.find(aliasPair.first) == groupMembers.end())
1046  {
1047  __COUT_ERR__ << "Group member \"" << aliasPair.first
1048  << "\" not found in group member map!";
1049 
1050  __SS__ << ("Alias table not found in member list!") << __E__;
1051  __SS_THROW__;
1052  }
1053  }
1054  } // end verify group aliases
1055 
1056  // verify groupNameWithKey and attempt to store
1057  try
1058  {
1059  // save meta data for group; reuse groupMetadataTable_
1060  std::string groupAliasesString = "";
1061  if(groupAliases)
1062  groupAliasesString = StringMacros::mapToString(
1063  *groupAliases, "," /*primary delimeter*/, ":" /*secondary delimeter*/);
1064  __COUT__ << "Metadata: " << username_ << " " << time(0) << " " << groupComment
1065  << " " << groupAliasesString << __E__;
1066 
1067  // to compensate for unusual errors upstream, make sure the metadata table has one
1068  // row
1069  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1070  groupMetadataTable_.getViewP()->deleteRow(0);
1071  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1072  groupMetadataTable_.getViewP()->addRow();
1073 
1074  // columns are uid,comment,author,time
1075  groupMetadataTable_.getViewP()->setValue(
1076  groupAliasesString, 0, ConfigurationManager::METADATA_COL_ALIASES);
1077  groupMetadataTable_.getViewP()->setValue(
1078  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
1079  groupMetadataTable_.getViewP()->setValue(
1080  username_, 0, ConfigurationManager::METADATA_COL_AUTHOR);
1081  groupMetadataTable_.getViewP()->setValue(
1082  time(0), 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
1083 
1084  // set version to first available persistent version
1085  groupMetadataTable_.getViewP()->setVersion(TableVersion::getNextVersion(
1086  theInterface_->findLatestVersion(&groupMetadataTable_)));
1087 
1088  // groupMetadataTable_.print();
1089 
1090  theInterface_->saveActiveVersion(&groupMetadataTable_);
1091 
1092  // force groupMetadataTable_ to be a member for the group
1093  groupMembers[groupMetadataTable_.getTableName()] =
1094  groupMetadataTable_.getViewVersion();
1095 
1096  theInterface_->saveTableGroup(
1097  groupMembers, TableGroupKey::getFullGroupString(groupName, newKey));
1098  __COUT__ << "Created table group: " << groupName << ":" << newKey << __E__;
1099  }
1100  catch(std::runtime_error& e)
1101  {
1102  __COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1103  << __E__;
1104  __COUT_ERR__ << "\n\n" << e.what() << __E__;
1105  throw;
1106  }
1107  catch(...)
1108  {
1109  __COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1110  << __E__;
1111  throw;
1112  }
1113 
1114  // store cache of recent groups
1115  cacheGroupKey(groupName, newKey);
1116 
1117  // at this point succeeded!
1118  return newKey;
1119 }
1120 
1121 //==============================================================================
1122 // saveNewBackbone
1123 // makes the new version the active version and returns new version number
1124 // INVALID will give a new backbone from mockup
1125 TableVersion ConfigurationManagerRW::saveNewBackbone(TableVersion temporaryVersion)
1126 {
1127  __COUT_INFO__ << "Creating new backbone from temporary version " << temporaryVersion
1128  << __E__;
1129 
1130  // find common available temporary version among backbone members
1131  TableVersion newVersion(TableVersion::DEFAULT);
1132  TableVersion retNewVersion;
1133  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1134  for(auto& name : backboneMemberNames)
1135  {
1136  retNewVersion = ConfigurationManager::getTableByName(name)->getNextVersion();
1137  __COUT__ << "New version for backbone member (" << name << "): " << retNewVersion
1138  << __E__;
1139  if(retNewVersion > newVersion)
1140  newVersion = retNewVersion;
1141  }
1142 
1143  __COUT__ << "Common new backbone version found as " << newVersion << __E__;
1144 
1145  // create new views from source temporary version
1146  for(auto& name : backboneMemberNames)
1147  {
1148  // saveNewVersion makes the new version the active version
1149  retNewVersion = getConfigurationInterface()->saveNewVersion(
1150  getTableByName(name), temporaryVersion, newVersion);
1151  if(retNewVersion != newVersion)
1152  {
1153  __SS__ << "Failure! New view requested was " << newVersion
1154  << ". Mismatched new view created: " << retNewVersion << __E__;
1155  __COUT_ERR__ << ss.str();
1156  __SS_THROW__;
1157  }
1158  }
1159 
1160  return newVersion;
1161 }
1162 
1163 //==============================================================================
1165 {
1166  // //test creating table group with author, create time, and comment
1167  // {
1168  // __COUT__ << __E__;
1169  //
1170  // std::string groupName = "testGroup";
1171  // TableGroupKey newKey;
1172  // //TableGroupMetadata
1173  //
1174  // try
1175  // {
1176  // {
1177  // std::map<std::string, TableVersion> members;
1178  // members["ARTDAQAggregatorTable"] = TableVersion(1);
1179  //
1180  // //TableGroupKey
1181  // // saveNewTableGroup
1182  // // (const std::string &groupName, const std::map<std::string,
1183  // // TableVersion> &groupMembers, TableGroupKey
1184  // previousVersion=TableGroupKey()); newKey =
1185  // saveNewTableGroup(groupName,members);
1186  // }
1187  //
1188  // //std::map<std::string, TableVersion >
1189  // // loadTableGroup
1190  // // (const std::string &configGroupName,
1191  // // TableGroupKey tableGroupKey, bool doActivate=false, ProgressBar*
1192  // progressBar=0, std::string *accumulateWarnings=0);
1193  // {
1194  // std::map<std::string, TableVersion > memberMap =
1195  // loadTableGroup(groupName,newKey);
1196  // __COUT__ << "Group members:" << __E__;
1197  // for(const auto &member: memberMap)
1198  // __COUT__ << member.first << " " << member.second << __E__;
1199  // }
1200  //
1201  //
1202  //
1203  // //do it again
1204  // {
1205  // std::map<std::string, TableVersion> members;
1206  // members["ARTDAQAggregatorTable"] = TableVersion(1);
1207  //
1208  // //TableGroupKey
1209  // // saveNewTableGroup
1210  // // (const std::string &groupName, const std::map<std::string,
1211  // // TableVersion> &groupMembers, TableGroupKey
1212  // previousVersion=TableGroupKey()); newKey =
1213  // saveNewTableGroup(groupName,members);
1214  // }
1215  //
1216  // //std::map<std::string, TableVersion >
1217  // // loadTableGroup
1218  // // (const std::string &configGroupName,
1219  // // TableGroupKey tableGroupKey, bool doActivate=false, ProgressBar*
1220  // progressBar=0, std::string *accumulateWarnings=0);
1221  // {
1222  // std::map<std::string, TableVersion > memberMap =
1223  // loadTableGroup(groupName,newKey);
1224  // __COUT__ << "Group members:" << __E__;
1225  // for(const auto &member: memberMap)
1226  // __COUT__ << member.first << " " << member.second << __E__;
1227  // }
1228  //
1229  //
1230  // }
1231  // catch(std::runtime_error &e)
1232  // {
1233  // __COUT_ERR__ << "Failed to create table group: " << groupName << ":" <<
1234  // newKey
1235  //<< __E__;
1236  // __COUT_ERR__ << "\n\n" << e.what() << __E__;
1237  // }
1238  // catch(...)
1239  // {
1240  // __COUT_ERR__ << "Failed to create table group: " << groupName << ":" <<
1241  // newKey
1242  //<< __E__;
1243  // }
1244  //
1245  // return;
1246  // }
1247 
1248  // //test creating table group and reading
1249  // {
1250  // __COUT__ << __E__;
1251  //
1252  // auto gcfgs = theInterface_->getAllTableGroupNames();
1253  // __COUT__ << "Global table size: " << gcfgs.size() << __E__;
1254  // for(auto &g:gcfgs)
1255  // {
1256  // __COUT__ << "Global table " << g << __E__;
1257  // auto gcMap = theInterface_->getTableGroupMembers(g, true
1259  //
1260  // for(auto &cv:gcMap)
1261  // __COUT__ << "\tMember table " << cv.first << ":" << cv.second <<
1262  // __E__;
1263  // }
1264  //
1265  // auto cfgs = theInterface_->getAllTableNames();
1266  // __COUT__ << "Sub-table size: " << cfgs.size() << __E__;
1267  // for(auto &c:cfgs)
1268  // {
1269  // __COUT__ << "table " << c << __E__;
1270  // auto vs = theInterface_->getVersions(getTableByName(c));
1271  // for(auto &v:vs)
1272  // __COUT__ << "\tversion " << v << __E__;
1273  // }
1274  //
1275  // if(0) //create a table group (storeGlobalConfiguration)
1276  // {
1277  // //storeGlobalConfiguration with latest of each
1278  // std::map<std::string /*name*/, TableVersion /*version*/> gcMap;
1279  //
1280  // for(auto &c:cfgs) //for each sub-table, take latest version
1281  // {
1282  // auto vs = theInterface_->getVersions(getTableByName(c));
1283  // if(1 && vs.rbegin() != vs.rend()) //create latest!
1284  // {
1285  // gcMap[c] = *(vs.rbegin());
1286  // __COUT__ << "Adding table " << c << ":" << gcMap[c] << __E__;
1287  // }
1288  // else if(vs.begin() != vs.end()) //create oldest!
1289  // {
1290  // gcMap[c] = *(vs.begin());
1291  // __COUT__ << "Adding table " << c << ":" << gcMap[c] << __E__;
1292  // }
1293  // }
1294  //
1295  // int i = 0;
1296  // bool done = false;
1297  // char gcname[100];
1298  // bool found;
1299  // while(!done && i<1)
1300  // {
1301  // do //avoid conflicting global table names
1302  // {
1303  // found = false;
1304  // sprintf(gcname,"GConfig_v%d",i++);
1305  // for(auto &g:gcfgs)
1306  // if(g == gcname) {found = true; break;}
1307  // }
1308  // while(found);
1309  // __COUT__ << "Trying Global table: " << gcname<< __E__;
1310  //
1311  // try
1312  // {
1313  // theInterface_->saveTableGroup(gcMap,gcname);
1314  // done = true;
1315  // __COUT__ << "Created Global table: " << gcname<< __E__;
1316  // }
1317  // catch(...) {++i;} //repeat names are not allowed, so increment name
1318  // }
1319  //
1320  // }
1321  //
1322  // //return;
1323  // }
1324  //
1325  // this is to test table tree
1326  try
1327  {
1328  __COUT__ << "Loading table..." << __E__;
1329  loadTableGroup("FETest", TableGroupKey(2)); // Context_1
1330  ConfigurationTree t = getNode("/FETable/DEFAULT/FrontEndType");
1331 
1332  std::string v;
1333 
1334  __COUT__ << __E__;
1335  t.getValue(v);
1336  __COUT__ << "Value: " << v << __E__;
1337  __COUT__ << "Value index: " << t.getValue<int>() << __E__;
1338 
1339  return;
1340 
1341  // ConfigurationTree t = getNode("XDAQContextTable");
1342  // ConfigurationTree t = getNode("/FETable/OtsUDPFSSR3/FrontEndType");
1343  // ConfigurationTree t = getNode("/FETable").getNode("OtsUDPFSSR3");
1344  // ConfigurationTree t = getNode("/XDAQContextTable/testContext/");
1345  //
1346  // __COUT__ << __E__;
1347  // t.getValue(v);
1348  // __COUT__ << "Value: " << v << __E__;
1349  //
1350  // if(!t.isValueNode())
1351  // {
1352  // auto C = t.getChildrenNames();
1353  // for(auto &c: C)
1354  // __COUT__ << "\t+ " << c << __E__;
1355  //
1356  // std::stringstream ss;
1357  // t.print(-1,ss);
1358  // __COUT__ << "\n" << ss.str() << __E__;
1359  //
1360  // try
1361  // {
1362  // ConfigurationTree tt = t.getNode("OtsUDPFSSR3");
1363  // tt.getValue(v);
1364  // __COUT__ << "Value: " << v << __E__;
1365  //
1366  // C = tt.getChildrenNames();
1367  // for(auto &c: C)
1368  // __COUT__ << "\t+ " << c << __E__;
1369  // }
1370  // catch(...)
1371  // {
1372  // __COUT__ << "Failed to find extra node." << __E__;
1373  // }
1374  // }
1375  }
1376  catch(...)
1377  {
1378  __COUT__ << "Failed to load table..." << __E__;
1379  }
1380 }