LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
ParameterSetRegistry.cc
Go to the documentation of this file.
2 
3 #include "cetlib/sqlite/Transaction.h"
4 #include "cetlib/sqlite/create_table.h"
5 #include "cetlib/sqlite/exec.h"
6 #include "cetlib/sqlite/select.h"
8 #include "fhiclcpp/exception.h"
10 
12 
13 namespace {
14  sqlite3*
15  openPrimaryDB()
16  {
17  sqlite3* result = nullptr;
18  sqlite3_open(":memory:", &result);
20  using namespace cet::sqlite;
21  Transaction txn{result};
22  create_table(result,
23  "ParameterSets",
24  column<std::string, primary_key>{"ID"},
25  column<std::string>{"PSetBlob"});
26  txn.commit();
27  return result;
28  }
29 }
30 
31 void
32 fhicl::detail::throwOnSQLiteFailure(sqlite3* db, char* msg)
33 {
34  std::string const msgString{msg ? msg : ""};
35  sqlite3_free(msg);
36  if (db == nullptr) {
37  throw fhicl::exception(fhicl::error::cant_open_db) << "Can't open DB.";
38  }
39  auto errcode = sqlite3_errcode(db);
40  if (errcode != SQLITE_OK) {
41  // Caller's responsibility to make sure this really is an error
42  // and not (say) SQLITE_ROW or SQLITE_DONE,
43  throw exception(error::sql_error, "SQLite error:")
44  << sqlite3_errstr(errcode) << " (" << errcode
45  << "): " << sqlite3_errmsg(db)
46  << (msgString.empty() ? "" : (std::string(". ") + msgString));
47  }
48 }
49 
51 {
52  sqlite3_finalize(stmt_);
53  try {
54  throwOnSQLiteFailure(primaryDB_);
55  }
56  catch (fhicl::exception const& e) {
57  std::cerr << e.what() << '\n';
58  }
59  catch (...) {
60  }
61  int retcode;
62  do {
63  retcode = sqlite3_close(primaryDB_);
64  } while (retcode == SQLITE_BUSY);
65 }
66 
67 void
69 {
70  assert(db);
71  std::lock_guard<decltype(mutex_)> lock{mutex_};
72 
73  // This does *not* cause anything new to be imported into the
74  // registry itself, just its backing DB.
75  sqlite3_stmt* oStmt = nullptr;
76  sqlite3* primaryDB = instance_().primaryDB_;
77 
78  // Index constraint on ID will prevent duplicates via INSERT OR IGNORE.
79  sqlite3_prepare_v2(
80  primaryDB,
81  "INSERT OR IGNORE INTO ParameterSets(ID, PSetBlob) VALUES(?, ?);",
82  -1,
83  &oStmt,
84  nullptr);
85  throwOnSQLiteFailure(primaryDB);
86 
87  using namespace cet::sqlite;
88  query_result<std::string, std::string> inputPSes;
89  inputPSes << select("*").from(db, "ParameterSets");
90 
91  for (auto const& row : inputPSes) {
92  std::string idString;
93  std::string psBlob;
94  std::tie(idString, psBlob) = row;
95 
96  sqlite3_bind_text(
97  oStmt, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
98  throwOnSQLiteFailure(primaryDB);
99  sqlite3_bind_text(
100  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
101  throwOnSQLiteFailure(primaryDB);
102  switch (sqlite3_step(oStmt)) {
103  case SQLITE_DONE:
104  break; // OK
105  default:
106  throwOnSQLiteFailure(primaryDB);
107  }
108  sqlite3_reset(oStmt);
109  throwOnSQLiteFailure(primaryDB);
110  }
111  sqlite3_finalize(oStmt);
112  throwOnSQLiteFailure(primaryDB);
113 }
114 
115 void
117 {
118  assert(db);
119  std::lock_guard<decltype(mutex_)> lock{mutex_};
120 
121  cet::sqlite::Transaction txn{db};
122  cet::sqlite::exec(db,
123  "DROP TABLE IF EXISTS ParameterSets;"
124  "CREATE TABLE ParameterSets(ID PRIMARY KEY, PSetBlob);");
125  txn.commit();
126 
127  sqlite3_stmt* oStmt = nullptr;
128  sqlite3_prepare_v2(
129  db,
130  "INSERT OR IGNORE INTO ParameterSets(ID, PSetBlob) VALUES(?, ?);",
131  -1,
132  &oStmt,
133  nullptr);
135  for (auto const& p : instance_().registry_) {
136  std::string id(p.first.to_string());
137  std::string psBlob(p.second.to_compact_string());
138  sqlite3_bind_text(oStmt, 1, id.c_str(), id.size() + 1, SQLITE_STATIC);
140  sqlite3_bind_text(
141  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
143  switch (sqlite3_step(oStmt)) {
144  case SQLITE_DONE:
145  sqlite3_reset(oStmt);
147  break; // OK
148  default:
150  }
151  }
152 
153  sqlite3* const primaryDB{instance_().primaryDB_};
154  using namespace cet::sqlite;
155  query_result<std::string, std::string> regPSes;
156  regPSes << select("*").from(primaryDB, "ParameterSets");
157 
158  for (auto const& row : regPSes) {
159  std::string idString;
160  std::string psBlob;
161  std::tie(idString, psBlob) = row;
162  sqlite3_bind_text(
163  oStmt, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
165  sqlite3_bind_text(
166  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
168  switch (sqlite3_step(oStmt)) {
169  case SQLITE_DONE:
170  sqlite3_reset(oStmt);
172  break; // OK
173  default:
175  }
176  }
177  sqlite3_finalize(oStmt);
179 }
180 
181 void
183 {
184  std::lock_guard<decltype(mutex_)> lock{mutex_};
185 
186  sqlite3* primaryDB = instance_().primaryDB_;
187  auto& registry = instance_().registry_;
188  using namespace cet::sqlite;
189  query_result<std::string, std::string> entriesToStageIn;
190  entriesToStageIn << select("*").from(primaryDB, "ParameterSets");
191 
192  cet::transform_all(entriesToStageIn,
193  std::inserter(registry, std::begin(registry)),
194  [](auto const& row) {
195  std::string idString;
196  std::string psBlob;
197  std::tie(idString, psBlob) = row;
198  ParameterSet pset;
199  fhicl::make_ParameterSet(psBlob, pset);
200  return std::make_pair(ParameterSetID{idString}, pset);
201  });
202 }
203 
205  : primaryDB_{openPrimaryDB()}
206 {}
207 
208 std::recursive_mutex fhicl::ParameterSetRegistry::mutex_{};
209 
210 auto
212 {
213  // No lock here -- it was already acquired by get(...).
214  auto it = registry_.find(id);
215  if (it == registry_.cend()) {
216  // Look in primary DB for this ID and its contained IDs.
217  if (stmt_ == nullptr) {
218  sqlite3_prepare_v2(primaryDB_,
219  "SELECT PSetBlob FROM ParameterSets WHERE ID = ?;",
220  -1,
221  &stmt_,
222  nullptr);
224  }
225  auto idString = id.to_string();
226  auto result = sqlite3_bind_text(
227  stmt_, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
229  result = sqlite3_step(stmt_);
230  switch (result) {
231  case SQLITE_ROW: // Found the ID in the DB.
232  {
233  ParameterSet pset;
235  reinterpret_cast<char const*>(sqlite3_column_text(stmt_, 0)), pset);
236  // Put into the registry without triggering ParameterSet::id().
237  it = registry_.emplace(id, pset).first;
238  } break;
239  case SQLITE_DONE:
240  break; // Not here.
241  default:
243  }
244  sqlite3_reset(stmt_);
245  }
246  return it;
247 }
void make_ParameterSet(intermediate_table const &tbl, ParameterSet &ps)
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
static std::recursive_mutex mutex_
typename collection_type::const_iterator const_iterator
const_iterator find_(ParameterSetID const &id)
Float_t e
Definition: plot.C:34
void throwOnSQLiteFailure(sqlite3 *db, char *msg=nullptr)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
static void exportTo(sqlite3 *db)
static void importFrom(sqlite3 *db)