ConfigDataTree.cpp
Go to the documentation of this file.
1 #include <DatabaseUtils/DAQConfig/ConfigDataTree.h>
2 #include <DatabaseUtils/DAQConfig/DBColumnParams.h>
3 #include <DatabaseUtils/DAQConfig/DBColumnUtils.h>
4 #include <DatabaseUtils/DAQConfig/NamedConfigUtils.h>
5 #include <NovaDAQUtilities/EnvVarCache.h>
6 #include <boost/algorithm/string.hpp>
7 #include <iostream>
8 
9 namespace NOVADB = nova::database;
10 
11 namespace dbutils {
12 namespace daqconfig {
13 
17 
18 // The meaning of the bits in the CONFIG_DATA_TREE_DEBUG env var:
19 // - bit 0: prints the hash key and DB values for each database result
20 // - bit 1: prints selector and data column details
21 // - bit 2: prints information about values that are written to the DB
22 // - bit 3: enables tracing via line-based print statements
23 // - bit 4: sets the verbosity of the Table query to 1
24 // - bit 5: sets the verbosity of the Table write to 1
25 
26 #define LINE_NUMBER_DEBUG if ((debugFlag & 0x08) != 0) { \
27  std::cout << "ConfigDataTree line=" << __LINE__ << std::endl;}
28 
29 bool sortingFunction(std::string leftString, std::string rightString) {
30  try {
31  int leftInt = boost::lexical_cast<int>(leftString);
32  int rightInt = boost::lexical_cast<int>(rightString);
33  return (leftInt < rightInt);
34  }
35  catch (...) {
36  return (leftString < rightString);
37  }
38 }
39 
40 /**
41  * Constructs a configuration data tree for the specified
42  * input parameters.
43  */
45 ConfigDataTree(const std::string& tableDefinitionFilename,
46  const std::vector<int64_t>& subsystemConfigIdList,
47  const ConfigDataSelector& selector,
48  std::vector<std::string> dataColumnNameList)
49 {
50  // seed failure
51  _hasValidData = false;
52  _tableDefinitionFilename = tableDefinitionFilename;
53 
54  // check if a debug flag has been specified
55  int debugFlag = 0;
56  std::string debugString =
57  novadaq::EnvVarCache::getInstance().getEnvVar("CONFIG_DATA_TREE_DEBUG");
58  if (debugString.length() > 0) {
59  try {debugFlag = boost::lexical_cast<int>(debugString);}
60  catch (...) {}
61  }
62 
63  // set up the Table instance and its connection to the DB
64  // (if something fails here, we simply return and leave the hasValidData
65  // flag set to false)
66  boost::shared_ptr<NOVADB::Table> dbTablePtr;
67  dbTablePtr.reset(new NOVADB::Table(tableDefinitionFilename.c_str()));
69  novadaq::EnvVarCache::getInstance().getEnvVar("NOVADAQ_ENVIRONMENT");
70  dbTablePtr->SetDetector(detName);
71  dbTablePtr->SetTableType(NOVADB::kDAQTable);
72  std::string dbUser =
73  novadaq::EnvVarCache::getInstance().getEnvVar("CFGMGR_DB_USER");
75  if (dbUser.length() > 0) {
77  dbTablePtr->SetUser(dbUser);
78  }
80  if (! dbTablePtr->GetConnection()) {return;}
82  if (! dbTablePtr->ExistsInDB()) {return;}
84  _configSelector = selector;
85  _dataColumnNameList = dataColumnNameList;
86  _dataColumnTypeList.assign(_dataColumnNameList.size(), "unknown");
87 
88  _initialize(dbTablePtr, subsystemConfigIdList,
89  selector, dataColumnNameList, debugFlag);
91 }
92 
93 /**
94  * Constructs a configuration data tree for the specified
95  * table and subsystem configuration ID list. Reasonable
96  * assumptions are made for which selector columns are of
97  * interest (e.g. dcmName, febId) and which data columns
98  * are of interest.
99  */
101 ConfigDataTree(const std::string& tableDefinitionFilename,
102  const std::vector<int64_t>& subsystemConfigIdList)
103 {
104  // seed failure
105  _hasValidData = false;
106  _tableDefinitionFilename = tableDefinitionFilename;
107 
108  // check if a debug flag has been specified
109  int debugFlag = 0;
110  std::string debugString =
111  novadaq::EnvVarCache::getInstance().getEnvVar("CONFIG_DATA_TREE_DEBUG");
112  if (debugString.length() > 0) {
113  try {debugFlag = boost::lexical_cast<int>(debugString);}
114  catch (...) {}
115  }
116 
117  // set up the Table instance and its connection to the DB
118  // (if something fails here, we simply return and leave the hasValidData
119  // flag set to false)
120  boost::shared_ptr<NOVADB::Table> dbTablePtr;
121  dbTablePtr.reset(new NOVADB::Table(tableDefinitionFilename.c_str()));
123  novadaq::EnvVarCache::getInstance().getEnvVar("NOVADAQ_ENVIRONMENT");
124  dbTablePtr->SetDetector(detName);
125  dbTablePtr->SetTableType(NOVADB::kDAQTable);
126  std::string dbUser =
127  novadaq::EnvVarCache::getInstance().getEnvVar("CFGMGR_DB_USER");
129  if (dbUser.length() > 0) {
131  dbTablePtr->SetUser(dbUser);
132  }
134  if (! dbTablePtr->GetConnection()) {return;}
136  if (! dbTablePtr->ExistsInDB()) {return;}
138 
139  // determine the selector and data columns of interest
140  std::vector<std::string> colNames = dbTablePtr->GetColNames();
141 
142  // the order of the selectors matters, so we'll handle those carefully
143  std::vector<std::string> tmpSelectionList;
144  uint32_t indexForStartOfNormalHierarchy = 0;
145 
146  for (uint32_t idx = 0; idx < colNames.size(); ++idx) {
147  std::string colName = boost::to_lower_copy(colNames[idx]);
148  if (DBColumnUtils::isInfrastructureColumn(colName)) {continue;}
150  continue;
151  }
152 
153  std::vector<std::string>::iterator iter = tmpSelectionList.begin();
154  if (colName == DBColumnParams::DCMNAME_COLUMN_NAME) {
155  if (tmpSelectionList.size() > indexForStartOfNormalHierarchy) {
156  tmpSelectionList.insert(iter+indexForStartOfNormalHierarchy,
157  colName);
158  }
159  else {
160  tmpSelectionList.push_back(colName);
161  }
162  }
163  else if (colName == DBColumnParams::FEBID_COLUMN_NAME) {
164  if (tmpSelectionList.size() > indexForStartOfNormalHierarchy+1) {
165  tmpSelectionList.insert(iter+indexForStartOfNormalHierarchy+1,
166  colName);
167  }
168  else {
169  tmpSelectionList.push_back(colName);
170  }
171  }
172  else if (colName == DBColumnParams::PIXELID_COLUMN_NAME) {
173  if (tmpSelectionList.size() > indexForStartOfNormalHierarchy+2) {
174  tmpSelectionList.insert(iter+indexForStartOfNormalHierarchy+2,
175  colName);
176  }
177  else {
178  tmpSelectionList.push_back(colName);
179  }
180  }
181  else if (colName == DBColumnParams::HOSTNAME_COLUMN_NAME) {
182  if (tmpSelectionList.size() > indexForStartOfNormalHierarchy) {
183  tmpSelectionList.insert(iter+indexForStartOfNormalHierarchy,
184  colName);
185  }
186  else {
187  tmpSelectionList.push_back(colName);
188  }
189  }
190  else if (colName == "coolingstate") {
191  if (tmpSelectionList.size() > 0) {
192  tmpSelectionList.insert(iter, colName);
193  }
194  else {
195  tmpSelectionList.push_back(colName);
196  }
197  ++indexForStartOfNormalHierarchy;
198  }
199  else if (colName == "pvname") {
200  if (tmpSelectionList.size() > 0) {
201  tmpSelectionList.insert(iter, colName);
202  }
203  else {
204  tmpSelectionList.push_back(colName);
205  }
206  ++indexForStartOfNormalHierarchy;
207  }
208  else {
209  _dataColumnNameList.push_back(colName);
210  _dataColumnTypeList.push_back("unknown");
211  }
212  }
214 
215  for (uint32_t idx = 0; idx < tmpSelectionList.size(); ++idx) {
216  std::string colName = tmpSelectionList[idx];
218  }
220 
221  _initialize(dbTablePtr, subsystemConfigIdList,
224 }
225 
226 bool ConfigDataTree::
227 saveValues(const std::vector<dbutils::SimpleParameterSet>& newDataList) const
228 {
229  // check if a debug flag has been specified
230  int debugFlag = 0;
231  std::string debugString =
232  novadaq::EnvVarCache::getInstance().getEnvVar("CONFIG_DATA_TREE_DEBUG");
233  if (debugString.length() > 0) {
234  try {debugFlag = boost::lexical_cast<int>(debugString);}
235  catch (...) {}
236  }
237 
238  boost::shared_ptr<NOVADB::Table> dbTablePtr;
239  dbTablePtr.reset(new NOVADB::Table(_tableDefinitionFilename.c_str()));
241  novadaq::EnvVarCache::getInstance().getEnvVar("NOVADAQ_ENVIRONMENT");
242  dbTablePtr->SetDetector(detName);
243  dbTablePtr->SetTableType(NOVADB::kDAQTable);
244  std::string dbUser =
245  novadaq::EnvVarCache::getInstance().getEnvVar("CFGMGR_DB_USER");
247  if (dbUser.length() > 0) {
249  dbTablePtr->SetUser(dbUser);
250  }
252  if (! dbTablePtr->GetConnection()) {return false;}
254  if (! dbTablePtr->ExistsInDB()) {return false;}
256 
257  if ((debugFlag & 0x20) != 0) {
258  dbTablePtr->SetVerbosity(1);
259  }
260 
261  if ((debugFlag & 0x04) != 0) {
262  std::cout << "*** ConfigDataTree for " << dbTablePtr->Name()
263  << ", storing values:" << std::endl;
264  }
265 
266  for (int idx = 0; idx < (int) newDataList.size(); ++idx) {
267  dbutils::SimpleParameterSet paramSet = newDataList[idx];
269 
270  if ((debugFlag & 0x04) != 0) {
271  std::cout << " " << paramSet.toString() << std::endl;
272  }
273 
274  boost::shared_ptr<NOVADB::Row> newRow(dbTablePtr->NewRow());
275  if (newRow.get() == 0) {return false;}
277 
278  std::vector<std::string> keyList = paramSet.keys();
279  for (int jdx = 0; jdx < (int) keyList.size(); ++jdx) {
280 
281  std::string key = keyList[jdx];
283  if (paramSet.get(key, value)) {
284  newRow->Set(key, value);
285  }
286  }
288 
289  dbTablePtr->AddRow(newRow.get());
291  }
293 
294  if (! dbTablePtr->WriteToDB()) {return false;}
296 
297  return true;
298 }
299 
300 /**
301  * Initializes the data in the tree by querying the database.
302  */
303 void ConfigDataTree::
304 _initialize(boost::shared_ptr<nova::database::Table> dbTablePtr,
305  const std::vector<int64_t>& subsystemConfigIdList,
306  const ConfigDataSelector& selector,
307  std::vector<std::string> dataColumnNameList,
308  int debugFlag)
309 {
310  _tableName = dbTablePtr->Name();
312 
313  // fetch information about keys to be used when selecting default values
314  std::string keyForSystemWideDefault;
316  if (selector.getSelectionCount() > 0) {
317  for (uint32_t sdx = 0; sdx < selector.getSelectionCount(); ++sdx) {
318  std::string keyForDefault = "";
319  std::string selectorName = selector.getSelectionColumn(sdx);
320  if (! colParams.
321  columnKeyToGetDefaultValue(selectorName, keyForDefault)) {
322  keyForDefault = NO_DEFAULT_KEY_STRING;
323  _noKeyElementForDefaults.push_back(true);
324  }
325  else {
326  _noKeyElementForDefaults.push_back(false);
327  }
328 
329  if (sdx > 0) {
330  keyForSystemWideDefault.append(KEY_SEPARATOR_STRING);
331  }
332  keyForSystemWideDefault.append(keyForDefault);
333 
334  _keyElementsForDefaults.push_back(keyForDefault);
335 
336  _selectorDefaultValueMap[selectorName] = keyForDefault;
337  }
338  }
339  else {
340  keyForSystemWideDefault = KEY_FOR_SYSTEM_WIDE_PARAM;
341  }
343 
344  // loop over each subsystem configuration ID that was provided
345  for (uint32_t cfgIdx = 0; cfgIdx < subsystemConfigIdList.size(); ++cfgIdx) {
346  dbTablePtr->Clear();
348 
349  // set the appropriate validity contexts
350  for (uint32_t sdx = 0; sdx < selector.getSelectionCount(); ++sdx) {
351  if (selector.hasSelectionValues(sdx)) {
352  if (! dbTablePtr->
353  SetValidityRange(selector.getSelectionColumn(sdx),
354  selector.getSelectionLowValue(sdx),
355  selector.getSelectionHighValue(sdx))) {
357  return;
358  }
359  }
360  }
361  if (! dbTablePtr->SetValidityRange("subsysCfgId",
362  subsystemConfigIdList[cfgIdx])) {
364  return;
365  }
366 
367  // fetch the data from the DB
368  if ((debugFlag & 0x10) != 0) {
369  dbTablePtr->SetVerbosity(1);
370  }
371  if (! dbTablePtr->LoadFromDB()) {
373  return;
374  }
376 
377  // also, fetch all default values that we may need
378  for (uint32_t sdx = selector.getSelectionCount(); sdx > 0; --sdx) {
379  if (selector.hasSelectionValues(sdx-1)) {
380  if (! dbTablePtr->
381  SetValidityRange(selector.getSelectionColumn(sdx-1),
383  _keyElementsForDefaults[sdx-1])) {
385  return;
386  }
387  if (! dbTablePtr->LoadFromDB()) {
389  return;
390  }
391  }
392  }
394 
395  // loop over each row that was selected and decide whether
396  // to add it to the internal result set
397  ConfigDataContainer tmpContainerForDefaults;
398  for (int32_t idx = 0; idx < dbTablePtr->NRow(); ++idx) {
399  NOVADB::Row* rowPtr = dbTablePtr->GetRow(idx);
400  std::string valueString;
401  NOVADB::Column* colPtr;
402 
403  // build the key that we'll use to store this entry in
404  // the result set
406  std::vector<std::string> keyElements;
407  bool thisKeyIsForADefault = false;
408  if (selector.getSelectionCount() > 0) {
409  for (uint32_t sdx = 0; sdx < selector.getSelectionCount();
410  ++sdx) {
411  std::string selectorName = selector.getSelectionColumn(sdx);
412  colPtr = rowPtr->Col(selectorName);
413  if (! colPtr->Get(valueString)) {
415  return;
416  }
417 
418  if (sdx > 0) {
419  key.append(KEY_SEPARATOR_STRING);
420  }
421  key.append(valueString);
422 
423  keyElements.push_back(valueString);
424 
425  if (valueString == _keyElementsForDefaults[sdx]) {
426  thisKeyIsForADefault = true;
427  }
428 
429  // build up the list(s) of unique selector values
430  ConfigValueListMap::const_iterator iter1 =
431  _distinctSelectorValueMap.find(selectorName);
432  if (iter1 == _distinctSelectorValueMap.end()) {
433  ConfigValueListPtr valueListPtr(new ConfigValueList());
434  valueListPtr->push_back(valueString);
435  _distinctSelectorValueMap[selectorName] = valueListPtr;
436  }
437  else {
438  ConfigValueListPtr valueListPtr = iter1->second;
439  ConfigValueList::const_iterator iter2 =
440  std::find(valueListPtr->begin(),
441  valueListPtr->end(), valueString);
442  if (iter2 == valueListPtr->end()) {
443  valueListPtr->push_back(valueString);
444  }
445  }
446  }
447  }
448  else {
450  }
451 
452  // check if the result set already has an entry for this key
453  ConfigDataContainer::const_iterator iter1 = _resultSet.find(key);
454  if (iter1 != _resultSet.end()) {continue;}
455 
456  // check if a default value exists that makes this entry irrelevant
457  bool foundDefault = false;
458  for (uint32_t testIdx = keyElements.size(); testIdx > 0; --testIdx) {
459  std::string tmpKey;
460  for (uint32_t sdx = 0; sdx < keyElements.size(); ++sdx) {
461  std::string keyFragment = keyElements[sdx];
462  if (sdx >= (testIdx - 1)) {
463  keyFragment = _keyElementsForDefaults[sdx];
464  }
465 
466  if (sdx > 0) {
467  tmpKey.append(KEY_SEPARATOR_STRING);
468  }
469  tmpKey.append(keyFragment);
470  }
471 
472  iter1 = _resultSet.find(tmpKey);
473  if (iter1 != _resultSet.end()) {
474  foundDefault = true;
475  break;
476  }
477  }
478  if (foundDefault) {continue;}
479 
480  // if we made it this far, then we should store the entry in the
481  // result set
482  ConfigValueMapPtr mapPtr(new ConfigValueMap());
483 
484  // fetch the requested data values from the DB row
485  for (uint32_t ndx = 0; ndx < dataColumnNameList.size(); ++ndx) {
486  std::string columnName = dataColumnNameList[ndx];
487  colPtr = rowPtr->Col(columnName);
488  _dataColumnTypeList[ndx] = colPtr->Type();
489  if (colPtr->IsNull()) {
490  (*mapPtr)[columnName] = "";
491  }
492  else {
493  if (! colPtr->Get(valueString)) {
495  return;
496  }
497  (*mapPtr)[columnName] = valueString;
498  }
499  }
500 
501  // insert the entry into the result set or the temporary
502  // container for defaults
503  if (thisKeyIsForADefault) {
504  tmpContainerForDefaults[key] = mapPtr;
505  }
506  else {
507  _resultSet[key] = mapPtr;
508  }
509  }
511 
512  // copy the defaults that were found with this configId to the
513  // result set, now that they won't mess up the logic above
514  ConfigDataContainer::const_iterator iter2;
515  ConfigDataContainer::const_iterator iter2End =
516  tmpContainerForDefaults.end();
517  for (iter2 = tmpContainerForDefaults.begin();
518  iter2 != iter2End; ++iter2) {
519  _resultSet[iter2->first] = iter2->second;
520  }
521 
522  // as soon as we find a system-wide default (or a system-wide
523  // parameter value), we're done
524  ConfigDataContainer::const_iterator iter3 =
525  _resultSet.find(keyForSystemWideDefault);
526  if (iter3 != _resultSet.end()) {break;}
527  }
529 
530  // sort the list(s) of distinct selector values
531  ConfigValueListMap::const_iterator iter;
532  ConfigValueListMap::const_iterator iterEnd =
534  for (iter = _distinctSelectorValueMap.begin(); iter != iterEnd; ++iter) {
535  ConfigValueListPtr valueListPtr = iter->second;
536  std::sort(valueListPtr->begin(), valueListPtr->end(), sortingFunction);
537  }
538 
539  // print out the contents of the tree, if requested
540  if ((debugFlag & 0x01) != 0) {
541  std::cout << "*** ConfigDataTree for " << dbTablePtr->Name()
542  << std::endl;
543  ConfigDataContainer::const_iterator resIterEnd = _resultSet.end();
544  ConfigDataContainer::const_iterator resIter;
545  for (resIter = _resultSet.begin(); resIter != resIterEnd; ++resIter) {
546  ConfigValueMapPtr mapPtr = resIter->second;
547  std::cout << " Key=" << resIter->first;
548  if (mapPtr.get() != 0) {
549  ConfigValueMap::const_iterator mapIterEnd = mapPtr->end();
550  ConfigValueMap::const_iterator mapIter;
551  for (mapIter = mapPtr->begin(); mapIter != mapIterEnd; ++mapIter) {
552  std::cout << ", " << mapIter->first << "=" << mapIter->second;
553  }
554  }
555  std::cout << std::endl;
556  }
557  }
558 
559  // print out the selector and data column details, if requested
560  if ((debugFlag & 0x02) != 0) {
561  std::cout << "*** ConfigDataTree for " << dbTablePtr->Name()
562  << std::endl;
563  std::vector<std::string> selectorColumnNames = getSelectorColumnNames();
564  for (uint32_t idx = 0; idx < selectorColumnNames.size(); ++idx) {
565  std::string columnName = selectorColumnNames[idx];
566  std::string defaultValue = getSelectorValueForDefault(columnName);
567  std::vector<std::string> distinctValues =
569  std::cout << " Selector = \"" << columnName << "\", default = \""
570  << defaultValue << "\"" << std::endl;
571  std::cout << " Distinct values = ";
572  for (uint32_t jdx = 0; jdx < distinctValues.size(); ++jdx) {
573  if (jdx > 0) {std::cout << ", ";}
574  std::cout << distinctValues[jdx];
575  }
576  std::cout << std::endl;
577  }
578  }
579 
580  // indicate success
581  _hasValidData = true;
583 }
584 
585 } // end of namespace daqconfig
586 } // end of namespace dbutils
std::vector< std::string > _keyElementsForDefaults
void addSelectionColumn(std::string columnName)
std::vector< std::string > keys() const
std::vector< bool > _noKeyElementForDefaults
std::vector< std::string > _dataColumnNameList
bool hasSelectionValues(uint32_t selectionIndex) const
static EnvVarCache & getInstance()
Definition: EnvVarCache.cpp:12
std::vector< std::string > _dataColumnTypeList
std::vector< std::string > getDistinctSelectorColumnValues(const std::string &columnName) const
#define LINE_NUMBER_DEBUG
ConfigValueListMap _distinctSelectorValueMap
std::string getSelectionLowValue(uint32_t selectionIndex) const
std::map< std::string, std::string > ConfigValueMap
boost::shared_ptr< ConfigValueMap > ConfigValueMapPtr
bool get(const std::string &key, T &resultValue) const
const XML_Char int const XML_Char * value
Definition: expat.h:331
bool saveValues(const std::vector< dbutils::SimpleParameterSet > &newDataList) const
void _initialize(boost::shared_ptr< nova::database::Table > dbTablePtr, const std::vector< int64_t > &subsystemConfigIdList, const ConfigDataSelector &selector, std::vector< std::string > dataColumnNameList, int debugFlag)
static const std::string HOSTNAME_COLUMN_NAME
std::string getSelectionHighValue(uint32_t selectionIndex) const
std::string getSelectorValueForDefault(std::string columnName) const
static const std::string PIXELID_COLUMN_NAME
std::vector< std::string > getSelectorColumnNames() const
static const std::string NO_DEFAULT_KEY_STRING
bool sortingFunction(std::string leftString, std::string rightString)
bool Get(T &val) const
Definition: Column.h:53
static bool isSubsystemConfigReferenceColumn(const std::string &columnName)
static const std::string KEY_FOR_SYSTEM_WIDE_PARAM
bool IsNull() const
Definition: Column.h:39
OStream cout
Definition: OStream.cxx:6
ConfigDataTree(const std::string &tableDefinitionFilename, const std::vector< int64_t > &subsystemConfigIdList, const ConfigDataSelector &selector, std::vector< std::string > dataColumnNameList)
static DBColumnParams & getInstance()
static const std::string DCMNAME_COLUMN_NAME
std::map< std::string, ConfigValueMapPtr > ConfigDataContainer
std::string getEnvVar(std::string name)
Definition: EnvVarCache.cpp:33
static const std::string FEBID_COLUMN_NAME
static bool isInfrastructureColumn(const std::string &columnName)
std::string getSelectionColumn(uint32_t selectionIndex) const
static const std::string KEY_SEPARATOR_STRING
std::vector< std::string > ConfigValueList
std::string Type() const
Definition: Column.h:36
detName
Definition: mkDefs.py:106
boost::shared_ptr< ConfigValueList > ConfigValueListPtr
Column & Col(int i)
Definition: Row.h:51
enum BeamMode string