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