otsdaq  3.06.00
ConfigurationManagerRW.cc
1 #include "otsdaq/ConfigurationInterface/ConfigurationManagerRW.h"
2 
3 #include <dirent.h>
4 
5 using namespace ots;
6 
7 #undef __MF_SUBJECT__
8 #define __MF_SUBJECT__ "ConfigurationManagerRW"
9 
10 #define TABLE_INFO_PATH std::string(__ENV__("TABLE_INFO_PATH")) + "/"
11 #define TABLE_INFO_EXT "Info.xml"
12 
13 #define CORE_TABLE_INFO_FILENAME \
14  ((getenv("SERVICE_DATA_PATH") == NULL) \
15  ? (std::string(__ENV__("USER_DATA")) + "/ServiceData") \
16  : (std::string(__ENV__("SERVICE_DATA_PATH")))) + \
17  "/CoreTableInfoNames.dat"
18 
19 std::atomic<bool> ConfigurationManagerRW::firstTimeConstructed_ = true;
20 
21 //==============================================================================
24  : ConfigurationManager(username) // for use as author of new views
25 {
26  __GEN_COUT__ << "Instantiating Config Manager with Write Access! (for " << username
27  << ") time=" << time(0) << " runTimeSeconds()=" << runTimeSeconds()
28  << __E__;
29 
30  theInterface_ = ConfigurationInterface::getInstance(
31  ConfigurationInterface::CONFIGURATION_MODE::
32  ARTDAQ_DATABASE); // false to use artdaq DB
33 
34  //=========================
35  // dump names of core tables (so UpdateOTS.sh can copy core tables for user)
36  // only if table does not exist
37  if(firstTimeConstructed_)
38  {
39  firstTimeConstructed_ = false;
40 
41  // make table group history directory here and at Gateway Supervisor (just in case)
42  mkdir((ConfigurationManager::LAST_TABLE_GROUP_SAVE_PATH).c_str(), 0755);
43 
44  const std::set<std::string>& contextMemberNames = getFixedContextMemberNames();
45  const std::set<std::string>& backboneMemberNames = getBackboneMemberNames();
46  const std::set<std::string>& iterateMemberNames = getIterateMemberNames();
47 
48  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "r");
49 
50  if(fp) // check for all core table names in file, and force their presence
51  {
52  std::vector<unsigned int> foundVector;
53  char line[100];
54  for(const auto& name : contextMemberNames)
55  {
56  foundVector.push_back(false);
57  rewind(fp);
58  while(fgets(line, 100, fp))
59  {
60  if(strlen(line) < 1)
61  continue;
62  line[strlen(line) - 1] = '\0'; // remove endline
63  if(strcmp(line, ("ContextGroup/" + name).c_str()) == 0) // is match?
64  {
65  foundVector.back() = true;
66  break;
67  }
68  }
69  }
70 
71  for(const auto& name : backboneMemberNames)
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, ("BackboneGroup/" + name).c_str()) == 0) // is match?
81  {
82  foundVector.back() = true;
83  break;
84  }
85  }
86  }
87 
88  for(const auto& name : iterateMemberNames)
89  {
90  foundVector.push_back(false);
91  rewind(fp);
92  while(fgets(line, 100, fp))
93  {
94  if(strlen(line) < 1)
95  continue;
96  line[strlen(line) - 1] = '\0'; // remove endline
97  if(strcmp(line, ("IterateGroup/" + name).c_str()) == 0) // is match?
98  {
99  foundVector.back() = true;
100  break;
101  }
102  }
103  }
104 
105  //look for optional Context table ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE
106  {
107  foundVector.push_back(false);
108  rewind(fp);
109  while(fgets(line, 100, fp))
110  {
111  if(strlen(line) < 1)
112  continue;
113  line[strlen(line) - 1] = '\0'; // remove endline
114  if(strcmp(line,
115  ("ContextGroup/" +
116  ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE)
117  .c_str()) == 0) // is match?
118  {
119  foundVector.back() = true;
120  break;
121  }
122  }
123  }
124 
125  fclose(fp);
126 
127  // open file for appending the missing names
128  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
129  if(fp)
130  {
131  unsigned int i = 0;
132  for(const auto& name : contextMemberNames)
133  {
134  if(!foundVector[i])
135  fprintf(fp, "\nContextGroup/%s", name.c_str());
136 
137  ++i;
138  }
139  for(const auto& name : backboneMemberNames)
140  {
141  if(!foundVector[i])
142  fprintf(fp, "\nBackboneGroup/%s", name.c_str());
143 
144  ++i;
145  }
146  for(const auto& name : iterateMemberNames)
147  {
148  if(!foundVector[i])
149  fprintf(fp, "\nIterateGroup/%s", name.c_str());
150 
151  ++i;
152  }
153 
154  //last is optional Context table ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE
155  if(!foundVector[i])
156  fprintf(
157  fp,
158  "\nContextGroup/%s",
159  ConfigurationManager::CONTEXT_SUBSYSTEM_OPTIONAL_TABLE.c_str());
160 
161  fclose(fp);
162  }
163  else
164  {
165  __SS__ << "Failed to open core table info file for appending: "
166  << CORE_TABLE_INFO_FILENAME << __E__;
167  __SS_THROW__;
168  }
169  }
170  else
171  {
172  fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "w");
173  if(fp)
174  {
175  fprintf(fp, "ARTDAQ/*");
176  fprintf(fp, "\nConfigCore/*");
177  for(const auto& name : contextMemberNames)
178  fprintf(fp, "\nContextGroup/%s", name.c_str());
179  for(const auto& name : backboneMemberNames)
180  fprintf(fp, "\nBackboneGroup/%s", name.c_str());
181  for(const auto& name : iterateMemberNames)
182  fprintf(fp, "\nIterateGroup/%s", name.c_str());
183  fclose(fp);
184  }
185  else
186  {
187  __SS__ << "Failed to open core table info file: "
188  << CORE_TABLE_INFO_FILENAME << __E__;
189  __SS_THROW__;
190  }
191  }
192  } // end dump names of core tables
193 
194  __GEN_COUTV__(runTimeSeconds());
195 } // end constructor
196 
197 //==============================================================================
204 const std::map<std::string, TableInfo>& ConfigurationManagerRW::getAllTableInfo(
205  bool refresh /* = false */,
206  std::string* accumulatedWarnings /* = 0 */,
207  const std::string& errorFilterName /* = "" */,
208  bool getGroupKeys /* = false */,
209  bool getGroupInfo /* = false */,
210  bool initializeActiveGroups /* = false */)
211 {
212  // allTableInfo_ is container to be returned
213 
214  if(!refresh)
215  return allTableInfo_;
216 
217  // else refresh!
218  allTableInfo_.clear();
219 
220  TableBase* table;
221 
222  // existing configurations are defined by which infos are in TABLE_INFO_PATH
223  // can test that the class exists based on this
224  // and then which versions
225  __GEN_COUT__ << "======================================================== "
226  "getAllTableInfo start runTimeSeconds()="
227  << runTimeSeconds() << __E__;
228  {
229  __GEN_COUT__ << "Refreshing all! Extracting list of tables..." << __E__;
230  DIR* pDIR;
231  struct dirent* entry;
232  std::string path = TABLE_INFO_PATH;
233  char fileExt[] = TABLE_INFO_EXT;
234  const unsigned char MIN_TABLE_NAME_SZ = 3;
235 
236  const int numOfThreads = PROCESSOR_COUNT / 2;
237  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> " << numOfThreads
238  << " threads." << __E__;
239  if(numOfThreads < 2) // no multi-threading
240  {
241  if((pDIR = opendir(path.c_str())) != 0)
242  {
243  while((entry = readdir(pDIR)) != 0)
244  {
245  // enforce table name length
246  if(strlen(entry->d_name) < strlen(fileExt) + MIN_TABLE_NAME_SZ)
247  continue;
248 
249  // find file names with correct file extenstion
250  if(strcmp(&(entry->d_name[strlen(entry->d_name) - strlen(fileExt)]),
251  fileExt) != 0)
252  continue; // skip different extentions
253 
254  entry->d_name[strlen(entry->d_name) - strlen(fileExt)] =
255  '\0'; // remove file extension to get table name
256 
257  // 0 will force the creation of new instance (and reload from Info)
258  table = 0;
259 
260  try // only add valid table instances to maps
261  {
262  theInterface_->get(table,
263  entry->d_name,
264  0,
265  0,
266  true); // dont fill
267  }
268  catch(cet::exception const&)
269  {
270  if(table)
271  delete table;
272  table = 0;
273 
274  __GEN_COUT__ << "Skipping! No valid class found for... "
275  << entry->d_name << "\n";
276  continue;
277  }
278  catch(std::runtime_error& e)
279  {
280  if(table)
281  delete table;
282  table = 0;
283 
284  __GEN_COUT__ << "Skipping! No valid class found for... "
285  << entry->d_name << "\n";
286  __GEN_COUT__ << "Error: " << e.what() << __E__;
287 
288  // for a runtime_error, it is likely that columns are the problem
289  // the Table Editor needs to still fix these.. so attempt to
290  // proceed.
291  if(accumulatedWarnings)
292  {
293  if(errorFilterName == "" || errorFilterName == entry->d_name)
294  {
295  *accumulatedWarnings += std::string("\nIn table '") +
296  entry->d_name + "'..." +
297  e.what(); // global accumulate
298 
299  __SS__ << "Attempting to allow illegal columns!" << __E__;
300  *accumulatedWarnings += ss.str();
301  }
302 
303  // attempt to recover and build a mock-up
304  __GEN_COUT__ << "Attempting to allow illegal columns!"
305  << __E__;
306 
307  std::string returnedAccumulatedErrors;
308  try
309  {
310  table = new TableBase(entry->d_name,
311  &returnedAccumulatedErrors);
312  }
313  catch(...)
314  {
315  __GEN_COUT__ << "Skipping! Allowing illegal columns "
316  "didn't work either... "
317  << entry->d_name << "\n";
318  continue;
319  }
320  __GEN_COUT__
321  << "Error (but allowed): " << returnedAccumulatedErrors
322  << __E__;
323 
324  if(errorFilterName == "" || errorFilterName == entry->d_name)
325  *accumulatedWarnings +=
326  std::string("\nIn table '") + entry->d_name + "'..." +
327  returnedAccumulatedErrors; // global accumulate
328  }
329  else
330  continue;
331  }
332 
333  if(nameToTableMap_[entry->d_name]) // handle if instance existed
334  {
335  // copy the existing temporary versions! (or else all is lost)
336  std::set<TableVersion> versions =
337  nameToTableMap_[entry->d_name]->getStoredVersions();
338  for(auto& version : versions)
339  if(version.isTemporaryVersion())
340  {
341  try // do NOT let TableView::init() throw here
342  {
343  nameToTableMap_[entry->d_name]->setActiveView(
344  version);
345  table->copyView( // this calls TableView::init()
346  nameToTableMap_[entry->d_name]->getView(),
347  version,
348  username_);
349  }
350  catch(
351  ...) // do NOT let invalid temporary version throw at this
352  // point
353  {
354  } // just trust configurationBase throws out the failed version
355  }
356 
357  delete nameToTableMap_[entry->d_name];
358  nameToTableMap_[entry->d_name] = 0;
359  }
360 
361  nameToTableMap_[entry->d_name] = table;
362 
363  allTableInfo_[entry->d_name].tablePtr_ = table;
364  allTableInfo_[entry->d_name].versions_ =
365  theInterface_->getVersions(table);
366 
367  // also add any existing temporary versions to all table info
368  // because the interface wont find those versions
369  std::set<TableVersion> versions =
370  nameToTableMap_[entry->d_name]->getStoredVersions();
371  for(auto& version : versions)
372  if(version.isTemporaryVersion())
373  {
374  allTableInfo_[entry->d_name].versions_.emplace(version);
375  }
376  } //end table name handling from directory
377  closedir(pDIR);
378  }
379  }
380  else //multi-threading
381  {
382  int threadsLaunched = 0;
383  int foundThreadIndex = 0;
384  std::string tableName;
385 
386  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
387  for(int i = 0; i < numOfThreads; ++i)
388  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
389 
390  std::vector<std::shared_ptr<ots::TableInfo>> sharedTableInfoPtrs;
391 
392  if((pDIR = opendir(path.c_str())) != 0)
393  {
394  while((entry = readdir(pDIR)) != 0)
395  {
396  // enforce table name length
397  if(strlen(entry->d_name) < strlen(fileExt) + MIN_TABLE_NAME_SZ)
398  continue;
399 
400  // find file names with correct file extenstion
401  if(strcmp(&(entry->d_name[strlen(entry->d_name) - strlen(fileExt)]),
402  fileExt) != 0)
403  continue; // skip different extentions
404 
405  entry->d_name[strlen(entry->d_name) - strlen(fileExt)] =
406  '\0'; // remove file extension to get table name
407  tableName =
408  entry
409  ->d_name; //copy immediate, thread does not like using pointer to char*, corrupts immediately on wraparound
410 
411  //make temporary table info for thread
412  sharedTableInfoPtrs.push_back(std::make_shared<ots::TableInfo>());
413  sharedTableInfoPtrs.back()->accumulatedWarnings_ =
414  accumulatedWarnings ? "ALLOW"
415  : ""; //mark to allow accumulated warnings
416 
417  if(threadsLaunched >= numOfThreads)
418  {
419  //find availableThreadIndex
420  foundThreadIndex = -1;
421  size_t ii = 0;
422  while(foundThreadIndex == -1)
423  {
424  for(int i = 0; i < numOfThreads; ++i)
425  if(*(threadDone[i]))
426  {
427  foundThreadIndex = i;
428  break;
429  }
430  if(foundThreadIndex == -1)
431  {
432  __GEN_COUT_TYPE__(TLVL_DEBUG + 2)
433  << __COUT_HDR__
434  << "Waiting for available thread... iteration # "
435  << ii << __E__;
436  if(++ii > 100 /* 1s */ * 10)
437  {
438  __GEN_SS__ << "Threads seem to be stuck getting "
439  "table info! Timeout while waiting..."
440  << __E__;
441  __GEN_SS_THROW__;
442  }
443  usleep(10000);
444  }
445  } //end thread search loop
446  threadsLaunched = numOfThreads - 1;
447  }
448  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex
449  << " for table " << tableName << __E__;
450 
451  *(threadDone[foundThreadIndex]) = false;
452  std::thread(
453  [](ConfigurationManagerRW* theCfgMgr,
454  std::string theTableName,
455  TableBase* existingTable,
456  std::shared_ptr<ots::TableInfo> theTableInfo,
457  std::shared_ptr<std::atomic<bool>> theThreadDone) {
459  theTableName,
460  existingTable,
461  theTableInfo,
462  theThreadDone);
463  },
464  this,
465  tableName,
466  nameToTableMap_[tableName],
467  sharedTableInfoPtrs.back(),
468  threadDone[foundThreadIndex])
469  .detach();
470 
471  ++threadsLaunched;
472  ++foundThreadIndex;
473  } //end table name handling from directory
474  closedir(pDIR);
475  } //end tableInfo thread loop
476 
477  //check for all threads done
478  do
479  {
480  foundThreadIndex = -1;
481  for(int i = 0; i < numOfThreads; ++i)
482  if(!*(threadDone[i]))
483  {
484  foundThreadIndex = i;
485  break;
486  }
487  if(foundThreadIndex != -1)
488  {
489  __GEN_COUTT__ << "Waiting for thread to finish... "
490  << foundThreadIndex << __E__;
491  usleep(10000);
492  }
493  } while(foundThreadIndex != -1); //end thread done search loop
494 
495  //threads done now, so copy table info
496  for(auto& tableInfo : sharedTableInfoPtrs)
497  {
498  if(tableInfo->tablePtr_ == nullptr)
499  {
500  __SS__ << "Fatal error occurred loading table info into cache! "
501  "Perhaps there is an illegal Table schema definition? "
502  "Check logs to resolve."
503  << __E__;
504  __SS_THROW__;
505  }
506  __GEN_COUT_TYPE__(TLVL_DEBUG + 3)
507  << __COUT_HDR__ << "Copying table info for "
508  << tableInfo->tablePtr_->getTableName() << __E__;
509  nameToTableMap_[tableInfo->tablePtr_->getTableName()] =
510  tableInfo->tablePtr_;
511  allTableInfo_[tableInfo->tablePtr_->getTableName()].tablePtr_ =
512  tableInfo->tablePtr_;
513  allTableInfo_[tableInfo->tablePtr_->getTableName()].versions_ =
514  tableInfo->versions_;
515  } //end copy group info loop
516  }
517  __GEN_COUT__ << "Extracting list of tables complete." << __E__;
518  } //end Extracting list of tables
519 
520  // call init to load active versions by default, activate with warnings allowed (assuming development going on)
521  if(initializeActiveGroups)
522  {
523  __GEN_COUT__ << "Now initializing..." << __E__;
524  // if there is a filter name, do not include init warnings (it just scares people in the table editor)
525  std::string tmpAccumulateWarnings;
526  init(0 /*accumulatedErrors*/,
527  false /*initForWriteAccess*/,
528  accumulatedWarnings ? &tmpAccumulateWarnings : nullptr);
529 
530  if(accumulatedWarnings && errorFilterName == "")
531  *accumulatedWarnings += tmpAccumulateWarnings;
532  }
533  __GEN_COUT__ << "======================================================== "
534  "getAllTableInfo end runTimeSeconds()="
535  << runTimeSeconds() << __E__;
536 
537  // get Group Info too!
538  if(getGroupKeys || getGroupInfo)
539  {
540  allGroupInfo_.clear();
541  try
542  {
543  // build allGroupInfo_ for the ConfigurationManagerRW
544 
545  std::set<std::string /*name*/> tableGroups =
546  theInterface_->getAllTableGroupNames();
547  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
548 
549  __GEN_COUTT__ << "Group Info start runTimeSeconds()=" << runTimeSeconds()
550  << __E__;
551 
552  TableGroupKey key;
553  std::string name;
554  for(const auto& fullName : tableGroups)
555  {
556  TableGroupKey::getGroupNameAndKey(fullName, name, key);
557  allGroupInfo_[name].keys_.emplace(key); //store in cache
558  }
559 
560  __GEN_COUTT__ << "Group Keys end runTimeSeconds()=" << runTimeSeconds()
561  << __E__;
562 
563  // for each group get member map & comment, author, time, and type for latest key
564  if(getGroupInfo)
565  {
566  const int numOfThreads = PROCESSOR_COUNT / 2;
567  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> "
568  << numOfThreads << " threads." << __E__;
569  if(numOfThreads < 2) // no multi-threading
570  for(auto& groupInfo : allGroupInfo_)
571  {
572  try
573  {
574  groupInfo.second.latestKey_ = groupInfo.second.getLastKey();
576  groupInfo.first /*groupName*/,
577  groupInfo.second.latestKey_,
578  false /*doActivate*/,
579  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
580  0 /*progressBar*/,
581  0 /*accumulateErrors*/,
582  &groupInfo.second.latestKeyGroupComment_,
583  &groupInfo.second.latestKeyGroupAuthor_,
584  &groupInfo.second.latestKeyGroupCreationTime_,
585  true /*doNotLoadMember*/,
586  &groupInfo.second.latestKeyGroupTypeString_);
587  }
588  catch(...)
589  {
590  __GEN_COUT_WARN__ << "Error occurred loading latest group "
591  "info into cache for '"
592  << groupInfo.first << "("
593  << groupInfo.second.latestKey_ << ")'..."
594  << __E__;
595  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
596  groupInfo.second.latestKeyGroupComment_ =
597  ConfigurationManager::UNKNOWN_INFO;
598  groupInfo.second.latestKeyGroupAuthor_ =
599  ConfigurationManager::UNKNOWN_INFO;
600  groupInfo.second.latestKeyGroupCreationTime_ =
601  ConfigurationManager::UNKNOWN_TIME;
602  groupInfo.second.latestKeyGroupTypeString_ =
603  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
604  groupInfo.second.latestKeyMemberMap_ = {};
605  }
606  } // end group info loop
607  else //multi-threading
608  {
609  int threadsLaunched = 0;
610  int foundThreadIndex = 0;
611 
612  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
613  for(int i = 0; i < numOfThreads; ++i)
614  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
615 
616  std::vector<std::shared_ptr<ots::GroupInfo>> sharedGroupInfoPtrs;
617 
618  for(auto& groupInfo : allGroupInfo_)
619  {
620  //make temporary group info for thread
621  sharedGroupInfoPtrs.push_back(std::make_shared<ots::GroupInfo>());
622 
623  if(threadsLaunched >= numOfThreads)
624  {
625  //find availableThreadIndex
626  foundThreadIndex = -1;
627  while(foundThreadIndex == -1)
628  {
629  for(int i = 0; i < numOfThreads; ++i)
630  if(*(threadDone[i]))
631  {
632  foundThreadIndex = i;
633  break;
634  }
635  if(foundThreadIndex == -1)
636  {
637  __GEN_COUTT__ << "Waiting for available thread..."
638  << __E__;
639  usleep(10000);
640  }
641  } //end thread search loop
642  threadsLaunched = numOfThreads - 1;
643  }
644  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex
645  << " for " << groupInfo.first << "("
646  << groupInfo.second.getLastKey() << ")" << __E__;
647 
648  *(threadDone[foundThreadIndex]) = false;
649 
650  std::thread(
651  [](ConfigurationManagerRW* theCfgMgr,
652  std::string theGroupName,
653  ots::TableGroupKey theGroupKey,
654  std::shared_ptr<ots::GroupInfo> theGroupInfo,
655  std::shared_ptr<std::atomic<bool>> theThreadDone) {
657  theCfgMgr,
658  theGroupName,
659  theGroupKey,
660  theGroupInfo,
661  theThreadDone);
662  },
663  this,
664  groupInfo.first,
665  groupInfo.second.getLastKey(),
666  sharedGroupInfoPtrs.back(),
667  threadDone[foundThreadIndex])
668  .detach();
669 
670  ++threadsLaunched;
671  ++foundThreadIndex;
672  } //end groupInfo thread loop
673 
674  //check for all threads done
675  do
676  {
677  foundThreadIndex = -1;
678  for(int i = 0; i < numOfThreads; ++i)
679  if(!*(threadDone[i]))
680  {
681  foundThreadIndex = i;
682  break;
683  }
684  if(foundThreadIndex != -1)
685  {
686  __GEN_COUTT__ << "Waiting for thread to finish... "
687  << foundThreadIndex << __E__;
688  usleep(10000);
689  }
690  } while(foundThreadIndex != -1); //end thread done search loop
691 
692  //threads done now, so copy group info
693  size_t i = 0;
694  for(auto& groupInfo : allGroupInfo_)
695  {
696  groupInfo.second.latestKey_ = sharedGroupInfoPtrs[i]->latestKey_;
697  groupInfo.second.latestKeyGroupComment_ =
698  sharedGroupInfoPtrs[i]->latestKeyGroupComment_;
699  groupInfo.second.latestKeyGroupAuthor_ =
700  sharedGroupInfoPtrs[i]->latestKeyGroupAuthor_;
701  groupInfo.second.latestKeyGroupCreationTime_ =
702  sharedGroupInfoPtrs[i]->latestKeyGroupCreationTime_;
703  groupInfo.second.latestKeyGroupTypeString_ =
704  sharedGroupInfoPtrs[i]->latestKeyGroupTypeString_;
705  groupInfo.second.latestKeyMemberMap_ =
706  sharedGroupInfoPtrs[i]->latestKeyMemberMap_;
707  ++i;
708  } //end copy group info loop
709 
710  } //end multi-thread handling
711  }
712  } // end get group info
713  catch(const std::runtime_error& e)
714  {
715  __SS__
716  << "A fatal error occurred reading the info for all table groups. Error: "
717  << e.what() << __E__;
718  __GEN_COUT_ERR__ << "Error at time: " << time(0) << "\n" << ss.str();
719  if(accumulatedWarnings)
720  *accumulatedWarnings += ss.str();
721  else
722  throw;
723  }
724  catch(...)
725  {
726  __SS__ << "An unknown fatal error occurred reading the info for all table "
727  "groups."
728  << __E__;
729  try
730  {
731  throw;
732  } //one more try to printout extra info
733  catch(const std::exception& e)
734  {
735  ss << "Exception message: " << e.what();
736  }
737  catch(...)
738  {
739  }
740  __GEN_COUT_ERR__ << "\n" << ss.str();
741  if(accumulatedWarnings)
742  *accumulatedWarnings += ss.str();
743  else
744  throw;
745  }
746  __GEN_COUTT__ << "Group Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
747  } //end getGroupInfo
748  else
749  __GEN_COUTT__ << "Table Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
750 
751  return allTableInfo_;
752 } // end getAllTableInfo()
753 
754 //==============================================================================
757  ConfigurationManagerRW* cfgMgr,
758  std::string tableName,
759  TableBase* existingTable,
760  std::shared_ptr<ots::TableInfo> tableInfo,
761  std::shared_ptr<std::atomic<bool>> threadDone)
762 try
763 {
764  __COUTT__ << "Thread started... table " << tableName << __E__;
765 
766  // 0 will force the creation of new instance (and reload from Info)
767  tableInfo->tablePtr_ = 0;
768 
769  try // only add valid table instances to maps
770  {
771  cfgMgr->theInterface_->get(tableInfo->tablePtr_,
772  tableName,
773  0,
774  0,
775  true); // dont fill
776  }
777  catch(cet::exception const&)
778  {
779  if(tableInfo->tablePtr_)
780  delete tableInfo->tablePtr_;
781  tableInfo->tablePtr_ = 0;
782 
783  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
784  *(threadDone) = true;
785  return;
786  }
787  catch(std::runtime_error& e)
788  {
789  if(tableInfo->tablePtr_)
790  delete tableInfo->tablePtr_;
791  tableInfo->tablePtr_ = 0;
792 
793  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
794  __COUTT__ << "Error: " << e.what() << __E__;
795 
796  // for a runtime_error, it is likely that columns are the problem
797  // the Table Editor needs to still fix these.. so attempt to
798  // proceed.
799  if(tableInfo->accumulatedWarnings_ == "ALLOW")
800  {
801  tableInfo->accumulatedWarnings_ = "";
802  if(1) //errorFilterName == "" || errorFilterName == tableName)
803  {
804  tableInfo->accumulatedWarnings_ += std::string("\nIn table '") +
805  tableName + "'..." +
806  e.what(); // global accumulate
807 
808  __SS__ << "Attempting to allow illegal columns!" << __E__;
809  tableInfo->accumulatedWarnings_ += ss.str();
810  }
811 
812  // attempt to recover and build a mock-up
813  __COUT__ << "Attempting to allow illegal columns!" << __E__;
814 
815  std::string returnedAccumulatedErrors;
816  try
817  {
818  tableInfo->tablePtr_ =
819  new TableBase(tableName, &returnedAccumulatedErrors);
820  }
821  catch(...)
822  {
823  __COUT__ << "Skipping! Allowing illegal columns didn't work either... "
824  << tableName << "\n";
825  *(threadDone) = true;
826  return;
827  }
828  __COUT_WARN__ << "Error (but allowed): " << returnedAccumulatedErrors
829  << __E__;
830 
831  if(1) //errorFilterName == "" || errorFilterName == entry->d_name)
832  tableInfo->accumulatedWarnings_ +=
833  std::string("\nIn table '") + tableName + "'..." +
834  returnedAccumulatedErrors; // global accumulate
835  }
836  else
837  {
838  tableInfo->accumulatedWarnings_ = "";
839  *(threadDone) = true;
840  return;
841  }
842  }
843 
844  if(existingTable) // handle if instance existed
845  {
846  __COUTT__ << "Copying temporary version from existing table object for "
847  << tableName << __E__;
848  // copy the existing temporary versions! (or else all is lost)
849  std::set<TableVersion> versions = existingTable->getStoredVersions();
850  for(auto& version : versions)
851  if(version.isTemporaryVersion())
852  {
853  try // do NOT let TableView::init() throw here
854  {
855  existingTable->setActiveView(version);
856  tableInfo->tablePtr_->copyView( // this calls TableView::init()
857  existingTable->getView(),
858  version,
859  cfgMgr->username_);
860  }
861  catch(...) // do NOT let invalid temporary version throw at this
862  // point
863  {
864  } // just trust configurationBase throws out the failed version
865  }
866 
867  delete existingTable;
868  existingTable = 0;
869  }
870 
871  tableInfo->versions_ = cfgMgr->theInterface_->getVersions(tableInfo->tablePtr_);
872 
873  // also add any existing temporary versions to all table info
874  // because the interface wont find those versions
875  std::set<TableVersion> versions = tableInfo->tablePtr_->getStoredVersions();
876  for(auto& version : versions)
877  if(version.isTemporaryVersion())
878  {
879  tableInfo->versions_.emplace(version);
880  }
881 
882  __COUTT__ << "Thread done... table " << tableName << __E__;
883  *(threadDone) = true;
884 } // end loadTableInfoThread
885 catch(...)
886 {
887  __COUT_ERR__ << "Error occurred loading latest table info into cache for '"
888  << tableName << "'..." << __E__;
889  *(threadDone) = true;
890 } // end loadTableInfoThread catch
891 
892 //==============================================================================
896  const std::string& groupName,
897  const TableGroupKey& groupKey,
898  bool doActivate /*=false*/,
899  std::map<std::string /*table name*/, TableVersion>*
900  groupMembers /*=0 , note: db time intensive! */,
901  ProgressBar* progressBar /*=0*/,
902  std::string* accumulatedWarnings /*=0*/,
903  std::string* groupComment /*=0 , note: in metadata */,
904  std::string* groupAuthor /*=0 , note: in metadata */,
905  std::string* groupCreateTime /*=0 , note: in metadata */,
906  bool doNotLoadMembers /*=false*/,
907  std::string* groupTypeString /*=0 , note: db time intensive! */,
908  std::map<std::string /*name*/, std::string /*alias*/>*
909  groupAliases /*=0 , note: in metadata */,
910  ConfigurationManager::LoadGroupType
911  groupTypeToLoad /*=ConfigurationManager::LoadGroupType::ALL_TYPES*/,
912  bool ignoreVersionTracking /*=false*/)
913 {
915  groupKey,
916  doActivate,
917  groupMembers,
918  progressBar,
919  accumulatedWarnings,
920  groupComment,
921  groupAuthor,
922  groupCreateTime,
923  doNotLoadMembers,
924  groupTypeString,
925  groupAliases,
926  groupTypeToLoad,
927  ignoreVersionTracking);
928 
929  if(!groupMembers || !groupMembers->size() || !groupComment || groupKey.isInvalid() ||
930  !groupAuthor || !groupCreateTime)
931  return;
932 
933  //treat successfull load as latest group key
934  auto groupInfo = allGroupInfo_.find(groupName);
935  if(groupInfo == allGroupInfo_.end())
936  return; //ignore if no group info cache
937 
938  groupInfo->second.latestKey_ = groupKey;
939  groupInfo->second.latestKeyGroupComment_ = *groupComment;
940  groupInfo->second.latestKeyGroupAuthor_ = *groupAuthor;
941  groupInfo->second.latestKeyGroupCreationTime_ = *groupCreateTime;
942  if(groupTypeString) //assume unlikely to change types
943  groupInfo->second.latestKeyGroupTypeString_ = *groupTypeString;
944  groupInfo->second.latestKeyMemberMap_ = *groupMembers;
945 
946 } //end loadTableGroup() RW version
947 
948 //==============================================================================
951  ConfigurationManagerRW* cfgMgr,
952  std::string groupName,
953  ots::TableGroupKey groupKey,
954  std::shared_ptr<ots::GroupInfo> groupInfo,
955  std::shared_ptr<std::atomic<bool>> threadDone)
956 try
957 {
958  __COUTT__ << "Thread started... " << groupName << "(" << groupKey << ")" << __E__;
959 
960  groupInfo->latestKey_ = groupKey;
961  cfgMgr->loadTableGroup(groupName,
962  groupKey,
963  false /*doActivate*/,
964  &(groupInfo->latestKeyMemberMap_) /*groupMembers*/,
965  0 /*progressBar*/,
966  0 /*accumulateErrors*/,
967  &(groupInfo->latestKeyGroupComment_),
968  &(groupInfo->latestKeyGroupAuthor_),
969  &(groupInfo->latestKeyGroupCreationTime_),
970  true /*doNotLoadMember*/,
971  &(groupInfo->latestKeyGroupTypeString_));
972 
973  *(threadDone) = true;
974 } // end loadTableGroupThread
975 catch(...)
976 {
977  __COUT_WARN__ << "Error occurred loading latest group info into cache for '"
978  << groupName << "(" << groupInfo->latestKey_ << ")'..." << __E__;
979  groupInfo->latestKey_ = TableGroupKey::INVALID;
980  groupInfo->latestKeyGroupComment_ = ConfigurationManager::UNKNOWN_INFO;
981  groupInfo->latestKeyGroupAuthor_ = ConfigurationManager::UNKNOWN_INFO;
982  groupInfo->latestKeyGroupCreationTime_ = ConfigurationManager::UNKNOWN_TIME;
983  groupInfo->latestKeyGroupTypeString_ = ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
984  groupInfo->latestKeyMemberMap_ = {};
985  *(threadDone) = true;
986 } // end loadTableGroupThread catch
987 
988 //==============================================================================
993  ConfigurationManagerRW* cfgMgr,
994  std::string groupName,
995  ots::TableGroupKey groupKeyToCompare,
996  const std::map<std::string, TableVersion>& groupMemberMap,
997  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases,
998  std::atomic<bool>* foundIdentical,
999  ots::TableGroupKey* identicalKey,
1000  std::mutex* threadMutex,
1001  std::shared_ptr<std::atomic<bool>> threadDone)
1002 try
1003 {
1004  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
1005  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
1006  std::map<std::string /*name*/, std::string /*alias*/>*
1007  compareToMemberTableAliasesPtr = nullptr;
1008  if(memberTableAliases
1009  .size()) //only give pointer if necessary, without will load group faster
1010  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
1011 
1012  cfgMgr->loadTableGroup(groupName,
1013  groupKeyToCompare,
1014  false /*doActivate*/,
1015  &compareToMemberMap /*memberMap*/,
1016  0, /*progressBar*/
1017  0, /*accumulatedWarnings*/
1018  0, /*groupComment*/
1019  0,
1020  0, /*null pointers*/
1021  true /*doNotLoadMember*/,
1022  0 /*groupTypeString*/,
1023  compareToMemberTableAliasesPtr);
1024 
1025  bool debug = false;
1026  if(TTEST(9)) // = DEBUG+9
1027  {
1028  debug = true;
1029  for(auto& memberPair : groupMemberMap)
1030  __COUTS__(9) << "member " << memberPair.first << " (" << memberPair.second
1031  << ")" << __E__;
1032  for(auto& memberPair : compareToMemberMap)
1033  __COUTS__(9) << "compare " << groupName << " (" << groupKeyToCompare
1034  << ") member:" << memberPair.first << " (" << memberPair.second
1035  << ")" << __E__;
1036  }
1037 
1038  bool isDifferent = false;
1039  for(auto& memberPair : groupMemberMap)
1040  {
1041  //groups can be different if Alias names are different
1042  // or if resolved Alias versions are different (for the current active backbone)
1043  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
1044  {
1045  // handle this table as alias, not version
1046  if(compareToMemberTableAliases.find(memberPair.first) ==
1047  compareToMemberTableAliases.end() || // alias is missing
1048  memberTableAliases.at(memberPair.first) !=
1049  compareToMemberTableAliases.at(memberPair.first))
1050  { // then different
1051  isDifferent = true;
1052  if(debug)
1053  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1054  << ") on alias " << memberPair.first << __E__;
1055  break;
1056  }
1057  } // else check if compareTo group is using an alias for table
1058  else if(compareToMemberTableAliases.find(memberPair.first) !=
1059  compareToMemberTableAliases.end())
1060  {
1061  // then different
1062  isDifferent = true;
1063  if(debug)
1064  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1065  << ") on reverse alias " << memberPair.first << __E__;
1066  break;
1067 
1068  } // else handle as table version comparison
1069 
1070  //normal table version check
1071  if(compareToMemberMap.find(memberPair.first) ==
1072  compareToMemberMap.end() || // name is missing
1073  memberPair.second !=
1074  compareToMemberMap.at(memberPair.first)) // or version mismatch
1075  {
1076  // then different
1077  isDifferent = true;
1078  if(debug)
1079  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1080  << ") on mismatch " << memberPair.first << __E__;
1081  break;
1082  }
1083  } //end table version mismatch checking loop
1084 
1085  // check member size for exact match
1086  if(!isDifferent &&
1087  groupMemberMap.size() !=
1088  compareToMemberMap
1089  .size()) // different size, so not same (groupMemberMap is a subset of memberPairs)
1090  {
1091  isDifferent = true;
1092 
1093  if(debug)
1094  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare << ") on size "
1095  << __E__;
1096  }
1097 
1098  if(!isDifferent) //found an exact match!
1099  {
1100  *foundIdentical = true;
1101  __COUT__ << "=====> Found exact match with key: " << groupKeyToCompare << __E__;
1102 
1103  std::lock_guard<std::mutex> lock(*threadMutex);
1104  *identicalKey = groupKeyToCompare;
1105  }
1106 
1107  *(threadDone) = true;
1108 } // end compareTableGroupThread
1109 catch(...)
1110 {
1111  __COUT_WARN__ << "Error occurred comparing group '" << groupName << "("
1112  << groupKeyToCompare << ")'..." << __E__;
1113 
1114  *(threadDone) = true;
1115 } // end compareTableGroupThread catch
1116 
1117 //==============================================================================
1121 std::map<std::string /*table name*/,
1122  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1124 {
1125  std::map<std::string /*table name*/,
1126  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1128 
1129  // always have scratch alias for each table that has a scratch version
1130  // overwrite map entry if necessary
1131  if(!ConfigurationInterface::isVersionTrackingEnabled())
1132  for(const auto& tableInfo : allTableInfo_)
1133  for(const auto& version : tableInfo.second.versions_)
1134  if(version.isScratchVersion())
1135  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
1136  TableVersion(TableVersion::SCRATCH);
1137 
1138  return retMap;
1139 } // end getVersionAliases()
1140 
1141 //==============================================================================
1145 void ConfigurationManagerRW::activateTableGroup(const std::string& tableGroupName,
1146  TableGroupKey tableGroupKey,
1147  std::string* accumulatedTreeErrors,
1148  std::string* groupTypeString)
1149 {
1150  try
1151  {
1152  loadTableGroup(tableGroupName,
1153  tableGroupKey,
1154  true, // loads and activates
1155  0, // no members needed
1156  0, // no progress bar
1157  accumulatedTreeErrors, // accumulate warnings or not
1158  0 /* groupComment */,
1159  0 /* groupAuthor */,
1160  0 /* groupCreateTime */,
1161  false /* doNotLoadMember */,
1162  groupTypeString);
1163  }
1164  catch(...)
1165  {
1166  __GEN_COUT_ERR__ << "There were errors, so de-activating group: "
1167  << tableGroupName << " (" << tableGroupKey << ")" << __E__;
1168  try // just in case any lingering pieces, let's deactivate
1169  {
1170  destroyTableGroup(tableGroupName, true);
1171  }
1172  catch(...)
1173  {
1174  }
1175  throw; // re-throw original exception
1176  }
1177 
1178  __GEN_COUT_INFO__ << "Updating persistent active groups to "
1179  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
1180 
1181  __COUT_INFO__ << "Active Context table group: " << theContextTableGroup_ << "("
1182  << (theContextTableGroupKey_
1183  ? theContextTableGroupKey_->toString().c_str()
1184  : "-1")
1185  << ")" << __E__;
1186  __COUT_INFO__ << "Active Backbone table group: " << theBackboneTableGroup_ << "("
1187  << (theBackboneTableGroupKey_
1188  ? theBackboneTableGroupKey_->toString().c_str()
1189  : "-1")
1190  << ")" << __E__;
1191  __COUT_INFO__ << "Active Iterate table group: " << theIterateTableGroup_ << "("
1192  << (theIterateTableGroupKey_
1193  ? theIterateTableGroupKey_->toString().c_str()
1194  : "-1")
1195  << ")" << __E__;
1196  __COUT_INFO__ << "Active Configuration table group: " << theConfigurationTableGroup_
1197  << "("
1198  << (theConfigurationTableGroupKey_
1199  ? theConfigurationTableGroupKey_->toString().c_str()
1200  : "-1")
1201  << ")" << __E__;
1202 
1204  FILE* fp = fopen(fn.c_str(), "w");
1205  if(!fp)
1206  {
1207  __SS__ << "Fatal Error! Unable to open the file "
1209  << " for editing! Is there a permissions problem?" << __E__;
1210  __GEN_COUT_ERR__ << ss.str();
1211  __SS_THROW__;
1212  return;
1213  }
1214  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
1215  fprintf(
1216  fp,
1217  "%s\n",
1218  theContextTableGroupKey_ ? theContextTableGroupKey_->toString().c_str() : "-1");
1219  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
1220  fprintf(
1221  fp,
1222  "%s\n",
1223  theBackboneTableGroupKey_ ? theBackboneTableGroupKey_->toString().c_str() : "-1");
1224  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
1225  fprintf(
1226  fp,
1227  "%s\n",
1228  theIterateTableGroupKey_ ? theIterateTableGroupKey_->toString().c_str() : "-1");
1229  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
1230  fprintf(fp,
1231  "%s\n",
1232  theConfigurationTableGroupKey_
1233  ? theConfigurationTableGroupKey_->toString().c_str()
1234  : "-1");
1235  fclose(fp);
1236 
1237  // save last activated group
1238  {
1239  std::pair<std::string /*group name*/, TableGroupKey> activatedGroup(
1240  std::string(tableGroupName), tableGroupKey);
1241  if(theConfigurationTableGroupKey_ &&
1242  theConfigurationTableGroup_ == tableGroupName &&
1243  *theConfigurationTableGroupKey_ == tableGroupKey)
1244  {
1245  ConfigurationManager::saveGroupNameAndKey(
1246  activatedGroup,
1247  ConfigurationManager::LAST_ACTIVATED_CONFIG_GROUP_FILE,
1248  false /* appendMode */,
1249  username_);
1250  ConfigurationManager::saveGroupNameAndKey(
1251  activatedGroup,
1252  ConfigurationManager::ACTIVATED_CONFIGS_FILE,
1253  true /* appendMode */,
1254  username_);
1255  }
1256  else if(theContextTableGroupKey_ && theContextTableGroup_ == tableGroupName &&
1257  *theContextTableGroupKey_ == tableGroupKey)
1258  {
1259  ConfigurationManager::saveGroupNameAndKey(
1260  activatedGroup,
1261  ConfigurationManager::LAST_ACTIVATED_CONTEXT_GROUP_FILE,
1262  false /* appendMode */,
1263  username_);
1264  ConfigurationManager::saveGroupNameAndKey(
1265  activatedGroup,
1266  ConfigurationManager::ACTIVATED_CONTEXTS_FILE,
1267  true /* appendMode */,
1268  username_);
1269  }
1270  else if(theBackboneTableGroupKey_ && theBackboneTableGroup_ == tableGroupName &&
1271  *theBackboneTableGroupKey_ == tableGroupKey)
1272  {
1273  ConfigurationManager::saveGroupNameAndKey(
1274  activatedGroup,
1275  ConfigurationManager::LAST_ACTIVATED_BACKBONE_GROUP_FILE,
1276  false /* appendMode */,
1277  username_);
1278  ConfigurationManager::saveGroupNameAndKey(
1279  activatedGroup,
1280  ConfigurationManager::ACTIVATED_BACKBONES_FILE,
1281  true /* appendMode */,
1282  username_);
1283  }
1284  else if(theIterateTableGroupKey_ && theIterateTableGroup_ == tableGroupName &&
1285  *theIterateTableGroupKey_ == tableGroupKey)
1286  {
1287  ConfigurationManager::saveGroupNameAndKey(
1288  activatedGroup,
1289  ConfigurationManager::LAST_ACTIVATED_ITERATE_GROUP_FILE,
1290  false /* appendMode */,
1291  username_);
1292  ConfigurationManager::saveGroupNameAndKey(
1293  activatedGroup,
1294  ConfigurationManager::ACTIVATED_ITERATES_FILE,
1295  true /* appendMode */,
1296  username_);
1297  }
1298  } // end save last activated group
1299 
1300 } // end activateTableGroup()
1301 
1302 //==============================================================================
1307  TableVersion sourceViewVersion)
1308 {
1309  __GEN_COUT_INFO__ << "Creating temporary backbone view from version "
1310  << sourceViewVersion << __E__;
1311 
1312  // find common available temporary version among backbone members
1313  TableVersion tmpVersion =
1314  TableVersion::getNextTemporaryVersion(); // get the default temporary version
1315  TableVersion retTmpVersion;
1316  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1317  for(auto& name : backboneMemberNames)
1318  {
1319  retTmpVersion =
1321  if(retTmpVersion < tmpVersion)
1322  tmpVersion = retTmpVersion;
1323  }
1324 
1325  __GEN_COUT__ << "Common temporary backbone version found as " << tmpVersion << __E__;
1326 
1327  // create temporary views from source version to destination temporary version
1328  for(auto& name : backboneMemberNames)
1329  {
1330  retTmpVersion =
1331  getTableByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
1332  if(retTmpVersion != tmpVersion)
1333  {
1334  __SS__ << "Failure! Temporary view requested was " << tmpVersion
1335  << ". Mismatched temporary view created: " << retTmpVersion << __E__;
1336  __GEN_COUT_ERR__ << ss.str();
1337  __SS_THROW__;
1338  }
1339  }
1340 
1341  return tmpVersion;
1342 } // end createTemporaryBackboneView()
1343 
1344 //==============================================================================
1345 TableBase* ConfigurationManagerRW::getTableByName(const std::string& tableName)
1346 {
1347  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
1348  {
1349  if(tableName == ConfigurationManager::ARTDAQ_TOP_TABLE_NAME)
1350  {
1351  __GEN_COUT_WARN__
1352  << "Since target table was the artdaq top configuration level, "
1353  "attempting to help user by appending to core tables file: "
1354  << CORE_TABLE_INFO_FILENAME << __E__;
1355  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
1356  if(fp)
1357  {
1358  fprintf(fp, "\nARTDAQ/*");
1359  fclose(fp);
1360  }
1361  }
1362 
1363  __SS__ << "Table not found with name: " << tableName << __E__;
1364  size_t f;
1365  if((f = tableName.find(' ')) != std::string::npos)
1366  ss << "There was a space character found in the table name needle at "
1367  "position "
1368  << f << " in the string (was this intended?). " << __E__;
1369 
1370  ss << "\nIf you think this table should exist in the core set of tables, try "
1371  "running 'UpdateOTS.sh --tables' to update your tables, then relaunch ots."
1372  << __E__;
1373  ss << "\nTables must be defined at path $USER_DATA/TableInfo/ to exist in ots. "
1374  "Please verify your table definitions, and then restart ots."
1375  << __E__;
1376  __GEN_COUT_ERR__ << "\n" << ss.str();
1377  __SS_THROW__;
1378  }
1379  return nameToTableMap_[tableName];
1380 } // end getTableByName()
1381 
1382 //==============================================================================
1386  TableVersion temporaryVersion,
1387  bool makeTemporary) //,
1389 {
1390  TableVersion newVersion(temporaryVersion);
1391 
1392  // set author of version
1393  TableBase* table = getTableByName(tableName);
1394  table->getTemporaryView(temporaryVersion)->setAuthor(username_);
1395  // NOTE: author is assigned to permanent versions when saved to DBI
1396 
1397  if(!makeTemporary) // saveNewVersion makes the new version the active version
1398  newVersion = theInterface_->saveNewVersion(table, temporaryVersion);
1399  else // make the temporary version active
1400  table->setActiveView(newVersion);
1401 
1402  // if there is a problem, try to recover
1403  while(!makeTemporary && !newVersion.isScratchVersion() &&
1404  allTableInfo_[tableName].versions_.find(newVersion) !=
1405  allTableInfo_[tableName].versions_.end())
1406  {
1407  __GEN_COUT_ERR__
1408  << "What happenened!?? ERROR::: new persistent version v" << newVersion
1409  << " already exists!? How is it possible? Retrace your steps and "
1410  "tell an admin."
1411  << __E__;
1412 
1413  // create a new temporary version of the target view
1414  temporaryVersion = table->createTemporaryView(newVersion);
1415 
1416  if(newVersion.isTemporaryVersion())
1417  newVersion = temporaryVersion;
1418  else
1419  newVersion = TableVersion::getNextVersion(newVersion);
1420 
1421  __GEN_COUT_WARN__ << "Attempting to recover and use v" << newVersion << __E__;
1422 
1423  if(!makeTemporary) // saveNewVersion makes the new version the active version
1424  newVersion =
1425  theInterface_->saveNewVersion(table, temporaryVersion, newVersion);
1426  else // make the temporary version active
1427  table->setActiveView(newVersion);
1428  }
1429 
1430  if(newVersion.isInvalid())
1431  {
1432  __SS__ << "Something went wrong saving the new version v" << newVersion
1433  << ". What happened?! (duplicates? database error?)" << __E__;
1434  __GEN_COUT_ERR__ << "\n" << ss.str();
1435  __SS_THROW__;
1436  }
1437 
1438  // update allTableInfo_ with the new version
1439  allTableInfo_[tableName].versions_.insert(newVersion);
1440 
1441  // table->getView().print();
1442  return newVersion;
1443 } // end saveNewTable()
1444 
1445 //==============================================================================
1450 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string& tableName,
1451  TableVersion targetVersion)
1452 {
1453  TableBase* table = getTableByName(tableName);
1454 
1455  table->trimTemporary(targetVersion);
1456 
1457  // if allTableInfo_ is not setup, then done
1458  if(allTableInfo_.find(tableName) == allTableInfo_.end())
1459  return;
1460  // else cleanup table info
1461 
1462  if(targetVersion.isInvalid())
1463  {
1464  // erase all temporary versions!
1465  for(auto it = allTableInfo_[tableName].versions_.begin();
1466  it != allTableInfo_[tableName].versions_.end();
1467  /*no increment*/)
1468  {
1469  if(it->isTemporaryVersion())
1470  {
1471  __GEN_COUT__ << "Removing '" << tableName << "' version info: " << *it
1472  << __E__;
1473  allTableInfo_[tableName].versions_.erase(it++);
1474  }
1475  else
1476  ++it;
1477  }
1478  }
1479  else // erase target version only
1480  {
1481  //__GEN_COUT__ << "Removing '" << tableName << "' version info: " << targetVersion << __E__;
1482  auto it = allTableInfo_[tableName].versions_.find(targetVersion);
1483  if(it == allTableInfo_[tableName].versions_.end())
1484  {
1485  __GEN_COUT__ << "Target '" << tableName << "' version v" << targetVersion
1486  << " was not found in info versions..." << __E__;
1487  return;
1488  }
1489  allTableInfo_[tableName].versions_.erase(
1490  allTableInfo_[tableName].versions_.find(targetVersion));
1491  }
1492 } // end eraseTemporaryVersion()
1493 
1494 //==============================================================================
1499 void ConfigurationManagerRW::clearCachedVersions(const std::string& tableName)
1500 {
1501  TableBase* table = getTableByName(tableName);
1502 
1503  table->trimCache(0);
1504 } // end clearCachedVersions()
1505 
1506 //==============================================================================
1512 {
1513  for(auto configInfo : allTableInfo_)
1514  configInfo.second.tablePtr_->trimCache(0);
1515 } // end clearAllCachedVersions()
1516 
1517 //==============================================================================
1520  const std::string& tableName, TableVersion sourceVersion)
1521 {
1522  getTableByName(tableName)->reset();
1523 
1524  // make sure source version is loaded
1525  // need to load with loose column rules!
1526  TableBase* table =
1527  getVersionedTableByName(tableName, TableVersion(sourceVersion), true);
1528 
1529  // copy from source version to a new temporary version
1530  TableVersion newTemporaryVersion =
1531  table->copyView(table->getView(), TableVersion(), username_);
1532 
1533  // update allTableInfo_ with the new version
1534  allTableInfo_[tableName].versions_.insert(newTemporaryVersion);
1535 
1536  return newTemporaryVersion;
1537 } // end copyViewToCurrentColumns()
1538 
1539 //==============================================================================
1544  const std::string& groupName, bool attemptToReloadKeys /* = false */)
1545 {
1546  // //NOTE: seems like this filter is taking the long amount of time
1547  // std::set<std::string /*name*/> fullGroupNames =
1548  // theInterface_->getAllTableGroupNames(groupName); //db filter by group name
1549 
1550  // so instead caching ourselves...
1551  auto it = allGroupInfo_.find(groupName);
1552  if(it == allGroupInfo_.end())
1553  {
1554  __SS__ << "Group name '" << groupName
1555  << "' not found in group info! (creating empty info)" << __E__;
1556  __GEN_COUT_WARN__ << ss.str();
1557  //__SS_THROW__;
1558  return allGroupInfo_[groupName];
1559  }
1560 
1561  if(attemptToReloadKeys) //load keys from Interface group cache
1562  {
1563  __GEN_COUT__ << "Reloading keys from special db group cache if it exists..."
1564  << __E__;
1565 
1566  std::set<TableGroupKey> keys;
1567  { //load keys from special db group cache (this avoids pre-cache filling and avoids long db lookup, unless speed table cache missing for this group)
1568  //attempt to use cache first! (potentially way faster .04 s vs 4 s)
1569  bool cacheFailed = false;
1570  try
1571  {
1572  TableBase localGroupMemberCacheLoader(
1573  true /*special table*/
1574  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),,
1575  TableBase::GROUP_CACHE_PREPEND + groupName);
1576  auto versions = theInterface_->getVersions(&localGroupMemberCacheLoader);
1577  for(const auto& version : versions)
1578  keys.emplace(TableGroupKey(version.version()));
1579  }
1580  catch(...)
1581  {
1582  __GEN_COUT__ << "Ignoring cache loading error. Doing full load of keys..."
1583  << __E__;
1584  cacheFailed = true;
1585  }
1586 
1587  if(cacheFailed && 0) //could consider full load if cache failed
1588  keys = theInterface_->getKeys(groupName);
1589 
1590  if(!cacheFailed) //take keys
1591  {
1592  __GEN_COUT__ << "Key from special db group cache were loaded." << __E__;
1593  it->second.keys_ = keys; //update ConfigManager cache!
1594  }
1595  }
1596  }
1597 
1598  return it->second;
1599 } // end getGroupInfo()
1600 
1601 //==============================================================================
1612  const std::string& groupName,
1613  const std::map<std::string, TableVersion>& groupMemberMap,
1614  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases)
1615 {
1616  if(!groupMemberMap.size() || groupName.empty())
1617  {
1618  __SS__ << "Illegal name/members for requested group of name '" << groupName
1619  << "' and member count = " << groupMemberMap.size() << __E__;
1620  __SS_THROW__;
1621  }
1622 
1623  // //NOTE: seems like this filter is taking the long amount of time
1624  // std::set<std::string /*name*/> fullGroupNames =
1625  // theInterface_->getAllTableGroupNames(groupName); //db filter bygroup name
1626  // const GroupInfo& groupInfo = getGroupInfo(groupName); // Note this also seems to take too long because requires a pre-cache load!
1627  std::set<TableGroupKey> keys;
1628  { //so instead load keys from special db group cache (this avoids pre-cache filling and avoids long db lookup, unless speed table cache missing for this group)
1629  //attempt to use cache first! (potentially way faster .04 s vs 4 s)
1630  bool cacheFailed = false;
1631  try
1632  {
1633  TableBase localGroupMemberCacheLoader(
1634  true /*special table*/
1635  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),,
1636  TableBase::GROUP_CACHE_PREPEND + groupName);
1637  auto versions = theInterface_->getVersions(&localGroupMemberCacheLoader);
1638  for(const auto& version : versions)
1639  keys.emplace(TableGroupKey(version.version()));
1640  }
1641  catch(...)
1642  {
1643  __COUT__ << "Ignoring cache loading error. Doing full load of keys..."
1644  << __E__;
1645  cacheFailed = true;
1646  }
1647 
1648  if(cacheFailed) //since cache failed, do full load
1649  keys = theInterface_->getKeys(groupName);
1650  }
1651 
1652  __COUTTV__(StringMacros::setToString(keys));
1653 
1654  const unsigned int MAX_DEPTH_TO_CHECK = 20;
1655  unsigned int keyMinToCheck = 0;
1656 
1657  if(keys.size())
1658  keyMinToCheck = keys.rbegin()->key();
1659  if(keyMinToCheck > MAX_DEPTH_TO_CHECK)
1660  {
1661  keyMinToCheck -= MAX_DEPTH_TO_CHECK;
1662  __GEN_COUT__ << "Checking groups back to key... " << keyMinToCheck << __E__;
1663  }
1664  else
1665  {
1666  keyMinToCheck = 0;
1667  __GEN_COUT__ << "Checking all groups." << __E__;
1668  }
1669 
1670  __GEN_COUTTV__(StringMacros::mapToString(groupMemberMap));
1671 
1672  // have min key to check, now loop through and check groups
1673 
1674  const int numOfThreads = PROCESSOR_COUNT / 2;
1675  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> " << numOfThreads
1676  << " threads." << __E__;
1677  if(numOfThreads < 2) // no multi-threading
1678  {
1679  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
1680  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
1681  std::map<std::string /*name*/, std::string /*alias*/>*
1682  compareToMemberTableAliasesPtr = nullptr;
1683  if(memberTableAliases.size())
1684  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
1685 
1686  bool isDifferent;
1687  for(const auto& key : keys)
1688  {
1689  if(key.key() < keyMinToCheck)
1690  continue; // skip keys that are too old
1691 
1692  loadTableGroup(groupName,
1693  key,
1694  false /*doActivate*/,
1695  &compareToMemberMap /*memberMap*/,
1696  0, /*progressBar*/
1697  0, /*accumulatedWarnings*/
1698  0, /*groupComment*/
1699  0, /*groupAuthor*/
1700  0, /*groupCreateTime*/
1701  true /*doNotLoadMember*/,
1702  0 /*groupTypeString*/,
1703  compareToMemberTableAliasesPtr);
1704 
1705  isDifferent = false;
1706  for(auto& memberPair : groupMemberMap)
1707  {
1708  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
1709  {
1710  // handle this table as alias, not version
1711  if(compareToMemberTableAliases.find(memberPair.first) ==
1712  compareToMemberTableAliases.end() || // alias is missing
1713  memberTableAliases.at(memberPair.first) !=
1714  compareToMemberTableAliases.at(memberPair.first))
1715  { // then different
1716  isDifferent = true;
1717  break;
1718  }
1719  // FIXED alias matches, but still need to check version
1720  } // else check if compareTo group is using an alias for table
1721  else if(compareToMemberTableAliases.find(memberPair.first) !=
1722  compareToMemberTableAliases.end())
1723  {
1724  // then different
1725  isDifferent = true;
1726  break;
1727  }
1728 
1729  // alias check complete
1730  // handle table version comparison
1731 
1732  if(compareToMemberMap.find(memberPair.first) ==
1733  compareToMemberMap.end() || // name is missing
1734  memberPair.second !=
1735  compareToMemberMap.at(memberPair.first)) // or version mismatch
1736  {
1737  // then different
1738  isDifferent = true;
1739  break;
1740  }
1741  }
1742  if(isDifferent)
1743  continue;
1744 
1745  // check member size for exact match
1746  if(groupMemberMap.size() != compareToMemberMap.size())
1747  continue; // different size, so not same (groupMemberMap is a subset of
1748  // memberPairs)
1749 
1750  __GEN_COUT__ << "Found exact match with key: " << key << __E__;
1751  // else found an exact match!
1752  return key;
1753  }
1754  __GEN_COUT__ << "No match found - this group is new!" << __E__;
1755  // if here, then no match found
1756  return TableGroupKey(); // return invalid key
1757  }
1758  else //multi-threading
1759  {
1760  int threadsLaunched = 0;
1761  int foundThreadIndex = 0;
1762  std::atomic<bool> foundIdentical = false;
1763  ots::TableGroupKey identicalKey;
1764  std::mutex threadMutex;
1765 
1766  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
1767  for(int i = 0; i < numOfThreads; ++i)
1768  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
1769 
1770  for(const auto& key : keys)
1771  {
1772  if(foundIdentical)
1773  break;
1774  if(key.key() < keyMinToCheck)
1775  continue; // skip keys that are too old
1776 
1777  if(threadsLaunched >= numOfThreads)
1778  {
1779  //find availableThreadIndex
1780  foundThreadIndex = -1;
1781  while(foundThreadIndex == -1)
1782  {
1783  if(foundIdentical)
1784  break;
1785 
1786  for(int i = 0; i < numOfThreads; ++i)
1787  if(*(threadDone[i]))
1788  {
1789  foundThreadIndex = i;
1790  break;
1791  }
1792  if(foundThreadIndex == -1)
1793  {
1794  __GEN_COUTT__ << "Waiting for available thread..." << __E__;
1795  usleep(10000);
1796  }
1797  } //end thread search loop
1798  threadsLaunched = numOfThreads - 1;
1799  }
1800  if(foundIdentical)
1801  break;
1802 
1803  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex << __E__;
1804  *(threadDone[foundThreadIndex]) = false;
1805 
1806  std::thread(
1807  [](ConfigurationManagerRW* cfgMgr,
1808  std::string theGroupName,
1809  ots::TableGroupKey groupKeyToCompare,
1810  const std::map<std::string, TableVersion>& groupMemberMap,
1811  const std::map<std::string /*name*/, std::string /*alias*/>&
1812  memberTableAliases,
1813  std::atomic<bool>* theFoundIdentical,
1814  ots::TableGroupKey* theIdenticalKey,
1815  std::mutex* theThreadMutex,
1816  std::shared_ptr<std::atomic<bool>> theThreadDone) {
1818  theGroupName,
1819  groupKeyToCompare,
1820  groupMemberMap,
1821  memberTableAliases,
1822  theFoundIdentical,
1823  theIdenticalKey,
1824  theThreadMutex,
1825  theThreadDone);
1826  },
1827  this,
1828  groupName,
1829  key,
1830  groupMemberMap,
1831  memberTableAliases,
1832  &foundIdentical,
1833  &identicalKey,
1834  &threadMutex,
1835  threadDone[foundThreadIndex])
1836  .detach();
1837 
1838  ++threadsLaunched;
1839  ++foundThreadIndex;
1840  } //end group key check thread loop
1841 
1842  //check for all threads done
1843  do
1844  {
1845  foundThreadIndex = -1;
1846  for(int i = 0; i < numOfThreads; ++i)
1847  if(!*(threadDone[i]))
1848  {
1849  foundThreadIndex = i;
1850  break;
1851  }
1852  if(foundThreadIndex != -1)
1853  {
1854  __GEN_COUTT__ << "Waiting for thread to finish... " << foundThreadIndex
1855  << __E__;
1856  usleep(10000);
1857  }
1858  } while(foundThreadIndex != -1); //end thread done search loop
1859 
1860  if(foundIdentical)
1861  {
1862  __GEN_COUT__ << "Found exact match with key: " << identicalKey << __E__;
1863  return identicalKey;
1864  }
1865 
1866  // if here, then no match found
1867  return TableGroupKey(); // return invalid key
1868  } //end multi-thread handling
1869 } // end findTableGroup()
1870 
1871 //==============================================================================
1877  TableVersion fillVersion /* = TableVersion()*/)
1878 {
1879  if(fillVersion.isInvalid())
1880  return &groupMetadataTable_;
1881  //else load specified fill version
1882 
1883  //only lock metadata table since it is shared by all group accesses
1884  std::lock_guard<std::mutex> lock(metaDataTableMutex_);
1885 
1886  // clear table
1887  while(groupMetadataTable_.getView().getNumberOfRows())
1888  groupMetadataTable_.getViewP()->deleteRow(0);
1889 
1890  // retrieve metadata from database
1891  try
1892  {
1893  theInterface_->fill(&groupMetadataTable_, fillVersion);
1894  }
1895  catch(const std::runtime_error& e)
1896  {
1897  __GEN_COUT_WARN__ << "Failed to load " << groupMetadataTable_.getTableName()
1898  << "-v" << fillVersion << ". Metadata error: " << e.what()
1899  << __E__;
1900  }
1901  catch(...)
1902  {
1903  __GEN_COUT_WARN__ << "Failed to load " << groupMetadataTable_.getTableName()
1904  << "-v" << fillVersion << ". Ignoring unknown metadata error. "
1905  << __E__;
1906  }
1907 
1908  // check that there is only 1 row
1909  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
1910  {
1911  groupMetadataTable_.print();
1912  __GEN_COUT_ERR__ << "Ignoring that groupMetadataTable_ v" << fillVersion
1913  << " has wrong "
1914  "number of rows!' Must "
1915  "be 1. Going with anonymous defaults."
1916  << __E__;
1917 
1918  // fix metadata table
1919  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1920  groupMetadataTable_.getViewP()->deleteRow(0);
1921  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1922  groupMetadataTable_.getViewP()->addRow();
1923  }
1924 
1925  return &groupMetadataTable_;
1926 } // end getMetadataTable()
1927 
1928 //==============================================================================
1936  const std::string& groupName,
1937  std::map<std::string, TableVersion>& groupMembers,
1938  const std::string& groupComment,
1939  std::map<std::string /*table*/, std::string /*alias*/>* groupAliases)
1940 {
1941  // steps:
1942  // determine new group key
1943  // verify group members
1944  // verify groupNameWithKey
1945  // verify store
1946 
1947  if(groupMembers.size() == 0) // do not allow empty groups
1948  {
1949  __SS__ << "Empty group member list. Can not create a group without members!"
1950  << __E__;
1951  __SS_THROW__;
1952  }
1953 
1954  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1955 
1956  // verify group members
1957  // - use all table info
1958  std::map<std::string, TableInfo> allCfgInfo = getAllTableInfo();
1959  for(auto& memberPair : groupMembers)
1960  {
1961  // check member name
1962  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
1963  {
1964  __GEN_COUT_ERR__ << "Group member \"" << memberPair.first
1965  << "\" not found in database!";
1966 
1967  if(groupMetadataTable_.getTableName() == memberPair.first)
1968  {
1969  __GEN_COUT_WARN__
1970  << "Looks like this is the groupMetadataTable_ '"
1971  << TableBase::GROUP_METADATA_TABLE_NAME
1972  << ".' Note that this table is added to the member map when groups "
1973  "are saved."
1974  << "It should not be part of member map when calling this function."
1975  << __E__;
1976  __GEN_COUT__ << "Attempting to recover." << __E__;
1977  groupMembers.erase(groupMembers.find(memberPair.first));
1978  }
1979  else
1980  {
1981  __SS__ << ("Group member not found!") << __E__;
1982  __SS_THROW__;
1983  }
1984  }
1985  // check member version
1986  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
1987  allCfgInfo[memberPair.first].versions_.end())
1988  {
1989  __SS__ << "Group member \"" << memberPair.first << "\" version \""
1990  << memberPair.second << "\" not found in database!";
1991  __SS_THROW__;
1992  }
1993  } // end verify members
1994 
1995  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1996 
1997  // verify group aliases
1998  if(groupAliases)
1999  {
2000  for(auto& aliasPair : *groupAliases)
2001  {
2002  // check for alias table in member names
2003  if(groupMembers.find(aliasPair.first) == groupMembers.end())
2004  {
2005  __GEN_COUT_ERR__ << "Group member \"" << aliasPair.first
2006  << "\" not found in group member map!";
2007 
2008  __SS__ << ("Alias table not found in member list!") << __E__;
2009  __SS_THROW__;
2010  }
2011  }
2012  } // end verify group aliases
2013 
2014  TableGroupKey newKey =
2015  TableGroupKey::getNextKey(theInterface_->findLatestGroupKey(groupName));
2016  __GEN_COUT__ << "New Key for group: " << groupName << " found as " << newKey << __E__;
2017  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2018 
2019  time_t groupCreationTime = time(0);
2020  // capture group type before adding metadata table!
2021  std::string groupType = getTypeNameOfGroup(groupMembers);
2022  std::map<std::string /*name*/, TableVersion /*version*/> groupMembersWithoutMeta =
2023  groupMembers;
2024 
2025  // verify groupNameWithKey and attempt to store
2026  try
2027  {
2028  // save meta data for group; reuse groupMetadataTable_
2029  std::string groupAliasesString = "";
2030  if(groupAliases)
2031  groupAliasesString = StringMacros::mapToString(
2032  *groupAliases, "," /*primary delimeter*/, ":" /*secondary delimeter*/);
2033  __GEN_COUT__ << "Metadata: " << username_ << " " << groupCreationTime << " "
2034  << groupComment << " " << groupAliasesString << " " << groupType
2035  << __E__;
2036 
2037  // to compensate for unusual errors upstream, make sure the metadata table has one
2038  // row
2039  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
2040  groupMetadataTable_.getViewP()->deleteRow(0);
2041  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
2042  groupMetadataTable_.getViewP()->addRow();
2043 
2044  // columns are uid,comment,author,time
2045  groupMetadataTable_.getViewP()->setValue(
2046  groupAliasesString, 0, ConfigurationManager::METADATA_COL_ALIASES);
2047  groupMetadataTable_.getViewP()->setValue(
2048  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
2049  groupMetadataTable_.getViewP()->setValue(
2050  username_, 0, ConfigurationManager::METADATA_COL_AUTHOR);
2051  groupMetadataTable_.getViewP()->setValue(
2052  groupCreationTime, 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
2053 
2054  if(TTEST(2))
2055  {
2056  std::stringstream ss;
2057  groupMetadataTable_.print(ss);
2058  __COUT_MULTI__(2, ss.str());
2059  }
2060 
2061  // save table, and retry on save collision
2062  {
2063  // set version to first available persistent version
2065  theInterface_->findLatestVersion(&groupMetadataTable_));
2066  groupMetadataTable_.getViewP()->setVersion(newVersion);
2067 
2068  uint16_t retries = 0;
2069  while(1)
2070  {
2071  try
2072  {
2073  theInterface_->saveActiveVersion(&groupMetadataTable_);
2074  }
2075  catch(const std::runtime_error& e)
2076  {
2077  __GEN_COUT__ << "Caught runtime_error exception during table save."
2078  << __E__;
2079  if(std::string(e.what()).find("there was a collision") !=
2080  std::string::npos)
2081  {
2082  __GEN_COUT_WARN__
2083  << "There was a collision saving the new table "
2084  << groupMetadataTable_ << "(" << newVersion
2085  << "), trying incremented table version... retries="
2086  << retries << __E__;
2087  if(++retries > 3) //give up
2088  throw;
2089  newVersion = TableVersion::getNextVersion(
2090  newVersion); //increment table version
2091  groupMetadataTable_.getViewP()->setVersion(newVersion);
2092  __GEN_COUT__ << "New version for table: " << groupMetadataTable_
2093  << " found as " << newVersion << __E__;
2094  continue;
2095  }
2096  else
2097  throw;
2098  }
2099 
2100  __GEN_COUT__ << "Created table: " << groupMetadataTable_ << "-v"
2101  << newVersion << __E__;
2102  break;
2103  } //end collission retry loop
2104  }
2105 
2106  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2107  << __E__;
2108 
2109  // force groupMetadataTable_ to be a member for the group
2110  groupMembers[groupMetadataTable_.getTableName()] =
2111  groupMetadataTable_.getViewVersion();
2112 
2113  // save group, and retry on save collision
2114  {
2115  uint16_t retries = 0;
2116  while(1)
2117  {
2118  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2119  << __E__;
2120 
2121  try
2122  {
2123  theInterface_->saveTableGroup(
2124  groupMembers,
2125  TableGroupKey::getFullGroupString(groupName, newKey));
2126  }
2127  catch(const std::runtime_error& e)
2128  {
2129  __GEN_COUT__ << "Caught runtime_error exception during group save."
2130  << __E__;
2131  if(std::string(e.what()).find("there was a collision") !=
2132  std::string::npos)
2133  {
2134  __GEN_COUT_WARN__
2135  << "There was a collision saving the new group " << groupName
2136  << "(" << newKey
2137  << "), trying incremented group key... retries=" << retries
2138  << __E__;
2139  if(++retries > 3) //give up
2140  throw;
2141  newKey = TableGroupKey::getNextKey(newKey); //increment group key
2142  __GEN_COUT__ << "New Key for group: " << groupName << " found as "
2143  << newKey << __E__;
2144  continue;
2145  }
2146  else
2147  throw;
2148  }
2149 
2150  __GEN_COUT__ << "Created table group: " << groupName << "(" << newKey
2151  << ")" << __E__;
2152  break;
2153  } //end collission retry loop
2154  }
2155 
2156  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2157  << __E__;
2158  }
2159  catch(std::runtime_error& e)
2160  {
2161  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << "(" << newKey
2162  << ")" << __E__;
2163  __GEN_COUT_ERR__ << "\n\n" << e.what() << __E__;
2164  throw;
2165  }
2166  catch(...)
2167  {
2168  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
2169  << __E__;
2170  throw;
2171  }
2172 
2173  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2174 
2175  // store cache of recent groups
2176  allGroupInfo_[groupName].keys_.emplace(newKey);
2177  //update latest group info with this group's info
2178  allGroupInfo_.at(groupName).latestKey_ = newKey;
2179  allGroupInfo_.at(groupName).latestKeyGroupAuthor_ = username_;
2180  allGroupInfo_.at(groupName).latestKeyGroupComment_ = groupComment;
2181  allGroupInfo_.at(groupName).latestKeyGroupCreationTime_ = groupCreationTime;
2182  allGroupInfo_.at(groupName).latestKeyGroupTypeString_ = groupType;
2183  allGroupInfo_.at(groupName).latestKeyMemberMap_ = groupMembersWithoutMeta;
2184 
2185  __GEN_COUT__ << "Saved " << groupName << "(" << newKey << ") of type " << groupType
2186  << __E__;
2187 
2188  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2189 
2190  // at this point succeeded!
2191  return newKey;
2192 } // end saveNewTableGroup()
2193 
2194 //==============================================================================
2199 {
2200  __GEN_COUT_INFO__ << "Creating new backbone from temporary version "
2201  << temporaryVersion << __E__;
2202 
2203  // find common available temporary version among backbone members
2204  TableVersion newVersion(TableVersion::DEFAULT);
2205  TableVersion retNewVersion;
2206  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
2207  for(auto& name : backboneMemberNames)
2208  {
2209  retNewVersion = ConfigurationManager::getTableByName(name)->getNextVersion();
2210  __GEN_COUT__ << "New version for backbone member (" << name
2211  << "): " << retNewVersion << __E__;
2212  if(retNewVersion > newVersion)
2213  newVersion = retNewVersion;
2214  }
2215 
2216  __GEN_COUT__ << "Common new backbone version found as " << newVersion << __E__;
2217 
2218  // create new views from source temporary version
2219  for(auto& name : backboneMemberNames)
2220  {
2221  // saveNewVersion makes the new version the active version
2222  retNewVersion = getConfigurationInterface()->saveNewVersion(
2223  getTableByName(name), temporaryVersion, newVersion);
2224  if(retNewVersion != newVersion)
2225  {
2226  __SS__ << "Failure! New view requested was " << newVersion
2227  << ". Mismatched new view created: " << retNewVersion << __E__;
2228  __GEN_COUT_ERR__ << ss.str();
2229  __SS_THROW__;
2230  }
2231  }
2232 
2233  return newVersion;
2234 } // end saveNewBackbone()
2235 
2236 //==============================================================================
2242  const std::string& tableName,
2243  TableVersion originalVersion,
2244  bool makeTemporary,
2245  TableBase* table,
2246  TableVersion temporaryModifiedVersion,
2247  bool ignoreDuplicates /*= false*/,
2248  bool lookForEquivalent /*= false*/,
2249  bool* foundEquivalent /*= nullptr*/)
2250 {
2251  bool needToEraseTemporarySource =
2252  (originalVersion.isTemporaryVersion() && !makeTemporary);
2253 
2254  if(foundEquivalent)
2255  *foundEquivalent = false; // initialize
2256 
2257  // check for duplicate tables already in cache, plus highest version numbers not in cache
2258  if(!ignoreDuplicates)
2259  {
2260  __GEN_COUT__ << "Checking for duplicate '" << tableName << "' tables..." << __E__;
2261 
2262  TableVersion duplicateVersion;
2263 
2264  {
2265  //"DEEP" checking
2266  // load into cache 'recent' versions for this table
2267  // 'recent' := those already in cache, plus highest version numbers not in cache
2268  const std::map<std::string, TableInfo>& allTableInfo =
2269  getAllTableInfo(); // do not refresh
2270 
2271  auto versionReverseIterator =
2272  allTableInfo.at(tableName).versions_.rbegin(); // get reverse iterator
2273  __GEN_COUT__ << "Filling up '" << tableName << "' cache from "
2274  << table->getNumberOfStoredViews() << " to max count of "
2275  << table->MAX_VIEWS_IN_CACHE << __E__;
2276  for(; table->getNumberOfStoredViews() < table->MAX_VIEWS_IN_CACHE &&
2277  versionReverseIterator != allTableInfo.at(tableName).versions_.rend();
2278  ++versionReverseIterator)
2279  {
2280  __GEN_COUTT__ << "'" << tableName << "' versions in reverse order "
2281  << *versionReverseIterator << __E__;
2282  try
2283  {
2284  getVersionedTableByName(tableName,
2285  *versionReverseIterator); // load to cache
2286  }
2287  catch(const std::runtime_error& e)
2288  {
2289  // ignore error
2290  __COUTT__ << "'" << tableName
2291  << "' version failed to load: " << *versionReverseIterator
2292  << __E__;
2293  }
2294  }
2295  }
2296 
2297  __GEN_COUT__ << "Checking '" << tableName << "' for duplicate..." << __E__;
2298 
2299  duplicateVersion = table->checkForDuplicate(
2300  temporaryModifiedVersion,
2301  (!originalVersion.isTemporaryVersion() && !makeTemporary)
2302  ? TableVersion()
2303  : // if from persistent to persistent, then include original version in search
2304  originalVersion);
2305 
2306  if(lookForEquivalent && !duplicateVersion.isInvalid())
2307  {
2308  // found an equivalent!
2309  __GEN_COUT__ << "Equivalent '" << tableName << "' table found in version v"
2310  << duplicateVersion << __E__;
2311 
2312  // if duplicate version was temporary, do not use
2313  if(duplicateVersion.isTemporaryVersion() && !makeTemporary)
2314  {
2315  __GEN_COUT__ << "Need persistent. Duplicate '" << tableName
2316  << "' version was temporary. "
2317  "Abandoning duplicate."
2318  << __E__;
2319  duplicateVersion = TableVersion(); // set invalid
2320  }
2321  else
2322  {
2323  // erase and return equivalent version
2324 
2325  // erase modified equivalent version
2326  eraseTemporaryVersion(tableName, temporaryModifiedVersion);
2327 
2328  // erase original if needed
2329  if(needToEraseTemporarySource)
2330  eraseTemporaryVersion(tableName, originalVersion);
2331 
2332  if(foundEquivalent)
2333  *foundEquivalent = true;
2334 
2335  __GEN_COUT__ << "\t\t Equivalent '" << tableName
2336  << "' assigned version: " << duplicateVersion << __E__;
2337 
2338  return duplicateVersion;
2339  }
2340  }
2341 
2342  if(!duplicateVersion.isInvalid())
2343  {
2344  __SS__ << "This version of table '" << tableName
2345  << "' is identical to another version currently cached v"
2346  << duplicateVersion << ". No reason to save a duplicate." << __E__;
2347  __GEN_COUT_ERR__ << "\n" << ss.str();
2348 
2349  // delete temporaryModifiedVersion
2350  table->eraseView(temporaryModifiedVersion);
2351  __SS_THROW__;
2352  }
2353 
2354  __GEN_COUT__ << "Check for duplicate '" << tableName << "' tables complete."
2355  << __E__;
2356  }
2357 
2358  if(makeTemporary)
2359  __GEN_COUT__ << "\t\t**************************** Save as temporary '"
2360  << tableName << "' table version" << __E__;
2361  else
2362  __GEN_COUT__ << "\t\t**************************** Save as new '" << tableName
2363  << "' table version" << __E__;
2364 
2365  TableVersion newAssignedVersion =
2366  saveNewTable(tableName, temporaryModifiedVersion, makeTemporary);
2367 
2368  __GEN_COUTTV__(table->getView().getComment());
2369 
2370  if(needToEraseTemporarySource)
2371  eraseTemporaryVersion(tableName, originalVersion);
2372 
2373  __GEN_COUT__ << "\t\t '" << tableName
2374  << "' new assigned version: " << newAssignedVersion << __E__;
2375  return newAssignedVersion;
2376 } // end saveModifiedVersion()
2377 
2378 //==============================================================================
2379 GroupEditStruct::GroupEditStruct(const ConfigurationManager::GroupType& groupType,
2380  ConfigurationManagerRW* cfgMgr)
2381  : groupType_(groupType)
2382  , originalGroupName_(cfgMgr->getActiveGroupName(groupType))
2383  , originalGroupKey_(cfgMgr->getActiveGroupKey(groupType))
2384  , cfgMgr_(cfgMgr)
2385  , mfSubject_(cfgMgr->getUsername())
2386 {
2387  if(originalGroupName_ == "" || originalGroupKey_.isInvalid())
2388  {
2389  __SS__ << "Error! No active group found for type '"
2391  << ".' There must be an active group to edit the group." << __E__ << __E__
2392  << StringMacros::stackTrace() << __E__;
2393  __SS_THROW__;
2394  }
2395 
2396  __GEN_COUT__ << "Extracting Group-Edit Struct for type "
2397  << ConfigurationManager::convertGroupTypeToName(groupType) << __E__;
2398 
2399  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
2400 
2401  const std::set<std::string>& memberNames =
2402  groupType == ConfigurationManager::GroupType::CONTEXT_TYPE
2403  ? cfgMgr->getActiveContextMemberNames()
2404  : (groupType == ConfigurationManager::GroupType::BACKBONE_TYPE
2405  ? ConfigurationManager::getBackboneMemberNames()
2406  : (groupType == ConfigurationManager::GroupType::ITERATE_TYPE
2407  ? ConfigurationManager::getIterateMemberNames()
2408  : cfgMgr->getConfigurationMemberNames()));
2409 
2410  for(auto& memberName : memberNames)
2411  try
2412  {
2413  groupMembers_.emplace(
2414  std::make_pair(memberName, activeTables.at(memberName)));
2415  groupTables_.emplace(std::make_pair(
2416  memberName,
2417  TableEditStruct(memberName, cfgMgr))); // Table ready for editing!
2418  }
2419  catch(...)
2420  {
2421  __GEN_COUTV__(StringMacros::mapToString(activeTables));
2422  __SS__ << "Error! Could not find group member table '" << memberName
2423  << "' for group type '"
2425  << ".' All group members must be present to create the group editing "
2426  "structure."
2427  << __E__ << __E__ << StringMacros::stackTrace() << __E__;
2428  __SS_THROW__;
2429  }
2430 
2431 } // end GroupEditStruct constructor()
2432 
2433 //==============================================================================
2434 GroupEditStruct::~GroupEditStruct()
2435 {
2436  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2437  << originalGroupKey_ << ")' Destructing..." << __E__;
2438  dropChanges();
2439  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2440  << originalGroupKey_ << ")' Desctructed." << __E__;
2441 } // end GroupEditStruct destructor()
2442 
2443 //==============================================================================
2446  bool markModified /*= false*/)
2447 {
2448  auto it = groupTables_.find(tableName);
2449  if(it == groupTables_.end())
2450  {
2451  if(groupType_ == ConfigurationManager::GroupType::CONFIGURATION_TYPE &&
2452  markModified)
2453  {
2454  __GEN_COUT__ << "Table '" << tableName
2455  << "' not found in configuration table members from editing '"
2456  << originalGroupName_ << "(" << originalGroupKey_ << ")..."
2457  << " Attempting to add it!" << __E__;
2458 
2459  // emplace returns pair<object,bool wasAdded>
2460  auto newIt = groupTables_.emplace(std::make_pair(
2461  tableName,
2462  TableEditStruct(tableName, cfgMgr_))); // Table ready for editing!
2463  if(newIt.second)
2464  {
2465  newIt.first->second.modified_ =
2466  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2467  groupMembers_.emplace(
2468  std::make_pair(tableName, newIt.first->second.temporaryVersion_));
2469  return newIt.first->second;
2470  }
2471  __GEN_COUT_ERR__ << "Failed to emplace new table..." << __E__;
2472  }
2473 
2474  __SS__ << "Table '" << tableName << "' not found in table members from editing '"
2475  << originalGroupName_ << "(" << originalGroupKey_ << ")!'" << __E__;
2476  __SS_THROW__;
2477  }
2478  it->second.modified_ =
2479  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2480  return it->second;
2481 } // end getTableEditStruct()
2482 
2483 //==============================================================================
2484 void GroupEditStruct::dropChanges()
2485 {
2486  __GEN_COUT__ << "Dropping unsaved changes from editing '" << originalGroupName_ << "("
2487  << originalGroupKey_ << ")'..." << __E__;
2488 
2489  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2490 
2491  // drop all temporary versions
2492  for(auto& groupTable : groupTables_)
2493  if(groupTable.second
2494  .createdTemporaryVersion_) // if temporary version created here
2495  {
2496  // erase with proper version management
2497  cfgMgr->eraseTemporaryVersion(groupTable.second.tableName_,
2498  groupTable.second.temporaryVersion_);
2499  groupTable.second.createdTemporaryVersion_ = false;
2500  groupTable.second.modified_ = false;
2501  }
2502 
2503  __GEN_COUT__ << "Unsaved changes dropped from editing '" << originalGroupName_ << "("
2504  << originalGroupKey_ << ").'" << __E__;
2505 } // end GroupEditStruct::dropChanges()
2506 
2507 //==============================================================================
2508 void GroupEditStruct::saveChanges(const std::string& groupNameToSave,
2509  TableGroupKey& newGroupKey,
2510  bool* foundEquivalentGroupKey /*= nullptr*/,
2511  bool activateNewGroup /*= false*/,
2512  bool updateGroupAliases /*= false*/,
2513  bool updateTableAliases /*= false*/,
2514  TableGroupKey* newBackboneKey /*= nullptr*/,
2515  bool* foundEquivalentBackboneKey /*= nullptr*/,
2516  std::string* accumulatedWarnings /*= nullptr*/)
2517 {
2518  __GEN_COUT__ << "Saving changes..." << __E__;
2519 
2520  newGroupKey = TableGroupKey(); // invalidate reference parameter
2521  if(newBackboneKey)
2522  *newBackboneKey = TableGroupKey(); // invalidate reference parameter
2523  if(foundEquivalentBackboneKey)
2524  *foundEquivalentBackboneKey = false; // clear to start
2525  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2526 
2527  // save all temporary modified versions
2528  bool anyTableNew = false;
2529  for(auto& groupTable : groupTables_)
2530  {
2531  if(!groupTable.second.modified_)
2532  continue; // skip if not modified
2533 
2534  __GEN_COUT__ << "Original version is " << groupTable.second.tableName_ << "-v"
2535  << groupTable.second.originalVersion_ << __E__;
2536 
2537  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2538  groupTable.second.tableName_,
2539  groupTable.second.originalVersion_,
2540  true /*make temporary*/,
2541  groupTable.second.table_,
2542  groupTable.second.temporaryVersion_,
2543  true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
2544 
2545  __GEN_COUT__ << "Temporary target version is " << groupTable.second.tableName_
2546  << "-v" << groupMembers_.at(groupTable.first) << "-v"
2547  << groupTable.second.temporaryVersion_ << __E__;
2548 
2549  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2550  groupTable.second.tableName_,
2551  groupTable.second.originalVersion_,
2552  false /*make temporary*/,
2553  groupTable.second.table_,
2554  groupTable.second.temporaryVersion_,
2555  false /*ignoreDuplicates*/,
2556  true /*lookForEquivalent*/); // save persistent version properly
2557 
2558  if(groupTable.second.originalVersion_ != groupMembers_.at(groupTable.first))
2559  {
2560  anyTableNew = true;
2561  __GEN_COUT__ << "Final NEW target version is " << groupTable.second.tableName_
2562  << "-v" << groupMembers_.at(groupTable.first) << __E__;
2563  }
2564  else
2565  __GEN_COUT__ << "Final target version is " << groupTable.second.tableName_
2566  << "-v" << groupMembers_.at(groupTable.first) << __E__;
2567 
2568  groupTable.second.modified_ = false; // clear modified flag
2569  groupTable.second.createdTemporaryVersion_ = false; // modified version is gone
2570  } // loop through table edit structs
2571 
2572  for(auto& table : groupMembers_)
2573  {
2574  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2575  }
2576 
2577  if(!anyTableNew) //then could be duplicate group
2578  {
2579  __GEN_COUT__ << "Checking for duplicate groups..." << __E__;
2580  newGroupKey = cfgMgr->findTableGroup(groupNameToSave, groupMembers_);
2581  }
2582  else
2583  __GEN_COUT__ << "New table found, so no need to check duplicate groups." << __E__;
2584 
2585  if(!newGroupKey.isInvalid())
2586  {
2587  __GEN_COUT__ << "Found equivalent group key (" << newGroupKey << ") for "
2588  << groupNameToSave << "." << __E__;
2589  if(foundEquivalentGroupKey)
2590  *foundEquivalentGroupKey = true;
2591  }
2592  else
2593  {
2594  newGroupKey = cfgMgr->saveNewTableGroup(groupNameToSave, groupMembers_);
2595  __GEN_COUT__ << "Saved new Context group key (" << newGroupKey << ") for "
2596  << groupNameToSave << "." << __E__;
2597  }
2598 
2599  bool groupAliasChange = false;
2600  bool tableAliasChange = false;
2601 
2602  if(groupType_ !=
2603  ConfigurationManager::GroupType::
2604  BACKBONE_TYPE) //if not backbone group save, consider changing aliases (not if it is backbone group, tables not necessarily active yet, which causes error in GroupEditStruct backboneGroupEdit)
2605  {
2606  GroupEditStruct backboneGroupEdit(ConfigurationManager::GroupType::BACKBONE_TYPE,
2607  cfgMgr);
2608 
2609  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE &&
2610  updateGroupAliases)
2611  {
2612  // check group aliases ... a la
2613  // ConfigurationGUISupervisor::handleSetGroupAliasInBackboneXML
2614 
2615  TableEditStruct& groupAliasTable = backboneGroupEdit.getTableEditStruct(
2616  ConfigurationManager::GROUP_ALIASES_TABLE_NAME, true /*markModified*/);
2617  TableView* tableView = groupAliasTable.tableView_;
2618 
2619  // unsigned int col;
2620  unsigned int row = 0;
2621 
2622  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2623  cfgMgr->getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME)
2624  .getChildren();
2625  std::string groupName, groupKey;
2626  for(auto& aliasNodePair : aliasNodePairs)
2627  {
2628  groupName = aliasNodePair.second.getNode("GroupName").getValueAsString();
2629  groupKey = aliasNodePair.second.getNode("GroupKey").getValueAsString();
2630 
2631  __GEN_COUT__ << "Group Alias: " << aliasNodePair.first << " => "
2632  << groupName << "(" << groupKey << "); row=" << row << __E__;
2633 
2634  if(groupName == originalGroupName_ &&
2635  TableGroupKey(groupKey) == originalGroupKey_)
2636  {
2637  __GEN_COUT__ << "Found alias! Changing group key from ("
2638  << originalGroupKey_ << ") to (" << newGroupKey << ")"
2639  << __E__;
2640 
2641  groupAliasChange = true;
2642 
2643  tableView->setValueAsString(
2644  newGroupKey.toString(), row, tableView->findCol("GroupKey"));
2645  }
2646 
2647  ++row;
2648  }
2649 
2650  if(groupAliasChange)
2651  {
2652  std::stringstream ss;
2653  tableView->print(ss);
2654  __GEN_COUT__ << ss.str();
2655  }
2656  } // end updateGroupAliases handling
2657 
2658  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE &&
2659  updateTableAliases)
2660  {
2661  // update all table version aliases
2662  TableView* tableView =
2663  backboneGroupEdit
2664  .getTableEditStruct(ConfigurationManager::VERSION_ALIASES_TABLE_NAME,
2665  true /*markModified*/)
2666  .tableView_;
2667 
2668  for(auto& groupTable : groupTables_)
2669  {
2670  if(groupTable.second.originalVersion_ ==
2671  groupMembers_.at(groupTable.second.tableName_))
2672  continue; // skip if no change
2673 
2674  __GEN_COUT__ << "Checking alias... original version is "
2675  << groupTable.second.tableName_ << "-v"
2676  << groupTable.second.originalVersion_
2677  << " and new version is v"
2678  << groupMembers_.at(groupTable.second.tableName_) << __E__;
2679 
2680  // unsigned int col;
2681  unsigned int row = 0;
2682 
2683  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2684  cfgMgr->getNode(ConfigurationManager::VERSION_ALIASES_TABLE_NAME)
2685  .getChildren();
2686  std::string tableName, tableVersion;
2687  for(auto& aliasNodePair : aliasNodePairs)
2688  {
2689  tableName =
2690  aliasNodePair.second.getNode("TableName").getValueAsString();
2691  tableVersion =
2692  aliasNodePair.second.getNode("Version").getValueAsString();
2693 
2694  __GEN_COUT__ << "Table Alias: " << aliasNodePair.first << " => "
2695  << tableName << "-v" << tableVersion << "" << __E__;
2696 
2697  if(tableName == groupTable.second.tableName_ &&
2698  TableVersion(tableVersion) == groupTable.second.originalVersion_)
2699  {
2700  __GEN_COUT__ << "Found alias! Changing icon table version alias."
2701  << __E__;
2702 
2703  tableAliasChange = true;
2704 
2705  tableView->setValueAsString(
2706  groupMembers_.at(groupTable.second.tableName_).toString(),
2707  row,
2708  tableView->findCol("Version"));
2709  }
2710 
2711  ++row;
2712  }
2713  }
2714 
2715  if(tableAliasChange)
2716  {
2717  std::stringstream ss;
2718  tableView->print(ss);
2719  __GEN_COUT__ << ss.str();
2720  }
2721  } // end updateTableAliases handling
2722 
2723  TableGroupKey localNewBackboneKey;
2724  // if backbone modified, save group and activate it
2725  if(groupAliasChange || tableAliasChange)
2726  {
2727  for(auto& table : backboneGroupEdit.groupMembers_)
2728  {
2729  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2730  }
2731  backboneGroupEdit.saveChanges(
2732  backboneGroupEdit.originalGroupName_,
2733  localNewBackboneKey,
2734  foundEquivalentBackboneKey ? foundEquivalentBackboneKey : nullptr);
2735 
2736  if(newBackboneKey)
2737  *newBackboneKey = localNewBackboneKey;
2738  }
2739 
2740  // acquire all active groups and ignore errors, so that activateTableGroup does not
2741  // erase other active groups
2742  {
2743  __GEN_COUT__
2744  << "Restoring active table groups, before activating new groups..."
2745  << __E__;
2746 
2747  std::string localAccumulatedWarnings;
2748  cfgMgr->restoreActiveTableGroups(
2749  false /*throwErrors*/,
2750  "" /*pathToActiveGroupsFile*/,
2751  ConfigurationManager::LoadGroupType::
2752  ALL_TYPES /*onlyLoadIfBackboneOrContext*/,
2753  &localAccumulatedWarnings);
2754  }
2755 
2756  // activate new groups
2757  if(!localNewBackboneKey.isInvalid())
2758  cfgMgr->activateTableGroup(
2759  backboneGroupEdit.originalGroupName_,
2760  localNewBackboneKey,
2761  accumulatedWarnings ? accumulatedWarnings : nullptr);
2762 
2763  } //end non-backbone save type handling
2764  else //is backbone save type
2765  {
2766  // acquire all active groups and ignore errors, so that activateTableGroup does not
2767  // erase other active groups
2768  {
2769  __GEN_COUT__
2770  << "Restoring active table groups, before activating new groups..."
2771  << __E__;
2772 
2773  std::string localAccumulatedWarnings;
2774  cfgMgr->restoreActiveTableGroups(
2775  false /*throwErrors*/,
2776  "" /*pathToActiveGroupsFile*/,
2777  ConfigurationManager::LoadGroupType::
2778  ALL_TYPES /*onlyLoadIfBackboneOrContext*/,
2779  &localAccumulatedWarnings);
2780  }
2781  } //end backbone save type handling
2782 
2783  if(activateNewGroup)
2784  cfgMgr->activateTableGroup(groupNameToSave,
2785  newGroupKey,
2786  accumulatedWarnings ? accumulatedWarnings : nullptr);
2787 
2788  __GEN_COUT__ << "Changes saved." << __E__;
2789 } // end GroupEditStruct::saveChanges()
2790 
2791 //==============================================================================
2794 {
2795  if(1)
2796  return; //if 0 to debug
2797  __GEN_COUTV__(runTimeSeconds());
2798 
2799  std::string accumulatedWarningsStr;
2800  std::string* accumulatedWarnings = &accumulatedWarningsStr;
2801 
2802  // get Group Info too!
2803  try
2804  {
2805  //test lookup of which groups a table is in
2806  {
2807  std::string documentNameToLoad = "XDAQApplicationTable";
2808  TableVersion documentVersionToLoad(
2809  (int)134); //1 is easy, 134 is hard on daq13 mongodb
2810 
2811  std::set<std::string> groupsContainingTable =
2812  theInterface_->findGroupsWithTable(documentNameToLoad,
2813  documentVersionToLoad);
2814  __GEN_COUT__ << "Groups containing " << documentNameToLoad << "-v"
2815  << documentVersionToLoad
2816  << " count: " << groupsContainingTable.size() << __E__;
2817  for(const auto& group : groupsContainingTable)
2818  {
2819  __GEN_COUT__ << "\t" << group << __E__;
2820  }
2821  }
2822 
2823  std::string debugGroupName = "Mu2eHWEmulatorContext";
2824 
2825  //final solution demo of getting latest group key:
2826  {
2827  TableGroupKey latestGroupKey =
2828  theInterface_->findLatestGroupKey(debugGroupName);
2829  __GEN_COUTV__(latestGroupKey);
2830 
2831  __GEN_COUTV__(runTimeSeconds());
2832  }
2833 
2834  //steps to do time comparison for getting last group key and table key:
2835 
2836  // build allGroupInfo_ for the ConfigurationManagerRW
2837 
2838  std::set<std::string /*name*/> tableGroups =
2839  theInterface_->getAllTableGroupNames();
2840  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
2841 
2842  __GEN_COUTV__(runTimeSeconds());
2843  // return;
2844 
2845  TableGroupKey key;
2846  std::string name;
2847  for(const auto& fullName : tableGroups)
2848  {
2849  TableGroupKey::getGroupNameAndKey(fullName, name, key);
2850  allGroupInfo_[name].keys_.emplace(key);
2851 
2852  if(name == debugGroupName)
2853  {
2854  __GEN_COUTV__(key);
2855  }
2856  }
2857  __GEN_COUTV__(runTimeSeconds());
2858 
2859  std::set<std::string /*name*/> tableNames = theInterface_->getAllTableNames();
2860  __GEN_COUT__ << "Number of Tables: " << tableNames.size() << __E__;
2861 
2862  __GEN_COUTV__(runTimeSeconds());
2863 
2864  for(const auto& fullName : tableNames)
2865  {
2866  if(fullName.find(debugGroupName) != std::string::npos)
2867  {
2868  __GEN_COUTV__(fullName);
2869  }
2870  }
2871  __GEN_COUTV__(runTimeSeconds());
2872 
2873  TableGroupKey latestGroupKey = theInterface_->findLatestGroupKey(debugGroupName);
2874  __GEN_COUTV__(latestGroupKey);
2875 
2876  __GEN_COUTV__(runTimeSeconds());
2877 
2878  TableBase localGroupMemberCacheSaver(
2879  true /*special table*/
2880  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),
2881  TableBase::GROUP_CACHE_PREPEND + debugGroupName);
2882  TableVersion lastestGroupCacheKey =
2883  theInterface_->findLatestVersion(&localGroupMemberCacheSaver);
2884  __GEN_COUTV__(lastestGroupCacheKey);
2885 
2886  __GEN_COUTV__(runTimeSeconds());
2887 
2888  //test a group save that already exists
2889  try
2890  {
2891  TableGroupKey groupKey(int(0));
2892  __GEN_COUT__ << "Testing group save of pre-existing " << debugGroupName << "("
2893  << groupKey << ")" << __E__;
2894  std::map<std::string, TableVersion> groupMembers;
2895  groupMembers["DesktopIconTable"] = TableVersion(123);
2896  theInterface_->saveTableGroup(
2897  groupMembers,
2898  TableGroupKey::getFullGroupString(debugGroupName, groupKey));
2899  }
2900  catch(...)
2901  {
2902  __GEN_COUT__ << "Exception during group save." << __E__;
2903  }
2904  __GEN_COUTV__(runTimeSeconds());
2905 
2906  //test a group save that does not already exists
2907  try
2908  {
2909  std::string debugGroupName = "testGroupSave";
2910  TableGroupKey groupKey(int(2));
2911  __GEN_COUT__ << "Testing group save of non-existing " << debugGroupName << "("
2912  << groupKey << ")" << __E__;
2913  std::map<std::string, TableVersion> groupMembers;
2914  groupMembers["DesktopIconTable"] = TableVersion(123);
2915  groupMembers["MessageFacilityTable"] = TableVersion(7);
2916  theInterface_->saveTableGroup(
2917  groupMembers,
2918  TableGroupKey::getFullGroupString(debugGroupName, groupKey));
2919  }
2920  catch(...)
2921  {
2922  __GEN_COUT__ << "Exception during new group save." << __E__;
2923  }
2924  __GEN_COUTV__(runTimeSeconds());
2925 
2926  //test a table save that already exists
2927  {
2928  std::string documentNameToLoad = "XDAQApplicationTable";
2929  TableVersion documentVersionToLoad(134);
2930 
2931  __GEN_COUT__ << "Testing table save of pre-existing " << documentNameToLoad
2932  << __E__;
2933 
2934  { //load to prove it exists
2935  TableBase localDocLoader(
2936  documentNameToLoad); //can not use special table when filling
2937  localDocLoader.changeVersionAndActivateView(
2938  localDocLoader.createTemporaryView(), documentVersionToLoad);
2939  theInterface_->fill(&localDocLoader, documentVersionToLoad);
2940  __SS__;
2941  localDocLoader.print(ss);
2942  __GEN_COUTV__(ss.str());
2943  }
2944  __GEN_COUTV__(runTimeSeconds());
2945 
2946  try
2947  { //attempt to save over existing version
2948  std::string documentNameToSave = documentNameToLoad;
2949  TableBase
2950  localDocSaver( //true /*special table*/, //special table only allows 1 view in cache and does not load schema (which is perfect for this check),
2951  documentNameToSave); //can not use special table when filling
2952  localDocSaver.changeVersionAndActivateView(
2953  localDocSaver.createTemporaryView(), documentVersionToLoad);
2954 
2955  std::string json = "{ }";
2956  localDocSaver.getViewP()->setCustomStorageData(json);
2957 
2958  __COUTT__ << "Saving JSON string: "
2959  << localDocSaver.getViewP()->getCustomStorageData() << __E__;
2960 
2961  __COUTT__ << "Saving JSON doc as "
2962  << localDocSaver.getView().getTableName() << "("
2963  << localDocSaver.getView().getVersion().toString() << ")"
2964  << __E__;
2965 
2966  // save to db, and do not allow overwrite
2967  theInterface_->saveActiveVersion(&localDocSaver, false /* overwrite */);
2968  }
2969  catch(...)
2970  {
2971  __GEN_COUT__ << "Exception during table save." << __E__;
2972  }
2973  __GEN_COUTV__(runTimeSeconds());
2974 
2975  { //load to prove it exists
2976  TableBase localDocLoader(
2977  documentNameToLoad); //can not use special table when filling
2978  localDocLoader.changeVersionAndActivateView(
2979  localDocLoader.createTemporaryView(), documentVersionToLoad);
2980  theInterface_->fill(&localDocLoader, documentVersionToLoad);
2981  __SS__;
2982  localDocLoader.print(ss);
2983  __GEN_COUTV__(ss.str());
2984  }
2985  __GEN_COUTV__(runTimeSeconds());
2986  }
2987  __GEN_COUTV__(runTimeSeconds());
2988 
2989  //test a table save that does not already exist
2990  {
2991  std::string documentNameToLoad = "MessageFacilityTable";
2992  TableVersion documentVersionToLoad(7);
2993  TableBase localDocLoader(
2994  documentNameToLoad); //can not use special table when filling
2995 
2996  __GEN_COUT__ << "Testing table save of non-existing " << documentNameToLoad
2997  << __E__;
2998 
2999  { //load to prove it exists
3000  localDocLoader.changeVersionAndActivateView(
3001  localDocLoader.createTemporaryView(), documentVersionToLoad);
3002  theInterface_->fill(&localDocLoader, documentVersionToLoad);
3003  __SS__;
3004  localDocLoader.print(ss);
3005  __GEN_COUTV__(ss.str());
3006  __GEN_COUTV__(runTimeSeconds());
3007  }
3008  __GEN_COUTV__(runTimeSeconds());
3009 
3010  try
3011  { //attempt to save new version
3012 
3013  // modify it
3015  theInterface_->findLatestVersion(&localDocLoader));
3016  localDocLoader.getViewP()->setVersion(newVersion);
3017 
3018  __GEN_COUTT__ << "Saving new table as "
3019  << localDocLoader.getView().getTableName() << "("
3020  << localDocLoader.getView().getVersion().toString() << ")"
3021  << __E__;
3022 
3023  localDocLoader.getViewP()->setValueAsString(
3024  "10.226.9.17", 0, 4); //modify value that is 10.226.9.16
3025 
3026  __SS__;
3027  localDocLoader.print(ss);
3028  __GEN_COUTV__(ss.str());
3029 
3030  // save to db, and do not allow overwrite
3031  theInterface_->saveActiveVersion(&localDocLoader, false /* overwrite */);
3032  }
3033  catch(...)
3034  {
3035  __GEN_COUT__ << "Exception during new table save." << __E__;
3036  }
3037  __GEN_COUTV__(runTimeSeconds());
3038  }
3039  __GEN_COUTV__(runTimeSeconds());
3040  return;
3041 
3042  // for each group get member map & comment, author, time, and type for latest key
3043  for(auto& groupInfo : allGroupInfo_)
3044  {
3045  try
3046  {
3047  groupInfo.second.latestKey_ = groupInfo.second.getLastKey();
3048  loadTableGroup(groupInfo.first /*groupName*/,
3049  groupInfo.second.latestKey_,
3050  false /*doActivate*/,
3051  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
3052  0 /*progressBar*/,
3053  0 /*accumulateErrors*/,
3054  &groupInfo.second.latestKeyGroupComment_,
3055  &groupInfo.second.latestKeyGroupAuthor_,
3056  &groupInfo.second.latestKeyGroupCreationTime_,
3057  true /*doNotLoadMember*/,
3058  &groupInfo.second.latestKeyGroupTypeString_);
3059  }
3060  catch(const std::runtime_error& e)
3061  {
3062  __GEN_COUT_WARN__
3063  << "Error occurred loading latest group info into cache for '"
3064  << groupInfo.first << "(" << groupInfo.second.latestKey_ << ")': \n"
3065  << e.what() << __E__;
3066 
3067  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
3068  groupInfo.second.latestKeyGroupComment_ =
3069  ConfigurationManager::UNKNOWN_INFO;
3070  groupInfo.second.latestKeyGroupAuthor_ =
3071  ConfigurationManager::UNKNOWN_INFO;
3072  groupInfo.second.latestKeyGroupCreationTime_ =
3073  ConfigurationManager::UNKNOWN_TIME;
3074  groupInfo.second.latestKeyGroupTypeString_ =
3075  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
3076  groupInfo.second.latestKeyMemberMap_ = {};
3077  }
3078  catch(...)
3079  {
3080  __GEN_COUT_WARN__
3081  << "Error occurred loading latest group info into cache for '"
3082  << groupInfo.first << "(" << groupInfo.second.latestKey_ << ")'..."
3083  << __E__;
3084 
3085  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
3086  groupInfo.second.latestKeyGroupComment_ =
3087  ConfigurationManager::UNKNOWN_INFO;
3088  groupInfo.second.latestKeyGroupAuthor_ =
3089  ConfigurationManager::UNKNOWN_INFO;
3090  groupInfo.second.latestKeyGroupCreationTime_ =
3091  ConfigurationManager::UNKNOWN_TIME;
3092  groupInfo.second.latestKeyGroupTypeString_ =
3093  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
3094  groupInfo.second.latestKeyMemberMap_ = {};
3095  }
3096  } // end group info loop
3097  __GEN_COUTV__(runTimeSeconds());
3098  } // end get group info
3099  catch(const std::runtime_error& e)
3100  {
3101  __SS__ << "A fatal error occurred reading the info for all table groups. Error: "
3102  << e.what() << __E__;
3103  __GEN_COUT_ERR__ << "\n" << ss.str();
3104  if(accumulatedWarnings)
3105  *accumulatedWarnings += ss.str();
3106  else
3107  throw;
3108  }
3109  catch(...)
3110  {
3111  __SS__ << "An unknown fatal error occurred reading the info for all table groups."
3112  << __E__;
3113  __GEN_COUT_ERR__ << "\n" << ss.str();
3114  if(accumulatedWarnings)
3115  *accumulatedWarnings += ss.str();
3116  else
3117  throw;
3118  } //end catch
3119 
3120  __GEN_COUT__ << "testXDAQContext() end runTimeSeconds()=" << runTimeSeconds()
3121  << __E__;
3122  return;
3123 
3124  try
3125  {
3126  __GEN_COUT__ << "Loading table..." << __E__;
3127  loadTableGroup("FETest", TableGroupKey(2)); // Context_1
3128  ConfigurationTree t = getNode("/FETable/DEFAULT/FrontEndType");
3129 
3130  std::string v;
3131 
3132  __GEN_COUT__ << __E__;
3133  t.getValue(v);
3134  __GEN_COUT__ << "Value: " << v << __E__;
3135  __GEN_COUT__ << "Value index: " << t.getValue<int>() << __E__;
3136 
3137  return;
3138  }
3139  catch(...)
3140  {
3141  __GEN_COUT__ << "Failed to load table..." << __E__;
3142  }
3143 } //end testXDAQContext()
TableVersion saveNewVersion(TableBase *table, TableVersion temporaryVersion, TableVersion newVersion=TableVersion())
TableVersion saveNewTable(const std::string &tableName, TableVersion temporaryVersion=TableVersion(), bool makeTemporary=false)
modifiers of generic TableBase
TableGroupKey findTableGroup(const std::string &groupName, const std::map< std::string, TableVersion > &groupMembers, const std::map< std::string, std::string > &groupAliases=std::map< std::string, std::string >())
void testXDAQContext(void)
for debugging
TableVersion saveNewBackbone(TableVersion temporaryVersion=TableVersion())
const GroupInfo & getGroupInfo(const std::string &groupName, bool attemptToReloadKeys=false)
public group cache handling
const std::map< std::string, TableInfo > & getAllTableInfo(bool refresh=false, std::string *accumulatedWarnings=0, const std::string &errorFilterName="", bool getGroupKeys=false, bool getGroupInfo=false, bool initializeActiveGroups=false)
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
TableVersion copyViewToCurrentColumns(const std::string &tableName, TableVersion sourceVersion)
copyViewToCurrentColumns
TableGroupKey saveNewTableGroup(const std::string &groupName, std::map< std::string, TableVersion > &groupMembers, const std::string &groupComment=TableViewColumnInfo::DATATYPE_COMMENT_DEFAULT, std::map< std::string, std::string > *groupAliases=0)
modifiers of a table group based on alias, e.g. "Physics"
void activateTableGroup(const std::string &tableGroupName, TableGroupKey tableGroupKey, std::string *accumulatedTreeErrors=0, std::string *groupTypeString=0)
modifiers of table groups
TableBase * getMetadataTable(TableVersion fillVersion=TableVersion())
created for use in otsdaq_flatten_system_aliases and otsdaq_export_system_aliases,...
TableVersion saveModifiedVersion(const std::string &tableName, TableVersion originalVersion, bool makeTemporary, TableBase *config, TableVersion temporaryModifiedVersion, bool ignoreDuplicates=false, bool lookForEquivalent=false, bool *foundEquivalent=nullptr)
TableVersion createTemporaryBackboneView(TableVersion sourceViewVersion=TableVersion())
-1, from MockUp, else from valid backbone view version
void clearCachedVersions(const std::string &tableName)
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
void eraseTemporaryVersion(const std::string &tableName, TableVersion targetVersion=TableVersion())
static void compareTableGroupThread(ConfigurationManagerRW *cfgMgr, std::string groupName, ots::TableGroupKey groupKeyToCompare, const std::map< std::string, TableVersion > &groupMemberMap, const std::map< std::string, std::string > &memberTableAliases, std::atomic< bool > *theFoundIdentical, ots::TableGroupKey *theIdenticalKey, std::mutex *theThreadMutex, std::shared_ptr< std::atomic< bool >> theThreadDone)
static void loadTableGroupThread(ConfigurationManagerRW *cfgMgr, std::string groupName, ots::TableGroupKey groupKey, std::shared_ptr< ots::GroupInfo > theGroupInfo, std::shared_ptr< std::atomic< bool >> theThreadDone)
loadTableGroupThread()
static void loadTableInfoThread(ConfigurationManagerRW *cfgMgr, std::string tableName, TableBase *existingTable, std::shared_ptr< ots::TableInfo > tableInfo, std::shared_ptr< std::atomic< bool >> threadDone)
loadTableInfoThread()
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
static const unsigned int PROCESSOR_COUNT
Static members.
static const std::string & convertGroupTypeToName(const ConfigurationManager::GroupType &groupTypeId)
void restoreActiveTableGroups(bool throwErrors=false, const std::string &pathToActiveGroupsFile="", ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, std::string *accumulatedWarnings=0)
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
void loadTableGroup(const std::string &tableGroupName, const TableGroupKey &tableGroupKey, bool doActivate=false, std::map< std::string, TableVersion > *groupMembers=0, ProgressBar *progressBar=0, std::string *accumulateWarnings=0, std::string *groupComment=0, std::string *groupAuthor=0, std::string *groupCreateTime=0, bool doNotLoadMember=false, std::string *groupTypeString=0, std::map< std::string, std::string > *groupAliases=0, ConfigurationManager::LoadGroupType groupTypeToLoad=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false, std::map< std::string, TableVersion > mergeInTables={}, std::map< std::string, TableVersion > overrideTables={})
void init(std::string *accumulatedErrors=0, bool initForWriteAccess=false, std::string *accumulatedWarnings=0)
static const std::string & getTypeNameOfGroup(const std::map< std::string, TableVersion > &memberMap)
void destroyTableGroup(const std::string &theGroup="", bool onlyDeactivate=false)
static const std::string ACTIVE_GROUPS_FILENAME
added env check for otsdaq_flatten_active_to_version to function
const TableBase * getTableByName(const std::string &configurationName) const
void getValue(T &value) const
std::vector< std::pair< std::string, ConfigurationTree > > getChildren(std::map< std::string, std::string > filterMap=std::map< std::string, std::string >(), bool byPriority=false, bool onlyStatusTrue=false) const
TableVersion createTemporaryView(TableVersion sourceViewVersion=TableVersion(), TableVersion destTemporaryViewVersion=TableVersion::getNextTemporaryVersion())
source of -1, from MockUp, else from valid view version
Definition: TableBase.cc:1769
void trimTemporary(TableVersion targetVersion=TableVersion())
Definition: TableBase.cc:362
unsigned int getNumberOfStoredViews(void) const
Definition: TableBase.cc:856
TableVersion checkForDuplicate(TableVersion needleVersion, TableVersion ignoreVersion=TableVersion()) const
Definition: TableBase.cc:404
TableView * getTemporaryView(TableVersion temporaryVersion)
Definition: TableBase.cc:1880
const unsigned int MAX_VIEWS_IN_CACHE
Definition: TableBase.h:30
TableVersion getNextVersion(void) const
Definition: TableBase.cc:1856
TableVersion copyView(const TableView &sourceView, TableVersion destinationVersion, const std::string &author, bool looseColumnMatching=false)
Definition: TableBase.cc:1710
void print(std::ostream &out=std::cout) const
always prints active view
Definition: TableBase.cc:277
TableVersion getNextTemporaryVersion(void) const
Definition: TableBase.cc:1833
void trimCache(unsigned int trimSize=-1)
Definition: TableBase.cc:322
std::string toString(void) const
toString
static TableGroupKey getNextKey(const TableGroupKey &key=TableGroupKey())
static void getGroupNameAndKey(const std::string &fullGroupString, std::string &groupName, TableGroupKey &key)
requires fullGroupString created as name + "_v" + key + ""
bool isInvalid(void) const
isInvalid
static std::string getFullGroupString(const std::string &groupName, const TableGroupKey &key, const std::string &preKey="_v", const std::string &postKey="")
std::string toString(void) const
toString
Definition: TableVersion.cc:33
bool isInvalid(void) const
isInvalid
static TableVersion getNextVersion(const TableVersion &version=TableVersion())
bool isScratchVersion(void) const
bool isTemporaryVersion(void) const
static TableVersion getNextTemporaryVersion(const TableVersion &version=TableVersion())
void setValueAsString(const std::string &value, unsigned int row, unsigned int col)
Definition: TableView.cc:1081
void setVersion(const T &version)
< in included .icc source
const std::string & getCustomStorageData(void) const
Getters.
Definition: TableView.h:71
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1962
void setCustomStorageData(const std::string &storageData)
Definition: TableView.h:168
defines used also by OtsConfigurationWizardSupervisor
TableEditStruct & getTableEditStruct(const std::string &tableName, bool markModified=false)
Note: if markModified, and table not found in group, this function will try to add it to group.
static std::string setToString(const std::set< T > &setToReturn, const std::string &delimeter=", ")
setToString ~
static std::string mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static std::string stackTrace(void)