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