otsdaq  v2_05_02_indev
otsdaq_flatten_active_to_version.cc
1 #include <dirent.h>
2 #include <cassert>
3 #include <iostream>
4 #include <memory>
5 #include <string>
6 #include "otsdaq/ConfigurationInterface/ConfigurationInterface.h"
7 #include "otsdaq/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_active_to_version <flatVersion> <pathToSwapIn (optional)>
13 //
14 // if flatVersion 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 FlattenActiveTableGroups(int argc, char* argv[])
20 {
21  std::cout << "=================================================\n";
22  std::cout << "=================================================\n";
23  std::cout << "=================================================\n";
24  __COUT__ << "\nFlattening Active Table Groups!" << std::endl;
25 
26  std::cout << "\n\nusage: Two arguments:\n\t pathToSwapIn <flatVersion> <pathToSwapIn "
27  "(optional)> \n\n"
28  << "\t Default values: flatVersion = 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 flatVersion 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 << "Must provide at least one parameter.";
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 << "Recognized parameter 1. as a 'help' option. Usage was printed. Exiting." << std::endl;
57  return;
58  }
59 
60  int flatVersion = 0;
61  std::string pathToSwapIn = "";
62  if(argc >= 2)
63  sscanf(argv[1], "%d", &flatVersion);
64  if(argc >= 3)
65  pathToSwapIn = argv[2];
66 
67  __COUT__ << "flatVersion = " << flatVersion << std::endl;
68  __COUT__ << "pathToSwapIn = " << pathToSwapIn << std::endl;
69 
70  //==============================================================================
71  // Define environment variables
72  // Note: normally these environment variables are set by StartOTS.sh
73 
74  // These are needed by
75  // otsdaq/otsdaq/ConfigurationDataFormats/ConfigurationInfoReader.cc [207]
76  setenv("CONFIGURATION_TYPE", "File", 1); // Can be File, Database, DatabaseTest
77  setenv("CONFIGURATION_DATA_PATH", (std::string(__ENV__("USER_DATA")) + "/ConfigurationDataExamples").c_str(), 1);
78  setenv("TABLE_INFO_PATH", (std::string(__ENV__("USER_DATA")) + "/TableInfo").c_str(), 1);
80 
81  // Some configuration plug-ins use __ENV__("SERVICE_DATA_PATH") in init() so define it
82  setenv("SERVICE_DATA_PATH", (std::string(__ENV__("USER_DATA")) + "/ServiceData").c_str(), 1);
83 
84  // also xdaq envs for XDAQContextTable
85  setenv("XDAQ_CONFIGURATION_DATA_PATH", (std::string(__ENV__("USER_DATA")) + "/XDAQConfigurations").c_str(), 1);
86  setenv("XDAQ_CONFIGURATION_XML", "otsConfigurationNoRU_CMake", 1);
88 
89  //==============================================================================
90  // get prepared with initial source db
91 
92  // ConfigurationManager instance immediately loads active groups
93  ConfigurationManagerRW cfgMgrInst("flatten_admin");
94  ConfigurationManagerRW* cfgMgr = &cfgMgrInst;
95 
96  __COUT__ << "\n\n\nLoading activeGroupsMap..." << std::endl;
97 
98  // save group members to reform groups
99  std::map<std::string, std::pair<std::string, TableGroupKey> > activeGroupsMap = cfgMgr->getActiveTableGroups();
100 
101  std::map<std::string, std::map<std::string, TableVersion> > activeGroupMembersMap;
102  std::map<std::string, std::map<std::string /*name*/, std::string /*alias*/> > activeGroupAliasesMap;
103  std::map<std::string, std::string> activeGroupCommentMap;
104  std::map<std::string, std::string> activeGroupAuthorMap;
105  std::string groupCreateTime;
106  std::map<std::string, time_t> activeGroupCreateTimeMap;
107  TableBase* groupMetadataTable = cfgMgr->getMetadataTable();
108 
109  for(auto& activeGroupPair : activeGroupsMap)
110  {
111  if(activeGroupPair.second.second.isInvalid())
112  {
113  __COUT__ << "Skipping invalid " << activeGroupPair.first << std::endl;
114  continue;
115  }
116 
117  __COUT__ << "Loading members for " << activeGroupPair.first << "\t" << activeGroupPair.second.first << "(" << activeGroupPair.second.second << ")"
118  << std::endl;
119 
120  // //old way before metadata
121  // activeGroupMembersMap[activeGroupPair.second.first] =
122  // cfgMgr->getConfigurationInterface()->getTableGroupMembers(
123  // TableGroupKey::getFullGroupString(
124  // activeGroupPair.second.first,activeGroupPair.second.second));
125 
126  //=========================
127  // load group, group metadata, and tables from original DB
128  try
129  {
130  cfgMgr->loadTableGroup(activeGroupPair.second.first,
131  activeGroupPair.second.second,
132  true /*doActivate*/,
133  &activeGroupMembersMap[activeGroupPair.second.first] /*memberMap*/,
134  0 /*progressBar*/,
135  &accumulateErrors,
136  &activeGroupCommentMap[activeGroupPair.second.first],
137  &activeGroupAuthorMap[activeGroupPair.second.first],
138  &groupCreateTime,
139  false /*doNotLoadMember*/,
140  0 /*groupTypeString*/,
141  &activeGroupAliasesMap[activeGroupPair.second.first]);
142  sscanf(groupCreateTime.c_str(), "%ld", &activeGroupCreateTimeMap[activeGroupPair.second.first]);
143  }
144  catch(std::runtime_error& e)
145  {
146  __COUT__ << "Error was caught loading members for " << groupPair.first.first << "(" << groupPair.first.second << ")" << std::endl;
147  __COUT__ << e.what() << std::endl;
148  errDetected = true;
149  }
150  catch(...)
151  {
152  __COUT__ << "Error was caught loading members for " << groupPair.first.first << "(" << groupPair.first.second << ")" << std::endl;
153  errDetected = true;
154  }
155 
156  //=========================
157  }
158 
159  //==============================================================================
160  // manipulate directories
161  std::string currentDir = __ENV__("ARTDAQ_DATABASE_URI");
162 
163  if(currentDir.find("filesystemdb://") != 0)
164  {
165  __SS__ << "filesystemdb:// was not found in $ARTDAQ_DATABASE_URI!" << std::endl;
166  __COUT_ERR__ << "\n" << ss.str();
167  __SS_THROW__;
168  }
169 
170  currentDir = currentDir.substr(std::string("filesystemdb://").length());
171  while(currentDir.length() && currentDir[currentDir.length() - 1] == '/') // remove trailing '/'s
172  currentDir = currentDir.substr(0, currentDir.length() - 1);
173  std::string moveToDir = currentDir + "_" + std::to_string(time(0));
174 
175  __COUT__ << "Moving current directory: \t" << currentDir << std::endl;
176  __COUT__ << "\t... to: \t\t" << moveToDir << std::endl;
177 
178  if(argc < 2)
179  {
180  __SS__ << ("Aborting move! Must at least give version argument to flatten to!") << std::endl;
181  __COUT_ERR__ << "\n" << ss.str();
182  __SS_THROW__;
183  }
184 
185  rename(currentDir.c_str(), moveToDir.c_str());
186  FILE* fp = fopen((moveToDir + "/README_otsdaq_flatten.txt").c_str(), "a");
187  if(!fp)
188  __COUT__ << "\tError opening README file!" << std::endl;
189  else
190  {
191  time_t rawtime;
192  struct tm* timeinfo;
193  char buffer[200];
194 
195  time(&rawtime);
196  timeinfo = localtime(&rawtime);
197  strftime(buffer, 200, "%b %d, %Y %I:%M%p %Z", timeinfo);
198 
199  fprintf(fp,
200  "This database was moved from...\n\t %s \nto...\n\t %s \nat this time "
201  "\n\t %lu \t %s\n\n\n",
202  currentDir.c_str(),
203  moveToDir.c_str(),
204  time(0),
205  buffer);
206 
207  fclose(fp);
208  }
209 
210  if(pathToSwapIn != "")
211  {
212  DIR* dp;
213  if((dp = opendir(pathToSwapIn.c_str())) == 0)
214  {
215  __COUT__ << "ERROR:(" << errno << "). Can't open directory: " << pathToSwapIn << std::endl;
216  exit(0);
217  }
218  closedir(dp);
219 
220  __COUT__ << "Swapping in directory: \t" << pathToSwapIn << std::endl;
221  __COUT__ << "\t.. to: \t\t" << currentDir << std::endl;
222 
223  rename(pathToSwapIn.c_str(), currentDir.c_str());
224  FILE* fp = fopen((currentDir + "/README_otsdaq_flatten.txt").c_str(), "a");
225  if(!fp)
226  __COUT__ << "\tError opening README file!" << std::endl;
227  else
228  {
229  time_t rawtime;
230  struct tm* timeinfo;
231  char buffer[200];
232 
233  time(&rawtime);
234  timeinfo = localtime(&rawtime);
235  strftime(buffer, 200, "%b %d, %Y %I:%M:%S%p %Z", timeinfo);
236 
237  fprintf(fp,
238  "This database was moved from...\t %s \t to...\t %s at this time \t "
239  "%lu \t %s\n\n",
240  pathToSwapIn.c_str(),
241  currentDir.c_str(),
242  time(0),
243  buffer);
244  fclose(fp);
245  }
246  }
247 
248  //==============================================================================
249  // save current active versions with flatVersion
250  // Note: do not try this at home kids.
251  ConfigurationInterface* theInterface_ = ConfigurationInterface::getInstance(false); // true for File interface, false for artdaq database;
252  TableView* cfgView;
253  TableBase* config;
254 
255  std::map<std::string, TableVersion> activeMap = cfgMgr->getActiveVersions();
256 
257  // modify Group Aliases Table and Version Aliases Table to point
258  // at DEFAULT and flatVersion respectively
259 
260  const std::string groupAliasesName = ConfigurationManager::GROUP_ALIASES_TABLE_NAME;
261  const std::string versionAliasesName = ConfigurationManager::VERSION_ALIASES_TABLE_NAME;
262 
263  // don't do anything more if flatVersion is not persistent
264  if(TableVersion(flatVersion).isInvalid() || TableVersion(flatVersion).isTemporaryVersion())
265  {
266  __COUT__ << "\n\nflatVersion " << TableVersion(flatVersion) << " is an invalid or temporary version. Skipping to end!" << std::endl;
267  goto CLEAN_UP;
268  }
269 
270  // modify Group Aliases Table
271  if(activeMap.find(groupAliasesName) != activeMap.end())
272  {
273  __COUT__ << "\n\nModifying " << groupAliasesName << std::endl;
274  config = cfgMgr->getTableByName(groupAliasesName);
275  cfgView = config->getViewP();
276 
277  unsigned int col1 = cfgView->findCol("GroupName");
278  unsigned int col2 = cfgView->findCol("GroupKey");
279 
280  // change all key entries to active groups to DEFAULT
281  for(unsigned int row = 0; row < cfgView->getNumberOfRows(); ++row)
282  for(auto& activeGroupPair : activeGroupsMap)
283  if(activeGroupPair.second.second.isInvalid())
284  continue;
285  else if(cfgView->getDataView()[row][col1] == activeGroupPair.second.first &&
286  cfgView->getDataView()[row][col2] == activeGroupPair.second.second.toString())
287  {
288  // found a matching group/key pair
289  __COUT__ << "Changing row " << row << " for " << cfgView->getDataView()[row][col1] << " key=" << cfgView->getDataView()[row][col2]
290  << " to DEFAULT=" << TableGroupKey(TableGroupKey::getDefaultKey()) << std::endl;
291  cfgView->setValue(TableGroupKey(TableGroupKey::getDefaultKey()).toString(), row, col2);
292  break;
293  }
294  }
295 
296  // modify Version Aliases Table
297  if(activeMap.find(versionAliasesName) != activeMap.end())
298  {
299  __COUT__ << "\n\nModifying " << versionAliasesName << std::endl;
300  config = cfgMgr->getTableByName(versionAliasesName);
301  cfgView = config->getViewP();
302  unsigned int col1 = cfgView->findCol("TableName");
303  unsigned int col2 = cfgView->findCol("Version");
304 
305  // change all version entries to active tables to flatVersion
306  for(unsigned int row = 0; row < cfgView->getNumberOfRows(); ++row)
307  for(auto& activePair : activeMap)
308  if(cfgView->getDataView()[row][col1] == activePair.first && cfgView->getDataView()[row][col2] == activePair.second.toString())
309  {
310  // found a matching group/key pair
311  __COUT__ << "Changing row " << row << " for " << cfgView->getDataView()[row][col1] << " version=" << cfgView->getDataView()[row][col2]
312  << " to flatVersion=" << TableVersion(flatVersion) << std::endl;
313  cfgView->setValue(TableVersion(flatVersion).toString(), row, col2);
314  break;
315  }
316  }
317 
318  __COUT__ << "\n\nChanging versions... " << std::endl;
319 
320  for(auto& activePair : activeMap)
321  {
322  __COUT__ << activePair.first << ":v" << activePair.second << std::endl;
323  // change the version of the active view to flatVersion and save it
324  config = cfgMgr->getTableByName(activePair.first);
325  cfgView = config->getViewP();
326  cfgView->setVersion(TableVersion(flatVersion));
327  theInterface_->saveActiveVersion(config);
328  }
329 
330  //==============================================================================
331  // save the active groups with the new member flatVersions
332  // Note: do not try this at home kids.
333  for(auto& activeGroupMembersPair : activeGroupMembersMap)
334  {
335  __COUT__ << "Group " << activeGroupMembersPair.first << std::endl;
336 
337  for(auto& groupMemberPair : activeGroupMembersPair.second)
338  {
339  __COUT__ << "\t from...\t" << groupMemberPair.first << ":v" << groupMemberPair.second << std::endl;
340  groupMemberPair.second = flatVersion;
341  }
342 
343  for(auto& groupMemberPair : activeGroupMembersPair.second)
344  {
345  __COUT__ << "\t to...\t" << groupMemberPair.first << ":v" << groupMemberPair.second << std::endl;
346  }
347 
348  // Note: this code copies actions in ConfigurationManagerRW::saveNewTableGroup
349 
350  // add meta data
351  __COUTV__(StringMacros::mapToString(activeGroupAliasesMap[activeGroupMembersPair.first]));
352  __COUTV__(activeGroupCommentMap[activeGroupMembersPair.first]);
353  __COUTV__(activeGroupAuthorMap[activeGroupMembersPair.first]);
354  __COUTV__(activeGroupCreateTimeMap[activeGroupMembersPair.first]);
355 
356  // to compensate for unusual errors upstream, make sure the metadata table has one
357  // row
358  while(groupMetadataTable->getViewP()->getNumberOfRows() > 1)
359  groupMetadataTable->getViewP()->deleteRow(0);
360  if(groupMetadataTable->getViewP()->getNumberOfRows() == 0)
361  groupMetadataTable->getViewP()->addRow();
362 
363  // columns are uid,comment,author,time
364  // ConfigurationManager::METADATA_COL_ALIASES TODO
365  groupMetadataTable->getViewP()->setValue(
366  StringMacros::mapToString(activeGroupAliasesMap[activeGroupMembersPair.first], "," /*primary delimiter*/, ":" /*secondary delimeter*/),
367  0,
368  ConfigurationManager::METADATA_COL_ALIASES);
369  groupMetadataTable->getViewP()->setValue(activeGroupCommentMap[activeGroupMembersPair.first], 0, ConfigurationManager::METADATA_COL_COMMENT);
370  groupMetadataTable->getViewP()->setValue(activeGroupAuthorMap[activeGroupMembersPair.first], 0, ConfigurationManager::METADATA_COL_AUTHOR);
371  groupMetadataTable->getViewP()->setValue(activeGroupCreateTimeMap[activeGroupMembersPair.first], 0, ConfigurationManager::METADATA_COL_TIMESTAMP);
372 
373  // set version of metadata table
374  groupMetadataTable->getViewP()->setVersion(TableVersion(flatVersion));
375  theInterface_->saveActiveVersion(groupMetadataTable);
376 
377  // force groupMetadataTable_ to be a member for the group
378  activeGroupMembersPair.second[groupMetadataTable->getTableName()] = groupMetadataTable->getViewVersion();
379 
380  // memberMap should now consist of members with new flat version, so save group
381  theInterface_->saveTableGroup(activeGroupMembersPair.second,
382  TableGroupKey::getFullGroupString(activeGroupMembersPair.first, TableGroupKey(TableGroupKey::getDefaultKey())));
383  }
384 
385 CLEAN_UP:
386  //==============================================================================
387  __COUT__ << "\n\nEnd of Flattening Active Table Groups!\n\n\n" << std::endl;
388 
389  __COUT__ << "Run the following to return to your previous database structure:" << std::endl;
390  __COUT__ << "\t otsdaq_flatten_active_to_version -1 " << moveToDir << "\n\n" << std::endl;
391 
392  return;
393 }
394 
395 int main(int argc, char* argv[])
396 {
397  FlattenActiveTableGroups(argc, argv);
398  return 0;
399 }
400 // BOOST_AUTO_TEST_SUITE_END()