ParameterSetRegistry.cc
Go to the documentation of this file.
2 
5 #include "cetlib/sqlite/column.h"
7 #include "cetlib/sqlite/exec.h"
9 #include "cetlib/sqlite/select.h"
11 #include "fhiclcpp/exception.h"
12 
13 #include "sqlite3.h"
14 
15 #include <cassert>
16 #include <iostream>
17 
19 
20 std::recursive_mutex fhicl::ParameterSetRegistry::mutex_{};
21 
22 namespace {
23  sqlite3*
24  openPrimaryDB()
25  {
26  sqlite3* result = nullptr;
27  sqlite3_open(":memory:", &result);
29  using namespace cet::sqlite;
30  Transaction txn{result};
31  create_table(result,
32  "ParameterSets",
34  column<std::string>{"PSetBlob"});
35  txn.commit();
36  return result;
37  }
38 }
39 
40 void
41 fhicl::detail::throwOnSQLiteFailure(int const errcode, char* msg)
42 {
43  std::string const msgString{msg ? msg : ""};
44  sqlite3_free(msg);
45  if (errcode != SQLITE_OK) {
46  // Caller's responsibility to make sure this really is an error
47  // and not (say) SQLITE_ROW or SQLITE_DONE,
48  throw exception(error::sql_error, "SQLite error:")
49  << sqlite3_errstr(errcode) << " (" << errcode << ')'
50  << (msgString.empty() ? "" : (std::string(": ") + msgString));
51  }
52 }
53 
54 void
56 {
57  if (db == nullptr) {
58  sqlite3_free(msg);
59  throw fhicl::exception(fhicl::error::cant_open_db) << "Can't open DB.";
60  }
61  auto const errcode = sqlite3_errcode(db);
62  throwOnSQLiteFailure(errcode, msg);
63 }
64 
66 {
67  sqlite3_finalize(stmt_);
68  try {
69  throwOnSQLiteFailure(primaryDB_);
70  }
71  catch (fhicl::exception const& e) {
72  std::cerr << e.what() << '\n';
73  }
74  catch (...) {
75  }
76  int retcode;
77  do {
78  retcode = sqlite3_close(primaryDB_);
79  } while (retcode == SQLITE_BUSY);
80 }
81 
82 void
84 {
85  assert(db);
86  std::lock_guard sentry{mutex_};
87 
88  // This does *not* cause anything new to be imported into the
89  // registry itself, just its backing DB.
90  sqlite3_stmt* oStmt = nullptr;
91  sqlite3* primaryDB = instance_().primaryDB_;
92 
93  // Index constraint on ID will prevent duplicates via INSERT OR IGNORE.
94  sqlite3_prepare_v2(
95  primaryDB,
96  "INSERT OR IGNORE INTO ParameterSets(ID, PSetBlob) VALUES(?, ?);",
97  -1,
98  &oStmt,
99  nullptr);
100  throwOnSQLiteFailure(primaryDB);
101 
102  using namespace cet::sqlite;
104  inputPSes << select("*").from(db, "ParameterSets");
105 
106  for (auto const& [idString, psBlob] : inputPSes) {
107  sqlite3_bind_text(
108  oStmt, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
109  throwOnSQLiteFailure(primaryDB);
110  sqlite3_bind_text(
111  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
112  throwOnSQLiteFailure(primaryDB);
113  switch (sqlite3_step(oStmt)) {
114  case SQLITE_DONE:
115  break; // OK
116  default:
117  throwOnSQLiteFailure(primaryDB);
118  }
119  sqlite3_reset(oStmt);
120  throwOnSQLiteFailure(primaryDB);
121  }
122  sqlite3_finalize(oStmt);
123  throwOnSQLiteFailure(primaryDB);
124 }
125 
126 void
128 {
129  assert(db);
130  std::lock_guard sentry{mutex_};
131 
132  cet::sqlite::Transaction txn{db};
134  "DROP TABLE IF EXISTS ParameterSets;"
135  "CREATE TABLE ParameterSets(ID PRIMARY KEY, PSetBlob);");
136  txn.commit();
137 
138  sqlite3_stmt* oStmt = nullptr;
139  sqlite3_prepare_v2(
140  db,
141  "INSERT OR IGNORE INTO ParameterSets(ID, PSetBlob) VALUES(?, ?);",
142  -1,
143  &oStmt,
144  nullptr);
146  for (auto const& p : instance_().registry_) {
147  std::string id(p.first.to_string());
148  std::string psBlob(p.second.to_compact_string());
149  sqlite3_bind_text(oStmt, 1, id.c_str(), id.size() + 1, SQLITE_STATIC);
151  sqlite3_bind_text(
152  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
154  switch (sqlite3_step(oStmt)) {
155  case SQLITE_DONE:
156  sqlite3_reset(oStmt);
158  break; // OK
159  default:
161  }
162  }
163 
164  sqlite3* const primaryDB{instance_().primaryDB_};
165  using namespace cet::sqlite;
167  regPSes << select("*").from(primaryDB, "ParameterSets");
168 
169  for (auto const& [idString, psBlob] : regPSes) {
170  sqlite3_bind_text(
171  oStmt, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
173  sqlite3_bind_text(
174  oStmt, 2, psBlob.c_str(), psBlob.size() + 1, SQLITE_STATIC);
176  switch (sqlite3_step(oStmt)) {
177  case SQLITE_DONE:
178  sqlite3_reset(oStmt);
180  break; // OK
181  default:
183  }
184  }
185  sqlite3_finalize(oStmt);
187 }
188 
189 void
191 {
192  std::lock_guard sentry{mutex_};
193 
194  sqlite3* primaryDB = instance_().primaryDB_;
195  auto& registry = instance_().registry_;
196  using namespace cet::sqlite;
198  entriesToStageIn << select("*").from(primaryDB, "ParameterSets");
199 
200  cet::transform_all(entriesToStageIn,
201  std::inserter(registry, std::begin(registry)),
202  [](auto const& row) {
203  auto const& [idString, psBlob] = row;
204  auto const pset = ParameterSet::make(psBlob);
205  return std::make_pair(ParameterSetID{idString}, pset);
206  });
207 }
208 
210  : primaryDB_{openPrimaryDB()}
211 {}
212 
213 auto
215 {
216  // No lock here -- it was already acquired by get(...).
217  auto it = registry_.find(id);
218  if (it == registry_.cend()) {
219  // Look in primary DB for this ID and its contained IDs.
220  if (stmt_ == nullptr) {
221  sqlite3_prepare_v2(primaryDB_,
222  "SELECT PSetBlob FROM ParameterSets WHERE ID = ?;",
223  -1,
224  &stmt_,
225  nullptr);
227  }
228  auto idString = id.to_string();
229  auto result = sqlite3_bind_text(
230  stmt_, 1, idString.c_str(), idString.size() + 1, SQLITE_STATIC);
232  result = sqlite3_step(stmt_);
233  switch (result) {
234  case SQLITE_ROW: // Found the ID in the DB.
235  {
236  auto const pset = ParameterSet::make(
237  reinterpret_cast<char const*>(sqlite3_column_text(stmt_, 0)));
238  // Put into the registry without triggering ParameterSet::id().
239  it = registry_.emplace(id, pset).first;
240  } break;
241  case SQLITE_DONE:
242  break; // Not here.
243  default:
245  }
246  sqlite3_reset(stmt_);
247  }
248  return it;
249 }
static QCString result
void msg(const char *fmt,...)
Definition: message.cpp:107
std::string string
Definition: nybbler.cc:12
static ParameterSet make(intermediate_table const &tbl)
Definition: ParameterSet.cc:68
struct sqlite3_stmt sqlite3_stmt
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
const double e
void create_table(sqlite3 *const db, std::string const &tablename, Cols const &...cols)
Definition: create_table.h:118
p
Definition: test.py:223
auto transform_all(Container &, OutputIt, UnaryOp)
auto select(T const &...t)
Definition: select.h:146
static std::recursive_mutex mutex_
struct sqlite3 sqlite3
unique_ptr< InputSource > make(ParameterSet const &conf, InputSourceDescription &desc)
typename collection_type::const_iterator const_iterator
void throwOnSQLiteFailure(int rc, char *msg=nullptr)
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
const_iterator find_(ParameterSetID const &id)
void exec(sqlite3 *db, std::string const &ddl)
Definition: exec.cc:5
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
static void exportTo(sqlite3 *db)
static void importFrom(sqlite3 *db)