otsdaq  v1_01_04
 All Classes Namespaces Functions
ConfigurationManagerRW.cc
1 #include "otsdaq-core/ConfigurationInterface/ConfigurationManagerRW.h"
2 
3 //backbone includes
4 //#include "otsdaq-core/ConfigurationPluginDataFormats/ConfigurationAliases.h"
5 //#include "otsdaq-core/ConfigurationPluginDataFormats/Configurations.h"
6 //#include "otsdaq-core/ConfigurationPluginDataFormats/DefaultConfigurations.h"
7 //#include "otsdaq-core/ConfigurationPluginDataFormats/VersionAliases.h"
8 
9 //#include "otsdaq-core/ConfigurationInterface/ConfigurationInterface.h"//All configurable objects are included here
10 
11 
12 //
13 //#include "otsdaq-core/ConfigurationPluginDataFormats/DetectorConfiguration.h"
14 //#include "otsdaq-core/ConfigurationPluginDataFormats/MaskConfiguration.h"
15 //#include "otsdaq-core/ConfigurationPluginDataFormats/DetectorToFEConfiguration.h"
16 //
17 
18 //#include "otsdaq-core/ConfigurationInterface/DACStream.h"
19 //#include "otsdaq-core/ConfigurationDataFormats/ConfigurationGroupKey.h"
20 //
21 //#include "otsdaq-core/ConfigurationInterface/FileConfigurationInterface.h"
22 //
23 //#include <cassert>
24 
25 #include<dirent.h>
26 
27 using namespace ots;
28 
29 
30 #undef __MF_SUBJECT__
31 #define __MF_SUBJECT__ "ConfigurationManagerRW"
32 
33 #define CONFIGURATION_INFO_PATH std::string(getenv("CONFIGURATION_INFO_PATH")) + "/"
34 #define CONFIGURATION_INFO_EXT "Info.xml"
35 
36 //==============================================================================
37 //ConfigurationManagerRW
38 ConfigurationManagerRW::ConfigurationManagerRW(std::string username)
39 : ConfigurationManager(username) //for use as author of new views
40 {
41  __COUT__ << "Using Config Mgr with Write Access! (for " << username << ")" << std::endl;
42 
43 
44  //FIXME only necessarily temporarily while Lore is still using fileSystem xml
45  theInterface_ = ConfigurationInterface::getInstance(false); //false to use artdaq DB
46  // FIXME -- can delete this change of interface once RW and regular use same interface instance
47 }
48 
49 //==============================================================================
50 //getAllConfigurationInfo()
51 // Used by ConfigurationGUISupervisor to get all the info for the existing configurations
52 //
53 //if(accumulatedErrors)
54 // this implies allowing column errors and accumulating such errors in given string
55 const std::map<std::string, ConfigurationInfo>& ConfigurationManagerRW::getAllConfigurationInfo(
56  bool refresh, std::string *accumulatedErrors, const std::string &errorFilterName)
57 {
58  //allConfigurationInfo_ is container to be returned
59 
60  if(accumulatedErrors) *accumulatedErrors = "";
61 
62  if(!refresh) return allConfigurationInfo_;
63 
64  //else refresh!
65  allConfigurationInfo_.clear();
66 
67  ConfigurationBase* configuration;
68 
69  //existing configurations are defined by which infos are in CONFIGURATION_INFO_PATH
70  //can test that the class exists based on this
71  //and then which versions
72  __COUT__ << "======================================================== getAllConfigurationInfo start" << std::endl;
73  __COUT__ << "Refreshing all! Extracting list of Configuration tables..." << std::endl;
74  DIR *pDIR;
75  struct dirent *entry;
76  std::string path = CONFIGURATION_INFO_PATH;
77  char fileExt[] = CONFIGURATION_INFO_EXT;
78  const unsigned char MIN_CONFIG_NAME_SZ = 3;
79  if( (pDIR=opendir( path.c_str() )) != 0 )
80  {
81  while((entry = readdir(pDIR)) != 0)
82  {
83  //enforce configuration name length
84  if(strlen(entry->d_name) < strlen(fileExt)+MIN_CONFIG_NAME_SZ)
85  continue;
86 
87  //find file names with correct file extenstion
88  if( strcmp(
89  &(entry->d_name[strlen(entry->d_name) - strlen(fileExt)]),
90  fileExt) != 0)
91  continue; //skip different extentions
92 
93 
94  entry->d_name[strlen(entry->d_name) - strlen(fileExt)] = '\0'; //remove file extension to get config name
95 
96  //__COUT__ << entry->d_name << std::endl;
97 
98  //0 will force the creation of new instance (and reload from Info)
99  configuration = 0;
100 
101  try //only add valid configuration instances to maps
102  {
103  theInterface_->get(configuration,
104  entry->d_name,
105  0, 0,
106  true); //dont fill
107  }
108  catch(cet::exception)
109  {
110  if(configuration) delete configuration;
111  configuration = 0;
112 
113  __COUT__ << "Skipping! No valid class found for... " << entry->d_name << "\n";
114  continue;
115  }
116  catch(std::runtime_error &e)
117  {
118  if(configuration) delete configuration;
119  configuration = 0;
120 
121  __COUT__ << "Skipping! No valid class found for... " << entry->d_name << "\n";
122  __COUT__ << "Error: " << e.what() << std::endl;
123 
124 
125  //for a runtime_error, it is likely that columns are the problem
126  // the Table Editor needs to still fix these.. so attempt to
127  // proceed.
128  if(accumulatedErrors)
129  {
130 
131  if(errorFilterName == "" ||
132  errorFilterName == entry->d_name)
133  {
134  *accumulatedErrors += std::string("\nIn table '") + entry->d_name +
135  "'..." + e.what(); //global accumulate
136 
137  __SS__ << "Attempting to allow illegal columns!" << std::endl;
138  *accumulatedErrors += ss.str();
139  }
140 
141  //attempt to recover and build a mock-up
142  __COUT__ << "Attempting to allow illegal columns!" << std::endl;
143 
144 
145  std::string returnedAccumulatedErrors;
146  try
147  {
148  //configuration = new ConfigurationBase(entry->d_name, &returnedAccumulatedErrors);
149  configuration = new ConfigurationBase(entry->d_name, &returnedAccumulatedErrors);
150  }
151  catch(...)
152  {
153  __COUT__ << "Skipping! Allowing illegal columns didn't work either... " <<
154  entry->d_name << "\n";
155  continue;
156  }
157  __COUT__ << "Error (but allowed): " << returnedAccumulatedErrors << std::endl;
158 
159  if(errorFilterName == "" ||
160  errorFilterName == entry->d_name)
161  *accumulatedErrors += std::string("\nIn table '") + entry->d_name +
162  "'..." + returnedAccumulatedErrors; //global accumulate
163  }
164  else
165  continue;
166  }
167 
168  //__COUT__ << "Instance created: " << entry->d_name << "\n"; //found!
169 
170  if(nameToConfigurationMap_[entry->d_name]) //handle if instance existed
171  {
172  //copy the temporary versions! (or else all is lost)
173  std::set<ConfigurationVersion> versions =
174  nameToConfigurationMap_[entry->d_name]->getStoredVersions();
175  for(auto &version:versions)
176  if(version.isTemporaryVersion())
177  {
178  __COUT__ << "copying tmp = " << version << std::endl;
179 
180  try //do NOT let ConfigurationView::init() throw here
181  {
182  nameToConfigurationMap_[entry->d_name]->setActiveView(version);
183  configuration->copyView( //this calls ConfigurationView::init()
184  nameToConfigurationMap_[entry->d_name]->getView(),
185  version,
186  username_);
187  }
188  catch(...) //do NOT let invalid temporary version throw at this point
189  {} //just trust configurationBase throws out the failed version
190  }
191  //__COUT__ << "deleting: " << entry->d_name << "\n"; //found!
192  delete nameToConfigurationMap_[entry->d_name];
193  nameToConfigurationMap_[entry->d_name] = 0;
194  }
195 
196  nameToConfigurationMap_[entry->d_name] = configuration;
197 
198  allConfigurationInfo_[entry->d_name].configurationPtr_ = configuration;
199  allConfigurationInfo_[entry->d_name].versions_ = theInterface_->getVersions(configuration);
200 
201  //also add any existing temporary versions to all config info
202  // because the interface wont find those versions
203  std::set<ConfigurationVersion> versions =
204  nameToConfigurationMap_[entry->d_name]->getStoredVersions();
205  for(auto &version:versions)
206  if(version.isTemporaryVersion())
207  {
208  __COUT__ << "surviving tmp = " << version << std::endl;
209  allConfigurationInfo_[entry->d_name].versions_.emplace(version);
210  }
211  }
212  closedir(pDIR);
213  }
214  __COUT__ << "Extracting list of Configuration tables complete" << std::endl;
215 
216  //call init to load active versions by default
217  init(accumulatedErrors);
218 
219  __COUT__ << "======================================================== getAllConfigurationInfo end" << std::endl;
220 
221  return allConfigurationInfo_;
222 }
223 
224 //==============================================================================
225 //getActiveAliases()
226 // get active version aliases organized by table
227 std::map<std::string,std::map<std::string,ConfigurationVersion> >
228 ConfigurationManagerRW::getActiveVersionAliases(void) const
229 {
230  __COUT__ << "getActiveVersionAliases()" << std::endl;
231  std::map<std::string,std::map<std::string,ConfigurationVersion> > retMap;
232 
233  std::map<std::string, ConfigurationVersion> activeVersions = getActiveVersions();
234  std::string versionAliasesTableName = "VersionAliasesConfiguration";
235  if(activeVersions.find(versionAliasesTableName) == activeVersions.end())
236  {
237  __SS__ << "Active version of VersionAliases missing!" <<
238  "Make sure you have a valid active Backbone Group." << std::endl;
239  __COUT_WARN__ << "\n" << ss.str();
240  return retMap;
241  }
242 
243  __COUT__ << "activeVersions[\"VersionAliasesConfiguration\"]=" <<
244  activeVersions[versionAliasesTableName] << std::endl;
245 
246  //always have scratch alias for each table that has a scratch version
247  if(!ConfigurationInterface::isVersionTrackingEnabled())
248  for(const auto &tableInfo:allConfigurationInfo_)
249  for(const auto &version:tableInfo.second.versions_)
250  if(version.isScratchVersion())
251  retMap[tableInfo.first][ConfigurationManager::SCRATCH_VERSION_ALIAS] =
252  ConfigurationVersion(ConfigurationVersion::SCRATCH);
253 
254  std::vector<std::pair<std::string,ConfigurationTree> > aliasNodePairs =
255  getNode(versionAliasesTableName).getChildren();
256 
257  //create map
258  // add the first of each configName, versionAlias pair encountered
259  // ignore any repeats (Note: this also prevents overwriting of Scratch alias)
260  std::string configName, versionAlias;
261  for(auto& aliasNodePair:aliasNodePairs)
262  {
263  configName = aliasNodePair.second.getNode(
264  "ConfigurationName").getValueAsString();
265  versionAlias = aliasNodePair.second.getNode(
266  "VersionAlias").getValueAsString();
267 
268  if(retMap.find(configName) != retMap.end() &&
269  retMap[configName].find(versionAlias) != retMap[configName].end())
270  continue; //skip repeats (Note: this also prevents overwriting of Scratch alias)
271 
272  //else add version to map
273  retMap[configName][versionAlias] = ConfigurationVersion(
274  aliasNodePair.second.getNode("Version").getValueAsString());
275  }
276 
277  return retMap;
278 }
279 
280 //==============================================================================
281 //setActiveGlobalConfiguration
282 // load config group and activate
283 // deactivates previous config group of same type if necessary
284 void ConfigurationManagerRW::activateConfigurationGroup(const std::string &configGroupName,
285  ConfigurationGroupKey configGroupKey, std::string *accumulatedTreeErrors)
286 {
287  loadConfigurationGroup(configGroupName,configGroupKey,
288  true, //loads and activates
289  0, //no progress bar
290  accumulatedTreeErrors); //accumulate warnings or not
291 
292  if(accumulatedTreeErrors &&
293  *accumulatedTreeErrors != "")
294  {
295  __COUT_ERR__ << "Errors were accumulated so de-activating group: " <<
296  configGroupName << " (" << configGroupKey << ")" << std::endl;
297  try //just in case any lingering pieces, lets deactivate
298  { destroyConfigurationGroup(configGroupName,true); }
299  catch(...){}
300  }
301 
302  __MOUT_INFO__ << "Updating persistent active groups to " <<
303  ConfigurationManager::ACTIVE_GROUP_FILENAME << " ..." << std::endl;
304 
305  std::string fn = ConfigurationManager::ACTIVE_GROUP_FILENAME;
306  FILE *fp = fopen(fn.c_str(),"w");
307  if(!fp)
308  {
309  __SS__ << "Fatal Error! Unable to open the file " <<
310  ConfigurationManager::ACTIVE_GROUP_FILENAME << " for editing! Is there a permissions problem?" << std::endl;
311  __COUT_ERR__ << ss.str();
312  throw std::runtime_error(ss.str());
313  return;
314  }
315 
316  __MOUT_INFO__ << "Active Context: " << theContextGroup_ << "(" <<
317  (theContextGroupKey_?theContextGroupKey_->toString().c_str():"-1") << ")" << std::endl;
318  __MOUT_INFO__ << "Active Backbone: " << theBackboneGroup_ << "(" <<
319  (theBackboneGroupKey_?theBackboneGroupKey_->toString().c_str():"-1") << ")" << std::endl;
320  __MOUT_INFO__ << "Active Iterate: " << theIterateGroup_ << "(" <<
321  (theIterateGroupKey_?theIterateGroupKey_->toString().c_str():"-1") << ")" << std::endl;
322  __MOUT_INFO__ << "Active Configuration: " << theConfigurationGroup_ << "(" <<
323  (theConfigurationGroupKey_?theConfigurationGroupKey_->toString().c_str():"-1") << ")" << std::endl;
324 
325  fprintf(fp,"%s\n",theContextGroup_.c_str());
326  fprintf(fp,"%s\n",theContextGroupKey_?theContextGroupKey_->toString().c_str():"-1");
327  fprintf(fp,"%s\n",theBackboneGroup_.c_str());
328  fprintf(fp,"%s\n",theBackboneGroupKey_?theBackboneGroupKey_->toString().c_str():"-1");
329  fprintf(fp,"%s\n",theIterateGroup_.c_str());
330  fprintf(fp,"%s\n",theIterateGroupKey_?theIterateGroupKey_->toString().c_str():"-1");
331  fprintf(fp,"%s\n",theConfigurationGroup_.c_str());
332  fprintf(fp,"%s\n",theConfigurationGroupKey_?theConfigurationGroupKey_->toString().c_str():"-1");
333  fclose(fp);
334 }
335 
336 //==============================================================================
337 //createTemporaryBackboneView
338 // sourceViewVersion of INVALID is from MockUp, else from valid view version
339 // returns temporary version number (which is always negative)
340 ConfigurationVersion ConfigurationManagerRW::createTemporaryBackboneView(ConfigurationVersion sourceViewVersion)
341 {
342  __COUT_INFO__ << "Creating temporary backbone view from version " <<
343  sourceViewVersion << std::endl;
344 
345  //find common available temporary version among backbone members
346  ConfigurationVersion tmpVersion = ConfigurationVersion::getNextTemporaryVersion(); //get the default temporary version
347  ConfigurationVersion retTmpVersion;
348  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
349  for (auto& name : backboneMemberNames)
350  {
351  retTmpVersion = ConfigurationManager::getConfigurationByName(name)->getNextTemporaryVersion();
352  if(retTmpVersion < tmpVersion)
353  tmpVersion = retTmpVersion;
354  }
355 
356  __COUT__ << "Common temporary backbone version found as " <<
357  tmpVersion << std::endl;
358 
359  //create temporary views from source version to destination temporary version
360  for (auto& name : backboneMemberNames)
361  {
362  retTmpVersion = getConfigurationByName(name)->createTemporaryView(sourceViewVersion, tmpVersion);
363  if(retTmpVersion != tmpVersion)
364  {
365  __SS__ << "Failure! Temporary view requested was " <<
366  tmpVersion << ". Mismatched temporary view created: " << retTmpVersion << std::endl;
367  __COUT_ERR__ << ss.str();
368  throw std::runtime_error(ss.str());
369  }
370  }
371 
372  return tmpVersion;
373 }
374 
375 
376 
377 //==============================================================================
378 ConfigurationBase* ConfigurationManagerRW::getConfigurationByName(const std::string &configurationName)
379 {
380  if(nameToConfigurationMap_.find(configurationName) == nameToConfigurationMap_.end())
381  {
382  __SS__ << "Configuration not found with name: " << configurationName << std::endl;
383  size_t f;
384  if((f=configurationName.find(' ')) != std::string::npos)
385  ss << "There was a space character found in the configuration name needle at position " <<
386  f << " in the string (was this intended?). " << std::endl;
387  __COUT_ERR__ << "\n" << ss.str();
388  throw std::runtime_error(ss.str());
389  }
390  return nameToConfigurationMap_[configurationName];
391 }
392 
393 //==============================================================================
394 //getVersionedConfigurationByName
395 // Used by configuration GUI to load a particular configuration-version pair as the active version.
396 // This configuration instance must already exist and be owned by ConfigurationManager.
397 // return null pointer on failure, on success return configuration pointer.
398 ConfigurationBase* ConfigurationManagerRW::getVersionedConfigurationByName(const std::string &configurationName,
399  ConfigurationVersion version, bool looseColumnMatching)
400 {
401  auto it = nameToConfigurationMap_.find(configurationName);
402  if(it == nameToConfigurationMap_.end())
403  {
404  __SS__ << "\nCan not find configuration named '" <<
405  configurationName <<
406  "'\n\n\n\nYou need to load the configuration before it can be used." <<
407  "It probably is missing from the member list of the Configuration Group that was loaded?\n\n\n\n\n"
408  << std::endl;
409  throw std::runtime_error(ss.str());
410  }
411  ConfigurationBase* configuration = it->second;
412  theInterface_->get(configuration, configurationName, 0 , 0,
413  false, //fill w/version
414  version,
415  false, //do not reset
416  looseColumnMatching);
417  return configuration;
418 }
419 
420 //==============================================================================
421 //saveNewConfiguration
422 // saves version, makes the new version the active version, and returns new version
423 ConfigurationVersion ConfigurationManagerRW::saveNewConfiguration(const std::string &configurationName,
424  ConfigurationVersion temporaryVersion, bool makeTemporary)
425 {
426  ConfigurationVersion newVersion(temporaryVersion);
427 
428  //set author of version
429  ConfigurationBase *config = getConfigurationByName(configurationName);
430  config->getTemporaryView(temporaryVersion)->setAuthor(username_);
431  //NOTE: somehow? author is assigned to permanent versions when saved to DBI?
432 
433  if(!makeTemporary) //saveNewVersion makes the new version the active version
434  newVersion = theInterface_->saveNewVersion(config, temporaryVersion);
435  else //make the temporary version active
436  config->setActiveView(newVersion);
437 
438  //if there is a problem, try to recover
439  while(!makeTemporary && !newVersion.isScratchVersion() &&
440  allConfigurationInfo_[configurationName].versions_.find(newVersion) !=
441  allConfigurationInfo_[configurationName].versions_.end())
442  {
443  __COUT_ERR__ << "What happenened!?? ERROR::: new persistent version v" << newVersion <<
444  " already exists!? How is it possible? Retrace your steps and tell an admin." << std::endl;
445 
446  //create a new temporary version of the target view
447  temporaryVersion = config->createTemporaryView(newVersion);
448 
449  if(newVersion.isTemporaryVersion())
450  newVersion = temporaryVersion;
451  else
452  newVersion = ConfigurationVersion::getNextVersion(newVersion);
453 
454  __COUT_WARN__ << "Attempting to recover and use v" << newVersion << std::endl;
455 
456 
457  if(!makeTemporary) //saveNewVersion makes the new version the active version
458  newVersion = theInterface_->saveNewVersion(config, temporaryVersion, newVersion);
459  else //make the temporary version active
460  config->setActiveView(newVersion);
461  }
462 
463  if(newVersion.isInvalid())
464  {
465  __SS__ << "Something went wrong saving the new version v" << newVersion <<
466  ". What happened?! (duplicates? database error?)" << std::endl;
467  __COUT_ERR__ << "\n" << ss.str();
468  throw std::runtime_error(ss.str());
469  }
470 
471  //update allConfigurationInfo_ with the new version
472  allConfigurationInfo_[configurationName].versions_.insert(newVersion);
473 
474  __COUT__ << "New version added to info " << newVersion << std::endl;
475 
476  return newVersion;
477 }
478 
479 //==============================================================================
480 //eraseTemporaryVersion
481 // if version is invalid then erases ALL temporary versions
482 //
483 // maintains allConfigurationInfo_ also while erasing
484 void ConfigurationManagerRW::eraseTemporaryVersion(const std::string &configurationName,
485  ConfigurationVersion targetVersion)
486 {
487  ConfigurationBase* config = getConfigurationByName(configurationName);
488 
489  config->trimTemporary(targetVersion);
490 
491  //if allConfigurationInfo_ is not setup, then done
492  if(allConfigurationInfo_.find(configurationName) ==
493  allConfigurationInfo_.end()) return;
494  //else cleanup config info
495 
496  if(targetVersion.isInvalid())
497  {
498  //erase all temporary versions!
499  for(auto it = allConfigurationInfo_[configurationName].versions_.begin();
500  it != allConfigurationInfo_[configurationName].versions_.end(); /*no increment*/)
501  {
502  if(it->isTemporaryVersion())
503  {
504  __COUT__ << "Removing version info: " << *it << std::endl;
505  allConfigurationInfo_[configurationName].versions_.erase(it++);
506  }
507  else
508  ++it;
509  }
510  }
511  else //erase target version only
512  {
513  __COUT__ << "Removing version info: " << targetVersion << std::endl;
514  auto it = allConfigurationInfo_[configurationName].versions_.find(targetVersion);
515  if(it == allConfigurationInfo_[configurationName].versions_.end())
516  {
517  __COUT__ << "Target version was not found in info versions..." << std::endl;
518  return;
519  }
520  allConfigurationInfo_[configurationName].versions_.erase(
521  allConfigurationInfo_[configurationName].versions_.find(targetVersion));
522  __COUT__ << "Target version was erased from info." << std::endl;
523  }
524 }
525 
526 //==============================================================================
527 //clearCachedVersions
528 // clear ALL cached persistent versions (does not erase temporary versions)
529 //
530 // maintains allConfigurationInfo_ also while erasing (trivial, do nothing)
531 void ConfigurationManagerRW::clearCachedVersions(const std::string &configurationName)
532 {
533  ConfigurationBase* config = getConfigurationByName(configurationName);
534 
535  config->trimCache(0);
536 }
537 
538 //==============================================================================
539 //clearAllCachedVersions
540 // clear ALL cached persistent versions (does not erase temporary versions)
541 //
542 // maintains allConfigurationInfo_ also while erasing (trivial, do nothing)
543 void ConfigurationManagerRW::clearAllCachedVersions()
544 {
545  for(auto configInfo: allConfigurationInfo_)
546  configInfo.second.configurationPtr_->trimCache(0);
547 }
548 
549 //==============================================================================
550 //copyViewToCurrentColumns
551 ConfigurationVersion ConfigurationManagerRW::copyViewToCurrentColumns(const std::string &configurationName,
552  ConfigurationVersion sourceVersion)
553 {
554  getConfigurationByName(configurationName)->reset();
555 
556  //make sure source version is loaded
557  //need to load with loose column rules!
558  ConfigurationBase *config = getVersionedConfigurationByName(configurationName,
559  ConfigurationVersion(sourceVersion), true);
560 
561  //copy from source version to a new temporary version
562  ConfigurationVersion newTemporaryVersion = config->copyView(config->getView(),
563  ConfigurationVersion(),username_);
564 
565  //update allConfigurationInfo_ with the new version
566  allConfigurationInfo_[configurationName].versions_.insert(newTemporaryVersion);
567 
568  return newTemporaryVersion;
569 }
570 
571 
572 
573 //==============================================================================
574 //findConfigurationGroup
575 // return group with same name and same members
576 // else return invalid key
577 //
578 // FIXME -- this is taking too long when there are a ton of groups.
579 // Change to going back only 20 or so.. (but the order also comes in alpha order from
580 // theInterface_->getAllConfigurationGroupNames which is a problem for choosing the
581 // most recent to check.
582 ConfigurationGroupKey ConfigurationManagerRW::findConfigurationGroup(const std::string &groupName,
583  const std::map<std::string, ConfigurationVersion> &groupMemberMap)
584 {
585  std::set<std::string /*name*/> fullGroupNames =
586  theInterface_->getAllConfigurationGroupNames(groupName); //db filter by group name
587 
588  std::string name;
590  std::map<std::string /*name*/, ConfigurationVersion /*version*/> compareToMemberMap;
591  bool isDifferent;
592 
593  const unsigned int MAX_DEPTH_TO_CHECK = 20;
594  unsigned int keyMinToCheck = 0;
595 
596  //determine min key to check
597  if(fullGroupNames.size() > MAX_DEPTH_TO_CHECK)
598  {
599  //find keyMinToCheck to avoid looking at all groups
600  for(const std::string& fullName: fullGroupNames)
601  {
602  ConfigurationGroupKey::getGroupNameAndKey(fullName,name,key);
603  if(key.key() > keyMinToCheck)
604  keyMinToCheck = key.key();
605  }
606 
607  //just in case of craziness, check not crossing 0
608  if(keyMinToCheck >= MAX_DEPTH_TO_CHECK - 1)
609  keyMinToCheck -= MAX_DEPTH_TO_CHECK - 1;
610  else
611  keyMinToCheck = 0;
612 
613  __COUT__ << "Checking groups back to key... " << keyMinToCheck << std::endl;
614  }
615  else
616  __COUT__ << "Checking all groups." << std::endl;
617 
618  //have min key to check, now loop through and check groups
619  for(const std::string& fullName: fullGroupNames)
620  {
621  ConfigurationGroupKey::getGroupNameAndKey(fullName,name,key);
622 
623  if(key.key() < keyMinToCheck) continue; //skip keys that are too old
624 
625  //__COUT__ << fullName << " has name " << name << " ==? " << groupName << std::endl;
626  //if( name != groupName) continue; // superfluous check, but just to make sure the db filter worked
627 
628  __COUT__ << "checking group... " << fullName << std::endl;
629  compareToMemberMap = theInterface_->getConfigurationGroupMembers(fullName);
630 
631  isDifferent = false;
632  for(auto &memberPair: groupMemberMap)
633  {
634  //__COUT__ << memberPair.first << " - " << memberPair.second << std::endl;
635  if(compareToMemberMap.find(memberPair.first) == compareToMemberMap.end() || //name is missing
636  memberPair.second != compareToMemberMap[memberPair.first]) //or version mismatch
637  { //then different
638  //__COUT__ << "mismatch found!" << std::endl;
639  isDifferent = true;
640  break;
641  }
642  }
643  if(isDifferent) continue;
644 
645  //check member size for exact match
646  if(groupMemberMap.size() != compareToMemberMap.size()) continue; //different size, so not same (groupMemberMap is a subset of memberPairs)
647 
648  __COUT__ << "Found exact match with key: " << key << std::endl;
649  //else found an exact match!
650  return key;
651  }
652  __COUT__ << "No match found - this group is new!" << std::endl;
653  //if here, then no match found
654  return ConfigurationGroupKey(); //return invalid key
655 }
656 
657 
658 //==============================================================================
659 //saveNewConfigurationGroup
660 // saves new group and returns the new group key
661 // if previousVersion is provided, attempts to just bump that version
662 // else, bumps latest version found in db
663 //
664 // Note: groupMembers map will get modified with group metadata table version
665 ConfigurationGroupKey ConfigurationManagerRW::saveNewConfigurationGroup(const std::string &groupName,
666  std::map<std::string, ConfigurationVersion> &groupMembers,
667  ConfigurationGroupKey previousVersion, const std::string &groupComment)
668 {
669  //steps:
670  // determine new group key
671  // verify group members
672  // verify groupNameWithKey
673  // verify store
674 
675 
676  if(groupMembers.size() == 0) //do not allow empty groups
677  {
678  __SS__ << "Empty group member list. Can not create a group without members!" << std::endl;
679  __COUT_ERR__ << ss.str();
680  throw std::runtime_error(ss.str());
681  }
682 
683  //determine new group key
684  ConfigurationGroupKey newKey;
685  if(!previousVersion.isInvalid()) //if previous provided, bump that
686  newKey = ConfigurationGroupKey::getNextKey(previousVersion);
687  else //get latest key from db, and bump
688  {
689  std::set<ConfigurationGroupKey> keys = theInterface_->getKeys(groupName);
690  if(keys.size()) //if keys exist, bump the last
691  newKey = ConfigurationGroupKey::getNextKey(*(keys.crbegin()));
692  else //else, take default
693  newKey = ConfigurationGroupKey::getDefaultKey();
694  }
695 
696  __COUT__ << "New Key for group: " << groupName << " found as " << newKey << std::endl;
697 
698  // verify group members
699  // - use all config info
700  std::map<std::string, ConfigurationInfo> allCfgInfo = getAllConfigurationInfo();
701  for(auto &memberPair : groupMembers )
702  {
703  //check member name
704  if(allCfgInfo.find(memberPair.first) == allCfgInfo.end())
705  {
706  __COUT_ERR__ << "Group member \"" << memberPair.first << "\" not found in configuration!";
707 
708  if(groupMetadataTable_.getConfigurationName() ==
709  memberPair.first)
710  {
711  __COUT_WARN__ << "Looks like this is the groupMetadataTable_. " <<
712  "Note that this table is added to the member map when groups are saved." <<
713  "It should not be part of member map when calling this function." << std::endl;
714  __COUT__ << "Attempting to recover." << std::endl;
715  groupMembers.erase(groupMembers.find(memberPair.first));
716  }
717  else
718  {
719  __SS__ << ("Group member not found!") << std::endl;
720  __COUT_ERR__ << ss.str();
721  throw std::runtime_error(ss.str());
722  }
723  }
724  //check member version
725  if(allCfgInfo[memberPair.first].versions_.find(memberPair.second) ==
726  allCfgInfo[memberPair.first].versions_.end())
727  {
728  __SS__ << "Group member \"" << memberPair.first << "\" version \"" <<
729  memberPair.second << "\" not found in configuration!";
730  __COUT_ERR__ << ss.str();
731  throw std::runtime_error(ss.str());
732  }
733  }
734 
735  // verify groupNameWithKey and attempt to store
736  try
737  {
738  //save meta data for group; reuse groupMetadataTable_
739 
740  __COUT__ << username_ << " " << time(0) << " " << groupComment << std::endl;
741  //columns are uid,comment,author,time
742  groupMetadataTable_.getViewP()->setValue(groupComment,0,1);
743  groupMetadataTable_.getViewP()->setValue(username_,0,2);
744  groupMetadataTable_.getViewP()->setValue(time(0),0,3);
745 
746  //set version to first available persistent version
747  groupMetadataTable_.getViewP()->setVersion(
748  ConfigurationVersion::getNextVersion(theInterface_->findLatestVersion(&groupMetadataTable_))
749  );
750 
751  //groupMetadataTable_.print();
752 
753  theInterface_->saveActiveVersion(&groupMetadataTable_);
754 
755  //force groupMetadataTable_ to be a member for the group
756  groupMembers[groupMetadataTable_.getConfigurationName()] =
757  groupMetadataTable_.getViewVersion();
758 
759  theInterface_->saveConfigurationGroup(groupMembers,
760  ConfigurationGroupKey::getFullGroupString(groupName,newKey));
761  __COUT__ << "Created config group: " << groupName << ":" << newKey << std::endl;
762  }
763  catch(std::runtime_error &e)
764  {
765  __COUT_ERR__ << "Failed to create config group: " << groupName << ":" << newKey << std::endl;
766  __COUT_ERR__ << "\n\n" << e.what() << std::endl;
767  throw;
768  }
769  catch(...)
770  {
771  __COUT_ERR__ << "Failed to create config group: " << groupName << ":" << newKey << std::endl;
772  throw;
773  }
774 
775  // at this point succeeded!
776  return newKey;
777 }
778 
779 //==============================================================================
780 //saveNewBackbone
781 // makes the new version the active version and returns new version number
782 // INVALID will give a new backbone from mockup
783 ConfigurationVersion ConfigurationManagerRW::saveNewBackbone(ConfigurationVersion temporaryVersion)
784 {
785  __COUT_INFO__ << "Creating new backbone from temporary version " <<
786  temporaryVersion << std::endl;
787 
788  //find common available temporary version among backbone members
789  ConfigurationVersion newVersion(ConfigurationVersion::DEFAULT);
790  ConfigurationVersion retNewVersion;
791  auto backboneMemberNames = ConfigurationManager::getBackboneMemberNames();
792  for (auto& name : backboneMemberNames)
793  {
794  retNewVersion = ConfigurationManager::getConfigurationByName(name)->getNextVersion();
795  __COUT__ << "New version for backbone member (" << name << "): " <<
796  retNewVersion << std::endl;
797  if(retNewVersion > newVersion)
798  newVersion = retNewVersion;
799  }
800 
801  __COUT__ << "Common new backbone version found as " <<
802  newVersion << std::endl;
803 
804  //create new views from source temporary version
805  for (auto& name : backboneMemberNames)
806  {
807  //saveNewVersion makes the new version the active version
808  retNewVersion = getConfigurationInterface()->saveNewVersion(
809  getConfigurationByName(name), temporaryVersion, newVersion);
810  if(retNewVersion != newVersion)
811  {
812  __SS__ << "Failure! New view requested was " <<
813  newVersion << ". Mismatched new view created: " << retNewVersion << std::endl;
814  __COUT_ERR__ << ss.str();
815  throw std::runtime_error(ss.str());
816  }
817  }
818 
819  return newVersion;
820 }
821 
822 //==============================================================================
823 void ConfigurationManagerRW::testXDAQContext()
824 {
825 // //test creating config group with author, create time, and comment
826 // {
827 // __COUT__ << std::endl;
828 //
829 // std::string groupName = "testGroup";
830 // ConfigurationGroupKey newKey;
831 // //ConfigurationGroupMetadata
832 //
833 // try
834 // {
835 // {
836 // std::map<std::string, ConfigurationVersion> members;
837 // members["ARTDAQAggregatorConfiguration"] = ConfigurationVersion(1);
838 //
839 // //ConfigurationGroupKey
840 // // saveNewConfigurationGroup
841 // // (const std::string &groupName, const std::map<std::string,
842 // // ConfigurationVersion> &groupMembers, ConfigurationGroupKey previousVersion=ConfigurationGroupKey());
843 // newKey =
844 // saveNewConfigurationGroup(groupName,members);
845 // }
846 //
847 // //std::map<std::string, ConfigurationVersion >
848 // // loadConfigurationGroup
849 // // (const std::string &configGroupName,
850 // // ConfigurationGroupKey configGroupKey, bool doActivate=false, ProgressBar* progressBar=0, std::string *accumulateWarnings=0);
851 // {
852 // std::map<std::string, ConfigurationVersion > memberMap =
853 // loadConfigurationGroup(groupName,newKey);
854 // __COUT__ << "Group members:" << std::endl;
855 // for(const auto &member: memberMap)
856 // __COUT__ << member.first << " " << member.second << std::endl;
857 // }
858 //
859 //
860 //
861 // //do it again
862 // {
863 // std::map<std::string, ConfigurationVersion> members;
864 // members["ARTDAQAggregatorConfiguration"] = ConfigurationVersion(1);
865 //
866 // //ConfigurationGroupKey
867 // // saveNewConfigurationGroup
868 // // (const std::string &groupName, const std::map<std::string,
869 // // ConfigurationVersion> &groupMembers, ConfigurationGroupKey previousVersion=ConfigurationGroupKey());
870 // newKey =
871 // saveNewConfigurationGroup(groupName,members);
872 // }
873 //
874 // //std::map<std::string, ConfigurationVersion >
875 // // loadConfigurationGroup
876 // // (const std::string &configGroupName,
877 // // ConfigurationGroupKey configGroupKey, bool doActivate=false, ProgressBar* progressBar=0, std::string *accumulateWarnings=0);
878 // {
879 // std::map<std::string, ConfigurationVersion > memberMap =
880 // loadConfigurationGroup(groupName,newKey);
881 // __COUT__ << "Group members:" << std::endl;
882 // for(const auto &member: memberMap)
883 // __COUT__ << member.first << " " << member.second << std::endl;
884 // }
885 //
886 //
887 // }
888 // catch(std::runtime_error &e)
889 // {
890 // __COUT_ERR__ << "Failed to create config group: " << groupName << ":" << newKey << std::endl;
891 // __COUT_ERR__ << "\n\n" << e.what() << std::endl;
892 // }
893 // catch(...)
894 // {
895 // __COUT_ERR__ << "Failed to create config group: " << groupName << ":" << newKey << std::endl;
896 // }
897 //
898 // return;
899 // }
900 
901 // //test creating config group and reading
902 // {
903 // __COUT__ << std::endl;
904 //
905 // auto gcfgs = theInterface_->getAllConfigurationGroupNames();
906 // __COUT__ << "Global config size: " << gcfgs.size() << std::endl;
907 // for(auto &g:gcfgs)
908 // {
909 // __COUT__ << "Global config " << g << std::endl;
910 // auto gcMap = theInterface_->getConfigurationGroupMembers(g);
911 //
912 // for(auto &cv:gcMap)
913 // __COUT__ << "\tMember config " << cv.first << ":" << cv.second << std::endl;
914 // }
915 //
916 // auto cfgs = theInterface_->getAllConfigurationNames();
917 // __COUT__ << "Sub-config size: " << cfgs.size() << std::endl;
918 // for(auto &c:cfgs)
919 // {
920 // __COUT__ << "config " << c << std::endl;
921 // auto vs = theInterface_->getVersions(getConfigurationByName(c));
922 // for(auto &v:vs)
923 // __COUT__ << "\tversion " << v << std::endl;
924 // }
925 //
926 // if(0) //create a global config group (storeGlobalConfiguration)
927 // {
928 // //storeGlobalConfiguration with latest of each
929 // std::map<std::string /*name*/, ConfigurationVersion /*version*/> gcMap;
930 //
931 // for(auto &c:cfgs) //for each sub-config, take latest version
932 // {
933 // auto vs = theInterface_->getVersions(getConfigurationByName(c));
934 // if(1 && vs.rbegin() != vs.rend()) //create latest!
935 // {
936 // gcMap[c] = *(vs.rbegin());
937 // __COUT__ << "Adding config " << c << ":" << gcMap[c] << std::endl;
938 // }
939 // else if(vs.begin() != vs.end()) //create oldest!
940 // {
941 // gcMap[c] = *(vs.begin());
942 // __COUT__ << "Adding config " << c << ":" << gcMap[c] << std::endl;
943 // }
944 // }
945 //
946 // int i = 0;
947 // bool done = false;
948 // char gcname[100];
949 // bool found;
950 // while(!done && i<1)
951 // {
952 // do //avoid conflicting global config names
953 // {
954 // found = false;
955 // sprintf(gcname,"GConfig_v%d",i++);
956 // for(auto &g:gcfgs)
957 // if(g == gcname) {found = true; break;}
958 // }
959 // while(found);
960 // __COUT__ << "Trying Global config: " << gcname<< std::endl;
961 //
962 // try
963 // {
964 // theInterface_->saveConfigurationGroup(gcMap,gcname);
965 // done = true;
966 // __COUT__ << "Created Global config: " << gcname<< std::endl;
967 // }
968 // catch(...) {++i;} //repeat names are not allowed, so increment name
969 // }
970 //
971 // }
972 //
973 // //return;
974 // }
975 //
976  //this is to test config tree
977  try
978  {
979  __COUT__ << "Loading config..." << std::endl;
980  loadConfigurationGroup("FETest",ConfigurationGroupKey(2)); // Context_1
981  ConfigurationTree t = getNode("/FEConfiguration/DEFAULT/FrontEndType");
982 
983  std::string v;
984 
985  __COUT__ << std::endl;
986  t.getValue(v);
987  __COUT__ << "Value: " << v << std::endl;
988  __COUT__ << "Value index: " << t.getValue<int>() << std::endl;
989 
990  return;
991 
992  //ConfigurationTree t = getNode("XDAQContextConfiguration");
993  //ConfigurationTree t = getNode("/FEConfiguration/OtsUDPFSSR3/FrontEndType");
994  //ConfigurationTree t = getNode("/FEConfiguration").getNode("OtsUDPFSSR3");
995 // ConfigurationTree t = getNode("/XDAQContextConfiguration/testContext/");
996 //
997 // __COUT__ << std::endl;
998 // t.getValue(v);
999 // __COUT__ << "Value: " << v << std::endl;
1000 //
1001 // if(!t.isValueNode())
1002 // {
1003 // auto C = t.getChildrenNames();
1004 // for(auto &c: C)
1005 // __COUT__ << "\t+ " << c << std::endl;
1006 //
1007 // std::stringstream ss;
1008 // t.print(-1,ss);
1009 // __COUT__ << "\n" << ss.str() << std::endl;
1010 //
1011 // try
1012 // {
1013 // ConfigurationTree tt = t.getNode("OtsUDPFSSR3");
1014 // tt.getValue(v);
1015 // __COUT__ << "Value: " << v << std::endl;
1016 //
1017 // C = tt.getChildrenNames();
1018 // for(auto &c: C)
1019 // __COUT__ << "\t+ " << c << std::endl;
1020 // }
1021 // catch(...)
1022 // {
1023 // __COUT__ << "Failed to find extra node." << std::endl;
1024 // }
1025 // }
1026 
1027  }
1028  catch(...)
1029  {
1030  __COUT__ << "Failed to load config..." << std::endl;
1031  }
1032 
1033 
1034 }
1035 
1036 
1037 
1038 
1039 
1040 
1041 
1042 
1043 
1044 
1045 
1046 
1047