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