CernVM-FS  2.9.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 channel = :target_chan " \
207  "AND branch = ''"
208 
209 #define MAKE_STATEMENT(STMT_TMPL, REV) \
210 static const std::string REV = \
211  ReplaceAll( \
212  ReplaceAll( \
213  ReplaceAll(STMT_TMPL, \
214  "@DB_FIELDS@", DB_FIELDS_ ## REV), \
215  "@DB_PLACEHOLDERS@", DB_PLACEHOLDERS), \
216  "@ROLLBACK_COND@", ROLLBACK_COND)
217 
218 #define MAKE_STATEMENTS(STMT_TMPL) \
219  MAKE_STATEMENT(STMT_TMPL, V1R0); \
220  MAKE_STATEMENT(STMT_TMPL, V1R1); \
221  MAKE_STATEMENT(STMT_TMPL, V1R3)
222 
223 #define DEFERRED_INIT(DB, REV) \
224  DeferredInit((DB)->sqlite_db(), (REV).c_str())
225 
226 #define DEFERRED_INITS(DB) \
227  if ((DB)->IsEqualSchema((DB)->schema_version(), 1.0f) && \
228  (DB)->schema_revision() == 0) { \
229  DEFERRED_INIT((DB), V1R0); \
230  } else if ((DB)->schema_revision() < 3) { \
231  DEFERRED_INIT((DB), V1R1); \
232  } else { \
233  DEFERRED_INIT((DB), V1R3); \
234  }
235 
237  MAKE_STATEMENTS("INSERT INTO tags (@DB_FIELDS@) VALUES (@DB_PLACEHOLDERS@);");
238  DEFERRED_INITS(database);
239 }
240 
241 
243  return
244  BindText(1, tag.name) &&
245  BindTextTransient(2, tag.root_hash.ToString()) && // temporary (ToString)
246  BindInt64(3, tag.revision) &&
247  BindInt64(4, tag.timestamp) &&
248  BindInt64(5, tag.channel) &&
249  BindText(6, tag.description) &&
250  BindInt64(7, tag.size) &&
251  BindText(8, tag.branch);
252 }
253 
254 
255 //------------------------------------------------------------------------------
256 
257 
259  DeferredInit(database->sqlite_db(), "DELETE FROM tags WHERE name = :name;");
260 }
261 
262 bool SqlRemoveTag::BindName(const std::string &name) {
263  return BindText(1, name);
264 }
265 
266 
267 //------------------------------------------------------------------------------
268 
269 
271  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags WHERE name = :name;");
272  DEFERRED_INITS(database);
273 }
274 
275 bool SqlFindTag::BindName(const std::string &name) {
276  return BindText(1, name);
277 }
278 
279 
280 //------------------------------------------------------------------------------
281 
282 
284  // figure out the tag that was HEAD to a given point in time
285  //
286  // conceptually goes back in the revision history | ORDER BY revision DESC
287  // and picks the first tag | LIMIT 1
288  // that is older than the given timestamp | WHICH timestamp <= :ts
289  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
290  "WHERE (branch = '') AND (timestamp <= :timestamp) "
291  "ORDER BY revision DESC LIMIT 1;");
292  DEFERRED_INITS(database);
293 }
294 
295 bool SqlFindTagByDate::BindTimestamp(const time_t timestamp) {
296  return BindInt64(1, timestamp);
297 }
298 
299 
300 //------------------------------------------------------------------------------
301 
302 
304  // One of the tags with the highest revision on a given branch
305  // Doesn't work on older database revisions
306  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
307  "WHERE (branch = :branch) "
308  "ORDER BY revision DESC LIMIT 1;");
309  DEFERRED_INITS(database);
310 }
311 
312 bool SqlFindBranchHead::BindBranchName(const std::string &branch_name) {
313  return BindText(1, branch_name);
314 }
315 
316 
317 //------------------------------------------------------------------------------
318 
319 
321  DeferredInit(database->sqlite_db(), "SELECT count(*) FROM tags;");
322 }
323 
324 unsigned SqlCountTags::RetrieveCount() const {
325  int64_t count = RetrieveInt64(0);
326  assert(count >= 0);
327  return static_cast<uint64_t>(count);
328 }
329 
330 
331 //------------------------------------------------------------------------------
332 
333 
336  "SELECT @DB_FIELDS@ FROM tags ORDER BY timestamp DESC, revision DESC;");
337  DEFERRED_INITS(database);
338 }
339 
340 
341 //------------------------------------------------------------------------------
342 
343 
345  MAKE_STATEMENTS("SELECT @DB_FIELDS@, MAX(revision) AS max_rev "
346  "FROM tags "
347  "WHERE branch = '' "
348  "GROUP BY channel;");
349  DEFERRED_INITS(database);
350 }
351 
353  DeferredInit(database->sqlite_db(), "SELECT DISTINCT hash FROM tags "
354  "ORDER BY timestamp, revision ASC");
355 }
356 
360 }
361 
362 
363 //------------------------------------------------------------------------------
364 
365 
367  MAKE_STATEMENTS("DELETE FROM tags WHERE @ROLLBACK_COND@;");
368  DEFERRED_INITS(database);
369 }
370 
371 
372 //------------------------------------------------------------------------------
373 
374 
376  MAKE_STATEMENTS("SELECT @DB_FIELDS@ FROM tags "
377  "WHERE @ROLLBACK_COND@ "
378  "ORDER BY revision DESC;");
379  DEFERRED_INITS(database);
380 }
381 
382 
383 //------------------------------------------------------------------------------
384 
385 
387  if (database->schema_revision() < 3)
388  DeferredInit(database->sqlite_db(), "SELECT '', NULL, 0;");
389  else
390  DeferredInit(database->sqlite_db(),
391  "SELECT branch, parent, initial_revision FROM branches;");
392 }
393 
394 
396  std::string branch = RetrieveString(0);
397  std::string parent =
398  (RetrieveType(1) == SQLITE_NULL) ? "" : RetrieveString(1);
399  unsigned initial_revision = RetrieveInt64(2);
400  return History::Branch(branch, parent, initial_revision);
401 }
402 
403 
404 //------------------------------------------------------------------------------
405 
406 
408  DeferredInit(database->sqlite_db(),
409  "INSERT INTO branches (branch, parent, initial_revision) "
410  "VALUES (:branch, :parent, :initial_revision);");
411 }
412 
413 
415  return
416  BindText(1, branch.branch) &&
417  BindText(2, branch.parent) &&
418  BindInt64(3, branch.initial_revision);
419 }
420 
421 
422 //------------------------------------------------------------------------------
423 
424 
425 bool SqlRecycleBin::CheckSchema(const HistoryDatabase *database) const {
426  return (database->IsEqualSchema(database->schema_version(), 1.0)) &&
427  (database->schema_revision() >= 2);
428 }
429 
430 
431 //------------------------------------------------------------------------------
432 
433 
435  assert(CheckSchema(database));
436  DeferredInit(database->sqlite_db(), "SELECT hash, flags FROM recycle_bin;");
437 }
438 
439 
441  const unsigned int flags = RetrieveInt64(1);
443  if (flags & SqlRecycleBin::kFlagCatalog) {
444  suffix = shash::kSuffixCatalog;
445  }
446 
448 }
449 
450 
451 //------------------------------------------------------------------------------
452 
453 
455  assert(CheckSchema(database));
456  DeferredInit(database->sqlite_db(), "DELETE FROM recycle_bin;");
457 }
458 
459 
460 }; /* namespace history */
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
UpdateChannel channel
Definition: history.h:118
bool BindTimestamp(const time_t timestamp)
Definition: history_sql.cc:295
static const float kLatestSchema
Definition: history_sql.h:22
unsigned initial_revision
Definition: history.h:55
bool BindTextTransient(const int index, const std::string &value)
Definition: sql.h:387
bool Execute()
Definition: sql.cc:42
unsigned RetrieveCount() const
Definition: history_sql.cc:324
SqlFindTag(const HistoryDatabase *database)
Definition: history_sql.cc:270
bool BindText(const int index, const std::string &value)
Definition: sql.h:393
bool CheckSchema(const HistoryDatabase *database) const
Definition: history_sql.cc:425
static const float kLatestSupportedSchema
Definition: history_sql.h:23
std::string name
Definition: history.h:113
std::string ToString(const bool with_suffix=false) const
Definition: hash.h:245
SqlFindTagByDate(const HistoryDatabase *database)
Definition: history_sql.cc:283
bool read_write() const
Definition: sql.h:151
const history::History * history() const
shash::Any RetrieveHash() const
Definition: history_sql.cc:357
assert((mem||(size==0))&&"Out Of Memory")
SqlInsertTag(const HistoryDatabase *database)
Definition: history_sql.cc:236
float schema_version() const
Definition: sql.h:149
SqlCountTags(const HistoryDatabase *database)
Definition: history_sql.cc:320
SqlListRollbackTags(const HistoryDatabase *database)
Definition: history_sql.cc:375
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:303
bool InsertInitialValues(const std::string &repository_name)
Definition: history_sql.cc:87
std::string description
Definition: history.h:119
bool BindBranchName(const std::string &branch_name)
Definition: history_sql.cc:312
void DeferredInit(const sqlite3 *database, const char *statement)
Definition: sql.cc:158
SqlRecycleBinFlush(const HistoryDatabase *database)
Definition: history_sql.cc:454
std::string parent
Definition: history.h:54
static const float kSchemaEpsilon
Definition: sql.h:105
static const unsigned int kFlagCatalog
Definition: history_sql.h:244
bool BindName(const std::string &name)
Definition: history_sql.cc:275
const char kSuffixCatalog
Definition: hash.h:52
bool BindTag(const History::Tag &tag)
Definition: history_sql.cc:242
SqlListTags(const HistoryDatabase *database)
Definition: history_sql.cc:334
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:83
sqlite3_int64 RetrieveInt64(const int idx_column) const
Definition: sql.h:440
#define MAKE_STATEMENTS(STMT_TMPL)
Definition: history_sql.cc:218
sqlite3 * sqlite_db() const
Definition: sql.h:147
bool BindBranch(const History::Branch &branch)
Definition: history_sql.cc:414
SqlGetChannelTips(const HistoryDatabase *database)
Definition: history_sql.cc:344
bool BindInt64(const int index, const sqlite3_int64 value)
Definition: sql.h:377
bool SetProperty(const std::string &key, const T value)
Definition: sql_impl.h:323
SqlInsertBranch(const HistoryDatabase *database)
Definition: history_sql.cc:407
static const unsigned kLatestSchemaRevision
Definition: history_sql.h:25
char Suffix
Definition: hash.h:112
bool IsEqualSchema(const float value, const float compare) const
Definition: sql.h:131
SqlGetHashes(const HistoryDatabase *database)
Definition: history_sql.cc:352
std::string RetrieveString(const int idx_column) const
Definition: sql.h:446
static const std::string kFqrnKey
Definition: history_sql.h:27
bool BindName(const std::string &name)
Definition: history_sql.cc:262
int RetrieveType(const int idx_column) const
Definition: sql.h:416
shash::Any root_hash
Definition: history.h:114
std::string branch
Definition: history.h:123
SqlRemoveTag(const HistoryDatabase *database)
Definition: history_sql.cc:258
bool ContainsRecycleBin() const
Definition: history_sql.cc:93
#define DEFERRED_INITS(DB)
Definition: history_sql.cc:226
std::string branch
Definition: history.h:53
bool StoreSchemaRevision()
Definition: sql_impl.h:262
const char kSuffixNone
Definition: hash.h:51
History::Branch RetrieveBranch() const
Definition: history_sql.cc:395
SqlRecycleBinList(const HistoryDatabase *database)
Definition: history_sql.cc:434
SqlRollbackTag(const HistoryDatabase *database)
Definition: history_sql.cc:366
SqlListBranches(const HistoryDatabase *database)
Definition: history_sql.cc:386