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