CernVM-FS  2.13.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
history_sql.cc
Go to the documentation of this file.
1 
5 #include "history_sql.h"
6 
7 #include <cassert>
8 
9 #include "util/string.h"
10 
11 namespace history {
12 
13 const float HistoryDatabase::kLatestSchema = 1.0;
16 
29 const std::string HistoryDatabase::kFqrnKey = "fqrn";
30 
31 
36  assert(read_write());
37 
38  sqlite::Sql sql_foreign_keys(sqlite_db(), "PRAGMA foreign_keys = ON;");
39  if (!sql_foreign_keys.Execute())
40  return false;
41 
43 }
44 
45 
47  assert(read_write());
48  return sqlite::Sql(
49  sqlite_db(),
50  "CREATE TABLE tags (name TEXT, hash TEXT, revision INTEGER, "
51  " timestamp INTEGER, channel INTEGER, description TEXT, size "
52  "INTEGER, "
53  " branch TEXT, CONSTRAINT pk_tags PRIMARY KEY (name), "
54  " FOREIGN KEY (branch) REFERENCES branches (branch));")
55  .Execute();
56 }
57 
58 
60  assert(read_write());
61  return sqlite::Sql(sqlite_db(),
62  "CREATE TABLE recycle_bin (hash TEXT, flags INTEGER, "
63  " CONSTRAINT pk_hash PRIMARY KEY (hash))")
64  .Execute();
65 }
66 
67 
69  assert(read_write());
70 
71  sqlite::Sql sql_create(sqlite_db(),
72  "CREATE TABLE branches (branch TEXT, parent TEXT, "
73  "initial_revision INTEGER,"
74  " CONSTRAINT pk_branch PRIMARY KEY (branch), "
75  " FOREIGN KEY (parent) REFERENCES branches (branch), "
76  " CHECK ((branch <> '') OR (parent IS NULL)), "
77  " CHECK ((branch = '') OR (parent IS NOT NULL)));");
78  bool retval = sql_create.Execute();
79  if (!retval)
80  return false;
81 
82  sqlite::Sql sql_init(
83  sqlite_db(),
84  "INSERT INTO branches (branch, parent, initial_revision) "
85  "VALUES ('', NULL, 0);");
86  retval = sql_init.Execute();
87  return retval;
88 }
89 
90 
91 bool HistoryDatabase::InsertInitialValues(const std::string &repository_name) {
92  assert(read_write());
93  return this->SetProperty(kFqrnKey, repository_name);
94 }
95 
96 
98  return schema_version() >= 1.0 - kSchemaEpsilon && schema_revision() >= 2;
99 }
100 
101 
105 }
106 
107 
109  assert(read_write());
111 
112  sqlite::Sql sql_foreign_keys(sqlite_db(), "PRAGMA foreign_keys = ON;");
113  if (!sql_foreign_keys.Execute())
114  return false;
116  return true;
117  }
118 
120  "upgrading history schema revision "
121  "%.2f (Rev: %d) to %.2f (Rev: %d)",
124 
125  const bool success = UpgradeSchemaRevision_10_1()
128 
129  return success && StoreSchemaRevision();
130 }
131 
132 
134  if (schema_revision() > 0) {
135  return true;
136  }
137 
138  sqlite::Sql sql_upgrade(sqlite_db(), "ALTER TABLE tags ADD size INTEGER;");
139  if (!sql_upgrade.Execute()) {
140  LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade tags table");
141  return false;
142  }
143 
145  return true;
146 }
147 
148 
150  if (schema_revision() > 1) {
151  return true;
152  }
153 
154  if (!CreateRecycleBinTable()) {
155  LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade history database");
156  return false;
157  }
158 
160  return true;
161 }
162 
163 
165  if (schema_revision() > 2) {
166  return true;
167  }
168 
169  if (!CreateBranchesTable()) {
170  LogCvmfs(kLogHistory, kLogStderr, "failed to create branches table");
171  return false;
172  }
173 
174  sqlite::Sql sql_upgrade(
175  sqlite_db(),
176  "ALTER TABLE tags ADD branch TEXT REFERENCES branches (branch);");
177  if (!sql_upgrade.Execute()) {
178  LogCvmfs(kLogHistory, kLogStderr, "failed to upgrade tags table");
179  return false;
180  }
181 
182  sqlite::Sql sql_fill(sqlite_db(), "UPDATE tags SET branch = '';");
183  if (!sql_fill.Execute()) {
184  LogCvmfs(kLogHistory, kLogStderr, "failed to set branch default value");
185  return false;
186  }
187 
188  // We keep the table in the schema for backwards compatibility
189  sqlite::Sql sql_flush(sqlite_db(), "DELETE FROM recycle_bin; VACUUM;");
190  if (!sql_flush.Execute()) {
191  LogCvmfs(kLogHistory, kLogStderr, "failed to flush recycle bin table");
192  return false;
193  }
194 
196  return true;
197 }
198 
199 
200 //------------------------------------------------------------------------------
201 
202 #define DB_FIELDS_V1R0 \
203  "name, hash, revision, timestamp, channel, " \
204  "description, 0, ''"
205 #define DB_FIELDS_V1R1 \
206  "name, hash, revision, timestamp, channel, " \
207  "description, size, ''"
208 #define DB_FIELDS_V1R3 \
209  "name, hash, revision, timestamp, channel, " \
210  "description, size, branch"
211 #define DB_PLACEHOLDERS \
212  ":name, :hash, :revision, :timestamp, :channel, " \
213  ":description, :size, :branch"
214 #define ROLLBACK_COND \
215  "(revision > :target_rev OR " \
216  " name = :target_name) " \
217  "AND branch = ''"
218 
219 #define MAKE_STATEMENT(STMT_TMPL, REV) \
220  static const std::string REV = ReplaceAll( \
221  ReplaceAll(ReplaceAll(STMT_TMPL, "@DB_FIELDS@", DB_FIELDS_##REV), \
222  "@DB_PLACEHOLDERS@", DB_PLACEHOLDERS), \
223  "@ROLLBACK_COND@", ROLLBACK_COND)
224 
225 #define MAKE_STATEMENTS(STMT_TMPL) \
226  MAKE_STATEMENT(STMT_TMPL, V1R0); \
227  MAKE_STATEMENT(STMT_TMPL, V1R1); \
228  MAKE_STATEMENT(STMT_TMPL, V1R3)
229 
230 #define DEFERRED_INIT(DB, REV) DeferredInit((DB)->sqlite_db(), (REV).c_str())
231 
232 #define DEFERRED_INITS(DB) \
233  if ((DB)->IsEqualSchema((DB)->schema_version(), 1.0f) \
234  && (DB)->schema_revision() == 0) { \
235  DEFERRED_INIT((DB), V1R0); \
236  } else if ((DB)->schema_revision() < 3) { \
237  DEFERRED_INIT((DB), V1R1); \
238  } else { \
239  DEFERRED_INIT((DB), V1R3); \
240  }
241 
243  MAKE_STATEMENTS("INSERT INTO tags (@DB_FIELDS@) VALUES (@DB_PLACEHOLDERS@);");
244  DEFERRED_INITS(database);
245 }
246 
247 
249  return BindText(1, tag.name) && BindTextTransient(2, tag.root_hash.ToString())
250  && // temporary (ToString)
251  BindInt64(3, tag.revision) && BindInt64(4, tag.timestamp) &&
252  // Channels are no longer supported: store 0 (i.e. kChannelTrunk)
253  // for backwards compatibility with existing databases
254  //
255  BindInt64(5, 0) && BindText(6, tag.description)
256  && BindInt64(7, tag.size) && BindText(8, tag.branch);
257 }
258 
259 
260 //------------------------------------------------------------------------------
261 
262 
264  DeferredInit(database->sqlite_db(), "DELETE FROM tags WHERE name = :name;");
265 }
266 
267 bool SqlRemoveTag::BindName(const std::string &name) {
268  return BindText(1, name);
269 }
270 
271 
272 //------------------------------------------------------------------------------
273 
274 
276  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags WHERE name = :name;");
277  DEFERRED_INITS(database);
278 }
279 
280 bool SqlFindTag::BindName(const std::string &name) { return BindText(1, name); }
281 
282 
283 //------------------------------------------------------------------------------
284 
285 
287  // figure out the tag that was HEAD to a given point in time
288  //
289  // conceptually goes back in the revision history | ORDER BY revision DESC
290  // and picks the first tag | LIMIT 1
291  // that is older than the given timestamp | WHICH timestamp <= :ts
292  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
293  "WHERE (branch = '') AND (timestamp <= :timestamp) "
294  "ORDER BY revision DESC LIMIT 1;");
295  DEFERRED_INITS(database);
296 }
297 
298 bool SqlFindTagByDate::BindTimestamp(const time_t timestamp) {
299  return BindInt64(1, timestamp);
300 }
301 
302 
303 //------------------------------------------------------------------------------
304 
305 
307  // One of the tags with the highest revision on a given branch
308  // Doesn't work on older database revisions
309  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
310  "WHERE (branch = :branch) "
311  "ORDER BY revision DESC LIMIT 1;");
312  DEFERRED_INITS(database);
313 }
314 
315 bool SqlFindBranchHead::BindBranchName(const std::string &branch_name) {
316  return BindText(1, branch_name);
317 }
318 
319 
320 //------------------------------------------------------------------------------
321 
322 
324  DeferredInit(database->sqlite_db(), "SELECT count(*) FROM tags;");
325 }
326 
327 unsigned SqlCountTags::RetrieveCount() const {
328  const int64_t count = RetrieveInt64(0);
329  assert(count >= 0);
330  return static_cast<uint64_t>(count);
331 }
332 
333 
334 //------------------------------------------------------------------------------
335 
336 
339  "SELECT @DB_FIELDS@ FROM tags ORDER BY timestamp DESC, revision DESC;");
340  DEFERRED_INITS(database);
341 }
342 
343 
344 //------------------------------------------------------------------------------
345 
346 
348  DeferredInit(database->sqlite_db(), "SELECT DISTINCT hash FROM tags "
349  "ORDER BY timestamp, revision ASC");
350 }
351 
355 }
356 
357 
358 //------------------------------------------------------------------------------
359 
360 
362  MAKE_STATEMENTS("DELETE FROM tags WHERE @ROLLBACK_COND@;");
363  DEFERRED_INITS(database);
364 }
365 
366 
367 //------------------------------------------------------------------------------
368 
369 
371  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
372  "WHERE @ROLLBACK_COND@ "
373  "ORDER BY revision DESC;");
374  DEFERRED_INITS(database);
375 }
376 
377 
378 //------------------------------------------------------------------------------
379 
380 
382  if (database->schema_revision() < 3)
383  DeferredInit(database->sqlite_db(), "SELECT '', NULL, 0;");
384  else
385  DeferredInit(database->sqlite_db(),
386  "SELECT branch, parent, initial_revision FROM branches;");
387 }
388 
389 
391  const std::string branch = RetrieveString(0);
392  const std::string parent =
393  (RetrieveType(1) == SQLITE_NULL) ? "" : RetrieveString(1);
394  const unsigned initial_revision = RetrieveInt64(2);
395  return History::Branch(branch, parent, initial_revision);
396 }
397 
398 
399 //------------------------------------------------------------------------------
400 
401 
403  DeferredInit(database->sqlite_db(),
404  "INSERT INTO branches (branch, parent, initial_revision) "
405  "VALUES (:branch, :parent, :initial_revision);");
406 }
407 
408 
410  return BindText(1, branch.branch) && BindText(2, branch.parent)
411  && BindInt64(3, branch.initial_revision);
412 }
413 
414 
415 //------------------------------------------------------------------------------
416 
417 
418 bool SqlRecycleBin::CheckSchema(const HistoryDatabase *database) const {
419  return (database->IsEqualSchema(database->schema_version(), 1.0))
420  && (database->schema_revision() >= 2);
421 }
422 
423 
424 //------------------------------------------------------------------------------
425 
426 
428  assert(CheckSchema(database));
429  DeferredInit(database->sqlite_db(), "SELECT hash, flags FROM recycle_bin;");
430 }
431 
432 
434  const unsigned int flags = RetrieveInt64(1);
436  if (flags & SqlRecycleBin::kFlagCatalog) {
437  suffix = shash::kSuffixCatalog;
438  }
439 
441 }
442 
443 
444 //------------------------------------------------------------------------------
445 
446 
448  assert(CheckSchema(database));
449  DeferredInit(database->sqlite_db(), "DELETE FROM recycle_bin;");
450 }
451 
452 
453 }; /* namespace history */
bool BindTimestamp(const time_t timestamp)
Definition: history_sql.cc:298
static const float kLatestSchema
Definition: history_sql.h:22
bool BindTextTransient(const int index, const std::string &value)
Definition: sql.h:386
bool Execute()
Definition: sql.cc:41
unsigned RetrieveCount() const
Definition: history_sql.cc:327
SqlFindTag(const HistoryDatabase *database)
Definition: history_sql.cc:275
bool BindText(const int index, const std::string &value)
Definition: sql.h:394
bool CheckSchema(const HistoryDatabase *database) const
Definition: history_sql.cc:418
static const float kLatestSupportedSchema
Definition: history_sql.h:23
std::string name
Definition: history.h:92
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:241
SqlFindTagByDate(const HistoryDatabase *database)
Definition: history_sql.cc:286
const history::History * history() const
shash::Any RetrieveHash() const
Definition: history_sql.cc:352
assert((mem||(size==0))&&"Out Of Memory")
SqlInsertTag(const HistoryDatabase *database)
Definition: history_sql.cc:242
float schema_version() const
Definition: sql.h:147
SqlCountTags(const HistoryDatabase *database)
Definition: history_sql.cc:323
SqlListRollbackTags(const HistoryDatabase *database)
Definition: history_sql.cc:370
void set_schema_revision(const unsigned rev)
Definition: sql.h:250
unsigned schema_revision() const
Definition: sql.h:148
SqlFindBranchHead(const HistoryDatabase *database)
Definition: history_sql.cc:306
bool InsertInitialValues(const std::string &repository_name)
Definition: history_sql.cc:91
std::string description
Definition: history.h:97
bool BindBranchName(const std::string &branch_name)
Definition: history_sql.cc:315
void DeferredInit(const sqlite3 *database, const char *statement)
Definition: sql.cc:159
SqlRecycleBinFlush(const HistoryDatabase *database)
Definition: history_sql.cc:447
std::string parent
Definition: history.h:40
static const float kSchemaEpsilon
Definition: sql.h:104
static const unsigned int kFlagCatalog
Definition: history_sql.h:226
bool BindName(const std::string &name)
Definition: history_sql.cc:280
const char kSuffixCatalog
Definition: hash.h:54
bool BindTag(const History::Tag &tag)
Definition: history_sql.cc:248
SqlListTags(const HistoryDatabase *database)
Definition: history_sql.cc:337
sqlite3_int64 RetrieveInt64(const int idx_column) const
Definition: sql.h:445
#define MAKE_STATEMENTS(STMT_TMPL)
Definition: history_sql.cc:225
sqlite3 * sqlite_db() const
Definition: sql.h:145
bool BindBranch(const History::Branch &branch)
Definition: history_sql.cc:409
bool BindInt64(const int index, const sqlite3_int64 value)
Definition: sql.h:376
bool SetProperty(const std::string &key, const T value)
SqlInsertBranch(const HistoryDatabase *database)
Definition: history_sql.cc:402
static const unsigned kLatestSchemaRevision
Definition: history_sql.h:25
char Suffix
Definition: hash.h:111
bool IsEqualSchema(const float value, const float compare) const
Definition: sql.h:129
SqlGetHashes(const HistoryDatabase *database)
Definition: history_sql.cc:347
std::string RetrieveString(const int idx_column) const
Definition: sql.h:451
static const std::string kFqrnKey
Definition: history_sql.h:27
bool BindName(const std::string &name)
Definition: history_sql.cc:267
int RetrieveType(const int idx_column) const
Definition: sql.h:416
shash::Any root_hash
Definition: history.h:93
uint64_t initial_revision
Definition: history.h:41
std::string branch
Definition: history.h:101
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:82
SqlRemoveTag(const HistoryDatabase *database)
Definition: history_sql.cc:263
bool ContainsRecycleBin() const
Definition: history_sql.cc:97
uint64_t revision
Definition: history.h:95
#define DEFERRED_INITS(DB)
Definition: history_sql.cc:232
std::string branch
Definition: history.h:39
const char kSuffixNone
Definition: hash.h:53
History::Branch RetrieveBranch() const
Definition: history_sql.cc:390
SqlRecycleBinList(const HistoryDatabase *database)
Definition: history_sql.cc:427
SqlRollbackTag(const HistoryDatabase *database)
Definition: history_sql.cc:361
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:545
SqlListBranches(const HistoryDatabase *database)
Definition: history_sql.cc:381