tdaq-develop-2025-02-12
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 = getContextMemberNames();
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,
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  while(foundThreadIndex == -1)
422  {
423  for(int i = 0; i < numOfThreads; ++i)
424  if(*(threadDone[i]))
425  {
426  foundThreadIndex = i;
427  break;
428  }
429  if(foundThreadIndex == -1)
430  {
431  __GEN_COUT_TYPE__(TLVL_DEBUG + 2)
432  << __COUT_HDR__ << "Waiting for available thread..."
433  << __E__;
434  usleep(10000);
435  }
436  } //end thread search loop
437  threadsLaunched = numOfThreads - 1;
438  }
439  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex
440  << " for table " << tableName << __E__;
441 
442  *(threadDone[foundThreadIndex]) = false;
443  std::thread(
444  [](ConfigurationManagerRW* theCfgMgr,
445  std::string theTableName,
446  TableBase* existingTable,
447  std::shared_ptr<ots::TableInfo> theTableInfo,
448  std::shared_ptr<std::atomic<bool>> theThreadDone) {
450  theTableName,
451  existingTable,
452  theTableInfo,
453  theThreadDone);
454  },
455  this,
456  tableName,
457  nameToTableMap_[tableName],
458  sharedTableInfoPtrs.back(),
459  threadDone[foundThreadIndex])
460  .detach();
461 
462  ++threadsLaunched;
463  ++foundThreadIndex;
464  } //end table name handling from directory
465  closedir(pDIR);
466  } //end tableInfo thread loop
467 
468  //check for all threads done
469  do
470  {
471  foundThreadIndex = -1;
472  for(int i = 0; i < numOfThreads; ++i)
473  if(!*(threadDone[i]))
474  {
475  foundThreadIndex = i;
476  break;
477  }
478  if(foundThreadIndex != -1)
479  {
480  __GEN_COUTT__ << "Waiting for thread to finish... "
481  << foundThreadIndex << __E__;
482  usleep(10000);
483  }
484  } while(foundThreadIndex != -1); //end thread done search loop
485 
486  //threads done now, so copy table info
487  for(auto& tableInfo : sharedTableInfoPtrs)
488  {
489  __GEN_COUT_TYPE__(TLVL_DEBUG + 2)
490  << __COUT_HDR__ << "Copying table info for "
491  << tableInfo->tablePtr_->getTableName() << __E__;
492  nameToTableMap_[tableInfo->tablePtr_->getTableName()] =
493  tableInfo->tablePtr_;
494  allTableInfo_[tableInfo->tablePtr_->getTableName()].tablePtr_ =
495  tableInfo->tablePtr_;
496  allTableInfo_[tableInfo->tablePtr_->getTableName()].versions_ =
497  tableInfo->versions_;
498  } //end copy group info loop
499  }
500  __GEN_COUT__ << "Extracting list of tables complete." << __E__;
501  } //end Extracting list of tables
502 
503  // call init to load active versions by default, activate with warnings allowed (assuming development going on)
504  if(initializeActiveGroups)
505  {
506  __GEN_COUT__ << "Now initializing..." << __E__;
507  // if there is a filter name, do not include init warnings (it just scares people in the table editor)
508  std::string tmpAccumulateWarnings;
509  init(0 /*accumulatedErrors*/,
510  false /*initForWriteAccess*/,
511  accumulatedWarnings ? &tmpAccumulateWarnings : nullptr);
512 
513  if(accumulatedWarnings && errorFilterName == "")
514  *accumulatedWarnings += tmpAccumulateWarnings;
515  }
516  __GEN_COUT__ << "======================================================== "
517  "getAllTableInfo end runTimeSeconds()="
518  << runTimeSeconds() << __E__;
519 
520  // get Group Info too!
521  if(getGroupKeys || getGroupInfo)
522  {
523  allGroupInfo_.clear();
524  try
525  {
526  // build allGroupInfo_ for the ConfigurationManagerRW
527 
528  std::set<std::string /*name*/> tableGroups =
529  theInterface_->getAllTableGroupNames();
530  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
531 
532  __GEN_COUTT__ << "Group Info start runTimeSeconds()=" << runTimeSeconds()
533  << __E__;
534 
535  TableGroupKey key;
536  std::string name;
537  for(const auto& fullName : tableGroups)
538  {
539  TableGroupKey::getGroupNameAndKey(fullName, name, key);
540  cacheGroupKey(name, key);
541  }
542 
543  __GEN_COUTT__ << "Group Keys end runTimeSeconds()=" << runTimeSeconds()
544  << __E__;
545 
546  // for each group get member map & comment, author, time, and type for latest key
547  if(getGroupInfo)
548  {
549  const int numOfThreads = PROCESSOR_COUNT / 2;
550  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> "
551  << numOfThreads << " threads." << __E__;
552  if(numOfThreads < 2) // no multi-threading
553  for(auto& groupInfo : allGroupInfo_)
554  {
555  try
556  {
558  groupInfo.first /*groupName*/,
559  groupInfo.second.getLatestKey(),
560  false /*doActivate*/,
561  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
562  0 /*progressBar*/,
563  0 /*accumulateErrors*/,
564  &groupInfo.second.latestKeyGroupComment_,
565  &groupInfo.second.latestKeyGroupAuthor_,
566  &groupInfo.second.latestKeyGroupCreationTime_,
567  true /*doNotLoadMember*/,
568  &groupInfo.second.latestKeyGroupTypeString_);
569  }
570  catch(...)
571  {
572  __GEN_COUT_WARN__ << "Error occurred loading latest group "
573  "info into cache for '"
574  << groupInfo.first << "("
575  << groupInfo.second.getLatestKey()
576  << ")'..." << __E__;
577  groupInfo.second.latestKeyGroupComment_ =
578  ConfigurationManager::UNKNOWN_INFO;
579  groupInfo.second.latestKeyGroupAuthor_ =
580  ConfigurationManager::UNKNOWN_INFO;
581  groupInfo.second.latestKeyGroupCreationTime_ =
582  ConfigurationManager::UNKNOWN_TIME;
583  groupInfo.second.latestKeyGroupTypeString_ =
584  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
585  groupInfo.second.latestKeyMemberMap_ = {};
586  }
587  } // end group info loop
588  else //multi-threading
589  {
590  int threadsLaunched = 0;
591  int foundThreadIndex = 0;
592 
593  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
594  for(int i = 0; i < numOfThreads; ++i)
595  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
596 
597  std::vector<std::shared_ptr<ots::GroupInfo>> sharedGroupInfoPtrs;
598 
599  for(auto& groupInfo : allGroupInfo_)
600  {
601  //make temporary group info for thread
602  sharedGroupInfoPtrs.push_back(std::make_shared<ots::GroupInfo>());
603 
604  if(threadsLaunched >= numOfThreads)
605  {
606  //find availableThreadIndex
607  foundThreadIndex = -1;
608  while(foundThreadIndex == -1)
609  {
610  for(int i = 0; i < numOfThreads; ++i)
611  if(*(threadDone[i]))
612  {
613  foundThreadIndex = i;
614  break;
615  }
616  if(foundThreadIndex == -1)
617  {
618  __GEN_COUTT__ << "Waiting for available thread..."
619  << __E__;
620  usleep(10000);
621  }
622  } //end thread search loop
623  threadsLaunched = numOfThreads - 1;
624  }
625  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex
626  << " for " << groupInfo.first << "("
627  << groupInfo.second.getLatestKey() << ")" << __E__;
628 
629  *(threadDone[foundThreadIndex]) = false;
630 
631  std::thread(
632  [](ConfigurationManagerRW* theCfgMgr,
633  std::string theGroupName,
634  ots::TableGroupKey theGroupKey,
635  std::shared_ptr<ots::GroupInfo> theGroupInfo,
636  std::shared_ptr<std::atomic<bool>> theThreadDone) {
638  theCfgMgr,
639  theGroupName,
640  theGroupKey,
641  theGroupInfo,
642  theThreadDone);
643  },
644  this,
645  groupInfo.first,
646  groupInfo.second.getLatestKey(),
647  sharedGroupInfoPtrs.back(),
648  threadDone[foundThreadIndex])
649  .detach();
650 
651  ++threadsLaunched;
652  ++foundThreadIndex;
653  } //end groupInfo thread loop
654 
655  //check for all threads done
656  do
657  {
658  foundThreadIndex = -1;
659  for(int i = 0; i < numOfThreads; ++i)
660  if(!*(threadDone[i]))
661  {
662  foundThreadIndex = i;
663  break;
664  }
665  if(foundThreadIndex != -1)
666  {
667  __GEN_COUTT__ << "Waiting for thread to finish... "
668  << foundThreadIndex << __E__;
669  usleep(10000);
670  }
671  } while(foundThreadIndex != -1); //end thread done search loop
672 
673  //threads done now, so copy group info
674  size_t i = 0;
675  for(auto& groupInfo : allGroupInfo_)
676  {
677  groupInfo.second.latestKeyGroupComment_ =
678  sharedGroupInfoPtrs[i]->latestKeyGroupComment_;
679  groupInfo.second.latestKeyGroupAuthor_ =
680  sharedGroupInfoPtrs[i]->latestKeyGroupAuthor_;
681  groupInfo.second.latestKeyGroupCreationTime_ =
682  sharedGroupInfoPtrs[i]->latestKeyGroupCreationTime_;
683  groupInfo.second.latestKeyGroupTypeString_ =
684  sharedGroupInfoPtrs[i]->latestKeyGroupTypeString_;
685  groupInfo.second.latestKeyMemberMap_ =
686  sharedGroupInfoPtrs[i]->latestKeyMemberMap_;
687  ++i;
688  } //end copy group info loop
689 
690  } //end multi-thread handling
691  }
692  } // end get group info
693  catch(const std::runtime_error& e)
694  {
695  __SS__
696  << "A fatal error occurred reading the info for all table groups. Error: "
697  << e.what() << __E__;
698  __GEN_COUT_ERR__ << "\n" << ss.str();
699  if(accumulatedWarnings)
700  *accumulatedWarnings += ss.str();
701  else
702  throw;
703  }
704  catch(...)
705  {
706  __SS__ << "An unknown fatal error occurred reading the info for all table "
707  "groups."
708  << __E__;
709  try
710  {
711  throw;
712  } //one more try to printout extra info
713  catch(const std::exception& e)
714  {
715  ss << "Exception message: " << e.what();
716  }
717  catch(...)
718  {
719  }
720  __GEN_COUT_ERR__ << "\n" << ss.str();
721  if(accumulatedWarnings)
722  *accumulatedWarnings += ss.str();
723  else
724  throw;
725  }
726  __GEN_COUTT__ << "Group Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
727  } //end getGroupInfo
728  else
729  __GEN_COUTT__ << "Table Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
730 
731  return allTableInfo_;
732 } // end getAllTableInfo()
733 
734 //==============================================================================
737  ConfigurationManagerRW* cfgMgr,
738  std::string tableName,
739  TableBase* existingTable,
740  std::shared_ptr<ots::TableInfo> tableInfo,
741  std::shared_ptr<std::atomic<bool>> threadDone)
742 try
743 {
744  __COUTT__ << "Thread started... table " << tableName << __E__;
745 
746  // 0 will force the creation of new instance (and reload from Info)
747  tableInfo->tablePtr_ = 0;
748 
749  try // only add valid table instances to maps
750  {
751  cfgMgr->theInterface_->get(tableInfo->tablePtr_,
752  tableName,
753  0,
754  0,
755  true); // dont fill
756  }
757  catch(cet::exception const&)
758  {
759  if(tableInfo->tablePtr_)
760  delete tableInfo->tablePtr_;
761  tableInfo->tablePtr_ = 0;
762 
763  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
764  *(threadDone) = true;
765  return;
766  }
767  catch(std::runtime_error& e)
768  {
769  if(tableInfo->tablePtr_)
770  delete tableInfo->tablePtr_;
771  tableInfo->tablePtr_ = 0;
772 
773  __COUT__ << "Skipping! No valid class found for... " << tableName << "\n";
774  __COUTT__ << "Error: " << e.what() << __E__;
775 
776  // for a runtime_error, it is likely that columns are the problem
777  // the Table Editor needs to still fix these.. so attempt to
778  // proceed.
779  if(tableInfo->accumulatedWarnings_ == "ALLOW")
780  {
781  tableInfo->accumulatedWarnings_ = "";
782  if(1) //errorFilterName == "" || errorFilterName == tableName)
783  {
784  tableInfo->accumulatedWarnings_ += std::string("\nIn table '") +
785  tableName + "'..." +
786  e.what(); // global accumulate
787 
788  __SS__ << "Attempting to allow illegal columns!" << __E__;
789  tableInfo->accumulatedWarnings_ += ss.str();
790  }
791 
792  // attempt to recover and build a mock-up
793  __COUT__ << "Attempting to allow illegal columns!" << __E__;
794 
795  std::string returnedAccumulatedErrors;
796  try
797  {
798  tableInfo->tablePtr_ =
799  new TableBase(tableName, &returnedAccumulatedErrors);
800  }
801  catch(...)
802  {
803  __COUT__ << "Skipping! Allowing illegal columns didn't work either... "
804  << tableName << "\n";
805  *(threadDone) = true;
806  return;
807  }
808  __COUT_WARN__ << "Error (but allowed): " << returnedAccumulatedErrors
809  << __E__;
810 
811  if(1) //errorFilterName == "" || errorFilterName == entry->d_name)
812  tableInfo->accumulatedWarnings_ +=
813  std::string("\nIn table '") + tableName + "'..." +
814  returnedAccumulatedErrors; // global accumulate
815  }
816  else
817  {
818  tableInfo->accumulatedWarnings_ = "";
819  *(threadDone) = true;
820  return;
821  }
822  }
823 
824  if(existingTable) // handle if instance existed
825  {
826  __COUTT__ << "Copying temporary version from existing table object for "
827  << tableName << __E__;
828  // copy the existing temporary versions! (or else all is lost)
829  std::set<TableVersion> versions = existingTable->getStoredVersions();
830  for(auto& version : versions)
831  if(version.isTemporaryVersion())
832  {
833  try // do NOT let TableView::init() throw here
834  {
835  existingTable->setActiveView(version);
836  tableInfo->tablePtr_->copyView( // this calls TableView::init()
837  existingTable->getView(),
838  version,
839  cfgMgr->username_);
840  }
841  catch(...) // do NOT let invalid temporary version throw at this
842  // point
843  {
844  } // just trust configurationBase throws out the failed version
845  }
846 
847  delete existingTable;
848  existingTable = 0;
849  }
850 
851  tableInfo->versions_ = cfgMgr->theInterface_->getVersions(tableInfo->tablePtr_);
852 
853  // also add any existing temporary versions to all table info
854  // because the interface wont find those versions
855  std::set<TableVersion> versions = tableInfo->tablePtr_->getStoredVersions();
856  for(auto& version : versions)
857  if(version.isTemporaryVersion())
858  {
859  tableInfo->versions_.emplace(version);
860  }
861 
862  __COUTT__ << "Thread done... table " << tableName << __E__;
863  *(threadDone) = true;
864 } // end loadTableInfoThread
865 catch(...)
866 {
867  __COUT_ERR__ << "Error occurred loading latest table info into cache for '"
868  << tableName << "'..." << __E__;
869  *(threadDone) = true;
870 } // end loadTableInfoThread catch
871 
872 //==============================================================================
875  ConfigurationManagerRW* cfgMgr,
876  std::string groupName,
877  ots::TableGroupKey groupKey,
878  std::shared_ptr<ots::GroupInfo> groupInfo,
879  std::shared_ptr<std::atomic<bool>> threadDone)
880 try
881 {
882  __COUTT__ << "Thread started... " << groupName << "(" << groupKey << ")" << __E__;
883 
884  cfgMgr->loadTableGroup(groupName /*groupName*/,
885  groupKey, //groupInfo->getLatestKey(),
886  false /*doActivate*/,
887  &(groupInfo->latestKeyMemberMap_) /*groupMembers*/,
888  0 /*progressBar*/,
889  0 /*accumulateErrors*/,
890  &(groupInfo->latestKeyGroupComment_),
891  &(groupInfo->latestKeyGroupAuthor_),
892  &(groupInfo->latestKeyGroupCreationTime_),
893  true /*doNotLoadMember*/,
894  &(groupInfo->latestKeyGroupTypeString_));
895 
896  *(threadDone) = true;
897 } // end loadTableGroupThread
898 catch(...)
899 {
900  __COUT_WARN__ << "Error occurred loading latest group info into cache for '"
901  << groupName << "(" << groupInfo->getLatestKey() << ")'..." << __E__;
902  groupInfo->latestKeyGroupComment_ = ConfigurationManager::UNKNOWN_INFO;
903  groupInfo->latestKeyGroupAuthor_ = ConfigurationManager::UNKNOWN_INFO;
904  groupInfo->latestKeyGroupCreationTime_ = ConfigurationManager::UNKNOWN_TIME;
905  groupInfo->latestKeyGroupTypeString_ = ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
906  groupInfo->latestKeyMemberMap_ = {};
907  *(threadDone) = true;
908 } // end loadTableGroupThread catch
909 
910 //==============================================================================
913  ConfigurationManagerRW* cfgMgr,
914  std::string groupName,
915  ots::TableGroupKey groupKeyToCompare,
916  const std::map<std::string, TableVersion>& groupMemberMap,
917  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases,
918  std::atomic<bool>* foundIdentical,
919  ots::TableGroupKey* identicalKey,
920  std::mutex* threadMutex,
921  std::shared_ptr<std::atomic<bool>> threadDone)
922 try
923 {
924  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
925  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
926  std::map<std::string /*name*/, std::string /*alias*/>*
927  compareToMemberTableAliasesPtr = nullptr;
928  if(memberTableAliases
929  .size()) //only give pointer if necessary, without will load group faster
930  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
931 
932  cfgMgr->loadTableGroup(groupName,
933  groupKeyToCompare,
934  false /*doActivate*/,
935  &compareToMemberMap /*memberMap*/,
936  0, /*progressBar*/
937  0, /*accumulatedWarnings*/
938  0, /*groupComment*/
939  0,
940  0, /*null pointers*/
941  true /*doNotLoadMember*/,
942  0 /*groupTypeString*/,
943  compareToMemberTableAliasesPtr);
944 
945  bool isDifferent = false;
946  for(auto& memberPair : groupMemberMap)
947  {
948  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
949  {
950  // handle this table as alias, not version
951  if(compareToMemberTableAliases.find(memberPair.first) ==
952  compareToMemberTableAliases.end() || // alias is missing
953  memberTableAliases.at(memberPair.first) !=
954  compareToMemberTableAliases.at(memberPair.first))
955  { // then different
956  isDifferent = true;
957  break;
958  }
959  else
960  continue;
961  } // else check if compareTo group is using an alias for table
962  else if(compareToMemberTableAliases.find(memberPair.first) !=
963  compareToMemberTableAliases.end())
964  {
965  // then different
966  isDifferent = true;
967  break;
968 
969  } // else handle as table version comparison
970  else if(compareToMemberMap.find(memberPair.first) ==
971  compareToMemberMap.end() || // name is missing
972  memberPair.second !=
973  compareToMemberMap.at(memberPair.first)) // or version mismatch
974  {
975  // then different
976  isDifferent = true;
977  break;
978  }
979  }
980 
981  // check member size for exact match
982  if(!isDifferent && groupMemberMap.size() != compareToMemberMap.size())
983  isDifferent =
984  true; // different size, so not same (groupMemberMap is a subset of memberPairs)
985 
986  if(!isDifferent) //found an exact match!
987  {
988  *foundIdentical = true;
989  __COUT__ << "=====> Found exact match with key: " << groupKeyToCompare << __E__;
990 
991  std::lock_guard<std::mutex> lock(*threadMutex);
992  *identicalKey = groupKeyToCompare;
993  }
994 
995  *(threadDone) = true;
996 } // end compareTableGroupThread
997 catch(...)
998 {
999  __COUT_WARN__ << "Error occurred comparing group '" << groupName << "("
1000  << groupKeyToCompare << ")'..." << __E__;
1001 
1002  *(threadDone) = true;
1003 } // end compareTableGroupThread catch
1004 
1005 //==============================================================================
1009 std::map<std::string /*table name*/,
1010  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1012 {
1013  std::map<std::string /*table name*/,
1014  std::map<std::string /*version alias*/, TableVersion /*aliased version*/>>
1016 
1017  // always have scratch alias for each table that has a scratch version
1018  // overwrite map entry if necessary
1019  if(!ConfigurationInterface::isVersionTrackingEnabled())
1020  for(const auto& tableInfo : allTableInfo_)
1021  for(const auto& version : tableInfo.second.versions_)
1022  if(version.isScratchVersion())
1023  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
1024  TableVersion(TableVersion::SCRATCH);
1025 
1026  return retMap;
1027 } // end getVersionAliases()
1028 
1029 //==============================================================================
1033 void ConfigurationManagerRW::activateTableGroup(const std::string& tableGroupName,
1034  TableGroupKey tableGroupKey,
1035  std::string* accumulatedTreeErrors,
1036  std::string* groupTypeString)
1037 {
1038  try
1039  {
1040  loadTableGroup(tableGroupName,
1041  tableGroupKey,
1042  true, // loads and activates
1043  0, // no members needed
1044  0, // no progress bar
1045  accumulatedTreeErrors, // accumulate warnings or not
1046  0 /* groupComment */,
1047  0 /* groupAuthor */,
1048  0 /* groupCreateTime */,
1049  false /* doNotLoadMember */,
1050  groupTypeString);
1051  }
1052  catch(...)
1053  {
1054  __GEN_COUT_ERR__ << "There were errors, so de-activating group: "
1055  << tableGroupName << " (" << tableGroupKey << ")" << __E__;
1056  try // just in case any lingering pieces, let's deactivate
1057  {
1058  destroyTableGroup(tableGroupName, true);
1059  }
1060  catch(...)
1061  {
1062  }
1063  throw; // re-throw original exception
1064  }
1065 
1066  __GEN_COUT_INFO__ << "Updating persistent active groups to "
1067  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..." << __E__;
1068 
1069  __COUT_INFO__ << "Active Context table group: " << theContextTableGroup_ << "("
1070  << (theContextTableGroupKey_
1071  ? theContextTableGroupKey_->toString().c_str()
1072  : "-1")
1073  << ")" << __E__;
1074  __COUT_INFO__ << "Active Backbone table group: " << theBackboneTableGroup_ << "("
1075  << (theBackboneTableGroupKey_
1076  ? theBackboneTableGroupKey_->toString().c_str()
1077  : "-1")
1078  << ")" << __E__;
1079  __COUT_INFO__ << "Active Iterate table group: " << theIterateTableGroup_ << "("
1080  << (theIterateTableGroupKey_
1081  ? theIterateTableGroupKey_->toString().c_str()
1082  : "-1")
1083  << ")" << __E__;
1084  __COUT_INFO__ << "Active Configuration table group: " << theConfigurationTableGroup_
1085  << "("
1086  << (theConfigurationTableGroupKey_
1087  ? theConfigurationTableGroupKey_->toString().c_str()
1088  : "-1")
1089  << ")" << __E__;
1090 
1092  FILE* fp = fopen(fn.c_str(), "w");
1093  if(!fp)
1094  {
1095  __SS__ << "Fatal Error! Unable to open the file "
1097  << " for editing! Is there a permissions problem?" << __E__;
1098  __GEN_COUT_ERR__ << ss.str();
1099  __SS_THROW__;
1100  return;
1101  }
1102  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
1103  fprintf(
1104  fp,
1105  "%s\n",
1106  theContextTableGroupKey_ ? theContextTableGroupKey_->toString().c_str() : "-1");
1107  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
1108  fprintf(
1109  fp,
1110  "%s\n",
1111  theBackboneTableGroupKey_ ? theBackboneTableGroupKey_->toString().c_str() : "-1");
1112  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
1113  fprintf(
1114  fp,
1115  "%s\n",
1116  theIterateTableGroupKey_ ? theIterateTableGroupKey_->toString().c_str() : "-1");
1117  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
1118  fprintf(fp,
1119  "%s\n",
1120  theConfigurationTableGroupKey_
1121  ? theConfigurationTableGroupKey_->toString().c_str()
1122  : "-1");
1123  fclose(fp);
1124 
1125  // save last activated group
1126  {
1127  std::pair<std::string /*group name*/, TableGroupKey> activatedGroup(
1128  std::string(tableGroupName), tableGroupKey);
1129  if(theConfigurationTableGroupKey_ &&
1130  theConfigurationTableGroup_ == tableGroupName &&
1131  *theConfigurationTableGroupKey_ == tableGroupKey)
1132  ConfigurationManager::saveGroupNameAndKey(activatedGroup,
1133  LAST_ACTIVATED_CONFIG_GROUP_FILE);
1134  else if(theContextTableGroupKey_ && theContextTableGroup_ == tableGroupName &&
1135  *theContextTableGroupKey_ == tableGroupKey)
1136  ConfigurationManager::saveGroupNameAndKey(activatedGroup,
1137  LAST_ACTIVATED_CONTEXT_GROUP_FILE);
1138  else if(theBackboneTableGroupKey_ && theBackboneTableGroup_ == tableGroupName &&
1139  *theBackboneTableGroupKey_ == tableGroupKey)
1140  ConfigurationManager::saveGroupNameAndKey(activatedGroup,
1141  LAST_ACTIVATED_BACKBONE_GROUP_FILE);
1142  else if(theIterateTableGroupKey_ && theIterateTableGroup_ == tableGroupName &&
1143  *theIterateTableGroupKey_ == tableGroupKey)
1144  ConfigurationManager::saveGroupNameAndKey(activatedGroup,
1145  LAST_ACTIVATED_ITERATOR_GROUP_FILE);
1146  } // end save last activated group
1147 
1148 } // end activateTableGroup()
1149 
1150 //==============================================================================
1155  TableVersion sourceViewVersion)
1156 {
1157  __GEN_COUT_INFO__ << "Creating temporary backbone view from version "
1158  << sourceViewVersion << __E__;
1159 
1160  // find common available temporary version among backbone members
1161  TableVersion tmpVersion =
1162  TableVersion::getNextTemporaryVersion(); // get the default temporary version
1163  TableVersion retTmpVersion;
1164  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1165  for(auto& name : backboneMemberNames)
1166  {
1167  retTmpVersion =
1169  if(retTmpVersion < tmpVersion)
1170  tmpVersion = retTmpVersion;
1171  }
1172 
1173  __GEN_COUT__ << "Common temporary backbone version found as " << tmpVersion << __E__;
1174 
1175  // create temporary views from source version to destination temporary version
1176  for(auto& name : backboneMemberNames)
1177  {
1178  retTmpVersion =
1179  getTableByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
1180  if(retTmpVersion != tmpVersion)
1181  {
1182  __SS__ << "Failure! Temporary view requested was " << tmpVersion
1183  << ". Mismatched temporary view created: " << retTmpVersion << __E__;
1184  __GEN_COUT_ERR__ << ss.str();
1185  __SS_THROW__;
1186  }
1187  }
1188 
1189  return tmpVersion;
1190 } // end createTemporaryBackboneView()
1191 
1192 //==============================================================================
1193 TableBase* ConfigurationManagerRW::getTableByName(const std::string& tableName)
1194 {
1195  if(nameToTableMap_.find(tableName) == nameToTableMap_.end())
1196  {
1197  if(tableName == ConfigurationManager::ARTDAQ_TOP_TABLE_NAME)
1198  {
1199  __GEN_COUT_WARN__
1200  << "Since target table was the artdaq top configuration level, "
1201  "attempting to help user by appending to core tables file: "
1202  << CORE_TABLE_INFO_FILENAME << __E__;
1203  FILE* fp = fopen((CORE_TABLE_INFO_FILENAME).c_str(), "a");
1204  if(fp)
1205  {
1206  fprintf(fp, "\nARTDAQ/*");
1207  fclose(fp);
1208  }
1209  }
1210 
1211  __SS__ << "Table not found with name: " << tableName << __E__;
1212  size_t f;
1213  if((f = tableName.find(' ')) != std::string::npos)
1214  ss << "There was a space character found in the table name needle at "
1215  "position "
1216  << f << " in the string (was this intended?). " << __E__;
1217 
1218  ss << "\nIf you think this table should exist in the core set of tables, try "
1219  "running 'UpdateOTS.sh --tables' to update your tables, then relaunch ots."
1220  << __E__;
1221  ss << "\nTables must be defined at path $USER_DATA/TableInfo/ to exist in ots. "
1222  "Please verify your table definitions, and then restart ots."
1223  << __E__;
1224  __GEN_COUT_ERR__ << "\n" << ss.str();
1225  __SS_THROW__;
1226  }
1227  return nameToTableMap_[tableName];
1228 } // end getTableByName()
1229 
1230 //==============================================================================
1236  const std::string& tableName,
1237  TableVersion version,
1238  bool looseColumnMatching /* = false */,
1239  std::string* accumulatedErrors /* = 0 */,
1240  bool getRawData /* = false */)
1241 {
1242  auto it = nameToTableMap_.find(tableName);
1243  if(it == nameToTableMap_.end())
1244  {
1245  __SS__ << "\nCan not find table named '" << tableName
1246  << "'\n\n\n\nYou need to load the table before it can be used."
1247  << "It probably is missing from the member list of the Table "
1248  "Group that was loaded?\n\n\n\n\n"
1249  << __E__;
1250  __SS_THROW__;
1251  }
1252  TableBase* table = it->second;
1253 
1254  if(version.isTemporaryVersion())
1255  {
1256  table->setActiveView(version);
1257 
1258  if(getRawData)
1259  {
1260  std::stringstream jsonSs;
1261  table->getViewP()->printJSON(jsonSs);
1262  table->getViewP()->doGetSourceRawData(true);
1263  table->getViewP()->fillFromJSON(jsonSs.str());
1264  }
1265  }
1266  else
1267  {
1268  theInterface_->get(table,
1269  tableName,
1270  0 /* groupKey */,
1271  0 /* groupName */,
1272  false /* dontFill */, // false to fill w/version
1273  version,
1274  false /* resetConfiguration*/, // false to not reset
1275  looseColumnMatching,
1276  getRawData,
1277  accumulatedErrors);
1278  }
1279  return table;
1280 } // end getVersionedTableByName()
1281 
1282 //==============================================================================
1286  TableVersion temporaryVersion,
1287  bool makeTemporary) //,
1289 {
1290  TableVersion newVersion(temporaryVersion);
1291 
1292  // set author of version
1293  TableBase* table = getTableByName(tableName);
1294  table->getTemporaryView(temporaryVersion)->setAuthor(username_);
1295  // NOTE: author is assigned to permanent versions when saved to DBI
1296 
1297  if(!makeTemporary) // saveNewVersion makes the new version the active version
1298  newVersion = theInterface_->saveNewVersion(table, temporaryVersion);
1299  else // make the temporary version active
1300  table->setActiveView(newVersion);
1301 
1302  // if there is a problem, try to recover
1303  while(!makeTemporary && !newVersion.isScratchVersion() &&
1304  allTableInfo_[tableName].versions_.find(newVersion) !=
1305  allTableInfo_[tableName].versions_.end())
1306  {
1307  __GEN_COUT_ERR__
1308  << "What happenened!?? ERROR::: new persistent version v" << newVersion
1309  << " already exists!? How is it possible? Retrace your steps and "
1310  "tell an admin."
1311  << __E__;
1312 
1313  // create a new temporary version of the target view
1314  temporaryVersion = table->createTemporaryView(newVersion);
1315 
1316  if(newVersion.isTemporaryVersion())
1317  newVersion = temporaryVersion;
1318  else
1319  newVersion = TableVersion::getNextVersion(newVersion);
1320 
1321  __GEN_COUT_WARN__ << "Attempting to recover and use v" << newVersion << __E__;
1322 
1323  if(!makeTemporary) // saveNewVersion makes the new version the active version
1324  newVersion =
1325  theInterface_->saveNewVersion(table, temporaryVersion, newVersion);
1326  else // make the temporary version active
1327  table->setActiveView(newVersion);
1328  }
1329 
1330  if(newVersion.isInvalid())
1331  {
1332  __SS__ << "Something went wrong saving the new version v" << newVersion
1333  << ". What happened?! (duplicates? database error?)" << __E__;
1334  __GEN_COUT_ERR__ << "\n" << ss.str();
1335  __SS_THROW__;
1336  }
1337 
1338  // update allTableInfo_ with the new version
1339  allTableInfo_[tableName].versions_.insert(newVersion);
1340 
1341  // table->getView().print();
1342  return newVersion;
1343 } // end saveNewTable()
1344 
1345 //==============================================================================
1350 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string& tableName,
1351  TableVersion targetVersion)
1352 {
1353  TableBase* table = getTableByName(tableName);
1354 
1355  table->trimTemporary(targetVersion);
1356 
1357  // if allTableInfo_ is not setup, then done
1358  if(allTableInfo_.find(tableName) == allTableInfo_.end())
1359  return;
1360  // else cleanup table info
1361 
1362  if(targetVersion.isInvalid())
1363  {
1364  // erase all temporary versions!
1365  for(auto it = allTableInfo_[tableName].versions_.begin();
1366  it != allTableInfo_[tableName].versions_.end();
1367  /*no increment*/)
1368  {
1369  if(it->isTemporaryVersion())
1370  {
1371  __GEN_COUT__ << "Removing '" << tableName << "' version info: " << *it
1372  << __E__;
1373  allTableInfo_[tableName].versions_.erase(it++);
1374  }
1375  else
1376  ++it;
1377  }
1378  }
1379  else // erase target version only
1380  {
1381  //__GEN_COUT__ << "Removing '" << tableName << "' version info: " << targetVersion << __E__;
1382  auto it = allTableInfo_[tableName].versions_.find(targetVersion);
1383  if(it == allTableInfo_[tableName].versions_.end())
1384  {
1385  __GEN_COUT__ << "Target '" << tableName << "' version v" << targetVersion
1386  << " was not found in info versions..." << __E__;
1387  return;
1388  }
1389  allTableInfo_[tableName].versions_.erase(
1390  allTableInfo_[tableName].versions_.find(targetVersion));
1391  }
1392 } // end eraseTemporaryVersion()
1393 
1394 //==============================================================================
1399 void ConfigurationManagerRW::clearCachedVersions(const std::string& tableName)
1400 {
1401  TableBase* table = getTableByName(tableName);
1402 
1403  table->trimCache(0);
1404 } // end clearCachedVersions()
1405 
1406 //==============================================================================
1412 {
1413  for(auto configInfo : allTableInfo_)
1414  configInfo.second.tablePtr_->trimCache(0);
1415 } // end clearAllCachedVersions()
1416 
1417 //==============================================================================
1420  const std::string& tableName, TableVersion sourceVersion)
1421 {
1422  getTableByName(tableName)->reset();
1423 
1424  // make sure source version is loaded
1425  // need to load with loose column rules!
1426  TableBase* table =
1427  getVersionedTableByName(tableName, TableVersion(sourceVersion), true);
1428 
1429  // copy from source version to a new temporary version
1430  TableVersion newTemporaryVersion =
1431  table->copyView(table->getView(), TableVersion(), username_);
1432 
1433  // update allTableInfo_ with the new version
1434  allTableInfo_[tableName].versions_.insert(newTemporaryVersion);
1435 
1436  return newTemporaryVersion;
1437 } // end copyViewToCurrentColumns()
1438 
1439 //==============================================================================
1441 void ConfigurationManagerRW::cacheGroupKey(const std::string& groupName,
1442  TableGroupKey key)
1443 {
1444  allGroupInfo_[groupName].keys_.emplace(key);
1445 
1446  // __SS__ << "Now keys are: " << __E__;
1447  // for(auto& key:allGroupInfo_[groupName].keys_)
1448  // ss << "\t" << key << __E__;
1449  // __GEN_COUT__ << ss.str() << __E__;
1450 } // end cacheGroupKey()
1451 
1452 //==============================================================================
1456 const GroupInfo& ConfigurationManagerRW::getGroupInfo(const std::string& groupName)
1457 {
1458  // //NOTE: seems like this filter is taking the long amount of time
1459  // std::set<std::string /*name*/> fullGroupNames =
1460  // theInterface_->getAllTableGroupNames(groupName); //db filter by
1461  // group name
1462 
1463  // so instead caching ourselves...
1464  auto it = allGroupInfo_.find(groupName);
1465  if(it == allGroupInfo_.end())
1466  {
1467  __SS__ << "Group name '" << groupName
1468  << "' not found in group info! (creating empty info)" << __E__;
1469  __GEN_COUT_WARN__ << ss.str();
1470  //__SS_THROW__;
1471  return allGroupInfo_[groupName];
1472  }
1473  return it->second;
1474 } // end getGroupInfo()
1475 
1476 //==============================================================================
1488  const std::string& groupName,
1489  const std::map<std::string, TableVersion>& groupMemberMap,
1490  const std::map<std::string /*name*/, std::string /*alias*/>& memberTableAliases)
1491 {
1492  // //NOTE: seems like this filter is taking the long amount of time
1493  // std::set<std::string /*name*/> fullGroupNames =
1494  // theInterface_->getAllTableGroupNames(groupName); //db filter by
1495  // group name
1496  const GroupInfo& groupInfo = getGroupInfo(groupName);
1497 
1498  // std::string name;
1499  // TableGroupKey key;
1500 
1501  const unsigned int MAX_DEPTH_TO_CHECK = 20;
1502  unsigned int keyMinToCheck = 0;
1503 
1504  if(groupInfo.keys_.size())
1505  keyMinToCheck = groupInfo.keys_.rbegin()->key();
1506  if(keyMinToCheck > MAX_DEPTH_TO_CHECK)
1507  {
1508  keyMinToCheck -= MAX_DEPTH_TO_CHECK;
1509  __GEN_COUT__ << "Checking groups back to key... " << keyMinToCheck << __E__;
1510  }
1511  else
1512  {
1513  keyMinToCheck = 0;
1514  __GEN_COUT__ << "Checking all groups." << __E__;
1515  }
1516 
1517  // have min key to check, now loop through and check groups
1518 
1519  const int numOfThreads = PROCESSOR_COUNT / 2;
1520  __GEN_COUT__ << " PROCESSOR_COUNT " << PROCESSOR_COUNT << " ==> " << numOfThreads
1521  << " threads." << __E__;
1522  if(numOfThreads < 2) // no multi-threading
1523  {
1524  std::map<std::string /*name*/, TableVersion /*version*/> compareToMemberMap;
1525  std::map<std::string /*name*/, std::string /*alias*/> compareToMemberTableAliases;
1526  std::map<std::string /*name*/, std::string /*alias*/>*
1527  compareToMemberTableAliasesPtr = nullptr;
1528  if(memberTableAliases.size())
1529  compareToMemberTableAliasesPtr = &compareToMemberTableAliases;
1530 
1531  bool isDifferent;
1532  for(const auto& key : groupInfo.keys_)
1533  {
1534  if(key.key() < keyMinToCheck)
1535  continue; // skip keys that are too old
1536 
1537  loadTableGroup(groupName,
1538  key,
1539  false /*doActivate*/,
1540  &compareToMemberMap /*memberMap*/,
1541  0, /*progressBar*/
1542  0, /*accumulatedWarnings*/
1543  0, /*groupComment*/
1544  0, /*groupAuthor*/
1545  0, /*groupCreateTime*/
1546  true /*doNotLoadMember*/,
1547  0 /*groupTypeString*/,
1548  compareToMemberTableAliasesPtr);
1549 
1550  isDifferent = false;
1551  for(auto& memberPair : groupMemberMap)
1552  {
1553  if(memberTableAliases.find(memberPair.first) != memberTableAliases.end())
1554  {
1555  // handle this table as alias, not version
1556  if(compareToMemberTableAliases.find(memberPair.first) ==
1557  compareToMemberTableAliases.end() || // alias is missing
1558  memberTableAliases.at(memberPair.first) !=
1559  compareToMemberTableAliases.at(memberPair.first))
1560  { // then different
1561  isDifferent = true;
1562  break;
1563  }
1564  else
1565  continue;
1566  } // else check if compareTo group is using an alias for table
1567  else if(compareToMemberTableAliases.find(memberPair.first) !=
1568  compareToMemberTableAliases.end())
1569  {
1570  // then different
1571  isDifferent = true;
1572  break;
1573 
1574  } // else handle as table version comparison
1575  else if(compareToMemberMap.find(memberPair.first) ==
1576  compareToMemberMap.end() || // name is missing
1577  memberPair.second !=
1578  compareToMemberMap.at(
1579  memberPair.first)) // or version mismatch
1580  {
1581  // then different
1582  isDifferent = true;
1583  break;
1584  }
1585  }
1586  if(isDifferent)
1587  continue;
1588 
1589  // check member size for exact match
1590  if(groupMemberMap.size() != compareToMemberMap.size())
1591  continue; // different size, so not same (groupMemberMap is a subset of
1592  // memberPairs)
1593 
1594  __GEN_COUT__ << "Found exact match with key: " << key << __E__;
1595  // else found an exact match!
1596  return key;
1597  }
1598  __GEN_COUT__ << "No match found - this group is new!" << __E__;
1599  // if here, then no match found
1600  return TableGroupKey(); // return invalid key
1601  }
1602  else //multi-threading
1603  {
1604  int threadsLaunched = 0;
1605  int foundThreadIndex = 0;
1606  std::atomic<bool> foundIdentical = false;
1607  ots::TableGroupKey identicalKey;
1608  std::mutex threadMutex;
1609 
1610  std::vector<std::shared_ptr<std::atomic<bool>>> threadDone;
1611  for(int i = 0; i < numOfThreads; ++i)
1612  threadDone.push_back(std::make_shared<std::atomic<bool>>(true));
1613 
1614  for(const auto& key : groupInfo.keys_)
1615  {
1616  if(foundIdentical)
1617  break;
1618  if(key.key() < keyMinToCheck)
1619  continue; // skip keys that are too old
1620 
1621  if(threadsLaunched >= numOfThreads)
1622  {
1623  //find availableThreadIndex
1624  foundThreadIndex = -1;
1625  while(foundThreadIndex == -1)
1626  {
1627  if(foundIdentical)
1628  break;
1629 
1630  for(int i = 0; i < numOfThreads; ++i)
1631  if(*(threadDone[i]))
1632  {
1633  foundThreadIndex = i;
1634  break;
1635  }
1636  if(foundThreadIndex == -1)
1637  {
1638  __GEN_COUTT__ << "Waiting for available thread..." << __E__;
1639  usleep(10000);
1640  }
1641  } //end thread search loop
1642  threadsLaunched = numOfThreads - 1;
1643  }
1644  if(foundIdentical)
1645  break;
1646 
1647  __GEN_COUTT__ << "Starting thread... " << foundThreadIndex << __E__;
1648  *(threadDone[foundThreadIndex]) = false;
1649 
1650  std::thread(
1651  [](ConfigurationManagerRW* cfgMgr,
1652  std::string theGroupName,
1653  ots::TableGroupKey groupKeyToCompare,
1654  const std::map<std::string, TableVersion>& groupMemberMap,
1655  const std::map<std::string /*name*/, std::string /*alias*/>&
1656  memberTableAliases,
1657  std::atomic<bool>* theFoundIdentical,
1658  ots::TableGroupKey* theIdenticalKey,
1659  std::mutex* theThreadMutex,
1660  std::shared_ptr<std::atomic<bool>> theThreadDone) {
1662  theGroupName,
1663  groupKeyToCompare,
1664  groupMemberMap,
1665  memberTableAliases,
1666  theFoundIdentical,
1667  theIdenticalKey,
1668  theThreadMutex,
1669  theThreadDone);
1670  },
1671  this,
1672  groupName,
1673  key,
1674  groupMemberMap,
1675  memberTableAliases,
1676  &foundIdentical,
1677  &identicalKey,
1678  &threadMutex,
1679  threadDone[foundThreadIndex])
1680  .detach();
1681 
1682  ++threadsLaunched;
1683  ++foundThreadIndex;
1684  } //end groupInfo thread loop
1685 
1686  //check for all threads done
1687  do
1688  {
1689  foundThreadIndex = -1;
1690  for(int i = 0; i < numOfThreads; ++i)
1691  if(!*(threadDone[i]))
1692  {
1693  foundThreadIndex = i;
1694  break;
1695  }
1696  if(foundThreadIndex != -1)
1697  {
1698  __GEN_COUTT__ << "Waiting for thread to finish... " << foundThreadIndex
1699  << __E__;
1700  usleep(10000);
1701  }
1702  } while(foundThreadIndex != -1); //end thread done search loop
1703 
1704  if(foundIdentical)
1705  {
1706  __GEN_COUT__ << "Found exact match with key: " << identicalKey << __E__;
1707  return identicalKey;
1708  }
1709  __GEN_COUT__ << "No match found - this group is new!" << __E__;
1710  // if here, then no match found
1711  return TableGroupKey(); // return invalid key
1712  } //end multi-thread handling
1713 } // end findTableGroup()
1714 
1715 //==============================================================================
1723  const std::string& groupName,
1724  std::map<std::string, TableVersion>& groupMembers,
1725  const std::string& groupComment,
1726  std::map<std::string /*table*/, std::string /*alias*/>* groupAliases)
1727 {
1728  // steps:
1729  // determine new group key
1730  // verify group members
1731  // verify groupNameWithKey
1732  // verify store
1733 
1734  if(groupMembers.size() == 0) // do not allow empty groups
1735  {
1736  __SS__ << "Empty group member list. Can not create a group without members!"
1737  << __E__;
1738  __SS_THROW__;
1739  }
1740 
1741  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1742 
1743  // determine new group key
1744  TableGroupKey newKey =
1745  TableGroupKey::getNextKey(theInterface_->findLatestGroupKey(groupName));
1746 
1747  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1748 
1749  __GEN_COUT__ << "New Key for group: " << groupName << " found as " << newKey << __E__;
1750 
1751  // verify group members
1752  // - use all table info
1753  std::map<std::string, TableInfo> allCfgInfo = getAllTableInfo();
1754  for(auto& memberPair : groupMembers)
1755  {
1756  // check member name
1757  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
1758  {
1759  __GEN_COUT_ERR__ << "Group member \"" << memberPair.first
1760  << "\" not found in database!";
1761 
1762  if(groupMetadataTable_.getTableName() == memberPair.first)
1763  {
1764  __GEN_COUT_WARN__
1765  << "Looks like this is the groupMetadataTable_ '"
1766  << ConfigurationInterface::GROUP_METADATA_TABLE_NAME
1767  << ".' Note that this table is added to the member map when groups "
1768  "are saved."
1769  << "It should not be part of member map when calling this function."
1770  << __E__;
1771  __GEN_COUT__ << "Attempting to recover." << __E__;
1772  groupMembers.erase(groupMembers.find(memberPair.first));
1773  }
1774  else
1775  {
1776  __SS__ << ("Group member not found!") << __E__;
1777  __SS_THROW__;
1778  }
1779  }
1780  // check member version
1781  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
1782  allCfgInfo[memberPair.first].versions_.end())
1783  {
1784  __SS__ << "Group member \"" << memberPair.first << "\" version \""
1785  << memberPair.second << "\" not found in database!";
1786  __SS_THROW__;
1787  }
1788  } // end verify members
1789 
1790  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1791 
1792  // verify group aliases
1793  if(groupAliases)
1794  {
1795  for(auto& aliasPair : *groupAliases)
1796  {
1797  // check for alias table in member names
1798  if(groupMembers.find(aliasPair.first) == groupMembers.end())
1799  {
1800  __GEN_COUT_ERR__ << "Group member \"" << aliasPair.first
1801  << "\" not found in group member map!";
1802 
1803  __SS__ << ("Alias table not found in member list!") << __E__;
1804  __SS_THROW__;
1805  }
1806  }
1807  } // end verify group aliases
1808 
1809  // verify groupNameWithKey and attempt to store
1810  try
1811  {
1812  // save meta data for group; reuse groupMetadataTable_
1813  std::string groupAliasesString = "";
1814  if(groupAliases)
1815  groupAliasesString = StringMacros::mapToString(
1816  *groupAliases, "," /*primary delimeter*/, ":" /*secondary delimeter*/);
1817  __GEN_COUT__ << "Metadata: " << username_ << " " << time(0) << " " << groupComment
1818  << " " << groupAliasesString << __E__;
1819 
1820  // to compensate for unusual errors upstream, make sure the metadata table has one
1821  // row
1822  while(groupMetadataTable_.getViewP()->getNumberOfRows() > 1)
1823  groupMetadataTable_.getViewP()->deleteRow(0);
1824  if(groupMetadataTable_.getViewP()->getNumberOfRows() == 0)
1825  groupMetadataTable_.getViewP()->addRow();
1826 
1827  // columns are uid,comment,author,time
1828  groupMetadataTable_.getViewP()->setValue(
1829  groupAliasesString, 0, ConfigurationManager::METADATA_COL_ALIASES);
1830  groupMetadataTable_.getViewP()->setValue(
1831  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
1832  groupMetadataTable_.getViewP()->setValue(
1833  username_, 0, ConfigurationManager::METADATA_COL_AUTHOR);
1834  groupMetadataTable_.getViewP()->setValue(
1835  time(0), 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
1836 
1837  // set version to first available persistent version
1838  groupMetadataTable_.getViewP()->setVersion(TableVersion::getNextVersion(
1839  theInterface_->findLatestVersion(&groupMetadataTable_)));
1840 
1841  // groupMetadataTable_.print();
1842 
1843  theInterface_->saveActiveVersion(&groupMetadataTable_);
1844 
1845  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds()
1846  << __E__;
1847 
1848  // force groupMetadataTable_ to be a member for the group
1849  groupMembers[groupMetadataTable_.getTableName()] =
1850  groupMetadataTable_.getViewVersion();
1851 
1852  theInterface_->saveTableGroup(
1853  groupMembers, TableGroupKey::getFullGroupString(groupName, newKey));
1854  __GEN_COUT__ << "Created table group: " << groupName << ":" << newKey << __E__;
1855  }
1856  catch(std::runtime_error& e)
1857  {
1858  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1859  << __E__;
1860  __GEN_COUT_ERR__ << "\n\n" << e.what() << __E__;
1861  throw;
1862  }
1863  catch(...)
1864  {
1865  __GEN_COUT_ERR__ << "Failed to create table group: " << groupName << ":" << newKey
1866  << __E__;
1867  throw;
1868  }
1869 
1870  __GEN_COUTT__ << "saveNewTableGroup runTimeSeconds()=" << runTimeSeconds() << __E__;
1871 
1872  // store cache of recent groups
1873  cacheGroupKey(groupName, newKey);
1874 
1875  // at this point succeeded!
1876  return newKey;
1877 } // end saveNewTableGroup()
1878 
1879 //==============================================================================
1884 {
1885  __GEN_COUT_INFO__ << "Creating new backbone from temporary version "
1886  << temporaryVersion << __E__;
1887 
1888  // find common available temporary version among backbone members
1889  TableVersion newVersion(TableVersion::DEFAULT);
1890  TableVersion retNewVersion;
1891  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
1892  for(auto& name : backboneMemberNames)
1893  {
1894  retNewVersion = ConfigurationManager::getTableByName(name)->getNextVersion();
1895  __GEN_COUT__ << "New version for backbone member (" << name
1896  << "): " << retNewVersion << __E__;
1897  if(retNewVersion > newVersion)
1898  newVersion = retNewVersion;
1899  }
1900 
1901  __GEN_COUT__ << "Common new backbone version found as " << newVersion << __E__;
1902 
1903  // create new views from source temporary version
1904  for(auto& name : backboneMemberNames)
1905  {
1906  // saveNewVersion makes the new version the active version
1907  retNewVersion = getConfigurationInterface()->saveNewVersion(
1908  getTableByName(name), temporaryVersion, newVersion);
1909  if(retNewVersion != newVersion)
1910  {
1911  __SS__ << "Failure! New view requested was " << newVersion
1912  << ". Mismatched new view created: " << retNewVersion << __E__;
1913  __GEN_COUT_ERR__ << ss.str();
1914  __SS_THROW__;
1915  }
1916  }
1917 
1918  return newVersion;
1919 } // end saveNewBackbone()
1920 
1921 //==============================================================================
1927  const std::string& tableName,
1928  TableVersion originalVersion,
1929  bool makeTemporary,
1930  TableBase* table,
1931  TableVersion temporaryModifiedVersion,
1932  bool ignoreDuplicates /*= false*/,
1933  bool lookForEquivalent /*= false*/,
1934  bool* foundEquivalent /*= nullptr*/)
1935 {
1936  bool needToEraseTemporarySource =
1937  (originalVersion.isTemporaryVersion() && !makeTemporary);
1938 
1939  if(foundEquivalent)
1940  *foundEquivalent = false; // initialize
1941 
1942  // check for duplicate tables already in cache
1943  if(!ignoreDuplicates)
1944  {
1945  __GEN_COUT__ << "Checking for duplicate '" << tableName << "' tables..." << __E__;
1946 
1947  TableVersion duplicateVersion;
1948 
1949  {
1950  //"DEEP" checking
1951  // load into cache 'recent' versions for this table
1952  // 'recent' := those already in cache, plus highest version numbers not
1953  // in cache
1954  const std::map<std::string, TableInfo>& allTableInfo =
1955  getAllTableInfo(); // do not refresh
1956 
1957  auto versionReverseIterator =
1958  allTableInfo.at(tableName).versions_.rbegin(); // get reverse iterator
1959  __GEN_COUT__ << "Filling up '" << tableName << "' cache from "
1960  << table->getNumberOfStoredViews() << " to max count of "
1961  << table->MAX_VIEWS_IN_CACHE << __E__;
1962  for(; table->getNumberOfStoredViews() < table->MAX_VIEWS_IN_CACHE &&
1963  versionReverseIterator != allTableInfo.at(tableName).versions_.rend();
1964  ++versionReverseIterator)
1965  {
1966  __GEN_COUTT__ << "'" << tableName << "' versions in reverse order "
1967  << *versionReverseIterator << __E__;
1968  try
1969  {
1970  getVersionedTableByName(tableName,
1971  *versionReverseIterator); // load to cache
1972  }
1973  catch(const std::runtime_error& e)
1974  {
1975  // ignore error
1976  }
1977  }
1978  }
1979 
1980  __GEN_COUT__ << "Checking '" << tableName << "' duplicate..." << __E__;
1981 
1982  duplicateVersion = table->checkForDuplicate(
1983  temporaryModifiedVersion,
1984  (!originalVersion.isTemporaryVersion() && !makeTemporary)
1985  ? TableVersion()
1986  : // if from persistent to persistent, then
1987  // include original version in search
1988  originalVersion);
1989 
1990  if(lookForEquivalent && !duplicateVersion.isInvalid())
1991  {
1992  // found an equivalent!
1993  __GEN_COUT__ << "Equivalent '" << tableName << "' table found in version v"
1994  << duplicateVersion << __E__;
1995 
1996  // if duplicate version was temporary, do not use
1997  if(duplicateVersion.isTemporaryVersion() && !makeTemporary)
1998  {
1999  __GEN_COUT__ << "Need persistent. Duplicate '" << tableName
2000  << "' version was temporary. "
2001  "Abandoning duplicate."
2002  << __E__;
2003  duplicateVersion = TableVersion(); // set invalid
2004  }
2005  else
2006  {
2007  // erase and return equivalent version
2008 
2009  // erase modified equivalent version
2010  eraseTemporaryVersion(tableName, temporaryModifiedVersion);
2011 
2012  // erase original if needed
2013  if(needToEraseTemporarySource)
2014  eraseTemporaryVersion(tableName, originalVersion);
2015 
2016  if(foundEquivalent)
2017  *foundEquivalent = true;
2018 
2019  __GEN_COUT__ << "\t\t Equivalent '" << tableName
2020  << "' assigned version: " << duplicateVersion << __E__;
2021 
2022  return duplicateVersion;
2023  }
2024  }
2025 
2026  if(!duplicateVersion.isInvalid())
2027  {
2028  __SS__ << "This version of table '" << tableName
2029  << "' is identical to another version currently cached v"
2030  << duplicateVersion << ". No reason to save a duplicate." << __E__;
2031  __GEN_COUT_ERR__ << "\n" << ss.str();
2032 
2033  // delete temporaryModifiedVersion
2034  table->eraseView(temporaryModifiedVersion);
2035  __SS_THROW__;
2036  }
2037 
2038  __GEN_COUT__ << "Check for duplicate '" << tableName << "' tables complete."
2039  << __E__;
2040  }
2041 
2042  if(makeTemporary)
2043  __GEN_COUT__ << "\t\t**************************** Save as temporary '"
2044  << tableName << "' table version" << __E__;
2045  else
2046  __GEN_COUT__ << "\t\t**************************** Save as new '" << tableName
2047  << "' table version" << __E__;
2048 
2049  TableVersion newAssignedVersion =
2050  saveNewTable(tableName, temporaryModifiedVersion, makeTemporary);
2051 
2052  __GEN_COUTTV__(table->getView().getComment());
2053 
2054  if(needToEraseTemporarySource)
2055  eraseTemporaryVersion(tableName, originalVersion);
2056 
2057  __GEN_COUT__ << "\t\t '" << tableName
2058  << "' new assigned version: " << newAssignedVersion << __E__;
2059  return newAssignedVersion;
2060 } // end saveModifiedVersion()
2061 
2062 //==============================================================================
2063 GroupEditStruct::GroupEditStruct(const ConfigurationManager::GroupType& groupType,
2064  ConfigurationManagerRW* cfgMgr)
2065  : groupType_(groupType)
2066  , originalGroupName_(cfgMgr->getActiveGroupName(groupType))
2067  , originalGroupKey_(cfgMgr->getActiveGroupKey(groupType))
2068  , cfgMgr_(cfgMgr)
2069  , mfSubject_(cfgMgr->getUsername())
2070 {
2071  if(originalGroupName_ == "" || originalGroupKey_.isInvalid())
2072  {
2073  __SS__ << "Error! No active group found for type '"
2075  << ".' There must be an active group to edit the group." << __E__ << __E__
2076  << StringMacros::stackTrace() << __E__;
2077  __SS_THROW__;
2078  }
2079 
2080  __GEN_COUT__ << "Extracting Group-Edit Struct for type "
2081  << ConfigurationManager::convertGroupTypeToName(groupType) << __E__;
2082 
2083  std::map<std::string, TableVersion> activeTables = cfgMgr->getActiveVersions();
2084 
2085  const std::set<std::string>& memberNames =
2086  groupType == ConfigurationManager::GroupType::CONTEXT_TYPE
2087  ? ConfigurationManager::getContextMemberNames()
2088  : (groupType == ConfigurationManager::GroupType::BACKBONE_TYPE
2089  ? ConfigurationManager::getBackboneMemberNames()
2090  : (groupType == ConfigurationManager::GroupType::ITERATE_TYPE
2091  ? ConfigurationManager::getIterateMemberNames()
2092  : cfgMgr->getConfigurationMemberNames()));
2093 
2094  for(auto& memberName : memberNames)
2095  try
2096  {
2097  groupMembers_.emplace(
2098  std::make_pair(memberName, activeTables.at(memberName)));
2099  groupTables_.emplace(std::make_pair(
2100  memberName,
2101  TableEditStruct(memberName, cfgMgr))); // Table ready for editing!
2102  }
2103  catch(...)
2104  {
2105  __SS__ << "Error! Could not find group member table '" << memberName
2106  << "' for group type '"
2108  << ".' All group members must be present to create the group editing "
2109  "structure."
2110  << __E__;
2111  __SS_THROW__;
2112  }
2113 
2114 } // end GroupEditStruct constructor()
2115 
2116 //==============================================================================
2117 GroupEditStruct::~GroupEditStruct()
2118 {
2119  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2120  << originalGroupKey_ << ")' Destructing..." << __E__;
2121  dropChanges();
2122  __GEN_COUT__ << "GroupEditStruct from editing '" << originalGroupName_ << "("
2123  << originalGroupKey_ << ")' Desctructed." << __E__;
2124 } // end GroupEditStruct destructor()
2125 
2126 //==============================================================================
2129  bool markModified /*= false*/)
2130 {
2131  auto it = groupTables_.find(tableName);
2132  if(it == groupTables_.end())
2133  {
2134  if(groupType_ == ConfigurationManager::GroupType::CONFIGURATION_TYPE &&
2135  markModified)
2136  {
2137  __GEN_COUT__ << "Table '" << tableName
2138  << "' not found in configuration table members from editing '"
2139  << originalGroupName_ << "(" << originalGroupKey_ << ")..."
2140  << " Attempting to add it!" << __E__;
2141 
2142  // emplace returns pair<object,bool wasAdded>
2143  auto newIt = groupTables_.emplace(std::make_pair(
2144  tableName,
2145  TableEditStruct(tableName, cfgMgr_))); // Table ready for editing!
2146  if(newIt.second)
2147  {
2148  newIt.first->second.modified_ =
2149  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2150  groupMembers_.emplace(
2151  std::make_pair(tableName, newIt.first->second.temporaryVersion_));
2152  return newIt.first->second;
2153  }
2154  __GEN_COUT_ERR__ << "Failed to emplace new table..." << __E__;
2155  }
2156 
2157  __SS__ << "Table '" << tableName << "' not found in table members from editing '"
2158  << originalGroupName_ << "(" << originalGroupKey_ << ")!'" << __E__;
2159  __SS_THROW__;
2160  }
2161  it->second.modified_ =
2162  markModified; // could indicate 'dirty' immediately in user code, which will cause a save of table
2163  return it->second;
2164 } // end getTableEditStruct()
2165 
2166 //==============================================================================
2167 void GroupEditStruct::dropChanges()
2168 {
2169  __GEN_COUT__ << "Dropping unsaved changes from editing '" << originalGroupName_ << "("
2170  << originalGroupKey_ << ")'..." << __E__;
2171 
2172  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2173 
2174  // drop all temporary versions
2175  for(auto& groupTable : groupTables_)
2176  if(groupTable.second
2177  .createdTemporaryVersion_) // if temporary version created here
2178  {
2179  // erase with proper version management
2180  cfgMgr->eraseTemporaryVersion(groupTable.second.tableName_,
2181  groupTable.second.temporaryVersion_);
2182  groupTable.second.createdTemporaryVersion_ = false;
2183  groupTable.second.modified_ = false;
2184  }
2185 
2186  __GEN_COUT__ << "Unsaved changes dropped from editing '" << originalGroupName_ << "("
2187  << originalGroupKey_ << ").'" << __E__;
2188 } // end GroupEditStruct::dropChanges()
2189 
2190 //==============================================================================
2191 void GroupEditStruct::saveChanges(const std::string& groupNameToSave,
2192  TableGroupKey& newGroupKey,
2193  bool* foundEquivalentGroupKey /*= nullptr*/,
2194  bool activateNewGroup /*= false*/,
2195  bool updateGroupAliases /*= false*/,
2196  bool updateTableAliases /*= false*/,
2197  TableGroupKey* newBackboneKey /*= nullptr*/,
2198  bool* foundEquivalentBackboneKey /*= nullptr*/,
2199  std::string* accumulatedWarnings /*= nullptr*/)
2200 {
2201  __GEN_COUT__ << "Saving changes..." << __E__;
2202 
2203  newGroupKey = TableGroupKey(); // invalidate reference parameter
2204  if(newBackboneKey)
2205  *newBackboneKey = TableGroupKey(); // invalidate reference parameter
2206  if(foundEquivalentBackboneKey)
2207  *foundEquivalentBackboneKey = false; // clear to start
2208  ConfigurationManagerRW* cfgMgr = cfgMgr_;
2209 
2210  // save all temporary modified versions
2211  for(auto& groupTable : groupTables_)
2212  {
2213  if(!groupTable.second.modified_)
2214  continue; // skip if not modified
2215 
2216  __GEN_COUT__ << "Original version is " << groupTable.second.tableName_ << "-v"
2217  << groupTable.second.originalVersion_ << __E__;
2218 
2219  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2220  groupTable.second.tableName_,
2221  groupTable.second.originalVersion_,
2222  true /*make temporary*/,
2223  groupTable.second.table_,
2224  groupTable.second.temporaryVersion_,
2225  true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
2226 
2227  __GEN_COUT__ << "Temporary target version is " << groupTable.second.tableName_
2228  << "-v" << groupMembers_.at(groupTable.first) << "-v"
2229  << groupTable.second.temporaryVersion_ << __E__;
2230 
2231  groupMembers_.at(groupTable.first) = cfgMgr->saveModifiedVersion(
2232  groupTable.second.tableName_,
2233  groupTable.second.originalVersion_,
2234  false /*make temporary*/,
2235  groupTable.second.table_,
2236  groupTable.second.temporaryVersion_,
2237  false /*ignoreDuplicates*/,
2238  true /*lookForEquivalent*/); // save persistent version properly
2239 
2240  __GEN_COUT__ << "Final target version is " << groupTable.second.tableName_ << "-v"
2241  << groupMembers_.at(groupTable.first) << __E__;
2242 
2243  groupTable.second.modified_ = false; // clear modified flag
2244  groupTable.second.createdTemporaryVersion_ = false; // modified version is gone
2245  } // loop through table edit structs
2246 
2247  for(auto& table : groupMembers_)
2248  {
2249  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2250  }
2251 
2252  __GEN_COUT__ << "Checking for duplicate groups..." << __E__;
2253  newGroupKey = cfgMgr->findTableGroup(groupNameToSave, groupMembers_);
2254 
2255  if(!newGroupKey.isInvalid())
2256  {
2257  __GEN_COUT__ << "Found equivalent group key (" << newGroupKey << ") for "
2258  << groupNameToSave << "." << __E__;
2259  if(foundEquivalentGroupKey)
2260  *foundEquivalentGroupKey = true;
2261  }
2262  else
2263  {
2264  newGroupKey = cfgMgr->saveNewTableGroup(groupNameToSave, groupMembers_);
2265  __GEN_COUT__ << "Saved new Context group key (" << newGroupKey << ") for "
2266  << groupNameToSave << "." << __E__;
2267  }
2268 
2269  bool groupAliasChange = false;
2270  bool tableAliasChange = false;
2271 
2272  GroupEditStruct backboneGroupEdit(ConfigurationManager::GroupType::BACKBONE_TYPE,
2273  cfgMgr);
2274 
2275  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE && updateGroupAliases)
2276  {
2277  // check group aliases ... a la
2278  // ConfigurationGUISupervisor::handleSetGroupAliasInBackboneXML
2279 
2280  TableEditStruct& groupAliasTable = backboneGroupEdit.getTableEditStruct(
2281  ConfigurationManager::GROUP_ALIASES_TABLE_NAME, true /*markModified*/);
2282  TableView* tableView = groupAliasTable.tableView_;
2283 
2284  // unsigned int col;
2285  unsigned int row = 0;
2286 
2287  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2288  cfgMgr->getNode(ConfigurationManager::GROUP_ALIASES_TABLE_NAME).getChildren();
2289  std::string groupName, groupKey;
2290  for(auto& aliasNodePair : aliasNodePairs)
2291  {
2292  groupName = aliasNodePair.second.getNode("GroupName").getValueAsString();
2293  groupKey = aliasNodePair.second.getNode("GroupKey").getValueAsString();
2294 
2295  __GEN_COUT__ << "Group Alias: " << aliasNodePair.first << " => " << groupName
2296  << "(" << groupKey << "); row=" << row << __E__;
2297 
2298  if(groupName == originalGroupName_ &&
2299  TableGroupKey(groupKey) == originalGroupKey_)
2300  {
2301  __GEN_COUT__ << "Found alias! Changing group key from ("
2302  << originalGroupKey_ << ") to (" << newGroupKey << ")"
2303  << __E__;
2304 
2305  groupAliasChange = true;
2306 
2307  tableView->setValueAsString(
2308  newGroupKey.toString(), row, tableView->findCol("GroupKey"));
2309  }
2310 
2311  ++row;
2312  }
2313 
2314  if(groupAliasChange)
2315  {
2316  std::stringstream ss;
2317  tableView->print(ss);
2318  __GEN_COUT__ << ss.str();
2319  //
2330  //
2331  // backboneGroupEdit.groupMembers_.at(ConfigurationManager::GROUP_ALIASES_TABLE_NAME) =
2332  // cfgMgr->saveModifiedVersion(
2333  // groupAliasTable.tableName_,
2334  // groupAliasTable.originalVersion_,
2335  // true /*make temporary*/,
2336  // groupAliasTable.table_,
2337  // groupAliasTable.temporaryVersion_,
2338  // true /*ignoreDuplicates*/); // make temporary version to save persistent version properly
2339  //
2340  // __GEN_COUT__ << "Temporary target version is " <<
2341  // groupAliasTable.table_->getTableName() << "-v"
2342  // << backboneGroupEdit.groupMembers_.at(ConfigurationManager::GROUP_ALIASES_TABLE_NAME) << "-v"
2343  // << groupAliasTable.temporaryVersion_ << __E__;
2344  //
2345  // backboneGroupEdit.groupMembers_.at(ConfigurationManager::GROUP_ALIASES_TABLE_NAME) =
2346  // cfgMgr->saveModifiedVersion(
2347  // groupAliasTable.tableName_,
2348  // groupAliasTable.originalVersion_,
2349  // false /*make temporary*/,
2350  // groupAliasTable.table_,
2351  // groupAliasTable.temporaryVersion_,
2352  // false /*ignoreDuplicates*/,
2353  // true /*lookForEquivalent*/); // save persistent version properly
2354  //
2355  // __GEN_COUT__
2356  // << "Original version is "
2357  // << groupAliasTable.table_->getTableName() << "-v"
2358  // << groupAliasTable.originalVersion_ << " and new version is v"
2359  // << backboneGroupEdit.groupMembers_.at(ConfigurationManager::GROUP_ALIASES_TABLE_NAME)
2360  // << __E__;
2361  }
2362  } // end updateGroupAliases handling
2363 
2364  if(groupType_ != ConfigurationManager::GroupType::BACKBONE_TYPE && updateTableAliases)
2365  {
2366  // update all table version aliases
2367  TableView* tableView =
2368  backboneGroupEdit
2369  .getTableEditStruct(ConfigurationManager::VERSION_ALIASES_TABLE_NAME,
2370  true /*markModified*/)
2371  .tableView_;
2372 
2373  for(auto& groupTable : groupTables_)
2374  {
2375  if(groupTable.second.originalVersion_ ==
2376  groupMembers_.at(groupTable.second.tableName_))
2377  continue; // skip if no change
2378 
2379  __GEN_COUT__ << "Checking alias... original version is "
2380  << groupTable.second.tableName_ << "-v"
2381  << groupTable.second.originalVersion_ << " and new version is v"
2382  << groupMembers_.at(groupTable.second.tableName_) << __E__;
2383 
2384  // unsigned int col;
2385  unsigned int row = 0;
2386 
2387  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
2388  cfgMgr->getNode(ConfigurationManager::VERSION_ALIASES_TABLE_NAME)
2389  .getChildren();
2390  std::string tableName, tableVersion;
2391  for(auto& aliasNodePair : aliasNodePairs)
2392  {
2393  tableName = aliasNodePair.second.getNode("TableName").getValueAsString();
2394  tableVersion = aliasNodePair.second.getNode("Version").getValueAsString();
2395 
2396  __GEN_COUT__ << "Table Alias: " << aliasNodePair.first << " => "
2397  << tableName << "-v" << tableVersion << "" << __E__;
2398 
2399  if(tableName == groupTable.second.tableName_ &&
2400  TableVersion(tableVersion) == groupTable.second.originalVersion_)
2401  {
2402  __GEN_COUT__ << "Found alias! Changing icon table version alias."
2403  << __E__;
2404 
2405  tableAliasChange = true;
2406 
2407  tableView->setValueAsString(
2408  groupMembers_.at(groupTable.second.tableName_).toString(),
2409  row,
2410  tableView->findCol("Version"));
2411  }
2412 
2413  ++row;
2414  }
2415  }
2416 
2417  if(tableAliasChange)
2418  {
2419  std::stringstream ss;
2420  tableView->print(ss);
2421  __GEN_COUT__ << ss.str();
2422  }
2423  } // end updateTableAliases handling
2424 
2425  // if backbone modified, save group and activate it
2426 
2427  TableGroupKey localNewBackboneKey;
2428  if(groupAliasChange || tableAliasChange)
2429  {
2430  for(auto& table : backboneGroupEdit.groupMembers_)
2431  {
2432  __GEN_COUT__ << table.first << " v" << table.second << __E__;
2433  }
2434  backboneGroupEdit.saveChanges(
2435  backboneGroupEdit.originalGroupName_,
2436  localNewBackboneKey,
2437  foundEquivalentBackboneKey ? foundEquivalentBackboneKey : nullptr);
2438 
2439  if(newBackboneKey)
2440  *newBackboneKey = localNewBackboneKey;
2441  }
2442 
2443  // acquire all active groups and ignore errors, so that activateTableGroup does not
2444  // erase other active groups
2445  {
2446  __GEN_COUT__ << "Restoring active table groups, before activating new groups..."
2447  << __E__;
2448 
2449  std::string localAccumulatedWarnings;
2450  cfgMgr->restoreActiveTableGroups(false /*throwErrors*/,
2451  "" /*pathToActiveGroupsFile*/,
2452  ConfigurationManager::LoadGroupType::
2453  ALL_TYPES /*onlyLoadIfBackboneOrContext*/,
2454  &localAccumulatedWarnings);
2455  }
2456 
2457  // activate new groups
2458  if(!localNewBackboneKey.isInvalid())
2459  cfgMgr->activateTableGroup(backboneGroupEdit.originalGroupName_,
2460  localNewBackboneKey,
2461  accumulatedWarnings ? accumulatedWarnings : nullptr);
2462 
2463  if(activateNewGroup)
2464  cfgMgr->activateTableGroup(groupNameToSave,
2465  newGroupKey,
2466  accumulatedWarnings ? accumulatedWarnings : nullptr);
2467 
2468  __GEN_COUT__ << "Changes saved." << __E__;
2469 } // end GroupEditStruct::saveChanges()
2470 
2471 //==============================================================================
2474 {
2475  if(1)
2476  return; //if 0 to debug
2477  __GEN_COUTV__(runTimeSeconds());
2478 
2479  std::string accumulatedWarningsStr;
2480  std::string* accumulatedWarnings = &accumulatedWarningsStr;
2481 
2482  // get Group Info too!
2483  try
2484  {
2485  // build allGroupInfo_ for the ConfigurationManagerRW
2486 
2487  std::set<std::string /*name*/> tableGroups =
2488  theInterface_->getAllTableGroupNames();
2489  __GEN_COUT__ << "Number of Groups: " << tableGroups.size() << __E__;
2490 
2491  __GEN_COUTV__(runTimeSeconds());
2492  TableGroupKey key;
2493  std::string name;
2494  for(const auto& fullName : tableGroups)
2495  {
2496  TableGroupKey::getGroupNameAndKey(fullName, name, key);
2497  cacheGroupKey(name, key);
2498  }
2499  __GEN_COUTV__(runTimeSeconds());
2500  // for each group get member map & comment, author, time, and type for latest key
2501  for(auto& groupInfo : allGroupInfo_)
2502  {
2503  try
2504  {
2505  loadTableGroup(groupInfo.first /*groupName*/,
2506  groupInfo.second.getLatestKey(),
2507  false /*doActivate*/,
2508  &groupInfo.second.latestKeyMemberMap_ /*groupMembers*/,
2509  0 /*progressBar*/,
2510  0 /*accumulateErrors*/,
2511  &groupInfo.second.latestKeyGroupComment_,
2512  &groupInfo.second.latestKeyGroupAuthor_,
2513  &groupInfo.second.latestKeyGroupCreationTime_,
2514  true /*doNotLoadMember*/,
2515  &groupInfo.second.latestKeyGroupTypeString_);
2516  }
2517  catch(const std::runtime_error& e)
2518  {
2519  __GEN_COUT_WARN__
2520  << "Error occurred loading latest group info into cache for '"
2521  << groupInfo.first << "(" << groupInfo.second.getLatestKey()
2522  << ")': \n"
2523  << e.what() << __E__;
2524 
2525  groupInfo.second.latestKeyGroupComment_ =
2526  ConfigurationManager::UNKNOWN_INFO;
2527  groupInfo.second.latestKeyGroupAuthor_ =
2528  ConfigurationManager::UNKNOWN_INFO;
2529  groupInfo.second.latestKeyGroupCreationTime_ =
2530  ConfigurationManager::UNKNOWN_TIME;
2531  groupInfo.second.latestKeyGroupTypeString_ =
2532  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
2533  groupInfo.second.latestKeyMemberMap_ = {};
2534  }
2535  catch(...)
2536  {
2537  __GEN_COUT_WARN__
2538  << "Error occurred loading latest group info into cache for '"
2539  << groupInfo.first << "(" << groupInfo.second.getLatestKey()
2540  << ")'..." << __E__;
2541  groupInfo.second.latestKeyGroupComment_ =
2542  ConfigurationManager::UNKNOWN_INFO;
2543  groupInfo.second.latestKeyGroupAuthor_ =
2544  ConfigurationManager::UNKNOWN_INFO;
2545  groupInfo.second.latestKeyGroupCreationTime_ =
2546  ConfigurationManager::UNKNOWN_TIME;
2547  groupInfo.second.latestKeyGroupTypeString_ =
2548  ConfigurationManager::GROUP_TYPE_NAME_UNKNOWN;
2549  groupInfo.second.latestKeyMemberMap_ = {};
2550  }
2551  } // end group info loop
2552  __GEN_COUTV__(runTimeSeconds());
2553  } // end get group info
2554  catch(const std::runtime_error& e)
2555  {
2556  __SS__ << "A fatal error occurred reading the info for all table groups. Error: "
2557  << e.what() << __E__;
2558  __GEN_COUT_ERR__ << "\n" << ss.str();
2559  if(accumulatedWarnings)
2560  *accumulatedWarnings += ss.str();
2561  else
2562  throw;
2563  }
2564  catch(...)
2565  {
2566  __SS__ << "An unknown fatal error occurred reading the info for all table groups."
2567  << __E__;
2568  __GEN_COUT_ERR__ << "\n" << ss.str();
2569  if(accumulatedWarnings)
2570  *accumulatedWarnings += ss.str();
2571  else
2572  throw;
2573  }
2574  __GEN_COUT__ << "Group Info end runTimeSeconds()=" << runTimeSeconds() << __E__;
2575 
2576  return;
2577  try
2578  {
2579  __GEN_COUT__ << "Loading table..." << __E__;
2580  loadTableGroup("FETest", TableGroupKey(2)); // Context_1
2581  ConfigurationTree t = getNode("/FETable/DEFAULT/FrontEndType");
2582 
2583  std::string v;
2584 
2585  __GEN_COUT__ << __E__;
2586  t.getValue(v);
2587  __GEN_COUT__ << "Value: " << v << __E__;
2588  __GEN_COUT__ << "Value index: " << t.getValue<int>() << __E__;
2589 
2590  return;
2591  }
2592  catch(...)
2593  {
2594  __GEN_COUT__ << "Failed to load table..." << __E__;
2595  }
2596 }
TableVersion saveNewVersion(TableBase *configuration, TableVersion temporaryVersion, TableVersion newVersion=TableVersion())
std::map< std::string, std::map< std::string, TableVersion > > getVersionAliases(void) const
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 onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, bool ignoreVersionTracking=false)
static const unsigned int PROCESSOR_COUNT
Static members.
static const std::string & convertGroupTypeToName(const ConfigurationManager::GroupType &groupTypeId)
void restoreActiveTableGroups(bool throwErrors=false, const std::string &pathToActiveGroupsFile="", ConfigurationManager::LoadGroupType onlyLoadIfBackboneOrContext=ConfigurationManager::LoadGroupType::ALL_TYPES, std::string *accumulatedWarnings=0)
std::map< std::string, TableVersion > getActiveVersions(void) const
getActiveVersions
ConfigurationTree getNode(const std::string &nodeString, bool doNotThrowOnBrokenUIDLinks=false) const
"root/parent/parent/"
void init(std::string *accumulatedErrors=0, bool initForWriteAccess=false, std::string *accumulatedWarnings=0)
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
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 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)
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
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
const GroupInfo & getGroupInfo(const std::string &groupName)
public group cache handling
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)
compareTableGroupThread()
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()
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:1601
void trimTemporary(TableVersion targetVersion=TableVersion())
Definition: TableBase.cc:245
unsigned int getNumberOfStoredViews(void) const
Definition: TableBase.cc:723
TableVersion checkForDuplicate(TableVersion needleVersion, TableVersion ignoreVersion=TableVersion()) const
Definition: TableBase.cc:287
TableView * getTemporaryView(TableVersion temporaryVersion)
Definition: TableBase.cc:1712
const unsigned int MAX_VIEWS_IN_CACHE
Definition: TableBase.h:22
TableVersion getNextVersion(void) const
Definition: TableBase.cc:1688
TableVersion copyView(const TableView &sourceView, TableVersion destinationVersion, const std::string &author, bool looseColumnMatching=false)
Definition: TableBase.cc:1542
TableVersion getNextTemporaryVersion(void) const
Definition: TableBase.cc:1665
void trimCache(unsigned int trimSize=-1)
Definition: TableBase.cc:205
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="")
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:1078
int fillFromJSON(const std::string &json)
Definition: TableView.cc:2337
unsigned int findCol(const std::string &name) const
Definition: TableView.cc:1935
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 mapToString(const std::map< std::string, T > &mapToReturn, const std::string &primaryDelimeter=", ", const std::string &secondaryDelimeter=": ")
static std::string stackTrace(void)