otsdaq  v2_04_02
ConfigurationInterface.h
1 #ifndef _ots_ConfigurationInterface_h_
2 #define _ots_ConfigurationInterface_h_
3 
4 #include <memory>
5 #include <set>
6 #include <sstream>
7 #include "otsdaq/Macros/CoutMacros.h"
8 
9 #include "otsdaq/PluginMakers/MakeTable.h"
10 #include "otsdaq/TableCore/TableBase.h"
11 #include "otsdaq/TableCore/TableGroupKey.h"
12 #include "otsdaq/TableCore/TableVersion.h"
13 
14 namespace ots
15 {
16 class ConfigurationHandlerBase;
17 
19 {
20  friend class ConfigurationManagerRW; // because need access to latestVersion() call
21  // for group metadata
22  friend class ConfigurationManager; // because need access to fill() call for group
23  // metadata
24 
25  public:
26  virtual ~ConfigurationInterface() { ; }
27 
28  static ConfigurationInterface* getInstance(bool mode);
29  static bool isVersionTrackingEnabled();
30  static void setVersionTrackingEnabled(bool setValue);
31 
32  static const std::string GROUP_METADATA_TABLE_NAME;
33  //==============================================================================
34  // get
35  // Note: If filling, assume, new view becomes active view.
36  //
37  // Loose column matching can be used to ignore column names when filling.
38  //
39  // if accumulatedErrors, then invalid data is allowed
40  // (not the same as "warnings allowed", because could create invalid tree
41  // situations)
42  void get(TableBase*& table,
43  const std::string tableName,
44  std::shared_ptr<const TableGroupKey> groupKey = 0,
45  const std::string* groupName = 0,
46  bool dontFill = false,
47  TableVersion version = TableVersion(),
48  bool resetConfiguration = true,
49  bool looseColumnMatching = false,
50  std::string* accumulatedErrors = 0)
51  {
52  if(table == 0)
53  {
54  // try making table table plugin, if fails use TableBase
55  try
56  {
57  table = makeTable(tableName);
58  }
59  catch(...)
60  {
61  }
62 
63  if(table == 0)
64  {
65  //__COUT__ << "Using TableBase object with table name " <<
66  // tableName << std::endl;
67 
68  // try making table base..
69  // if it fails, then probably something wrong with Info file
70  try
71  {
72  table = new TableBase(tableName);
73  }
74  catch(...) // failure so cleanup any halfway complete table work
75  {
76  __COUT_WARN__ << "Failed to even use TableBase!" << std::endl;
77  if(table)
78  delete table;
79  table = 0;
80  throw;
81  }
82  }
83  //__COUT__ << "Table constructed!" << std::endl;
84  }
85 
86  if(groupKey != 0 && groupName != 0)
87  { // FIXME -- new TableGroup and TableGroupKey should be used!
88  // version = configurations->getConditionVersion(*groupKey,
89  // table->getTableName());
90  __SS__ << "FATAL ERROR: new TableGroup and TableGroupKey should be used!"
91  << std::endl;
92  __SS_THROW__;
93  }
94  else if(!dontFill)
95  {
96  // check version choice
97  if(version == TableVersion::INVALID &&
98  (version = findLatestVersion(table)) == TableVersion::INVALID)
99  {
100  __COUT__ << "FATAL ERROR: Can't ask to fill a table object with "
101  "a negative version! "
102  << tableName << std::endl;
103  __SS__ << "FATAL ERROR: Invalid latest version." << std::endl
104  << std::endl
105  << std::endl
106  << "*******************" << std::endl
107  << "Suggestion: If you expect a version to exist for this "
108  "table, perhaps this is your first time running with "
109  "the artdaq database. (and your old configurations have not "
110  "been transferred?) "
111  << std::endl
112  << "Try running this once:\n\n\totsdaq_database_migrate"
113  << std::endl
114  << std::endl
115  << "This will migrate the old ots file system table to "
116  "the artdaq database approach."
117  << std::endl
118  << std::endl
119  << std::endl;
120  __SS_THROW__;
121  }
122  }
123 
124  if(resetConfiguration) // reset to empty table views and no active view
125  { // EXCEPT, keep temporary views! (call TableBase::reset to really reset all)
126  table->deactivate();
127  std::set<TableVersion> versions = table->getStoredVersions();
128  for(auto& version : versions)
129  if(!version.isTemporaryVersion()) // if not temporary
130  table->eraseView(version);
131  }
132 
133  if(dontFill)
134  return;
135 
136  // Note: assume new view becomes active view
137 
138  // take advantage of version possibly being cached
139  if(table->isStored(version))
140  {
141  //__COUT__ << "Using archived version: " << version << std::endl;
142 
143  // Make sure this version is not already active
144  if(!table->isActive() || version != table->getViewVersion())
145  table->setActiveView(version);
146 
147  table->getViewP()->setLastAccessTime();
148 
149  try
150  {
151  // sanitize for column info and dataTypes
152  table->getViewP()->init();
153  }
154  catch(const std::runtime_error& e)
155  {
156  __SS__ << "Error occurred while getting and filling Table \"" << tableName
157  << "\" version:" << version << std::endl;
158  ss << "\n" << e.what() << __E__;
159  __COUT__ << StringMacros::stackTrace() << __E__;
160 
161  // if accumulating errors, allow invalid data
162  if(accumulatedErrors)
163  *accumulatedErrors += ss.str();
164  else
165  throw;
166  }
167 
168  return;
169  }
170 
171  try // to fill
172  {
173  if(version.isTemporaryVersion())
174  {
175  __SS__ << "FATAL ERROR: Can not use interface to fill a "
176  "table object with a temporary version!"
177  << std::endl;
178  ss << "FATAL ERROR: Invalid temporary version v" << version << std::endl;
179  __SS_THROW__;
180  }
181 
182  table->setupMockupView(version);
183  table->setActiveView(version);
184 
185  // loose column matching can be used to ignore column names
186  table->getViewP()->setLooseColumnMatching(looseColumnMatching);
187  fill(table, version);
188  if(looseColumnMatching)
189  table->getViewP()->setLooseColumnMatching(false);
190  table->getViewP()->setLastAccessTime();
191 
193  // verify the new view
194  if(table->getViewP()->getVersion() != version)
195  {
196  __SS__ << "Version mismatch!! " << table->getViewP()->getVersion()
197  << " vs " << version << std::endl;
198  __SS_THROW__;
199  }
200 
201  // match key by ignoring '_'
202  bool nameIsMatch = true;
203  unsigned int nameIsMatchIndex, nameIsMatchStorageIndex;
204  for(nameIsMatchIndex = 0, nameIsMatchStorageIndex = 0;
205  nameIsMatchIndex < table->getViewP()->getTableName().size();
206  ++nameIsMatchIndex)
207  {
208  if(table->getMockupViewP()->getTableName()[nameIsMatchStorageIndex] ==
209  '_')
210  ++nameIsMatchStorageIndex; // skip to next storage character
211  if(table->getViewP()->getTableName()[nameIsMatchIndex] == '_')
212  continue; // skip to next character
213 
214  // match to storage name
215  if(nameIsMatchStorageIndex >=
216  table->getMockupViewP()->getTableName().size() ||
217  table->getViewP()->getTableName()[nameIsMatchIndex] !=
218  table->getMockupViewP()->getTableName()[nameIsMatchStorageIndex])
219  {
220  // size mismatch or character mismatch
221  nameIsMatch = false;
222  break;
223  }
224  ++nameIsMatchStorageIndex;
225  }
226 
227  if(nameIsMatch) // if name is considered match by above rule, then force
228  // matchup
229  table->getViewP()->setTableName(table->getMockupViewP()->getTableName());
230  else // table->getViewP()->getTableName() !=
231  // table->getMockupViewP()->getTableName())
232  {
233  __SS__ << "View Table Name mismatch!! "
234  << table->getViewP()->getTableName() << " vs "
235  << table->getMockupViewP()->getTableName() << std::endl;
236  __SS_THROW__;
237  }
238 
239  try
240  {
241  // sanitize for column info and dataTypes
242  table->getViewP()->init();
243  }
244  catch(const std::runtime_error& e)
245  {
246  __SS__ << "Error occurred while getting and filling Table \"" << tableName
247  << "\" version:" << version << std::endl;
248  ss << "\n" << e.what() << __E__;
249  __COUT__ << StringMacros::stackTrace() << __E__;
250 
251  // if accumulating errors, allow invalid data
252  if(accumulatedErrors)
253  *accumulatedErrors += ss.str();
254  else
255  throw;
256  }
257 
258  // at this point, view has been verified!
260  }
261  catch(const std::runtime_error& e)
262  {
263  __SS__ << "Error occurred while getting and filling Table \"" << tableName
264  << "\" version:" << version << std::endl;
265  ss << "\n" << e.what() << __E__;
266  __SS_THROW__;
267  }
268  catch(...)
269  {
270  __SS__ << "Unknown error occurred while getting and filling Table \""
271  << tableName << "\" version:" << version << std::endl;
272  __SS_THROW__;
273  }
274 
275  } // end get()
276 
277  // table handling
278  virtual std::set<std::string /*name*/> getAllTableNames() const
279  {
280  __SS__;
281  __THROW__(ss.str() +
282  "ConfigurationInterface::... Must only call "
283  "getAllTableNames in a mode with this functionality "
284  "implemented (e.g. DatabaseConfigurationInterface).");
285  }
286  virtual std::set<TableVersion> getVersions(const TableBase* configuration) const = 0;
287  const bool& getMode() const { return theMode_; }
288  TableVersion saveNewVersion(TableBase* configuration,
289  TableVersion temporaryVersion,
290  TableVersion newVersion = TableVersion());
291 
292  // group handling
293  virtual std::set<std::string /*name*/> getAllTableGroupNames(
294  const std::string& filterString = "") const
295  {
296  __SS__;
297  __THROW__(ss.str() +
298  "ConfigurationInterface::... Must only call "
299  "getAllTableGroupNames in a mode with this functionality "
300  "implemented (e.g. DatabaseConfigurationInterface).");
301  }
302  virtual std::set<TableGroupKey> getKeys(const std::string& groupName) const
303  {
304  __SS__;
305  __THROW__(ss.str() +
306  "ConfigurationInterface::... Must only call "
307  "getKeys in a mode with this functionality "
308  "implemented (e.g. DatabaseConfigurationInterface).");
309  }
310 
311  // Caution: getTableGroupMembers must be carefully used.. the table versions
312  // are as initially defined for table versions aliases, i.e. not converted according
313  // to the metadata groupAliases!
314  virtual std::map<std::string /*name*/, TableVersion /*version*/> getTableGroupMembers(
315  std::string const& /*groupName*/, bool includeMetaDataTable = false) const
316  {
317  __SS__;
318  __THROW__(ss.str() +
319  "ConfigurationInterface::... Must only call "
320  "getTableGroupMembers in a mode with this functionality "
321  "implemented (e.g. DatabaseConfigurationInterface).");
322  }
323 
324  virtual void saveTableGroup(
325  std::map<std::string /*name*/,
326  TableVersion /*version*/> const& /*tableToVersionMap*/,
327  std::string const& /*groupName*/) const
328  {
329  __SS__;
330  __THROW__(ss.str() +
331  "ConfigurationInterface::... Must only call "
332  "saveTableGroup in a mode with this functionality "
333  "implemented (e.g. DatabaseConfigurationInterface).");
334  };
335 
336  protected:
337  ConfigurationInterface(void); // Protected constructor
338 
339  virtual void fill(TableBase* configuration, TableVersion version) const = 0;
340 
341  public: // was protected,.. unfortunately, must be public to allow
342  // otsdaq_database_migrate and otsdaq_import_system_aliases to compile
343  virtual TableGroupKey findLatestGroupKey(
344  const std::string& groupName) const /* return INVALID if no existing versions */
345  {
346  __SS__;
347  __THROW__(ss.str() +
348  "ConfigurationInterface::... Must only call findLatestGroupKey in a "
349  "mode with this functionality implemented (e.g. "
350  "DatabaseConfigurationInterface).");
351  }
352  virtual TableVersion findLatestVersion(const TableBase* configuration)
353  const = 0; // return INVALID if no existing versions
354  virtual void saveActiveVersion(const TableBase* configuration,
355  bool overwrite = false) const = 0;
356 
357  protected:
358  ConfigurationHandlerBase* theConfigurationHandler_;
359 
360  private:
361  static ConfigurationInterface* theInstance_;
362  static bool theMode_; // 1 is FILE, 0 is artdaq-DB
363  static bool
364  theVersionTrackingEnabled_; // tracking versions 1 is enabled, 0 is disabled
365 };
366 
367 } // namespace ots
368 #endif