otsdaq  3.04.02
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  __GEN_COUT_TYPE__(TLVL_DEBUG + 3)
499  << __COUT_HDR__ << "Copying table info for "
500  << tableInfo->tablePtr_->getTableName() << __E__;
501  nameToTableMap_[tableInfo->tablePtr_->getTableName()] =
502  tableInfo->tablePtr_;
503  allTableInfo_[tableInfo->tablePtr_->getTableName()].tablePtr_ =
504  tableInfo->tablePtr_;
505  allTableInfo_[tableInfo->tablePtr_->getTableName()].versions_ =
506  tableInfo->versions_;
507  } //end copy group info loop
508  }
509  __GEN_COUT__ << "Extracting list of tables complete." << __E__;
510  } //end Extracting list of tables
511 
512  // call init to load active versions by default, activate with warnings allowed (assuming development going on)
513  if(initializeActiveGroups)
514  {
515  __GEN_COUT__ << "Now initializing..." << __E__;
516  // if there is a filter name, do not include init warnings (it just scares people in the table editor)
517  std::string tmpAccumulateWarnings;
518  init(0 /*accumulatedErrors*/,
519  false /*initForWriteAccess*/,
520  accumulatedWarnings ? &tmpAccumulateWarnings : nullptr);
521 
522  if(accumulatedWarnings && errorFilterName == "")
523  *accumulatedWarnings += tmpAccumulateWarnings;
524  }
525  __GEN_COUT__ << "======================================================== "
526  "getAllTableInfo end runTimeSeconds()="
527  << runTimeSeconds() << __E__;
528 
529  // get Group Info too!
530  if(getGroupKeys || getGroupInfo)
531  {
532  allGroupInfo_.clear();
533  try
534  {
535  // build allGroupInfo_ for the ConfigurationManagerRW
536 
537  std::set<std::string /*name*/> tableGroups =
538  theInterface_->getAllTableGroupNames();
539  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
540 
541  __GEN_COUTT__ << "Group Info start runTimeSeconds()=" << runTimeSeconds()
542  << __E__;
543 
544  TableGroupKey key;
545  std::string name;
546  for(const auto& fullName : tableGroups)
547  {
548  TableGroupKey::getGroupNameAndKey(fullName, name, key);
549  allGroupInfo_[name].keys_.emplace(key); //store in cache
550  }
551 
552  __GEN_COUTT__ << "Group Keys end runTimeSeconds()=" << runTimeSeconds()
553  << __E__;
554 
555  // for each group get member map & comment, author, time, and type for latest key
556  if(getGroupInfo)
557  {
558  const int numOfThreads = PROCESSOR_COUNT / 2;
559  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> "
560  << numOfThreads << " threads." << __E__;
561  if(numOfThreads < 2) // no multi-threading
562  for(auto& groupInfo : allGroupInfo_)
563  {
564  try
565  {
566  groupInfo.second.latestKey_ = groupInfo.second.getLastKey();
568  groupInfo.first /*groupName*/,
569  groupInfo.second.latestKey_,
570  false /*doActivate*/,
571  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
572  0 /*progressBar*/,
573  0 /*accumulateErrors*/,
574  &groupInfo.second.latestKeyGroupComment_,
575  &groupInfo.second.latestKeyGroupAuthor_,
576  &groupInfo.second.latestKeyGroupCreationTime_,
577  true /*doNotLoadMember*/,
578  &groupInfo.second.latestKeyGroupTypeString_);
579  }
580  catch(...)
581  {
582  __GEN_COUT_WARN__ << "Error occurred loading latest group "
583  "info into cache for '"
584  << groupInfo.first << "("
585  << groupInfo.second.latestKey_ << ")'..."
586  << __E__;
587  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
588  groupInfo.second.latestKeyGroupComment_ =
589  ConfigurationManager::UNKNOWN_INFO;
590  groupInfo.second.latestKeyGroupAuthor_ =
591  ConfigurationManager::UNKNOWN_INFO;
592  groupInfo.second.latestKeyGroupCreationTime_ =
593  ConfigurationManager::UNKNOWN_TIME;
594  groupInfo.second.latestKeyGroupTypeString_ =
595  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
596  groupInfo.second.latestKeyMemberMap_ = {};
597  }
598  } // end group info loop
599  else //multi-threading
600  {
601  int threadsLaunched = 0;
602  int foundThreadIndex = 0;
603 
604  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
605  for(int i = 0; i < numOfThreads; ++i)
606  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
607 
608  std::vector<std::shared_ptr<ots::GroupInfo>> sharedGroupInfoPtrs;
609 
610  for(auto& groupInfo : allGroupInfo_)
611  {
612  //make temporary group info for thread
613  sharedGroupInfoPtrs.push_back(std::make_shared<ots::GroupInfo>());
614 
615  if(threadsLaunched >= numOfThreads)
616  {
617  //find availableThreadIndex
618  foundThreadIndex = -1;
619  while(foundThreadIndex == -1)
620  {
621  for(int i = 0; i < numOfThreads; ++i)
622  if(*(threadDone[i]))
623  {
624  foundThreadIndex = i;
625  break;
626  }
627  if(foundThreadIndex == -1)
628  {
629  __GEN_COUTT__ << "Waiting for available thread..."
630  << __E__;
631  usleep(10000);
632  }
633  } //end thread search loop
634  threadsLaunched = numOfThreads - 1;
635  }
636  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex
637  << " for " << groupInfo.first << "("
638  << groupInfo.second.getLastKey() << ")" << __E__;
639 
640  *(threadDone[foundThreadIndex]) = false;
641 
642  std::thread(
643  [](ConfigurationManagerRW* theCfgMgr,
644  std::string theGroupName,
645  ots::TableGroupKey theGroupKey,
646  std::shared_ptr<ots::GroupInfo> theGroupInfo,
647  std::shared_ptr<std::atomic<bool>> theThreadDone) {
649  theCfgMgr,
650  theGroupName,
651  theGroupKey,
652  theGroupInfo,
653  theThreadDone);
654  },
655  this,
656  groupInfo.first,
657  groupInfo.second.getLastKey(),
658  sharedGroupInfoPtrs.back(),
659  threadDone[foundThreadIndex])
660  .detach();
661 
662  ++threadsLaunched;
663  ++foundThreadIndex;
664  } //end groupInfo thread loop
665 
666  //check for all threads done
667  do
668  {
669  foundThreadIndex = -1;
670  for(int i = 0; i < numOfThreads; ++i)
671  if(!*(threadDone[i]))
672  {
673  foundThreadIndex = i;
674  break;
675  }
676  if(foundThreadIndex != -1)
677  {
678  __GEN_COUTT__ << "Waiting for thread to finish... "
679  << foundThreadIndex << __E__;
680  usleep(10000);
681  }
682  } while(foundThreadIndex != -1); //end thread done search loop
683 
684  //threads done now, so copy group info
685  size_t i = 0;
686  for(auto& groupInfo : allGroupInfo_)
687  {
688  groupInfo.second.latestKey_ = sharedGroupInfoPtrs[i]->latestKey_;
689  groupInfo.second.latestKeyGroupComment_ =
690  sharedGroupInfoPtrs[i]->latestKeyGroupComment_;
691  groupInfo.second.latestKeyGroupAuthor_ =
692  sharedGroupInfoPtrs[i]->latestKeyGroupAuthor_;
693  groupInfo.second.latestKeyGroupCreationTime_ =
694  sharedGroupInfoPtrs[i]->latestKeyGroupCreationTime_;
695  groupInfo.second.latestKeyGroupTypeString_ =
696  sharedGroupInfoPtrs[i]->latestKeyGroupTypeString_;
697  groupInfo.second.latestKeyMemberMap_ =
698  sharedGroupInfoPtrs[i]->latestKeyMemberMap_;
699  ++i;
700  } //end copy group info loop
701 
702  } //end multi-thread handling
703  }
704  } // end get group info
705  catch(const std::runtime_error& e)
706  {
707  __SS__
708  << "A fatal error occurred reading the info for all table groups. Error: "
709  << e.what() << __E__;
710  __GEN_COUT_ERR__ << "Error at time: " << time(0) << "\n" << ss.str();
711  if(accumulatedWarnings)
712  *accumulatedWarnings += ss.str();
713  else
714  throw;
715  }
716  catch(...)
717  {
718  __SS__ << "An unknown fatal error occurred reading the info for all table "
719  "groups."
720  << __E__;
721  try
722  {
723  throw;
724  } //one more try to printout extra info
725  catch(const std::exception& e)
726  {
727  ss << "Exception message: " << e.what();
728  }
729  catch(...)
730  {
731  }
732  __GEN_COUT_ERR__ << "\n" << ss.str();
733  if(accumulatedWarnings)
734  *accumulatedWarnings += ss.str();
735  else
736  throw;
737  }
738  __GEN_COUTT__ << "Group Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
739  } //end getGroupInfo
740  else
741  __GEN_COUTT__ << "Table Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
742 
743  return allTableInfo_;
744 } // end getAllTableInfo()
745 
746 //==============================================================================
749  ConfigurationManagerRW* cfgMgr,
750  std::string tableName,
751  TableBase* existingTable,
752  std::shared_ptr<ots::TableInfo> tableInfo,
753  std::shared_ptr<std::atomic<bool>> threadDone)
754 try
755 {
756  __COUTT__ << "Thread started... table " << tableName << __E__;
757 
758  // 0 will force the creation of new instance (and reload from Info)
759  tableInfo->tablePtr_ = 0;
760 
761  try // only add valid table instances to maps
762  {
763  cfgMgr->theInterface_->get(tableInfo->tablePtr_,
764  tableName,
765  0,
766  0,
767  true); // dont fill
768  }
769  catch(cet::exception const&)
770  {
771  if(tableInfo->tablePtr_)
772  delete tableInfo->tablePtr_;
773  tableInfo->tablePtr_ = 0;
774 
775  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
776  *(threadDone) = true;
777  return;
778  }
779  catch(std::runtime_error& e)
780  {
781  if(tableInfo->tablePtr_)
782  delete tableInfo->tablePtr_;
783  tableInfo->tablePtr_ = 0;
784 
785  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
786  __COUTT__ << "Error: " << e.what() << __E__;
787 
788  // for a runtime_error, it is likely that columns are the problem
789  // the Table Editor needs to still fix these.. so attempt to
790  // proceed.
791  if(tableInfo->accumulatedWarnings_ == "ALLOW")
792  {
793  tableInfo->accumulatedWarnings_ = "";
794  if(1) //errorFilterName == "" || errorFilterName == tableName)
795  {
796  tableInfo->accumulatedWarnings_ += std::string("\nIn table '") +
797  tableName + "'..." +
798  e.what(); // global accumulate
799 
800  __SS__ << "Attempting to allow illegal columns!" << __E__;
801  tableInfo->accumulatedWarnings_ += ss.str();
802  }
803 
804  // attempt to recover and build a mock-up
805  __COUT__ << "Attempting to allow illegal columns!" << __E__;
806 
807  std::string returnedAccumulatedErrors;
808  try
809  {
810  tableInfo->tablePtr_ =
811  new TableBase(tableName, &returnedAccumulatedErrors);
812  }
813  catch(...)
814  {
815  __COUT__ << "Skipping! Allowing illegal columns didn't work either... "
816  << tableName << "\n";
817  *(threadDone) = true;
818  return;
819  }
820  __COUT_WARN__ << "Error (but allowed): " << returnedAccumulatedErrors
821  << __E__;
822 
823  if(1) //errorFilterName == "" || errorFilterName == entry->d_name)
824  tableInfo->accumulatedWarnings_ +=
825  std::string("\nIn table '") + tableName + "'..." +
826  returnedAccumulatedErrors; // global accumulate
827  }
828  else
829  {
830  tableInfo->accumulatedWarnings_ = "";
831  *(threadDone) = true;
832  return;
833  }
834  }
835 
836  if(existingTable) // handle if instance existed
837  {
838  __COUTT__ << "Copying temporary version from existing table object for "
839  << tableName << __E__;
840  // copy the existing temporary versions! (or else all is lost)
841  std::set<TableVersion> versions = existingTable->getStoredVersions();
842  for(auto& version : versions)
843  if(version.isTemporaryVersion())
844  {
845  try // do NOT let TableView::init() throw here
846  {
847  existingTable->setActiveView(version);
848  tableInfo->tablePtr_->copyView( // this calls TableView::init()
849  existingTable->getView(),
850  version,
851  cfgMgr->username_);
852  }
853  catch(...) // do NOT let invalid temporary version throw at this
854  // point
855  {
856  } // just trust configurationBase throws out the failed version
857  }
858 
859  delete existingTable;
860  existingTable = 0;
861  }
862 
863  tableInfo->versions_ = cfgMgr->theInterface_->getVersions(tableInfo->tablePtr_);
864 
865  // also add any existing temporary versions to all table info
866  // because the interface wont find those versions
867  std::set<TableVersion> versions = tableInfo->tablePtr_->getStoredVersions();
868  for(auto& version : versions)
869  if(version.isTemporaryVersion())
870  {
871  tableInfo->versions_.emplace(version);
872  }
873 
874  __COUTT__ << "Thread done... table " << tableName << __E__;
875  *(threadDone) = true;
876 } // end loadTableInfoThread
877 catch(...)
878 {
879  __COUT_ERR__ << "Error occurred loading latest table info into cache for '"
880  << tableName << "'..." << __E__;
881  *(threadDone) = true;
882 } // end loadTableInfoThread catch
883 
884 //==============================================================================
888  const std::string& groupName,
889  const TableGroupKey& groupKey,
890  bool doActivate /*=false*/,
891  std::map<std::string /*table name*/, TableVersion>*
892  groupMembers /*=0 , note: db time intensive! */,
893  ProgressBar* progressBar /*=0*/,
894  std::string* accumulatedWarnings /*=0*/,
895  std::string* groupComment /*=0 , note: in metadata */,
896  std::string* groupAuthor /*=0 , note: in metadata */,
897  std::string* groupCreateTime /*=0 , note: in metadata */,
898  bool doNotLoadMembers /*=false*/,
899  std::string* groupTypeString /*=0 , note: db time intensive! */,
900  std::map<std::string /*name*/, std::string /*alias*/>*
901  groupAliases /*=0 , note: in metadata */,
902  ConfigurationManager::LoadGroupType
903  groupTypeToLoad /*=ConfigurationManager::LoadGroupType::ALL_TYPES*/,
904  bool ignoreVersionTracking /*=false*/)
905 {
907  groupKey,
908  doActivate,
909  groupMembers,
910  progressBar,
911  accumulatedWarnings,
912  groupComment,
913  groupAuthor,
914  groupCreateTime,
915  doNotLoadMembers,
916  groupTypeString,
917  groupAliases,
918  groupTypeToLoad,
919  ignoreVersionTracking);
920 
921  if(!groupMembers || !groupMembers->size() || !groupComment || groupKey.isInvalid() ||
922  !groupAuthor || !groupCreateTime)
923  return;
924 
925  //treat successfull load as latest group key
926  auto groupInfo = allGroupInfo_.find(groupName);
927  if(groupInfo == allGroupInfo_.end())
928  return; //ignore if no group info cache
929 
930  groupInfo->second.latestKey_ = groupKey;
931  groupInfo->second.latestKeyGroupComment_ = *groupComment;
932  groupInfo->second.latestKeyGroupAuthor_ = *groupAuthor;
933  groupInfo->second.latestKeyGroupCreationTime_ = *groupCreateTime;
934  if(groupTypeString) //assume unlikely to change types
935  groupInfo->second.latestKeyGroupTypeString_ = *groupTypeString;
936  groupInfo->second.latestKeyMemberMap_ = *groupMembers;
937 
938 } //end loadTableGroup() RW version
939 
940 //==============================================================================
943  ConfigurationManagerRW* cfgMgr,
944  std::string groupName,
945  ots::TableGroupKey groupKey,
946  std::shared_ptr<ots::GroupInfo> groupInfo,
947  std::shared_ptr<std::atomic<bool>> threadDone)
948 try
949 {
950  __COUTT__ << "Thread started... " << groupName << "(" << groupKey << ")" << __E__;
951 
952  groupInfo->latestKey_ = groupKey;
953  cfgMgr->loadTableGroup(groupName,
954  groupKey,
955  false /*doActivate*/,
956  &(groupInfo->latestKeyMemberMap_) /*groupMembers*/,
957  0 /*progressBar*/,
958  0 /*accumulateErrors*/,
959  &(groupInfo->latestKeyGroupComment_),
960  &(groupInfo->latestKeyGroupAuthor_),
961  &(groupInfo->latestKeyGroupCreationTime_),
962  true /*doNotLoadMember*/,
963  &(groupInfo->latestKeyGroupTypeString_));
964 
965  *(threadDone) = true;
966 } // end loadTableGroupThread
967 catch(...)
968 {
969  __COUT_WARN__ << "Error occurred loading latest group info into cache for '"
970  << groupName << "(" << groupInfo->latestKey_ << ")'..." << __E__;
971  groupInfo->latestKey_ = TableGroupKey::INVALID;
972  groupInfo->latestKeyGroupComment_ = ConfigurationManager::UNKNOWN_INFO;
973  groupInfo->latestKeyGroupAuthor_ = ConfigurationManager::UNKNOWN_INFO;
974  groupInfo->latestKeyGroupCreationTime_ = ConfigurationManager::UNKNOWN_TIME;
975  groupInfo->latestKeyGroupTypeString_ = ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
976  groupInfo->latestKeyMemberMap_ = {};
977  *(threadDone) = true;
978 } // end loadTableGroupThread catch
979 
980 //==============================================================================
985  ConfigurationManagerRW* cfgMgr,
986  std::string groupName,
987  ots::TableGroupKey groupKeyToCompare,
988  const std::map<std::string, TableVersion>& groupMemberMap,
989  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases,
990  std::atomic<bool>* foundIdentical,
991  ots::TableGroupKey* identicalKey,
992  std::mutex* threadMutex,
993  std::shared_ptr<std::atomic<bool>> threadDone)
994 try
995 {
996  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
997  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
998  std::map<std::string /*name*/, std::string /*alias*/>*
999  compareToMemberTableAliasesPtr = nullptr;
1000  if(memberTableAliases
1001  .size()) //only give pointer if necessary, without will load group faster
1002  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
1003 
1004  cfgMgr->loadTableGroup(groupName,
1005  groupKeyToCompare,
1006  false /*doActivate*/,
1007  &compareToMemberMap /*memberMap*/,
1008  0, /*progressBar*/
1009  0, /*accumulatedWarnings*/
1010  0, /*groupComment*/
1011  0,
1012  0, /*null pointers*/
1013  true /*doNotLoadMember*/,
1014  0 /*groupTypeString*/,
1015  compareToMemberTableAliasesPtr);
1016 
1017  bool debug = false;
1018  if(TTEST(9)) // = DEBUG+9
1019  {
1020  debug = true;
1021  for(auto& memberPair : groupMemberMap)
1022  __COUTS__(9) << "member " << memberPair.first << " (" << memberPair.second
1023  << ")" << __E__;
1024  for(auto& memberPair : compareToMemberMap)
1025  __COUTS__(9) << "compare " << groupName << " (" << groupKeyToCompare
1026  << ") member:" << memberPair.first << " (" << memberPair.second
1027  << ")" << __E__;
1028  }
1029 
1030  bool isDifferent = false;
1031  for(auto& memberPair : groupMemberMap)
1032  {
1033  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
1034  {
1035  // handle this table as alias, not version
1036  if(compareToMemberTableAliases.find(memberPair.first) ==
1037  compareToMemberTableAliases.end() || // alias is missing
1038  memberTableAliases.at(memberPair.first) !=
1039  compareToMemberTableAliases.at(memberPair.first))
1040  { // then different
1041  isDifferent = true;
1042  if(debug)
1043  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1044  << ") on alias " << memberPair.first << __E__;
1045  break;
1046  }
1047  else
1048  continue;
1049  } // else check if compareTo group is using an alias for table
1050  else if(compareToMemberTableAliases.find(memberPair.first) !=
1051  compareToMemberTableAliases.end())
1052  {
1053  // then different
1054  isDifferent = true;
1055  if(debug)
1056  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1057  << ") on reverse alias " << memberPair.first << __E__;
1058  break;
1059 
1060  } // else handle as table version comparison
1061  else if(compareToMemberMap.find(memberPair.first) ==
1062  compareToMemberMap.end() || // name is missing
1063  memberPair.second !=
1064  compareToMemberMap.at(memberPair.first)) // or version mismatch
1065  {
1066  // then different
1067  isDifferent = true;
1068  if(debug)
1069  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare
1070  << ") on mismatch " << memberPair.first << __E__;
1071  break;
1072  }
1073  }
1074 
1075  // check member size for exact match
1076  if(!isDifferent &&
1077  groupMemberMap.size() !=
1078  compareToMemberMap
1079  .size()) // different size, so not same (groupMemberMap is a subset of memberPairs)
1080  {
1081  isDifferent = true;
1082 
1083  if(debug)
1084  __COUTT__ << "diff " << groupName << " (" << groupKeyToCompare << ") on size "
1085  << __E__;
1086  }
1087 
1088  if(!isDifferent) //found an exact match!
1089  {
1090  *foundIdentical = true;
1091  __COUT__ << "=====> Found exact match with key: " << groupKeyToCompare << __E__;
1092 
1093  std::lock_guard<std::mutex> lock(*threadMutex);
1094  *identicalKey = groupKeyToCompare;
1095  }
1096 
1097  *(threadDone) = true;
1098 } // end compareTableGroupThread
1099 catch(...)
1100 {
1101  __COUT_WARN__ << "Error occurred comparing group '" << groupName << "("
1102  << groupKeyToCompare << ")'..." << __E__;
1103 
1104  *(threadDone) = true;
1105 } // end compareTableGroupThread catch
1106 
1107 //==============================================================================
1111 std::map<std::string /*table name*/,
1112  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1114 {
1115  std::map<std::string /*table name*/,
1116  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1118 
1119  // always have scratch alias for each table that has a scratch version
1120  // overwrite map entry if necessary
1121  if(!ConfigurationInterface::isVersionTrackingEnabled())
1122  for(const auto& tableInfo : allTableInfo_)
1123  for(const auto& version : tableInfo.second.versions_)
1124  if(version.isScratchVersion())
1125  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
1126  TableVersion(TableVersion::SCRATCH);
1127 
1128  return retMap;
1129 } // end getVersionAliases()
1130 
1131 //==============================================================================
1135 void ConfigurationManagerRW::activateTableGroup(const std::string& tableGroupName,
1136  TableGroupKey tableGroupKey,
1137  std::string* accumulatedTreeErrors,
1138  std::string* groupTypeString)
1139 {
1140  try
1141  {
1142  loadTableGroup(tableGroupName,
1143  tableGroupKey,
1144  true, // loads and activates
1145  0, // no members needed
1146  0, // no progress bar
1147  accumulatedTreeErrors, // accumulate warnings or not
1148  0 /* groupComment */,
1149  0 /* groupAuthor */,
1150  0 /* groupCreateTime */,
1151  false /* doNotLoadMember */,
1152  groupTypeString);
1153  }
1154  catch(...)
1155  {
1156  __GEN_COUT_ERR__ << "There were errors, so de-activating group: "
1157  << tableGroupName << " (" << tableGroupKey << ")" << __E__;
1158  try // just in case any lingering pieces, let's deactivate
1159  {
1160  destroyTableGroup(tableGroupName, true);
1161  }
1162  catch(...)
1163  {
1164  }
1165  throw; // re-throw original exception
1166  }
1167 
1168  __GEN_COUT_INFO__ << "Updating persistent active groups to "
1169  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
1170 
1171  __COUT_INFO__ << "Active Context table group: " << theContextTableGroup_ << "("
1172  << (theContextTableGroupKey_
1173  ? theContextTableGroupKey_->toString().c_str()
1174  : "-1")
1175  << ")" << __E__;
1176  __COUT_INFO__ << "Active Backbone table group: " << theBackboneTableGroup_ << "("
1177  << (theBackboneTableGroupKey_
1178  ? theBackboneTableGroupKey_->toString().c_str()
1179  : "-1")
1180  << ")" << __E__;
1181  __COUT_INFO__ << "Active Iterate table group: " << theIterateTableGroup_ << "("
1182  << (theIterateTableGroupKey_
1183  ? theIterateTableGroupKey_->toString().c_str()
1184  : "-1")
1185  << ")" << __E__;
1186  __COUT_INFO__ << "Active Configuration table group: " << theConfigurationTableGroup_
1187  << "("
1188  << (theConfigurationTableGroupKey_
1189  ? theConfigurationTableGroupKey_->toString().c_str()
1190  : "-1")
1191  << ")" << __E__;
1192 
1194  FILE* fp = fopen(fn.c_str(), "w");
1195  if(!fp)
1196  {
1197  __SS__ << "Fatal Error! Unable to open the file "
1199  << " for editing! Is there a permissions problem?" << __E__;
1200  __GEN_COUT_ERR__ << ss.str();
1201  __SS_THROW__;
1202  return;
1203  }
1204  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
1205  fprintf(
1206  fp,
1207  "%s\n",
1208  theContextTableGroupKey_ ? theContextTableGroupKey_->toString().c_str() : "-1");
1209  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
1210  fprintf(
1211  fp,
1212  "%s\n",
1213  theBackboneTableGroupKey_ ? theBackboneTableGroupKey_->toString().c_str() : "-1");
1214  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
1215  fprintf(
1216  fp,
1217  "%s\n",
1218  theIterateTableGroupKey_ ? theIterateTableGroupKey_->toString().c_str() : "-1");
1219  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
1220  fprintf(fp,
1221  "%s\n",
1222  theConfigurationTableGroupKey_
1223  ? theConfigurationTableGroupKey_->toString().c_str()
1224  : "-1");
1225  fclose(fp);
1226 
1227  // save last activated group
1228  {
1229  std::pair<std::string /*group name*/, TableGroupKey> activatedGroup(
1230  std::string(tableGroupName), tableGroupKey);
1231  if(theConfigurationTableGroupKey_ &&
1232  theConfigurationTableGroup_ == tableGroupName &&
1233  *theConfigurationTableGroupKey_ == tableGroupKey)
1234  {
1235  ConfigurationManager::saveGroupNameAndKey(
1236  activatedGroup,
1237  ConfigurationManager::LAST_ACTIVATED_CONFIG_GROUP_FILE,
1238  false /* appendMode */,
1239  username_);
1240  ConfigurationManager::saveGroupNameAndKey(
1241  activatedGroup,
1242  ConfigurationManager::ACTIVATED_CONFIGS_FILE,
1243  true /* appendMode */,
1244  username_);
1245  }
1246  else if(theContextTableGroupKey_ && theContextTableGroup_ == tableGroupName &&
1247  *theContextTableGroupKey_ == tableGroupKey)
1248  {
1249  ConfigurationManager::saveGroupNameAndKey(
1250  activatedGroup,
1251  ConfigurationManager::LAST_ACTIVATED_CONTEXT_GROUP_FILE,
1252  false /* appendMode */,
1253  username_);
1254  ConfigurationManager::saveGroupNameAndKey(
1255  activatedGroup,
1256  ConfigurationManager::ACTIVATED_CONTEXTS_FILE,
1257  true /* appendMode */,
1258  username_);
1259  }
1260  else if(theBackboneTableGroupKey_ && theBackboneTableGroup_ == tableGroupName &&
1261  *theBackboneTableGroupKey_ == tableGroupKey)
1262  {
1263  ConfigurationManager::saveGroupNameAndKey(
1264  activatedGroup,
1265  ConfigurationManager::LAST_ACTIVATED_BACKBONE_GROUP_FILE,
1266  false /* appendMode */,
1267  username_);
1268  ConfigurationManager::saveGroupNameAndKey(
1269  activatedGroup,
1270  ConfigurationManager::ACTIVATED_BACKBONES_FILE,
1271  true /* appendMode */,
1272  username_);
1273  }
1274  else if(theIterateTableGroupKey_ && theIterateTableGroup_ == tableGroupName &&
1275  *theIterateTableGroupKey_ == tableGroupKey)
1276  {
1277  ConfigurationManager::saveGroupNameAndKey(
1278  activatedGroup,
1279  ConfigurationManager::LAST_ACTIVATED_ITERATE_GROUP_FILE,
1280  false /* appendMode */,
1281  username_);
1282  ConfigurationManager::saveGroupNameAndKey(
1283  activatedGroup,
1284  ConfigurationManager::ACTIVATED_ITERATES_FILE,
1285  true /* appendMode */,
1286  username_);
1287  }
1288  } // end save last activated group
1289 
1290 } // end activateTableGroup()
1291 
1292 //==============================================================================
1297  TableVersion sourceViewVersion)
1298 {
1299  __GEN_COUT_INFO__ << "Creating temporary backbone view from version "
1300  << sourceViewVersion << __E__;
1301 
1302  // find common available temporary version among backbone members
1303  TableVersion tmpVersion =
1304  TableVersion::getNextTemporaryVersion(); // get the default temporary version
1305  TableVersion retTmpVersion;
1306  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1307  for(auto& name : backboneMemberNames)
1308  {
1309  retTmpVersion =
1311  if(retTmpVersion < tmpVersion)
1312  tmpVersion = retTmpVersion;
1313  }
1314 
1315  __GEN_COUT__ << "Common temporary backbone version found as " << tmpVersion << __E__;
1316 
1317  // create temporary views from source version to destination temporary version
1318  for(auto& name : backboneMemberNames)
1319  {
1320  retTmpVersion =
1321  getTableByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
1322  if(retTmpVersion != tmpVersion)
1323  {
1324  __SS__ << "Failure! Temporary view requested was " << tmpVersion
1325  << ". Mismatched temporary view created: " << retTmpVersion << __E__;
1326  __GEN_COUT_ERR__ << ss.str();
1327  __SS_THROW__;
1328  }
1329  }
1330 
1331  return tmpVersion;
1332 } // end createTemporaryBackboneView()
1333 
1334 //==============================================================================
1335 TableBase* ConfigurationManagerRW::getTableByName(const std::string& tableName)
1336 {
1337  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
1338  {
1339  if(tableName == ConfigurationManager::ARTDAQ_TOP_TABLE_NAME)
1340  {
1341  __GEN_COUT_WARN__
1342  << "Since target table was the artdaq top configuration level, "
1343  "attempting to help user by appending to core tables file: "
1344  << CORE_TABLE_INFO_FILENAME << __E__;
1345  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
1346  if(fp)
1347  {
1348  fprintf(fp, "\nARTDAQ/*");
1349  fclose(fp);
1350  }
1351  }
1352 
1353  __SS__ << "Table not found with name: " << tableName << __E__;
1354  size_t f;
1355  if((f = tableName.find(' ')) != std::string::npos)
1356  ss << "There was a space character found in the table name needle at "
1357  "position "
1358  << f << " in the string (was this intended?). " << __E__;
1359 
1360  ss << "\nIf you think this table should exist in the core set of tables, try "
1361  "running 'UpdateOTS.sh --tables' to update your tables, then relaunch ots."
1362  << __E__;
1363  ss << "\nTables must be defined at path $USER_DATA/TableInfo/ to exist in ots. "
1364  "Please verify your table definitions, and then restart ots."
1365  << __E__;
1366  __GEN_COUT_ERR__ << "\n" << ss.str();
1367  __SS_THROW__;
1368  }
1369  return nameToTableMap_[tableName];
1370 } // end getTableByName()
1371 
1372 //==============================================================================
1378  const std::string& tableName,
1379  TableVersion version,
1380  bool looseColumnMatching /* = false */,
1381  std::string* accumulatedErrors /* = 0 */,
1382  bool getRawData /* = false */)
1383 {
1384  auto it = nameToTableMap_.find(tableName);
1385  if(it == nameToTableMap_.end())
1386  {
1387  __SS__ << "\nCan not find table named '" << tableName
1388  << "'\n\n\n\nYou need to load the table before it can be used."
1389  << "It probably is missing from the member list of the Table "
1390  "Group that was loaded?\n\n\n\n\n"
1391  << __E__;
1392  __SS_THROW__;
1393  }
1394  TableBase* table = it->second;
1395 
1396  if(version.isTemporaryVersion())
1397  {
1398  table->setActiveView(version);
1399 
1400  if(getRawData)
1401  {
1402  std::stringstream jsonSs;
1403  table->getViewP()->printJSON(jsonSs);
1404  table->getViewP()->doGetSourceRawData(true);
1405  table->getViewP()->fillFromJSON(jsonSs.str());
1406  }
1407  }
1408  else
1409  {
1410  theInterface_->get(table,
1411  tableName,
1412  0 /* groupKey */,
1413  0 /* groupName */,
1414  false /* dontFill */, // false to fill w/version
1415  version,
1416  false /* resetConfiguration*/, // false to not reset
1417  looseColumnMatching,
1418  getRawData,
1419  accumulatedErrors);
1420  }
1421  return table;
1422 } // end getVersionedTableByName()
1423 
1424 //==============================================================================
1428  TableVersion temporaryVersion,
1429  bool makeTemporary) //,
1431 {
1432  TableVersion newVersion(temporaryVersion);
1433 
1434  // set author of version
1435  TableBase* table = getTableByName(tableName);
1436  table->getTemporaryView(temporaryVersion)->setAuthor(username_);
1437  // NOTE: author is assigned to permanent versions when saved to DBI
1438 
1439  if(!makeTemporary) // saveNewVersion makes the new version the active version
1440  newVersion = theInterface_->saveNewVersion(table, temporaryVersion);
1441  else // make the temporary version active
1442  table->setActiveView(newVersion);
1443 
1444  // if there is a problem, try to recover
1445  while(!makeTemporary && !newVersion.isScratchVersion() &&
1446  allTableInfo_[tableName].versions_.find(newVersion) !=
1447  allTableInfo_[tableName].versions_.end())
1448  {
1449  __GEN_COUT_ERR__
1450  << "What happenened!?? ERROR::: new persistent version v" << newVersion
1451  << " already exists!? How is it possible? Retrace your steps and "
1452  "tell an admin."
1453  << __E__;
1454 
1455  // create a new temporary version of the target view
1456  temporaryVersion = table->createTemporaryView(newVersion);
1457 
1458  if(newVersion.isTemporaryVersion())
1459  newVersion = temporaryVersion;
1460  else
1461  newVersion = TableVersion::getNextVersion(newVersion);
1462 
1463  __GEN_COUT_WARN__ << "Attempting to recover and use v" << newVersion << __E__;
1464 
1465  if(!makeTemporary) // saveNewVersion makes the new version the active version
1466  newVersion =
1467  theInterface_->saveNewVersion(table, temporaryVersion, newVersion);
1468  else // make the temporary version active
1469  table->setActiveView(newVersion);
1470  }
1471 
1472  if(newVersion.isInvalid())
1473  {
1474  __SS__ << "Something went wrong saving the new version v" << newVersion
1475  << ". What happened?! (duplicates? database error?)" << __E__;
1476  __GEN_COUT_ERR__ << "\n" << ss.str();
1477  __SS_THROW__;
1478  }
1479 
1480  // update allTableInfo_ with the new version
1481  allTableInfo_[tableName].versions_.insert(newVersion);
1482 
1483  // table->getView().print();
1484  return newVersion;
1485 } // end saveNewTable()
1486 
1487 //==============================================================================
1492 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string& tableName,
1493  TableVersion targetVersion)
1494 {
1495  TableBase* table = getTableByName(tableName);
1496 
1497  table->trimTemporary(targetVersion);
1498 
1499  // if allTableInfo_ is not setup, then done
1500  if(allTableInfo_.find(tableName) == allTableInfo_.end())
1501  return;
1502  // else cleanup table info
1503 
1504  if(targetVersion.isInvalid())
1505  {
1506  // erase all temporary versions!
1507  for(auto it = allTableInfo_[tableName].versions_.begin();
1508  it != allTableInfo_[tableName].versions_.end();
1509  /*no increment*/)
1510  {
1511  if(it->isTemporaryVersion())
1512  {
1513  __GEN_COUT__ << "Removing '" << tableName << "' version info: " << *it
1514  << __E__;
1515  allTableInfo_[tableName].versions_.erase(it++);
1516  }
1517  else
1518  ++it;
1519  }
1520  }
1521  else // erase target version only
1522  {
1523  //__GEN_COUT__ << "Removing '" << tableName << "' version info: " << targetVersion << __E__;
1524  auto it = allTableInfo_[tableName].versions_.find(targetVersion);
1525  if(it == allTableInfo_[tableName].versions_.end())
1526  {
1527  __GEN_COUT__ << "Target '" << tableName << "' version v" << targetVersion
1528  << " was not found in info versions..." << __E__;
1529  return;
1530  }
1531  allTableInfo_[tableName].versions_.erase(
1532  allTableInfo_[tableName].versions_.find(targetVersion));
1533  }
1534 } // end eraseTemporaryVersion()
1535 
1536 //==============================================================================
1541 void ConfigurationManagerRW::clearCachedVersions(const std::string& tableName)
1542 {
1543  TableBase* table = getTableByName(tableName);
1544 
1545  table->trimCache(0);
1546 } // end clearCachedVersions()
1547 
1548 //==============================================================================
1554 {
1555  for(auto configInfo : allTableInfo_)
1556  configInfo.second.tablePtr_->trimCache(0);
1557 } // end clearAllCachedVersions()
1558 
1559 //==============================================================================
1562  const std::string& tableName, TableVersion sourceVersion)
1563 {
1564  getTableByName(tableName)->reset();
1565 
1566  // make sure source version is loaded
1567  // need to load with loose column rules!
1568  TableBase* table =
1569  getVersionedTableByName(tableName, TableVersion(sourceVersion), true);
1570 
1571  // copy from source version to a new temporary version
1572  TableVersion newTemporaryVersion =
1573  table->copyView(table->getView(), TableVersion(), username_);
1574 
1575  // update allTableInfo_ with the new version
1576  allTableInfo_[tableName].versions_.insert(newTemporaryVersion);
1577 
1578  return newTemporaryVersion;
1579 } // end copyViewToCurrentColumns()
1580 
1581 //==============================================================================
1586  const std::string& groupName, bool attemptToReloadKeys /* = false */)
1587 {
1588  // //NOTE: seems like this filter is taking the long amount of time
1589  // std::set<std::string /*name*/> fullGroupNames =
1590  // theInterface_->getAllTableGroupNames(groupName); //db filter by group name
1591 
1592  // so instead caching ourselves...
1593  auto it = allGroupInfo_.find(groupName);
1594  if(it == allGroupInfo_.end())
1595  {
1596  __SS__ << "Group name '" << groupName
1597  << "' not found in group info! (creating empty info)" << __E__;
1598  __GEN_COUT_WARN__ << ss.str();
1599  //__SS_THROW__;
1600  return allGroupInfo_[groupName];
1601  }
1602 
1603  if(attemptToReloadKeys) //load keys from Interface group cache
1604  {
1605  __GEN_COUT__ << "Reloading keys from special db group cache if it exists..."
1606  << __E__;
1607 
1608  std::set<TableGroupKey> keys;
1609  { //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)
1610  //attempt to use cache first! (potentially way faster .04 s vs 4 s)
1611  bool cacheFailed = false;
1612  try
1613  {
1614  TableBase localGroupMemberCacheLoader(
1615  true /*special table*/
1616  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),,
1617  TableBase::GROUP_CACHE_PREPEND + groupName);
1618  auto versions = theInterface_->getVersions(&localGroupMemberCacheLoader);
1619  for(const auto& version : versions)
1620  keys.emplace(TableGroupKey(version.version()));
1621  }
1622  catch(...)
1623  {
1624  __GEN_COUT__ << "Ignoring cache loading error. Doing full load of keys..."
1625  << __E__;
1626  cacheFailed = true;
1627  }
1628 
1629  if(cacheFailed && 0) //could consider full load if cache failed
1630  keys = theInterface_->getKeys(groupName);
1631 
1632  if(!cacheFailed) //take keys
1633  {
1634  __GEN_COUT__ << "Key from special db group cache were loaded." << __E__;
1635  it->second.keys_ = keys; //update ConfigManager cache!
1636  }
1637  }
1638  }
1639 
1640  return it->second;
1641 } // end getGroupInfo()
1642 
1643 //==============================================================================
1654  const std::string& groupName,
1655  const std::map<std::string, TableVersion>& groupMemberMap,
1656  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases)
1657 {
1658  if(!groupMemberMap.size() || groupName.empty())
1659  {
1660  __SS__ << "Illegal name/members for requested group of name '" << groupName
1661  << "' and member count = " << groupMemberMap.size() << __E__;
1662  __SS_THROW__;
1663  }
1664 
1665  // //NOTE: seems like this filter is taking the long amount of time
1666  // std::set<std::string /*name*/> fullGroupNames =
1667  // theInterface_->getAllTableGroupNames(groupName); //db filter bygroup name
1668  // const GroupInfo& groupInfo = getGroupInfo(groupName); // Note this also seems to take too long because requires a pre-cache load!
1669  std::set<TableGroupKey> keys;
1670  { //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)
1671  //attempt to use cache first! (potentially way faster .04 s vs 4 s)
1672  bool cacheFailed = false;
1673  try
1674  {
1675  TableBase localGroupMemberCacheLoader(
1676  true /*special table*/
1677  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),,
1678  TableBase::GROUP_CACHE_PREPEND + groupName);
1679  auto versions = theInterface_->getVersions(&localGroupMemberCacheLoader);
1680  for(const auto& version : versions)
1681  keys.emplace(TableGroupKey(version.version()));
1682  }
1683  catch(...)
1684  {
1685  __COUT__ << "Ignoring cache loading error. Doing full load of keys..."
1686  << __E__;
1687  cacheFailed = true;
1688  }
1689 
1690  if(cacheFailed) //since cache failed, do full load
1691  keys = theInterface_->getKeys(groupName);
1692  }
1693 
1694  __COUTTV__(StringMacros::setToString(keys));
1695 
1696  const unsigned int MAX_DEPTH_TO_CHECK = 20;
1697  unsigned int keyMinToCheck = 0;
1698 
1699  if(keys.size())
1700  keyMinToCheck = keys.rbegin()->key();
1701  if(keyMinToCheck > MAX_DEPTH_TO_CHECK)
1702  {
1703  keyMinToCheck -= MAX_DEPTH_TO_CHECK;
1704  __GEN_COUT__ << "Checking groups back to key... " << keyMinToCheck << __E__;
1705  }
1706  else
1707  {
1708  keyMinToCheck = 0;
1709  __GEN_COUT__ << "Checking all groups." << __E__;
1710  }
1711 
1712  __GEN_COUTTV__(StringMacros::mapToString(groupMemberMap));
1713 
1714  // have min key to check, now loop through and check groups
1715 
1716  const int numOfThreads = PROCESSOR_COUNT / 2;
1717  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> " << numOfThreads
1718  << " threads." << __E__;
1719  if(numOfThreads < 2) // no multi-threading
1720  {
1721  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
1722  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
1723  std::map<std::string /*name*/, std::string /*alias*/>*
1724  compareToMemberTableAliasesPtr = nullptr;
1725  if(memberTableAliases.size())
1726  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
1727 
1728  bool isDifferent;
1729  for(const auto& key : keys)
1730  {
1731  if(key.key() < keyMinToCheck)
1732  continue; // skip keys that are too old
1733 
1734  loadTableGroup(groupName,
1735  key,
1736  false /*doActivate*/,
1737  &compareToMemberMap /*memberMap*/,
1738  0, /*progressBar*/
1739  0, /*accumulatedWarnings*/
1740  0, /*groupComment*/
1741  0, /*groupAuthor*/
1742  0, /*groupCreateTime*/
1743  true /*doNotLoadMember*/,
1744  0 /*groupTypeString*/,
1745  compareToMemberTableAliasesPtr);
1746 
1747  isDifferent = false;
1748  for(auto& memberPair : groupMemberMap)
1749  {
1750  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
1751  {
1752  // handle this table as alias, not version
1753  if(compareToMemberTableAliases.find(memberPair.first) ==
1754  compareToMemberTableAliases.end() || // alias is missing
1755  memberTableAliases.at(memberPair.first) !=
1756  compareToMemberTableAliases.at(memberPair.first))
1757  { // then different
1758  isDifferent = true;
1759  break;
1760  }
1761  else
1762  continue;
1763  } // else check if compareTo group is using an alias for table
1764  else if(compareToMemberTableAliases.find(memberPair.first) !=
1765  compareToMemberTableAliases.end())
1766  {
1767  // then different
1768  isDifferent = true;
1769  break;
1770 
1771  } // else handle as table version comparison
1772  else if(compareToMemberMap.find(memberPair.first) ==
1773  compareToMemberMap.end() || // name is missing
1774  memberPair.second !=
1775  compareToMemberMap.at(
1776  memberPair.first)) // or version mismatch
1777  {
1778  // then different
1779  isDifferent = true;
1780  break;
1781  }
1782  }
1783  if(isDifferent)
1784  continue;
1785 
1786  // check member size for exact match
1787  if(groupMemberMap.size() != compareToMemberMap.size())
1788  continue; // different size, so not same (groupMemberMap is a subset of
1789  // memberPairs)
1790 
1791  __GEN_COUT__ << "Found exact match with key: " << key << __E__;
1792  // else found an exact match!
1793  return key;
1794  }
1795  __GEN_COUT__ << "No match found - this group is new!" << __E__;
1796  // if here, then no match found
1797  return TableGroupKey(); // return invalid key
1798  }
1799  else //multi-threading
1800  {
1801  int threadsLaunched = 0;
1802  int foundThreadIndex = 0;
1803  std::atomic<bool> foundIdentical = false;
1804  ots::TableGroupKey identicalKey;
1805  std::mutex threadMutex;
1806 
1807  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
1808  for(int i = 0; i < numOfThreads; ++i)
1809  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
1810 
1811  for(const auto& key : keys)
1812  {
1813  if(foundIdentical)
1814  break;
1815  if(key.key() < keyMinToCheck)
1816  continue; // skip keys that are too old
1817 
1818  if(threadsLaunched >= numOfThreads)
1819  {
1820  //find availableThreadIndex
1821  foundThreadIndex = -1;
1822  while(foundThreadIndex == -1)
1823  {
1824  if(foundIdentical)
1825  break;
1826 
1827  for(int i = 0; i < numOfThreads; ++i)
1828  if(*(threadDone[i]))
1829  {
1830  foundThreadIndex = i;
1831  break;
1832  }
1833  if(foundThreadIndex == -1)
1834  {
1835  __GEN_COUTT__ << "Waiting for available thread..." << __E__;
1836  usleep(10000);
1837  }
1838  } //end thread search loop
1839  threadsLaunched = numOfThreads - 1;
1840  }
1841  if(foundIdentical)
1842  break;
1843 
1844  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex << __E__;
1845  *(threadDone[foundThreadIndex]) = false;
1846 
1847  std::thread(
1848  [](ConfigurationManagerRW* cfgMgr,
1849  std::string theGroupName,
1850  ots::TableGroupKey groupKeyToCompare,
1851  const std::map<std::string, TableVersion>& groupMemberMap,
1852  const std::map<std::string /*name*/, std::string /*alias*/>&
1853  memberTableAliases,
1854  std::atomic<bool>* theFoundIdentical,
1855  ots::TableGroupKey* theIdenticalKey,
1856  std::mutex* theThreadMutex,
1857  std::shared_ptr<std::atomic<bool>> theThreadDone) {
1859  theGroupName,
1860  groupKeyToCompare,
1861  groupMemberMap,
1862  memberTableAliases,
1863  theFoundIdentical,
1864  theIdenticalKey,
1865  theThreadMutex,
1866  theThreadDone);
1867  },
1868  this,
1869  groupName,
1870  key,
1871  groupMemberMap,
1872  memberTableAliases,
1873  &foundIdentical,
1874  &identicalKey,
1875  &threadMutex,
1876  threadDone[foundThreadIndex])
1877  .detach();
1878 
1879  ++threadsLaunched;
1880  ++foundThreadIndex;
1881  } //end group key check thread loop
1882 
1883  //check for all threads done
1884  do
1885  {
1886  foundThreadIndex = -1;
1887  for(int i = 0; i < numOfThreads; ++i)
1888  if(!*(threadDone[i]))
1889  {
1890  foundThreadIndex = i;
1891  break;
1892  }
1893  if(foundThreadIndex != -1)
1894  {
1895  __GEN_COUTT__ << "Waiting for thread to finish... " << foundThreadIndex
1896  << __E__;
1897  usleep(10000);
1898  }
1899  } while(foundThreadIndex != -1); //end thread done search loop
1900 
1901  if(foundIdentical)
1902  {
1903  __GEN_COUT__ << "Found exact match with key: " << identicalKey << __E__;
1904  return identicalKey;
1905  }
1906 
1907  // if here, then no match found
1908  return TableGroupKey(); // return invalid key
1909  } //end multi-thread handling
1910 } // end findTableGroup()
1911 
1912 //==============================================================================
1918  TableVersion fillVersion /* = TableVersion()*/)
1919 {
1920  if(fillVersion.isInvalid())
1921  return &groupMetadataTable_;
1922  //else load specified fill version
1923 
1924  //only lock metadata table since it is shared by all group accesses
1925  std::lock_guard<std::mutex> lock(metaDataTableMutex_);
1926 
1927  // clear table
1928  while(groupMetadataTable_.getView().getNumberOfRows())
1929  groupMetadataTable_.getViewP()->deleteRow(0);
1930 
1931  // retrieve metadata from database
1932  try
1933  {
1934  theInterface_->fill(&groupMetadataTable_, fillVersion);
1935  }
1936  catch(const std::runtime_error& e)
1937  {
1938  __GEN_COUT_WARN__ << "Failed to load " << groupMetadataTable_.getTableName()
1939  << "-v" << fillVersion << ". Metadata error: " << e.what()
1940  << __E__;
1941  }
1942  catch(...)
1943  {
1944  __GEN_COUT_WARN__ << "Failed to load " << groupMetadataTable_.getTableName()
1945  << "-v" << fillVersion << ". Ignoring unknown metadata error. "
1946  << __E__;
1947  }
1948 
1949  // check that there is only 1 row
1950  if(groupMetadataTable_.getView().getNumberOfRows() != 1)
1951  {
1952  groupMetadataTable_.print();
1953  __GEN_COUT_ERR__ << "Ignoring that groupMetadataTable_ v" << fillVersion
1954  << " has wrong "
1955  "number of rows!' Must "
1956  "be 1. Going with anonymous defaults."
1957  << __E__;
1958 
1959  // fix metadata table
1960  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1961  groupMetadataTable_.getViewP()->deleteRow(0);
1962  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1963  groupMetadataTable_.getViewP()->addRow();
1964  }
1965 
1966  return &groupMetadataTable_;
1967 } // end getMetadataTable()
1968 
1969 //==============================================================================
1977  const std::string& groupName,
1978  std::map<std::string, TableVersion>& groupMembers,
1979  const std::string& groupComment,
1980  std::map<std::string /*table*/, std::string /*alias*/>* groupAliases)
1981 {
1982  // steps:
1983  // determine new group key
1984  // verify group members
1985  // verify groupNameWithKey
1986  // verify store
1987 
1988  if(groupMembers.size() == 0) // do not allow empty groups
1989  {
1990  __SS__ << "Empty group member list. Can not create a group without members!"
1991  << __E__;
1992  __SS_THROW__;
1993  }
1994 
1995  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1996 
1997  // verify group members
1998  // - use all table info
1999  std::map<std::string, TableInfo> allCfgInfo = getAllTableInfo();
2000  for(auto& memberPair : groupMembers)
2001  {
2002  // check member name
2003  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
2004  {
2005  __GEN_COUT_ERR__ << "Group member \"" << memberPair.first
2006  << "\" not found in database!";
2007 
2008  if(groupMetadataTable_.getTableName() == memberPair.first)
2009  {
2010  __GEN_COUT_WARN__
2011  << "Looks like this is the groupMetadataTable_ '"
2012  << TableBase::GROUP_METADATA_TABLE_NAME
2013  << ".' Note that this table is added to the member map when groups "
2014  "are saved."
2015  << "It should not be part of member map when calling this function."
2016  << __E__;
2017  __GEN_COUT__ << "Attempting to recover." << __E__;
2018  groupMembers.erase(groupMembers.find(memberPair.first));
2019  }
2020  else
2021  {
2022  __SS__ << ("Group member not found!") << __E__;
2023  __SS_THROW__;
2024  }
2025  }
2026  // check member version
2027  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
2028  allCfgInfo[memberPair.first].versions_.end())
2029  {
2030  __SS__ << "Group member \"" << memberPair.first << "\" version \""
2031  << memberPair.second << "\" not found in database!";
2032  __SS_THROW__;
2033  }
2034  } // end verify members
2035 
2036  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2037 
2038  // verify group aliases
2039  if(groupAliases)
2040  {
2041  for(auto& aliasPair : *groupAliases)
2042  {
2043  // check for alias table in member names
2044  if(groupMembers.find(aliasPair.first) == groupMembers.end())
2045  {
2046  __GEN_COUT_ERR__ << "Group member \"" << aliasPair.first
2047  << "\" not found in group member map!";
2048 
2049  __SS__ << ("Alias table not found in member list!") << __E__;
2050  __SS_THROW__;
2051  }
2052  }
2053  } // end verify group aliases
2054 
2055  TableGroupKey newKey =
2056  TableGroupKey::getNextKey(theInterface_->findLatestGroupKey(groupName));
2057  __GEN_COUT__ << "New Key for group: " << groupName << " found as " << newKey << __E__;
2058  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2059 
2060  time_t groupCreationTime = time(0);
2061  // capture group type before adding metadata table!
2062  std::string groupType = getTypeNameOfGroup(groupMembers);
2063  std::map<std::string /*name*/, TableVersion /*version*/> groupMembersWithoutMeta =
2064  groupMembers;
2065 
2066  // verify groupNameWithKey and attempt to store
2067  try
2068  {
2069  // save meta data for group; reuse groupMetadataTable_
2070  std::string groupAliasesString = "";
2071  if(groupAliases)
2072  groupAliasesString = StringMacros::mapToString(
2073  *groupAliases, "," /*primary delimeter*/, ":" /*secondary delimeter*/);
2074  __GEN_COUT__ << "Metadata: " << username_ << " " << groupCreationTime << " "
2075  << groupComment << " " << groupAliasesString << " " << groupType
2076  << __E__;
2077 
2078  // to compensate for unusual errors upstream, make sure the metadata table has one
2079  // row
2080  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
2081  groupMetadataTable_.getViewP()->deleteRow(0);
2082  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
2083  groupMetadataTable_.getViewP()->addRow();
2084 
2085  // columns are uid,comment,author,time
2086  groupMetadataTable_.getViewP()->setValue(
2087  groupAliasesString, 0, ConfigurationManager::METADATA_COL_ALIASES);
2088  groupMetadataTable_.getViewP()->setValue(
2089  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
2090  groupMetadataTable_.getViewP()->setValue(
2091  username_, 0, ConfigurationManager::METADATA_COL_AUTHOR);
2092  groupMetadataTable_.getViewP()->setValue(
2093  groupCreationTime, 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
2094 
2095  if(TTEST(2))
2096  {
2097  std::stringstream ss;
2098  groupMetadataTable_.print(ss);
2099  __COUT_MULTI__(2, ss.str());
2100  }
2101 
2102  // save table, and retry on save collision
2103  {
2104  // set version to first available persistent version
2106  theInterface_->findLatestVersion(&groupMetadataTable_));
2107  groupMetadataTable_.getViewP()->setVersion(newVersion);
2108 
2109  uint16_t retries = 0;
2110  while(1)
2111  {
2112  try
2113  {
2114  theInterface_->saveActiveVersion(&groupMetadataTable_);
2115  }
2116  catch(const std::runtime_error& e)
2117  {
2118  __GEN_COUT__ << "Caught runtime_error exception during table save."
2119  << __E__;
2120  if(std::string(e.what()).find("there was a collision") !=
2121  std::string::npos)
2122  {
2123  __GEN_COUT_WARN__
2124  << "There was a collision saving the new table "
2125  << groupMetadataTable_ << "(" << newVersion
2126  << "), trying incremented table version... retries="
2127  << retries << __E__;
2128  if(++retries > 3) //give up
2129  throw;
2130  newVersion = TableVersion::getNextVersion(
2131  newVersion); //increment table version
2132  groupMetadataTable_.getViewP()->setVersion(newVersion);
2133  __GEN_COUT__ << "New version for table: " << groupMetadataTable_
2134  << " found as " << newVersion << __E__;
2135  continue;
2136  }
2137  else
2138  throw;
2139  }
2140 
2141  __GEN_COUT__ << "Created table: " << groupMetadataTable_ << "-v"
2142  << newVersion << __E__;
2143  break;
2144  } //end collission retry loop
2145  }
2146 
2147  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2148  << __E__;
2149 
2150  // force groupMetadataTable_ to be a member for the group
2151  groupMembers[groupMetadataTable_.getTableName()] =
2152  groupMetadataTable_.getViewVersion();
2153 
2154  // save group, and retry on save collision
2155  {
2156  uint16_t retries = 0;
2157  while(1)
2158  {
2159  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2160  << __E__;
2161 
2162  try
2163  {
2164  theInterface_->saveTableGroup(
2165  groupMembers,
2166  TableGroupKey::getFullGroupString(groupName, newKey));
2167  }
2168  catch(const std::runtime_error& e)
2169  {
2170  __GEN_COUT__ << "Caught runtime_error exception during group save."
2171  << __E__;
2172  if(std::string(e.what()).find("there was a collision") !=
2173  std::string::npos)
2174  {
2175  __GEN_COUT_WARN__
2176  << "There was a collision saving the new group " << groupName
2177  << "(" << newKey
2178  << "), trying incremented group key... retries=" << retries
2179  << __E__;
2180  if(++retries > 3) //give up
2181  throw;
2182  newKey = TableGroupKey::getNextKey(newKey); //increment group key
2183  __GEN_COUT__ << "New Key for group: " << groupName << " found as "
2184  << newKey << __E__;
2185  continue;
2186  }
2187  else
2188  throw;
2189  }
2190 
2191  __GEN_COUT__ << "Created table group: " << groupName << "(" << newKey
2192  << ")" << __E__;
2193  break;
2194  } //end collission retry loop
2195  }
2196 
2197  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
2198  << __E__;
2199  }
2200  catch(std::runtime_error& e)
2201  {
2202  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << "(" << newKey
2203  << ")" << __E__;
2204  __GEN_COUT_ERR__ << "\n\n" << e.what() << __E__;
2205  throw;
2206  }
2207  catch(...)
2208  {
2209  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
2210  << __E__;
2211  throw;
2212  }
2213 
2214  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2215 
2216  // store cache of recent groups
2217  allGroupInfo_[groupName].keys_.emplace(newKey);
2218  //update latest group info with this group's info
2219  allGroupInfo_.at(groupName).latestKey_ = newKey;
2220  allGroupInfo_.at(groupName).latestKeyGroupAuthor_ = username_;
2221  allGroupInfo_.at(groupName).latestKeyGroupComment_ = groupComment;
2222  allGroupInfo_.at(groupName).latestKeyGroupCreationTime_ = groupCreationTime;
2223  allGroupInfo_.at(groupName).latestKeyGroupTypeString_ = groupType;
2224  allGroupInfo_.at(groupName).latestKeyMemberMap_ = groupMembersWithoutMeta;
2225 
2226  __GEN_COUT__ << "Saved " << groupName << "(" << newKey << ") of type " << groupType
2227  << __E__;
2228 
2229  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
2230 
2231  // at this point succeeded!
2232  return newKey;
2233 } // end saveNewTableGroup()
2234 
2235 //==============================================================================
2240 {
2241  __GEN_COUT_INFO__ << "Creating new backbone from temporary version "
2242  << temporaryVersion << __E__;
2243 
2244  // find common available temporary version among backbone members
2245  TableVersion newVersion(TableVersion::DEFAULT);
2246  TableVersion retNewVersion;
2247  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
2248  for(auto& name : backboneMemberNames)
2249  {
2250  retNewVersion = ConfigurationManager::getTableByName(name)->getNextVersion();
2251  __GEN_COUT__ << "New version for backbone member (" << name
2252  << "): " << retNewVersion << __E__;
2253  if(retNewVersion > newVersion)
2254  newVersion = retNewVersion;
2255  }
2256 
2257  __GEN_COUT__ << "Common new backbone version found as " << newVersion << __E__;
2258 
2259  // create new views from source temporary version
2260  for(auto& name : backboneMemberNames)
2261  {
2262  // saveNewVersion makes the new version the active version
2263  retNewVersion = getConfigurationInterface()->saveNewVersion(
2264  getTableByName(name), temporaryVersion, newVersion);
2265  if(retNewVersion != newVersion)
2266  {
2267  __SS__ << "Failure! New view requested was " << newVersion
2268  << ". Mismatched new view created: " << retNewVersion << __E__;
2269  __GEN_COUT_ERR__ << ss.str();
2270  __SS_THROW__;
2271  }
2272  }
2273 
2274  return newVersion;
2275 } // end saveNewBackbone()
2276 
2277 //==============================================================================
2283  const std::string& tableName,
2284  TableVersion originalVersion,
2285  bool makeTemporary,
2286  TableBase* table,
2287  TableVersion temporaryModifiedVersion,
2288  bool ignoreDuplicates /*= false*/,
2289  bool lookForEquivalent /*= false*/,
2290  bool* foundEquivalent /*= nullptr*/)
2291 {
2292  bool needToEraseTemporarySource =
2293  (originalVersion.isTemporaryVersion() && !makeTemporary);
2294 
2295  if(foundEquivalent)
2296  *foundEquivalent = false; // initialize
2297 
2298  // check for duplicate tables already in cache, plus highest version numbers not in cache
2299  if(!ignoreDuplicates)
2300  {
2301  __GEN_COUT__ << "Checking for duplicate '" << tableName << "' tables..." << __E__;
2302 
2303  TableVersion duplicateVersion;
2304 
2305  {
2306  //"DEEP" checking
2307  // load into cache 'recent' versions for this table
2308  // 'recent' := those already in cache, plus highest version numbers not in cache
2309  const std::map<std::string, TableInfo>& allTableInfo =
2310  getAllTableInfo(); // do not refresh
2311 
2312  auto versionReverseIterator =
2313  allTableInfo.at(tableName).versions_.rbegin(); // get reverse iterator
2314  __GEN_COUT__ << "Filling up '" << tableName << "' cache from "
2315  << table->getNumberOfStoredViews() << " to max count of "
2316  << table->MAX_VIEWS_IN_CACHE << __E__;
2317  for(; table->getNumberOfStoredViews() < table->MAX_VIEWS_IN_CACHE &&
2318  versionReverseIterator != allTableInfo.at(tableName).versions_.rend();
2319  ++versionReverseIterator)
2320  {
2321  __GEN_COUTT__ << "'" << tableName << "' versions in reverse order "
2322  << *versionReverseIterator << __E__;
2323  try
2324  {
2325  getVersionedTableByName(tableName,
2326  *versionReverseIterator); // load to cache
2327  }
2328  catch(const std::runtime_error& e)
2329  {
2330  // ignore error
2331  __COUTT__ << "'" << tableName
2332  << "' version failed to load: " << *versionReverseIterator
2333  << __E__;
2334  }
2335  }
2336  }
2337 
2338  __GEN_COUT__ << "Checking '" << tableName << "' for duplicate..." << __E__;
2339 
2340  duplicateVersion = table->checkForDuplicate(
2341  temporaryModifiedVersion,
2342  (!originalVersion.isTemporaryVersion() && !makeTemporary)
2343  ? TableVersion()
2344  : // if from persistent to persistent, then include original version in search
2345  originalVersion);
2346 
2347  if(lookForEquivalent && !duplicateVersion.isInvalid())
2348  {
2349  // found an equivalent!
2350  __GEN_COUT__ << "Equivalent '" << tableName << "' table found in version v"
2351  << duplicateVersion << __E__;
2352 
2353  // if duplicate version was temporary, do not use
2354  if(duplicateVersion.isTemporaryVersion() && !makeTemporary)
2355  {
2356  __GEN_COUT__ << "Need persistent. Duplicate '" << tableName
2357  << "' version was temporary. "
2358  "Abandoning duplicate."
2359  << __E__;
2360  duplicateVersion = TableVersion(); // set invalid
2361  }
2362  else
2363  {
2364  // erase and return equivalent version
2365 
2366  // erase modified equivalent version
2367  eraseTemporaryVersion(tableName, temporaryModifiedVersion);
2368 
2369  // erase original if needed
2370  if(needToEraseTemporarySource)
2371  eraseTemporaryVersion(tableName, originalVersion);
2372 
2373  if(foundEquivalent)
2374  *foundEquivalent = true;
2375 
2376  __GEN_COUT__ << "\t\t Equivalent '" << tableName
2377  << "' assigned version: " << duplicateVersion << __E__;
2378 
2379  return duplicateVersion;
2380  }
2381  }
2382 
2383  if(!duplicateVersion.isInvalid())
2384  {
2385  __SS__ << "This version of table '" << tableName
2386  << "' is identical to another version currently cached v"
2387  << duplicateVersion << ". No reason to save a duplicate." << __E__;
2388  __GEN_COUT_ERR__ << "\n" << ss.str();
2389 
2390  // delete temporaryModifiedVersion
2391  table->eraseView(temporaryModifiedVersion);
2392  __SS_THROW__;
2393  }
2394 
2395  __GEN_COUT__ << "Check for duplicate '" << tableName << "' tables complete."
2396  << __E__;
2397  }
2398 
2399  if(makeTemporary)
2400  __GEN_COUT__ << "\t\t**************************** Save as temporary '"
2401  << tableName << "' table version" << __E__;
2402  else
2403  __GEN_COUT__ << "\t\t**************************** Save as new '" << tableName
2404  << "' table version" << __E__;
2405 
2406  TableVersion newAssignedVersion =
2407  saveNewTable(tableName, temporaryModifiedVersion, makeTemporary);
2408 
2409  __GEN_COUTTV__(table->getView().getComment());
2410 
2411  if(needToEraseTemporarySource)
2412  eraseTemporaryVersion(tableName, originalVersion);
2413 
2414  __GEN_COUT__ << "\t\t '" << tableName
2415  << "' new assigned version: " << newAssignedVersion << __E__;
2416  return newAssignedVersion;
2417 } // end saveModifiedVersion()
2418 
2419 //==============================================================================
2420 GroupEditStruct::GroupEditStruct(const ConfigurationManager::GroupType& groupType,
2421  ConfigurationManagerRW* cfgMgr)
2422  : groupType_(groupType)
2423  , originalGroupName_(cfgMgr->getActiveGroupName(groupType))
2424  , originalGroupKey_(cfgMgr->getActiveGroupKey(groupType))
2425  , cfgMgr_(cfgMgr)
2426  , mfSubject_(cfgMgr->getUsername())
2427 {
2428  if(originalGroupName_ == "" || originalGroupKey_.isInvalid())
2429  {
2430  __SS__ << "Error! No active group found for type '"
2432  << ".' There must be an active group to edit the group." << __E__ << __E__
2433  << StringMacros::stackTrace() << __E__;
2434  __SS_THROW__;
2435  }
2436 
2437  __GEN_COUT__ << "Extracting Group-Edit Struct for type "
2438  << ConfigurationManager::convertGroupTypeToName(groupType) << __E__;
2439 
2440  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
2441 
2442  const std::set<std::string>& memberNames =
2443  groupType == ConfigurationManager::GroupType::CONTEXT_TYPE
2444  ? cfgMgr->getActiveContextMemberNames()
2445  : (groupType == ConfigurationManager::GroupType::BACKBONE_TYPE
2446  ? ConfigurationManager::getBackboneMemberNames()
2447  : (groupType == ConfigurationManager::GroupType::ITERATE_TYPE
2448  ? ConfigurationManager::getIterateMemberNames()
2449  : cfgMgr->getConfigurationMemberNames()));
2450 
2451  for(auto& memberName : memberNames)
2452  try
2453  {
2454  groupMembers_.emplace(
2455  std::make_pair(memberName, activeTables.at(memberName)));
2456  groupTables_.emplace(std::make_pair(
2457  memberName,
2458  TableEditStruct(memberName, cfgMgr))); // Table ready for editing!
2459  }
2460  catch(...)
2461  {
2462  __GEN_COUTV__(StringMacros::mapToString(activeTables));
2463  __SS__ << "Error! Could not find group member table '" << memberName
2464  << "' for group type '"
2466  << ".' All group members must be present to create the group editing "
2467  "structure."
2468  << __E__ << __E__ << StringMacros::stackTrace() << __E__;
2469  __SS_THROW__;
2470  }
2471 
2472 } // end GroupEditStruct constructor()
2473 
2474 //==============================================================================
2475 GroupEditStruct::~GroupEditStruct()
2476 {
2477  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2478  << originalGroupKey_ << ")' Destructing..." << __E__;
2479  dropChanges();
2480  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2481  << originalGroupKey_ << ")' Desctructed." << __E__;
2482 } // end GroupEditStruct destructor()
2483 
2484 //==============================================================================
2487  bool markModified /*= false*/)
2488 {
2489  auto it = groupTables_.find(tableName);
2490  if(it == groupTables_.end())
2491  {
2492  if(groupType_ == ConfigurationManager::GroupType::CONFIGURATION_TYPE &&
2493  markModified)
2494  {
2495  __GEN_COUT__ << "Table '" << tableName
2496  << "' not found in configuration table members from editing '"
2497  << originalGroupName_ << "(" << originalGroupKey_ << ")..."
2498  << " Attempting to add it!" << __E__;
2499 
2500  // emplace returns pair<object,bool wasAdded>
2501  auto newIt = groupTables_.emplace(std::make_pair(
2502  tableName,
2503  TableEditStruct(tableName, cfgMgr_))); // Table ready for editing!
2504  if(newIt.second)
2505  {
2506  newIt.first->second.modified_ =
2507  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2508  groupMembers_.emplace(
2509  std::make_pair(tableName, newIt.first->second.temporaryVersion_));
2510  return newIt.first->second;
2511  }
2512  __GEN_COUT_ERR__ << "Failed to emplace new table..." << __E__;
2513  }
2514 
2515  __SS__ << "Table '" << tableName << "' not found in table members from editing '"
2516  << originalGroupName_ << "(" << originalGroupKey_ << ")!'" << __E__;
2517  __SS_THROW__;
2518  }
2519  it->second.modified_ =
2520  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2521  return it->second;
2522 } // end getTableEditStruct()
2523 
2524 //==============================================================================
2525 void GroupEditStruct::dropChanges()
2526 {
2527  __GEN_COUT__ << "Dropping unsaved changes from editing '" << originalGroupName_ << "("
2528  << originalGroupKey_ << ")'..." << __E__;
2529 
2530  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2531 
2532  // drop all temporary versions
2533  for(auto& groupTable : groupTables_)
2534  if(groupTable.second
2535  .createdTemporaryVersion_) // if temporary version created here
2536  {
2537  // erase with proper version management
2538  cfgMgr->eraseTemporaryVersion(groupTable.second.tableName_,
2539  groupTable.second.temporaryVersion_);
2540  groupTable.second.createdTemporaryVersion_ = false;
2541  groupTable.second.modified_ = false;
2542  }
2543 
2544  __GEN_COUT__ << "Unsaved changes dropped from editing '" << originalGroupName_ << "("
2545  << originalGroupKey_ << ").'" << __E__;
2546 } // end GroupEditStruct::dropChanges()
2547 
2548 //==============================================================================
2549 void GroupEditStruct::saveChanges(const std::string& groupNameToSave,
2550  TableGroupKey& newGroupKey,
2551  bool* foundEquivalentGroupKey /*= nullptr*/,
2552  bool activateNewGroup /*= false*/,
2553  bool updateGroupAliases /*= false*/,
2554  bool updateTableAliases /*= false*/,
2555  TableGroupKey* newBackboneKey /*= nullptr*/,
2556  bool* foundEquivalentBackboneKey /*= nullptr*/,
2557  std::string* accumulatedWarnings /*= nullptr*/)
2558 {
2559  __GEN_COUT__ << "Saving changes..." << __E__;
2560 
2561  newGroupKey = TableGroupKey(); // invalidate reference parameter
2562  if(newBackboneKey)
2563  *newBackboneKey = TableGroupKey(); // invalidate reference parameter
2564  if(foundEquivalentBackboneKey)
2565  *foundEquivalentBackboneKey = false; // clear to start
2566  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2567 
2568  // save all temporary modified versions
2569  bool anyTableNew = false;
2570  for(auto& groupTable : groupTables_)
2571  {
2572  if(!groupTable.second.modified_)
2573  continue; // skip if not modified
2574 
2575  __GEN_COUT__ << "Original version is " << groupTable.second.tableName_ << "-v"
2576  << groupTable.second.originalVersion_ << __E__;
2577 
2578  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2579  groupTable.second.tableName_,
2580  groupTable.second.originalVersion_,
2581  true /*make temporary*/,
2582  groupTable.second.table_,
2583  groupTable.second.temporaryVersion_,
2584  true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
2585 
2586  __GEN_COUT__ << "Temporary target version is " << groupTable.second.tableName_
2587  << "-v" << groupMembers_.at(groupTable.first) << "-v"
2588  << groupTable.second.temporaryVersion_ << __E__;
2589 
2590  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2591  groupTable.second.tableName_,
2592  groupTable.second.originalVersion_,
2593  false /*make temporary*/,
2594  groupTable.second.table_,
2595  groupTable.second.temporaryVersion_,
2596  false /*ignoreDuplicates*/,
2597  true /*lookForEquivalent*/); // save persistent version properly
2598 
2599  if(groupTable.second.originalVersion_ != groupMembers_.at(groupTable.first))
2600  {
2601  anyTableNew = true;
2602  __GEN_COUT__ << "Final NEW target version is " << groupTable.second.tableName_
2603  << "-v" << groupMembers_.at(groupTable.first) << __E__;
2604  }
2605  else
2606  __GEN_COUT__ << "Final target version is " << groupTable.second.tableName_
2607  << "-v" << groupMembers_.at(groupTable.first) << __E__;
2608 
2609  groupTable.second.modified_ = false; // clear modified flag
2610  groupTable.second.createdTemporaryVersion_ = false; // modified version is gone
2611  } // loop through table edit structs
2612 
2613  for(auto& table : groupMembers_)
2614  {
2615  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2616  }
2617 
2618  if(!anyTableNew) //then could be duplicate group
2619  {
2620  __GEN_COUT__ << "Checking for duplicate groups..." << __E__;
2621  newGroupKey = cfgMgr->findTableGroup(groupNameToSave, groupMembers_);
2622  }
2623  else
2624  __GEN_COUT__ << "New table found, so no need to check duplicate groups." << __E__;
2625 
2626  if(!newGroupKey.isInvalid())
2627  {
2628  __GEN_COUT__ << "Found equivalent group key (" << newGroupKey << ") for "
2629  << groupNameToSave << "." << __E__;
2630  if(foundEquivalentGroupKey)
2631  *foundEquivalentGroupKey = true;
2632  }
2633  else
2634  {
2635  newGroupKey = cfgMgr->saveNewTableGroup(groupNameToSave, groupMembers_);
2636  __GEN_COUT__ << "Saved new Context group key (" << newGroupKey << ") for "
2637  << groupNameToSave << "." << __E__;
2638  }
2639 
2640  bool groupAliasChange = false;
2641  bool tableAliasChange = false;
2642 
2643  if(groupType_ !=
2644  ConfigurationManager::GroupType::
2645  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)
2646  {
2647  GroupEditStruct backboneGroupEdit(ConfigurationManager::GroupType::BACKBONE_TYPE,
2648  cfgMgr);
2649 
2650  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE &&
2651  updateGroupAliases)
2652  {
2653  // check group aliases ... a la
2654  // ConfigurationGUISupervisor::handleSetGroupAliasInBackboneXML
2655 
2656  TableEditStruct& groupAliasTable = backboneGroupEdit.getTableEditStruct(
2657  ConfigurationManager::GROUP_ALIASES_TABLE_NAME, true /*markModified*/);
2658  TableView* tableView = groupAliasTable.tableView_;
2659 
2660  // unsigned int col;
2661  unsigned int row = 0;
2662 
2663  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2664  cfgMgr->getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME)
2665  .getChildren();
2666  std::string groupName, groupKey;
2667  for(auto& aliasNodePair : aliasNodePairs)
2668  {
2669  groupName = aliasNodePair.second.getNode("GroupName").getValueAsString();
2670  groupKey = aliasNodePair.second.getNode("GroupKey").getValueAsString();
2671 
2672  __GEN_COUT__ << "Group Alias: " << aliasNodePair.first << " => "
2673  << groupName << "(" << groupKey << "); row=" << row << __E__;
2674 
2675  if(groupName == originalGroupName_ &&
2676  TableGroupKey(groupKey) == originalGroupKey_)
2677  {
2678  __GEN_COUT__ << "Found alias! Changing group key from ("
2679  << originalGroupKey_ << ") to (" << newGroupKey << ")"
2680  << __E__;
2681 
2682  groupAliasChange = true;
2683 
2684  tableView->setValueAsString(
2685  newGroupKey.toString(), row, tableView->findCol("GroupKey"));
2686  }
2687 
2688  ++row;
2689  }
2690 
2691  if(groupAliasChange)
2692  {
2693  std::stringstream ss;
2694  tableView->print(ss);
2695  __GEN_COUT__ << ss.str();
2696  }
2697  } // end updateGroupAliases handling
2698 
2699  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE &&
2700  updateTableAliases)
2701  {
2702  // update all table version aliases
2703  TableView* tableView =
2704  backboneGroupEdit
2705  .getTableEditStruct(ConfigurationManager::VERSION_ALIASES_TABLE_NAME,
2706  true /*markModified*/)
2707  .tableView_;
2708 
2709  for(auto& groupTable : groupTables_)
2710  {
2711  if(groupTable.second.originalVersion_ ==
2712  groupMembers_.at(groupTable.second.tableName_))
2713  continue; // skip if no change
2714 
2715  __GEN_COUT__ << "Checking alias... original version is "
2716  << groupTable.second.tableName_ << "-v"
2717  << groupTable.second.originalVersion_
2718  << " and new version is v"
2719  << groupMembers_.at(groupTable.second.tableName_) << __E__;
2720 
2721  // unsigned int col;
2722  unsigned int row = 0;
2723 
2724  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2725  cfgMgr->getNode(ConfigurationManager::VERSION_ALIASES_TABLE_NAME)
2726  .getChildren();
2727  std::string tableName, tableVersion;
2728  for(auto& aliasNodePair : aliasNodePairs)
2729  {
2730  tableName =
2731  aliasNodePair.second.getNode("TableName").getValueAsString();
2732  tableVersion =
2733  aliasNodePair.second.getNode("Version").getValueAsString();
2734 
2735  __GEN_COUT__ << "Table Alias: " << aliasNodePair.first << " => "
2736  << tableName << "-v" << tableVersion << "" << __E__;
2737 
2738  if(tableName == groupTable.second.tableName_ &&
2739  TableVersion(tableVersion) == groupTable.second.originalVersion_)
2740  {
2741  __GEN_COUT__ << "Found alias! Changing icon table version alias."
2742  << __E__;
2743 
2744  tableAliasChange = true;
2745 
2746  tableView->setValueAsString(
2747  groupMembers_.at(groupTable.second.tableName_).toString(),
2748  row,
2749  tableView->findCol("Version"));
2750  }
2751 
2752  ++row;
2753  }
2754  }
2755 
2756  if(tableAliasChange)
2757  {
2758  std::stringstream ss;
2759  tableView->print(ss);
2760  __GEN_COUT__ << ss.str();
2761  }
2762  } // end updateTableAliases handling
2763 
2764  TableGroupKey localNewBackboneKey;
2765  // if backbone modified, save group and activate it
2766  if(groupAliasChange || tableAliasChange)
2767  {
2768  for(auto& table : backboneGroupEdit.groupMembers_)
2769  {
2770  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2771  }
2772  backboneGroupEdit.saveChanges(
2773  backboneGroupEdit.originalGroupName_,
2774  localNewBackboneKey,
2775  foundEquivalentBackboneKey ? foundEquivalentBackboneKey : nullptr);
2776 
2777  if(newBackboneKey)
2778  *newBackboneKey = localNewBackboneKey;
2779  }
2780 
2781  // acquire all active groups and ignore errors, so that activateTableGroup does not
2782  // erase other active groups
2783  {
2784  __GEN_COUT__
2785  << "Restoring active table groups, before activating new groups..."
2786  << __E__;
2787 
2788  std::string localAccumulatedWarnings;
2789  cfgMgr->restoreActiveTableGroups(
2790  false /*throwErrors*/,
2791  "" /*pathToActiveGroupsFile*/,
2792  ConfigurationManager::LoadGroupType::
2793  ALL_TYPES /*onlyLoadIfBackboneOrContext*/,
2794  &localAccumulatedWarnings);
2795  }
2796 
2797  // activate new groups
2798  if(!localNewBackboneKey.isInvalid())
2799  cfgMgr->activateTableGroup(
2800  backboneGroupEdit.originalGroupName_,
2801  localNewBackboneKey,
2802  accumulatedWarnings ? accumulatedWarnings : nullptr);
2803 
2804  } //end non-backbone save type handling
2805  else //is backbone save type
2806  {
2807  // acquire all active groups and ignore errors, so that activateTableGroup does not
2808  // erase other active groups
2809  {
2810  __GEN_COUT__
2811  << "Restoring active table groups, before activating new groups..."
2812  << __E__;
2813 
2814  std::string localAccumulatedWarnings;
2815  cfgMgr->restoreActiveTableGroups(
2816  false /*throwErrors*/,
2817  "" /*pathToActiveGroupsFile*/,
2818  ConfigurationManager::LoadGroupType::
2819  ALL_TYPES /*onlyLoadIfBackboneOrContext*/,
2820  &localAccumulatedWarnings);
2821  }
2822  } //end backbone save type handling
2823 
2824  if(activateNewGroup)
2825  cfgMgr->activateTableGroup(groupNameToSave,
2826  newGroupKey,
2827  accumulatedWarnings ? accumulatedWarnings : nullptr);
2828 
2829  __GEN_COUT__ << "Changes saved." << __E__;
2830 } // end GroupEditStruct::saveChanges()
2831 
2832 //==============================================================================
2835 {
2836  if(1)
2837  return; //if 0 to debug
2838  __GEN_COUTV__(runTimeSeconds());
2839 
2840  std::string accumulatedWarningsStr;
2841  std::string* accumulatedWarnings = &accumulatedWarningsStr;
2842 
2843  // get Group Info too!
2844  try
2845  {
2846  //test lookup of which groups a table is in
2847  {
2848  std::string documentNameToLoad = "XDAQApplicationTable";
2849  TableVersion documentVersionToLoad(
2850  (int)134); //1 is easy, 134 is hard on daq13 mongodb
2851 
2852  std::set<std::string> groupsContainingTable =
2853  theInterface_->findGroupsWithTable(documentNameToLoad,
2854  documentVersionToLoad);
2855  __GEN_COUT__ << "Groups containing " << documentNameToLoad << "-v"
2856  << documentVersionToLoad
2857  << " count: " << groupsContainingTable.size() << __E__;
2858  for(const auto& group : groupsContainingTable)
2859  {
2860  __GEN_COUT__ << "\t" << group << __E__;
2861  }
2862  }
2863 
2864  std::string debugGroupName = "Mu2eHWEmulatorContext";
2865 
2866  //final solution demo of getting latest group key:
2867  {
2868  TableGroupKey latestGroupKey =
2869  theInterface_->findLatestGroupKey(debugGroupName);
2870  __GEN_COUTV__(latestGroupKey);
2871 
2872  __GEN_COUTV__(runTimeSeconds());
2873  }
2874 
2875  //steps to do time comparison for getting last group key and table key:
2876 
2877  // build allGroupInfo_ for the ConfigurationManagerRW
2878 
2879  std::set<std::string /*name*/> tableGroups =
2880  theInterface_->getAllTableGroupNames();
2881  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
2882 
2883  __GEN_COUTV__(runTimeSeconds());
2884  // return;
2885 
2886  TableGroupKey key;
2887  std::string name;
2888  for(const auto& fullName : tableGroups)
2889  {
2890  TableGroupKey::getGroupNameAndKey(fullName, name, key);
2891  allGroupInfo_[name].keys_.emplace(key);
2892 
2893  if(name == debugGroupName)
2894  {
2895  __GEN_COUTV__(key);
2896  }
2897  }
2898  __GEN_COUTV__(runTimeSeconds());
2899 
2900  std::set<std::string /*name*/> tableNames = theInterface_->getAllTableNames();
2901  __GEN_COUT__ << "Number of Tables: " << tableNames.size() << __E__;
2902 
2903  __GEN_COUTV__(runTimeSeconds());
2904 
2905  for(const auto& fullName : tableNames)
2906  {
2907  if(fullName.find(debugGroupName) != std::string::npos)
2908  {
2909  __GEN_COUTV__(fullName);
2910  }
2911  }
2912  __GEN_COUTV__(runTimeSeconds());
2913 
2914  TableGroupKey latestGroupKey = theInterface_->findLatestGroupKey(debugGroupName);
2915  __GEN_COUTV__(latestGroupKey);
2916 
2917  __GEN_COUTV__(runTimeSeconds());
2918 
2919  TableBase localGroupMemberCacheSaver(
2920  true /*special table*/
2921  , //special table only allows 1 view in cache and does not load schema (which is perfect for this temporary table),
2922  TableBase::GROUP_CACHE_PREPEND + debugGroupName);
2923  TableVersion lastestGroupCacheKey =
2924  theInterface_->findLatestVersion(&localGroupMemberCacheSaver);
2925  __GEN_COUTV__(lastestGroupCacheKey);
2926 
2927  __GEN_COUTV__(runTimeSeconds());
2928 
2929  //test a group save that already exists
2930  try
2931  {
2932  TableGroupKey groupKey(int(0));
2933  __GEN_COUT__ << "Testing group save of pre-existing " << debugGroupName << "("
2934  << groupKey << ")" << __E__;
2935  std::map<std::string, TableVersion> groupMembers;
2936  groupMembers["DesktopIconTable"] = TableVersion(123);
2937  theInterface_->saveTableGroup(
2938  groupMembers,
2939  TableGroupKey::getFullGroupString(debugGroupName, groupKey));
2940  }
2941  catch(...)
2942  {
2943  __GEN_COUT__ << "Exception during group save." << __E__;
2944  }
2945  __GEN_COUTV__(runTimeSeconds());
2946 
2947  //test a group save that does not already exists
2948  try
2949  {
2950  std::string debugGroupName = "testGroupSave";
2951  TableGroupKey groupKey(int(2));
2952  __GEN_COUT__ << "Testing group save of non-existing " << debugGroupName << "("
2953  << groupKey << ")" << __E__;
2954  std::map<std::string, TableVersion> groupMembers;
2955  groupMembers["DesktopIconTable"] = TableVersion(123);
2956  groupMembers["MessageFacilityTable"] = TableVersion(7);
2957  theInterface_->saveTableGroup(
2958  groupMembers,
2959  TableGroupKey::getFullGroupString(debugGroupName, groupKey));
2960  }
2961  catch(...)
2962  {
2963  __GEN_COUT__ << "Exception during new group save." << __E__;
2964  }
2965  __GEN_COUTV__(runTimeSeconds());
2966 
2967  //test a table save that already exists
2968  {
2969  std::string documentNameToLoad = "XDAQApplicationTable";
2970  TableVersion documentVersionToLoad(134);
2971 
2972  __GEN_COUT__ << "Testing table save of pre-existing " << documentNameToLoad
2973  << __E__;
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  try
2988  { //attempt to save over existing version
2989  std::string documentNameToSave = documentNameToLoad;
2990  TableBase
2991  localDocSaver( //true /*special table*/, //special table only allows 1 view in cache and does not load schema (which is perfect for this check),
2992  documentNameToSave); //can not use special table when filling
2993  localDocSaver.changeVersionAndActivateView(
2994  localDocSaver.createTemporaryView(), documentVersionToLoad);
2995 
2996  std::string json = "{ }";
2997  localDocSaver.getViewP()->setCustomStorageData(json);
2998 
2999  __COUTT__ << "Saving JSON string: "
3000  << localDocSaver.getViewP()->getCustomStorageData() << __E__;
3001 
3002  __COUTT__ << "Saving JSON doc as "
3003  << localDocSaver.getView().getTableName() << "("
3004  << localDocSaver.getView().getVersion().toString() << ")"
3005  << __E__;
3006 
3007  // save to db, and do not allow overwrite
3008  theInterface_->saveActiveVersion(&localDocSaver, false /* overwrite */);
3009  }
3010  catch(...)
3011  {
3012  __GEN_COUT__ << "Exception during table save." << __E__;
3013  }
3014  __GEN_COUTV__(runTimeSeconds());
3015 
3016  { //load to prove it exists
3017  TableBase localDocLoader(
3018  documentNameToLoad); //can not use special table when filling
3019  localDocLoader.changeVersionAndActivateView(
3020  localDocLoader.createTemporaryView(), documentVersionToLoad);
3021  theInterface_->fill(&localDocLoader, documentVersionToLoad);
3022  __SS__;
3023  localDocLoader.print(ss);
3024  __GEN_COUTV__(ss.str());
3025  }
3026  __GEN_COUTV__(runTimeSeconds());
3027  }
3028  __GEN_COUTV__(runTimeSeconds());
3029 
3030  //test a table save that does not already exist
3031  {
3032  std::string documentNameToLoad = "MessageFacilityTable";
3033  TableVersion documentVersionToLoad(7);
3034  TableBase localDocLoader(
3035  documentNameToLoad); //can not use special table when filling
3036 
3037  __GEN_COUT__ << "Testing table save of non-existing " << documentNameToLoad
3038  << __E__;
3039 
3040  { //load to prove it exists
3041  localDocLoader.changeVersionAndActivateView(
3042  localDocLoader.createTemporaryView(), documentVersionToLoad);
3043  theInterface_->fill(&localDocLoader, documentVersionToLoad);
3044  __SS__;
3045  localDocLoader.print(ss);
3046  __GEN_COUTV__(ss.str());
3047  __GEN_COUTV__(runTimeSeconds());
3048  }
3049  __GEN_COUTV__(runTimeSeconds());
3050 
3051  try
3052  { //attempt to save new version
3053 
3054  // modify it
3056  theInterface_->findLatestVersion(&localDocLoader));
3057  localDocLoader.getViewP()->setVersion(newVersion);
3058 
3059  __GEN_COUTT__ << "Saving new table as "
3060  << localDocLoader.getView().getTableName() << "("
3061  << localDocLoader.getView().getVersion().toString() << ")"
3062  << __E__;
3063 
3064  localDocLoader.getViewP()->setValueAsString(
3065  "10.226.9.17", 0, 4); //modify value that is 10.226.9.16
3066 
3067  __SS__;
3068  localDocLoader.print(ss);
3069  __GEN_COUTV__(ss.str());
3070 
3071  // save to db, and do not allow overwrite
3072  theInterface_->saveActiveVersion(&localDocLoader, false /* overwrite */);
3073  }
3074  catch(...)
3075  {
3076  __GEN_COUT__ << "Exception during new table save." << __E__;
3077  }
3078  __GEN_COUTV__(runTimeSeconds());
3079  }
3080  __GEN_COUTV__(runTimeSeconds());
3081  return;
3082 
3083  // for each group get member map & comment, author, time, and type for latest key
3084  for(auto& groupInfo : allGroupInfo_)
3085  {
3086  try
3087  {
3088  groupInfo.second.latestKey_ = groupInfo.second.getLastKey();
3089  loadTableGroup(groupInfo.first /*groupName*/,
3090  groupInfo.second.latestKey_,
3091  false /*doActivate*/,
3092  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
3093  0 /*progressBar*/,
3094  0 /*accumulateErrors*/,
3095  &groupInfo.second.latestKeyGroupComment_,
3096  &groupInfo.second.latestKeyGroupAuthor_,
3097  &groupInfo.second.latestKeyGroupCreationTime_,
3098  true /*doNotLoadMember*/,
3099  &groupInfo.second.latestKeyGroupTypeString_);
3100  }
3101  catch(const std::runtime_error& e)
3102  {
3103  __GEN_COUT_WARN__
3104  << "Error occurred loading latest group info into cache for '"
3105  << groupInfo.first << "(" << groupInfo.second.latestKey_ << ")': \n"
3106  << e.what() << __E__;
3107 
3108  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
3109  groupInfo.second.latestKeyGroupComment_ =
3110  ConfigurationManager::UNKNOWN_INFO;
3111  groupInfo.second.latestKeyGroupAuthor_ =
3112  ConfigurationManager::UNKNOWN_INFO;
3113  groupInfo.second.latestKeyGroupCreationTime_ =
3114  ConfigurationManager::UNKNOWN_TIME;
3115  groupInfo.second.latestKeyGroupTypeString_ =
3116  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
3117  groupInfo.second.latestKeyMemberMap_ = {};
3118  }
3119  catch(...)
3120  {
3121  __GEN_COUT_WARN__
3122  << "Error occurred loading latest group info into cache for '"
3123  << groupInfo.first << "(" << groupInfo.second.latestKey_ << ")'..."
3124  << __E__;
3125 
3126  groupInfo.second.latestKey_ = TableGroupKey::INVALID;
3127  groupInfo.second.latestKeyGroupComment_ =
3128  ConfigurationManager::UNKNOWN_INFO;
3129  groupInfo.second.latestKeyGroupAuthor_ =
3130  ConfigurationManager::UNKNOWN_INFO;
3131  groupInfo.second.latestKeyGroupCreationTime_ =
3132  ConfigurationManager::UNKNOWN_TIME;
3133  groupInfo.second.latestKeyGroupTypeString_ =
3134  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
3135  groupInfo.second.latestKeyMemberMap_ = {};
3136  }
3137  } // end group info loop
3138  __GEN_COUTV__(runTimeSeconds());
3139  } // end get group info
3140  catch(const std::runtime_error& e)
3141  {
3142  __SS__ << "A fatal error occurred reading the info for all table groups. Error: "
3143  << e.what() << __E__;
3144  __GEN_COUT_ERR__ << "\n" << ss.str();
3145  if(accumulatedWarnings)
3146  *accumulatedWarnings += ss.str();
3147  else
3148  throw;
3149  }
3150  catch(...)
3151  {
3152  __SS__ << "An unknown fatal error occurred reading the info for all table groups."
3153  << __E__;
3154  __GEN_COUT_ERR__ << "\n" << ss.str();
3155  if(accumulatedWarnings)
3156  *accumulatedWarnings += ss.str();
3157  else
3158  throw;
3159  } //end catch
3160 
3161  __GEN_COUT__ << "testXDAQContext() end runTimeSeconds()=" << runTimeSeconds()
3162  << __E__;
3163  return;
3164 
3165  try
3166  {
3167  __GEN_COUT__ << "Loading table..." << __E__;
3168  loadTableGroup("FETest", TableGroupKey(2)); // Context_1
3169  ConfigurationTree t = getNode("/FETable/DEFAULT/FrontEndType");
3170 
3171  std::string v;
3172 
3173  __GEN_COUT__ << __E__;
3174  t.getValue(v);
3175  __GEN_COUT__ << "Value: " << v << __E__;
3176  __GEN_COUT__ << "Value index: " << t.getValue<int>() << __E__;
3177 
3178  return;
3179  }
3180  catch(...)
3181  {
3182  __GEN_COUT__ << "Failed to load table..." << __E__;
3183  }
3184 } //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())
TableBase * getVersionedTableByName(const std::string &tableName, TableVersion version, bool looseColumnMatching=false, std::string *accumulatedErrors=0, bool getRawData=false)
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
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)
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
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:1734
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:1845
const unsigned int MAX_VIEWS_IN_CACHE
Definition: TableBase.h:22
TableVersion getNextVersion(void) const
Definition: TableBase.cc:1821
TableVersion copyView(const TableView &sourceView, TableVersion destinationVersion, const std::string &author, bool looseColumnMatching=false)
Definition: TableBase.cc:1675
void print(std::ostream &out=std::cout) const
always prints active view
Definition: TableBase.cc:277
TableVersion getNextTemporaryVersion(void) const
Definition: TableBase.cc:1798
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
int fillFromJSON(const std::string &json)
Definition: TableView.cc:2344
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1943
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)