otsdaq  v2_04_01
otsdaq_flatten_system_aliases.cc
1 
2 
3 #include <dirent.h>
4 #include <cassert>
5 #include <iostream>
6 #include <memory>
7 #include <string>
8 
9 #include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h"
10 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h"
11 //#include "artdaq-database/StorageProviders/FileSystemDB/provider_filedb_index.h"
12 //#include "artdaq-database/JsonDocument/JSONDocument.h"
13 
14 // usage:
15 // otsdaq_flatten_system_aliases <baseFlatVersion> <pathToSwapIn (optional)>
16 //
17 // if baseFlatVersion is invalid or temporary nothing is saved in the new db
18 // (Note: this can be used to swap dbs using pathToSwapIn)
19 
20 using namespace ots;
21 
22 void FlattenActiveSystemAliasTableGroups(int argc, char* argv[])
23 {
24  std::cout << "=================================================\n";
25  std::cout << "=================================================\n";
26  std::cout << "=================================================\n";
27  __COUT__ << "\nFlattening Active System Aliases!" << std::endl;
28 
29  std::cout << "\n\nusage: Two arguments:\n\t <baseFlatVersion> <pathToSwapIn "
30  "(optional)> \n\n"
31  << "\t Default values: baseFlatVersion = 0, pathToSwapIn = \"\" \n\n"
32  << std::endl;
33 
34  std::cout << "\n\nNote: you can optionally just swap databases (and not modify their "
35  "contents at all)"
36  << " by providing an invalid baseFlatVersion of -1.\n\n"
37  << std::endl;
38 
39  std::cout << "\n\nNote: This assumes artdaq db file type interface. "
40  << "The current database/ will be moved to database_<linuxtime>/ "
41  << "and if a pathToSwapIn is specified it will be copied to database/ "
42  << "before saving the currently active groups.\n\n"
43  << std::endl;
44 
45  std::cout << "argc = " << argc << std::endl;
46  for(int i = 0; i < argc; i++)
47  std::cout << "argv[" << i << "] = " << argv[i] << std::endl;
48 
49  if(argc < 2)
50  {
51  std::cout << "Error! Must provide at least one parameter.\n\n" << std::endl;
52  return;
53  }
54 
55  // determine if "h"elp was first parameter
56  std::string flatVersionStr = argv[1];
57  if(flatVersionStr.find('h') != std::string::npos)
58  {
59  std::cout
60  << "Recognized parameter 1. as a 'help' option. Usage was printed. Exiting."
61  << std::endl;
62  return;
63  }
64 
65  int flatVersion = 0;
66  std::string pathToSwapIn = "";
67  if(argc >= 2)
68  sscanf(argv[1], "%d", &flatVersion);
69  if(argc >= 3)
70  pathToSwapIn = argv[2];
71 
72  __COUT__ << "flatVersion = " << flatVersion << std::endl;
73  __COUT__ << "pathToSwapIn = " << pathToSwapIn << std::endl;
74 
75  // return;
76 
77  //==============================================================================
78  // Define environment variables
79  // Note: normally these environment variables are set by StartOTS.sh
80 
81  // These are needed by
82  // otsdaq/otsdaq-core/ConfigurationDataFormats/ConfigurationInfoReader.cc [207]
83  setenv("CONFIGURATION_TYPE", "File", 1); // Can be File, Database, DatabaseTest
84  setenv("CONFIGURATION_DATA_PATH",
85  (std::string(getenv("USER_DATA")) + "/ConfigurationDataExamples").c_str(),
86  1);
87  setenv(
88  "TABLE_INFO_PATH", (std::string(getenv("USER_DATA")) + "/TableInfo").c_str(), 1);
90 
91  // Some configuration plug-ins use __ENV__("SERVICE_DATA_PATH") in init() so define it
92  setenv("SERVICE_DATA_PATH",
93  (std::string(getenv("USER_DATA")) + "/ServiceData").c_str(),
94  1);
95 
96  // Some configuration plug-ins use __ENV__("OTSDAQ_LIB") and
97  // __ENV__("OTSDAQ_UTILITIES_LIB") in init() so define it to a non-sense place is ok
98  setenv("OTSDAQ_LIB", (std::string(getenv("USER_DATA")) + "/").c_str(), 1);
99  setenv("OTSDAQ_UTILITIES_LIB", (std::string(getenv("USER_DATA")) + "/").c_str(), 1);
100 
101  // Some configuration plug-ins use __ENV__("OTS_MAIN_PORT") in init() so define it
102  setenv("OTS_MAIN_PORT", "2015", 1);
103 
104  // also xdaq envs for XDAQContextTable
105  setenv("XDAQ_CONFIGURATION_DATA_PATH",
106  (std::string(getenv("USER_DATA")) + "/XDAQConfigurations").c_str(),
107  1);
108  setenv("XDAQ_CONFIGURATION_XML", "otsConfigurationNoRU_CMake", 1);
110 
111  //==============================================================================
112  // get prepared with initial source db
113 
114  // ConfigurationManager instance immediately loads active groups
115  std::cout << "\n\n\n" << __COUT_HDR_FL__ << "Loading active Aliases..." << std::endl;
116  ConfigurationManagerRW cfgMgrInst("flatten_admin");
117  ConfigurationManagerRW* cfgMgr = &cfgMgrInst;
118 
119  // create set of groups to persist
120  // include active context
121  // include active backbone
122  // include active iterate group
123  // include active config group
124  // (keep key translation separate activeGroupKeys)
125  // include all groups with system aliases
126 
127  // for group in set
128  // load/activate group and flatten tables to flatVersion to new DB
129  // save new version to modifiedTables
130  // save group with flatVersion key to new DB
131  // save new key to groupSet
132  // ++flatVersion
133 
134  // reload the active backbone (using activeGroupKeys)
135  // modify group aliases and table aliases properly based on groupSet and
136  // modifiedTables save new backbone with flatVersion to new DB
137 
138  // backup the file ConfigurationManager::ACTIVE_GROUPS_FILENAME with time
139  // and change the ConfigurationManager::ACTIVE_GROUPS_FILENAME
140  // to reflect new group names/keys
141 
142  /* map<<groupName, origKey>, newKey> */
143  std::map<std::pair<std::string, TableGroupKey>, TableGroupKey> groupSet;
144  /* <tableName, <origVersion, newVersion> >*/
145  std::map<std::pair<std::string, TableVersion>, TableVersion> modifiedTables;
146  std::map<std::string, std::pair<TableGroupKey, TableGroupKey>> activeGroupKeys;
147  std::map<std::pair<std::string, TableGroupKey>, std::string> groupErrors;
148 
149  std::string activeBackboneGroupName = "";
150  std::string activeContextGroupName = "";
151  std::string activeIterateGroupName = "";
152  std::string activeConfigGroupName = "";
153 
154  std::string nowTime = std::to_string(time(0));
155 
156  std::string thenTime = "";
157  if(pathToSwapIn != "") // get target then time
158  {
159  thenTime = pathToSwapIn.substr(pathToSwapIn.rfind('_') + 1);
160  __COUT__ << "thenTime = " << thenTime << std::endl;
161  // return;
162  }
163 
164  // add active groups to set
165  std::map<std::string, std::pair<std::string, TableGroupKey>> activeGroupsMap =
166  cfgMgr->getActiveTableGroups();
167 
168  for(const auto& activeGroup : activeGroupsMap)
169  {
170  groupSet.insert(std::pair<std::pair<std::string, TableGroupKey>, TableGroupKey>(
171  std::pair<std::string, TableGroupKey>(activeGroup.second.first,
172  activeGroup.second.second),
173  TableGroupKey()));
174  activeGroupKeys.insert(
175  std::pair<std::string, std::pair<TableGroupKey, TableGroupKey>>(
176  activeGroup.second.first,
177  std::pair<TableGroupKey, TableGroupKey>(activeGroup.second.second,
178  TableGroupKey())));
179 
180  if(activeGroup.first == ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE)
181  {
182  activeBackboneGroupName = activeGroup.second.first;
183  __COUT__ << "found activeBackboneGroupName = " << activeBackboneGroupName
184  << std::endl;
185  }
186  else if(activeGroup.first == ConfigurationManager::ACTIVE_GROUP_NAME_CONTEXT)
187  {
188  activeContextGroupName = activeGroup.second.first;
189  __COUT__ << "found activeContextGroupName = " << activeContextGroupName
190  << std::endl;
191  }
192  else if(activeGroup.first == ConfigurationManager::ACTIVE_GROUP_NAME_ITERATE)
193  {
194  activeIterateGroupName = activeGroup.second.first;
195  __COUT__ << "found activeIterateGroupName = " << activeIterateGroupName
196  << std::endl;
197  }
198  else if(activeGroup.first ==
199  ConfigurationManager::ACTIVE_GROUP_NAME_CONFIGURATION)
200  {
201  activeConfigGroupName = activeGroup.second.first;
202  __COUT__ << "found activeConfigGroupName = " << activeConfigGroupName
203  << std::endl;
204  }
205  }
206 
207  // return;
208 
209  // add system alias groups to set
210  const std::string groupAliasesTableName =
211  ConfigurationManager::GROUP_ALIASES_TABLE_NAME;
212  std::map<std::string, TableVersion> activeVersions = cfgMgr->getActiveVersions();
213  if(activeVersions.find(groupAliasesTableName) == activeVersions.end())
214  {
215  __SS__ << "\nActive version of " << groupAliasesTableName << " missing! "
216  << groupAliasesTableName
217  << " is a required member of the Backbone configuration group."
218  << "\n\nLikely you need to activate a valid Backbone group." << std::endl;
219  __SS_THROW__;
220  }
221 
222  std::vector<std::pair<std::string, ConfigurationTree>> aliasNodePairs =
223  cfgMgr->getNode(groupAliasesTableName).getChildren();
224  for(auto& groupPair : aliasNodePairs)
225  groupSet.insert(std::pair<std::pair<std::string, TableGroupKey>, TableGroupKey>(
226  std::pair<std::string, TableGroupKey>(
227  groupPair.second.getNode("GroupName").getValueAsString(),
228  TableGroupKey(groupPair.second.getNode("GroupKey").getValueAsString())),
229  TableGroupKey()));
230 
231  __COUT__ << "Identified groups:" << std::endl;
232  for(auto& group : groupSet)
233  __COUT__ << group.first.first << " " << group.first.second << std::endl;
234  __COUT__ << std::endl;
235  __COUT__ << std::endl;
236 
237  // return;
238  //==============================================================================
239  // prepare to manipulate directories
240  std::string currentDir = __ENV__("ARTDAQ_DATABASE_URI");
241 
242  if(currentDir.find("filesystemdb://") != 0)
243  {
244  __SS__ << "filesystemdb:// was not found in $ARTDAQ_DATABASE_URI!" << std::endl;
245  __COUT_ERR__ << "\n" << ss.str();
246  __SS_THROW__;
247  }
248 
249  currentDir = currentDir.substr(std::string("filesystemdb://").length());
250  while(currentDir.length() &&
251  currentDir[currentDir.length() - 1] == '/') // remove trailing '/'s
252  currentDir = currentDir.substr(0, currentDir.length() - 1);
253  std::string moveToDir = currentDir + "_" + nowTime;
254  if(argc < 2)
255  {
256  __SS__ << ("Aborting move! Must at least give version argument to flatten to!")
257  << std::endl;
258  __COUT_ERR__ << "\n" << ss.str();
259  __SS_THROW__;
260  }
261 
262  if(pathToSwapIn != "")
263  {
264  DIR* dp;
265  if((dp = opendir(pathToSwapIn.c_str())) == 0)
266  {
267  __COUT__ << "ERROR:(" << errno << "). Can't open directory: " << pathToSwapIn
268  << std::endl;
269  exit(0);
270  }
271  closedir(dp);
272  }
273 
274  // handle directory swap
275  __COUT__ << "Moving current directory: \t" << currentDir << std::endl;
276  __COUT__ << "\t... to: \t\t" << moveToDir << std::endl;
277  // return;
278  rename(currentDir.c_str(), moveToDir.c_str());
279 
280  if(pathToSwapIn != "")
281  {
282  __COUT__ << "Swapping in directory: \t" << pathToSwapIn << std::endl;
283  __COUT__ << "\t.. to: \t\t" << currentDir << std::endl;
284  rename(pathToSwapIn.c_str(), currentDir.c_str());
285 
286  // also swap in active groups file
287  // check if original active file exists
288  std::string activeGroupsFile =
289  ConfigurationManager::ACTIVE_GROUPS_FILENAME + "." + thenTime;
290  FILE* fp = fopen(activeGroupsFile.c_str(), "r");
291  if(fp)
292  {
293  __COUT__ << "Swapping active groups file: \t" << activeGroupsFile
294  << std::endl;
295  __COUT__ << "\t.. to: \t\t" << ConfigurationManager::ACTIVE_GROUPS_FILENAME
296  << std::endl;
297  rename(activeGroupsFile.c_str(),
298  ConfigurationManager::ACTIVE_GROUPS_FILENAME.c_str());
299  }
300  }
301 
302  ConfigurationInterface* theInterface_ = ConfigurationInterface::getInstance(
303  false); // true for File interface, false for artdaq database;
304  TableView* cfgView;
305  TableBase* config;
306 
307  bool errDetected;
308  std::string accumulateErrors = "";
309  int count = 0;
310 
311  std::map<std::string /*name*/, TableVersion> memberMap;
312  std::map<std::string /*name*/, std::string /*alias*/> groupAliases;
313  std::string groupComment;
314  std::string groupAuthor;
315  std::string groupCreateTime;
316  time_t groupCreateTime_t;
317  TableBase* groupMetadataTable = cfgMgr->getMetadataTable();
318 
319  // don't do anything more if flatVersion is not persistent
320  if(TableVersion(flatVersion).isInvalid() ||
321  TableVersion(flatVersion).isTemporaryVersion())
322  {
323  __COUT__ << "\n\nflatVersion " << TableVersion(flatVersion)
324  << " is an invalid or temporary version. Skipping to end!" << std::endl;
325  goto CLEAN_UP;
326  }
327 
328  for(auto& groupPair : groupSet)
329  {
330  errDetected = false;
331 
332  __COUT__ << "****************************" << std::endl;
333  __COUT__ << "Loading members for " << groupPair.first.first << "("
334  << groupPair.first.second << ")" << std::endl;
335  __COUT__ << "flatVersion = " << flatVersion << std::endl;
336 
337  // handle directory swap BACK
338  if(pathToSwapIn != "")
339  {
340  __COUT__ << "REVERT by Swapping back directory: \t" << currentDir
341  << std::endl;
342  __COUT__ << "\t.. to: \t\t" << pathToSwapIn << std::endl;
343  if(rename(currentDir.c_str(), pathToSwapIn.c_str()) < 0)
344  {
345  __SS__ << "Problem!" << std::endl;
346  __SS_THROW__;
347  }
348  }
349  else if(count) // if not first time, move currentDir to temporarily holding area
350  {
351  __COUT__ << "REVERT by Moving directory: \t" << currentDir << std::endl;
352  __COUT__ << "\t.. to temporary directory: \t\t" << (moveToDir + "_tmp")
353  << std::endl;
354  if(rename(currentDir.c_str(), (moveToDir + "_tmp").c_str()) < 0)
355  {
356  __SS__ << "Problem!" << std::endl;
357  __SS_THROW__;
358  }
359  }
360 
361  __COUT__ << "REVERT by Moving directory: \t" << moveToDir << std::endl;
362  __COUT__ << "\t... to: \t\t" << currentDir << std::endl;
363  if(rename(moveToDir.c_str(), currentDir.c_str()) < 0)
364  {
365  __SS__ << "Problem!" << std::endl;
366  __SS_THROW__;
367  }
368 
369  //=========================
370  // load group, group metadata, and tables from original DB
371  try
372  {
373  accumulateErrors = "";
374  cfgMgr->loadTableGroup(groupPair.first.first,
375  groupPair.first.second,
376  true /*doActivate*/,
377  &memberMap /*memberMap*/,
378  0 /*progressBar*/,
379  &accumulateErrors,
380  &groupComment,
381  &groupAuthor,
382  &groupCreateTime,
383  false /*doNotLoadMember*/,
384  0 /*groupTypeString*/,
385  &groupAliases);
386  }
387  catch(std::runtime_error& e)
388  {
389  __COUT__ << "Error was caught loading members for " << groupPair.first.first
390  << "(" << groupPair.first.second << ")" << std::endl;
391  __COUT__ << e.what() << std::endl;
392  errDetected = true;
393  }
394  catch(...)
395  {
396  __COUT__ << "Error was caught loading members for " << groupPair.first.first
397  << "(" << groupPair.first.second << ")" << std::endl;
398  errDetected = true;
399  }
400 
401  //=========================
402 
403  // if(count == 2) break;
404 
405  // handle directory swap
406  __COUT__ << "Moving current directory: \t" << currentDir << std::endl;
407  __COUT__ << "\t... to: \t\t" << moveToDir << std::endl;
408  if(rename(currentDir.c_str(), moveToDir.c_str()) < 0)
409  {
410  __SS__ << "Problem!" << std::endl;
411  __SS_THROW__;
412  }
413 
414  if(pathToSwapIn != "")
415  {
416  __COUT__ << "Swapping in directory: \t" << pathToSwapIn << std::endl;
417  __COUT__ << "\t.. to: \t\t" << currentDir << std::endl;
418  if(rename(pathToSwapIn.c_str(), currentDir.c_str()) < 0)
419  {
420  __SS__ << "Problem!" << std::endl;
421  __SS_THROW__;
422  }
423  }
424  else if(count) // if not first time, replace from temporarily holding area
425  {
426  __COUT__ << "Moving temporary directory: \t" << (moveToDir + "_tmp")
427  << std::endl;
428  __COUT__ << "\t.. to current directory: \t\t" << currentDir << std::endl;
429  if(rename((moveToDir + "_tmp").c_str(), currentDir.c_str()) < 0)
430  {
431  __SS__ << "Problem!" << std::endl;
432  __SS_THROW__;
433  }
434  }
435 
436  // exit loop if any (loading) failure
437  if(errDetected)
438  {
439  // goto CLEAN_UP;
440 
441  // power on if group failed
442  // and record error
443 
444  groupErrors.insert(
445  std::pair<std::pair<std::string, TableGroupKey>, std::string>(
446  std::pair<std::string, TableGroupKey>(groupPair.first.first,
447  groupPair.first.second),
448  "Error caught loading the group."));
449  continue;
450  }
451 
452  //=========================
453  // save group and its tables with new key and versions!
454  try
455  {
456  // saving tables
457  for(auto& memberPair : memberMap)
458  {
459  __COUT__ << memberPair.first << ":v" << memberPair.second << std::endl;
460 
461  // check if table has already been modified by a previous group
462  // (i.e. two groups using the same version of a table)
463  if(modifiedTables.find(std::pair<std::string, TableVersion>(
464  memberPair.first, memberPair.second)) != modifiedTables.end())
465  {
466  __COUT__ << "Table was already modified!" << std::endl;
467  memberPair.second =
468  modifiedTables[std::pair<std::string, TableVersion>(
469  memberPair.first, memberPair.second)];
470  __COUT__ << "\t to...\t" << memberPair.first << ":v"
471  << memberPair.second << std::endl;
472  continue;
473  }
474 
475  // change the version of the active view to flatVersion and save it
476  config = cfgMgr->getTableByName(memberPair.first);
477  cfgView = config->getViewP();
478  cfgView->setVersion(TableVersion(flatVersion));
479  theInterface_->saveActiveVersion(config);
480 
481  // set it back for the table so that future groups can re-use cached
482  // version
483  cfgView->setVersion(memberPair.second); // IMPORTANT
484 
485  // save new version to modifiedTables
486  modifiedTables.insert(
487  std::pair<std::pair<std::string, TableVersion>, TableVersion>(
488  std::pair<std::string, TableVersion>(memberPair.first,
489  memberPair.second),
490  TableVersion(flatVersion)));
491 
492  memberPair.second = flatVersion; // change version in the member map
493 
494  __COUT__ << "\t to...\t" << memberPair.first << ":v" << memberPair.second
495  << std::endl;
496  }
497 
498  // Note: this code copies actions in ConfigurationManagerRW::saveNewTableGroup
499 
500  // add meta data
501  __COUTV__(StringMacros::mapToString(groupAliases));
502  __COUTV__(groupComment);
503  __COUTV__(groupAuthor);
504  __COUTV__(groupCreateTime);
505  sscanf(groupCreateTime.c_str(), "%ld", &groupCreateTime_t);
506  __COUTV__(groupCreateTime_t);
507 
508  // to compensate for unusual errors upstream, make sure the metadata table has
509  // one row
510  while(groupMetadataTable->getViewP()->getNumberOfRows() > 1)
511  groupMetadataTable->getViewP()->deleteRow(0);
512  if(groupMetadataTable->getViewP()->getNumberOfRows() == 0)
513  groupMetadataTable->getViewP()->addRow();
514 
515  // columns are uid,comment,author,time
516  // ConfigurationManager::METADATA_COL_ALIASES TODO
517  groupMetadataTable->getViewP()->setValue(
518  StringMacros::mapToString(
519  groupAliases, "," /*primary delimiter*/, ":" /*secondary delimeter*/),
520  0,
521  ConfigurationManager::METADATA_COL_ALIASES);
522  groupMetadataTable->getViewP()->setValue(
523  groupComment, 0, ConfigurationManager::METADATA_COL_COMMENT);
524  groupMetadataTable->getViewP()->setValue(
525  groupAuthor, 0, ConfigurationManager::METADATA_COL_AUTHOR);
526  groupMetadataTable->getViewP()->setValue(
527  groupCreateTime_t, 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
528 
529  // set version of metadata table
530  groupMetadataTable->getViewP()->setVersion(TableVersion(flatVersion));
531  theInterface_->saveActiveVersion(groupMetadataTable);
532 
533  // force groupMetadataTable_ to be a member for the group
534  memberMap[groupMetadataTable->getTableName()] =
535  groupMetadataTable->getViewVersion();
536 
537  // memberMap should now consist of members with new flat version, so save
538  // group
539  theInterface_->saveTableGroup(
540  memberMap,
541  TableGroupKey::getFullGroupString(groupPair.first.first,
542  TableGroupKey(flatVersion)));
543 
544  // and modify groupSet and activeGroupKeys keys
545  groupPair.second = TableGroupKey(flatVersion);
546 
547  // if this is an active group, save key change
548  if(activeGroupKeys.find(groupPair.first.first) != activeGroupKeys.end() &&
549  activeGroupKeys[groupPair.first.first].first == groupPair.first.second)
550  activeGroupKeys[groupPair.first.first].second =
551  TableGroupKey(flatVersion);
552  }
553  catch(std::runtime_error& e)
554  {
555  __COUT__ << "Error was caught saving group " << groupPair.first.first << " ("
556  << groupPair.first.second << ") " << std::endl;
557  __COUT__ << e.what() << std::endl;
558 
559  groupErrors.insert(
560  std::pair<std::pair<std::string, TableGroupKey>, std::string>(
561  std::pair<std::string, TableGroupKey>(groupPair.first.first,
562  groupPair.first.second),
563  "Error caught saving the group."));
564  }
565  catch(...)
566  {
567  __COUT__ << "Error was caught saving group " << groupPair.first.first << " ("
568  << groupPair.first.second << ") " << std::endl;
569 
570  groupErrors.insert(
571  std::pair<std::pair<std::string, TableGroupKey>, std::string>(
572  std::pair<std::string, TableGroupKey>(groupPair.first.first,
573  groupPair.first.second),
574  "Error caught saving the group."));
575  }
576  //=========================
577 
578  // increment flat version
579  ++flatVersion;
580  ++count;
581  }
582 
583  // record in readme for moveto
584  {
585  FILE* fp = fopen((moveToDir + "/README_otsdaq_flatten.txt").c_str(), "a");
586  if(!fp)
587  __COUT__ << "\tError opening README file!" << std::endl;
588  else
589  {
590  time_t rawtime;
591  struct tm* timeinfo;
592  char buffer[200];
593 
594  time(&rawtime);
595  timeinfo = localtime(&rawtime);
596  strftime(buffer, 200, "%b %d, %Y %I:%M%p %Z", timeinfo);
597 
598  fprintf(fp,
599  "This database was moved from...\n\t %s \nto...\n\t %s \nat this "
600  "time \n\t %lu \t %s\n\n\n",
601  currentDir.c_str(),
602  moveToDir.c_str(),
603  time(0),
604  buffer);
605 
606  fclose(fp);
607  }
608  }
609 
610  // record in readme for swapin
611  {
612  FILE* fp = fopen((currentDir + "/README_otsdaq_flatten.txt").c_str(), "a");
613 
614  if(!fp)
615  __COUT__ << "\tError opening README file!" << std::endl;
616  else
617  {
618  time_t rawtime;
619  struct tm* timeinfo;
620  char buffer[200];
621 
622  time(&rawtime);
623  timeinfo = localtime(&rawtime);
624  strftime(buffer, 200, "%b %d, %Y %I:%M:%S%p %Z", timeinfo);
625 
626  fprintf(fp,
627  "This database was moved from...\t %s \t to...\t %s at this time \t "
628  "%lu \t %s\n\n",
629  pathToSwapIn.c_str(),
630  currentDir.c_str(),
631  time(0),
632  buffer);
633  fclose(fp);
634  }
635  }
636 
637  // //print resulting all groups
638  //
639  // std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Groups:" << std::endl;
640  // for(const auto &group: groupSet)
641  // __COUT__<< group.first.first << ": " <<
642  // group.first.second << " => " << group.second << std::endl;
643  // std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Groups end." << std::endl;
644  //
645  //
646  // //print resulting active groups
647  //
648  // std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Active Groups:" << std::endl;
649  // for(const auto &activeGroup: activeGroupKeys)
650  // __COUT__<< activeGroup.first << ": " <<
651  // activeGroup.second.first << " => " << activeGroup.second.second <<
652  // std::endl;
653  //
654  // __COUT__<< activeBackboneGroupName << " is the " <<
655  // ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE << "." << std::endl;
656  // std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Active Groups end." <<
657  // std::endl;
658 
659  // reload the active backbone (using activeGroupKeys)
660  // modify group aliases and table aliases properly based on groupSet and
661  // modifiedTables save new backbone with flatVersion to new DB
662 
663  if(activeBackboneGroupName == "")
664  {
665  __COUT__ << "No active Backbone table identified." << std::endl;
666  goto CLEAN_UP;
667  }
668 
669  std::cout << "\n\n"
670  << __COUT_HDR_FL__
671  << "Modifying the active Backbone table to reflect new table versions and "
672  "group keys."
673  << std::endl;
674 
675  {
676  cfgMgr->loadTableGroup(activeBackboneGroupName,
677  activeGroupKeys[activeBackboneGroupName].second,
678  true,
679  &memberMap,
680  0,
681  &accumulateErrors);
682 
683  // modify Group Aliases Table and Version Aliases Table to point
684  // at DEFAULT and flatVersion respectively
685 
686  const std::string groupAliasesName =
687  ConfigurationManager::GROUP_ALIASES_TABLE_NAME;
688  const std::string versionAliasesName =
689  ConfigurationManager::VERSION_ALIASES_TABLE_NAME;
690 
691  std::map<std::string, TableVersion> activeMap = cfgMgr->getActiveVersions();
692 
693  // modify Group Aliases Table
694  if(activeMap.find(groupAliasesName) != activeMap.end())
695  {
696  __COUT__ << "\n\nModifying " << groupAliasesName << std::endl;
697  config = cfgMgr->getTableByName(groupAliasesName);
698  cfgView = config->getViewP();
699 
700  unsigned int col1 = cfgView->findCol("GroupName");
701  unsigned int col2 = cfgView->findCol("GroupKey");
702 
703  // cfgView->print();
704 
705  // change all key entries found to the new key and delete rows for groups not
706  // found
707  bool found;
708  for(unsigned int row = 0; row < cfgView->getNumberOfRows(); ++row)
709  {
710  found = false;
711  for(const auto& group : groupSet)
712  if(group.second.isInvalid())
713  continue;
714  else if(cfgView->getDataView()[row][col1] == group.first.first &&
715  cfgView->getDataView()[row][col2] ==
716  group.first.second.toString())
717  {
718  // found a matching group/key pair
719  __COUT__ << "Changing row " << row << " for "
720  << cfgView->getDataView()[row][col1]
721  << " key=" << cfgView->getDataView()[row][col2]
722  << " to NEW key=" << group.second << std::endl;
723  cfgView->setValue(group.second.toString(), row, col2);
724  found = true;
725  break;
726  }
727 
728  if(!found) // delete row
729  cfgView->deleteRow(row--);
730  }
731  // cfgView->print();
732  }
733 
734  // modify Version Aliases Table
735  if(activeMap.find(versionAliasesName) != activeMap.end())
736  {
737  __COUT__ << "\n\nModifying " << versionAliasesName << std::endl;
738  config = cfgMgr->getTableByName(versionAliasesName);
739  cfgView = config->getViewP();
740  unsigned int col1 = cfgView->findCol("TableName");
741  unsigned int col2 = cfgView->findCol("Version");
742 
743  // change all version entries to the new version and delete rows with no match
744  bool found;
745  for(unsigned int row = 0; row < cfgView->getNumberOfRows(); ++row)
746  {
747  found = false;
748  for(const auto& table : modifiedTables)
749  if(cfgView->getDataView()[row][col1] == table.first.first &&
750  cfgView->getDataView()[row][col2] == table.first.second.toString())
751  {
752  // found a matching group/key pair
753  __COUT__ << "Changing row " << row << " for "
754  << cfgView->getDataView()[row][col1]
755  << " version=" << cfgView->getDataView()[row][col2]
756  << " to NEW version=" << table.second << std::endl;
757  cfgView->setValue(table.second.toString(), row, col2);
758  found = true;
759  break;
760  }
761 
762  if(!found) // delete row
763  cfgView->deleteRow(row--);
764  }
765  }
766 
767  // save new Group Aliases Table and Version Aliases Table
768 
769  __COUT__ << groupAliasesName << ":v" << memberMap[groupAliasesName] << std::endl;
770  // change the version of the active view to flatVersion and save it
771  config = cfgMgr->getTableByName(groupAliasesName);
772  cfgView = config->getViewP();
773  cfgView->setVersion(TableVersion(flatVersion));
774  theInterface_->saveActiveVersion(config);
775 
776  memberMap[groupAliasesName] = flatVersion; // change version in the member map
777 
778  __COUT__ << "\t to...\t" << groupAliasesName << ":v"
779  << memberMap[groupAliasesName] << std::endl;
780 
781  __COUT__ << versionAliasesName << ":v" << memberMap[versionAliasesName]
782  << std::endl;
783  // change the version of the active view to flatVersion and save it
784  config = cfgMgr->getTableByName(versionAliasesName);
785  cfgView = config->getViewP();
786  cfgView->setVersion(TableVersion(flatVersion));
787  theInterface_->saveActiveVersion(config);
788 
789  memberMap[versionAliasesName] = flatVersion; // change version in the member map
790 
791  __COUT__ << "\t to...\t" << versionAliasesName << ":v"
792  << memberMap[versionAliasesName] << std::endl;
793 
794  // memberMap should now consist of members with new flat version, so save
795  theInterface_->saveTableGroup(
796  memberMap,
797  TableGroupKey::getFullGroupString(activeBackboneGroupName,
798  TableGroupKey(flatVersion)));
799 
800  activeGroupKeys[activeBackboneGroupName].second = TableGroupKey(flatVersion);
801 
802  __COUT__ << "New to-be-active backbone group " << activeBackboneGroupName << ":v"
803  << activeGroupKeys[activeBackboneGroupName].second << std::endl;
804  }
805 
806  // backup the file ConfigurationManager::ACTIVE_GROUPS_FILENAME with time
807  // and change the ConfigurationManager::ACTIVE_GROUPS_FILENAME
808  // to reflect new group names/keys
809 
810  {
811  std::cout << "\n\n"
812  << __COUT_HDR_FL__ << "Manipulating the Active Groups file..."
813  << std::endl;
814 
815  // check if original active file exists
816  FILE* fp = fopen(ConfigurationManager::ACTIVE_GROUPS_FILENAME.c_str(), "r");
817  if(!fp)
818  {
819  __SS__ << "Original active groups file '"
820  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << "' not found."
821  << std::endl;
822  goto CLEAN_UP;
823  }
824 
825  __COUT__ << "Backing up file: " << ConfigurationManager::ACTIVE_GROUPS_FILENAME
826  << std::endl;
827 
828  fclose(fp);
829 
830  std::string renameFile =
831  ConfigurationManager::ACTIVE_GROUPS_FILENAME + "." + nowTime;
832  rename(ConfigurationManager::ACTIVE_GROUPS_FILENAME.c_str(), renameFile.c_str());
833 
834  __COUT__ << "Backup file name: " << renameFile << std::endl;
835 
836  TableGroupKey *theConfigurationTableGroupKey_, *theContextTableGroupKey_,
837  *theBackboneTableGroupKey_, *theIterateTableGroupKey_;
838  std::string theConfigurationTableGroup_, theContextTableGroup_,
839  theBackboneTableGroup_, theIterateTableGroup_;
840 
841  theConfigurationTableGroup_ = activeConfigGroupName;
842  theConfigurationTableGroupKey_ = &(activeGroupKeys[activeConfigGroupName].second);
843 
844  theContextTableGroup_ = activeContextGroupName;
845  theContextTableGroupKey_ = &(activeGroupKeys[activeContextGroupName].second);
846 
847  theBackboneTableGroup_ = activeBackboneGroupName;
848  theBackboneTableGroupKey_ = &(activeGroupKeys[activeBackboneGroupName].second);
849 
850  theIterateTableGroup_ = activeIterateGroupName;
851  theIterateTableGroupKey_ = &(activeGroupKeys[activeIterateGroupName].second);
852 
853  // the following is copied from ConfigurationManagerRW::activateTableGroup
854  {
855  __COUT__ << "Updating persistent active groups to "
856  << ConfigurationManager::ACTIVE_GROUPS_FILENAME << " ..."
857  << std::endl;
858 
859  std::string fn = ConfigurationManager::ACTIVE_GROUPS_FILENAME;
860  FILE* fp = fopen(fn.c_str(), "w");
861  if(!fp)
862  return;
863 
864  fprintf(fp, "%s\n", theContextTableGroup_.c_str());
865  fprintf(fp,
866  "%s\n",
867  theContextTableGroupKey_
868  ? theContextTableGroupKey_->toString().c_str()
869  : "-1");
870  fprintf(fp, "%s\n", theBackboneTableGroup_.c_str());
871  fprintf(fp,
872  "%s\n",
873  theBackboneTableGroupKey_
874  ? theBackboneTableGroupKey_->toString().c_str()
875  : "-1");
876  fprintf(fp, "%s\n", theConfigurationTableGroup_.c_str());
877  fprintf(fp,
878  "%s\n",
879  theConfigurationTableGroupKey_
880  ? theConfigurationTableGroupKey_->toString().c_str()
881  : "-1");
882  fprintf(fp, "%s\n", theIterateTableGroup_.c_str());
883  fprintf(fp,
884  "%s\n",
885  theIterateTableGroupKey_
886  ? theIterateTableGroupKey_->toString().c_str()
887  : "-1");
888  fclose(fp);
889  }
890  }
891 
892  // print resulting all groups
893 
894  std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Groups:" << std::endl;
895  for(const auto& group : groupSet)
896  __COUT__ << "\t" << group.first.first << ": " << group.first.second << " => "
897  << group.second << std::endl;
898  std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Groups end." << std::endl;
899 
900  // print resulting active groups
901 
902  std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Active Groups:" << std::endl;
903  for(const auto& activeGroup : activeGroupKeys)
904  __COUT__ << "\t" << activeGroup.first << ": " << activeGroup.second.first
905  << " => " << activeGroup.second.second << std::endl;
906 
907  __COUT__ << activeBackboneGroupName << " is the "
908  << ConfigurationManager::ACTIVE_GROUP_NAME_BACKBONE << "." << std::endl;
909  std::cout << "\n\n" << __COUT_HDR_FL__ << "Resulting Active Groups end." << std::endl;
910 
911 CLEAN_UP:
912  //==============================================================================
913  std::cout << "\n\n"
914  << __COUT_HDR_FL__ << "End of Flattening Active Table Groups!\n\n\n"
915  << std::endl;
916 
917  __COUT__ << "****************************" << std::endl;
918  __COUT__ << "There were " << groupSet.size() << " groups considered, and there were "
919  << groupErrors.size() << " errors found handling those groups." << std::endl;
920  __COUT__ << "The following errors were found handling the groups:" << std::endl;
921  for(auto& groupErr : groupErrors)
922  __COUT__ << "\t" << groupErr.first.first << " " << groupErr.first.second << ": \t"
923  << groupErr.second << std::endl;
924  __COUT__ << "End of errors.\n\n" << std::endl;
925 
926  __COUT__ << "Run the following to return to your previous database structure:"
927  << std::endl;
928  __COUT__ << "\t otsdaq_flatten_system_aliases -1 " << moveToDir << "\n\n"
929  << std::endl;
930 
931  return;
932 }
933 
934 int main(int argc, char* argv[])
935 {
936  FlattenActiveSystemAliasTableGroups(argc, argv);
937  return 0;
938 }
939 // BOOST_AUTO_TEST_SUITE_END()