GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/history_sqlite.cc
Date: 2026-10-04 02:40:33
Exec Total Coverage
Lines: 244 267 91.4%
Branches: 187 346 54.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "history_sqlite.h"
6
7 using namespace std; // NOLINT
8
9 namespace history {
10
11 const std::string SqliteHistory::kPreviousRevisionKey = "previous_revision";
12
13
14 187 SqliteHistory *SqliteHistory::Open(const std::string &file_name) {
15 187 const bool read_write = false;
16 187 return Open(file_name, read_write);
17 }
18
19
20 104 SqliteHistory *SqliteHistory::OpenWritable(const std::string &file_name) {
21 104 const bool read_write = true;
22 104 return Open(file_name, read_write);
23 }
24
25
26 291 SqliteHistory *SqliteHistory::Open(const std::string &file_name,
27 const bool read_write) {
28 291 SqliteHistory *history = new SqliteHistory();
29
3/6
✓ Branch 0 taken 291 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 291 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 291 times.
291 if (NULL == history || !history->OpenDatabase(file_name, read_write)) {
30 ✗ delete history;
31 ✗ return NULL;
32 }
33
34 582 LogCvmfs(kLogHistory, kLogDebug,
35 "opened history database '%s' for repository '%s' %s",
36 291 file_name.c_str(), history->fqrn().c_str(),
37
2/2
✓ Branch 1 taken 104 times.
✓ Branch 2 taken 187 times.
291 ((history->IsWritable()) ? "(writable)" : ""));
38
39 291 return history;
40 }
41
42
43 1116 SqliteHistory *SqliteHistory::Create(const std::string &file_name,
44 const std::string &fqrn) {
45 1116 SqliteHistory *history = new SqliteHistory();
46
3/6
✓ Branch 0 taken 1116 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1116 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1116 times.
1116 if (NULL == history || !history->CreateDatabase(file_name, fqrn)) {
47 ✗ delete history;
48 ✗ return NULL;
49 }
50
51 1116 LogCvmfs(kLogHistory, kLogDebug,
52 "created empty history database '%s' for"
53 "repository '%s'",
54 file_name.c_str(), fqrn.c_str());
55 1116 return history;
56 }
57
58
59 291 bool SqliteHistory::OpenDatabase(const std::string &file_name,
60 const bool read_write) {
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 291 times.
291 assert(database_.get() == nullptr);
62 291 const HistoryDatabase::OpenMode mode = (read_write)
63
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 187 times.
291 ? HistoryDatabase::kOpenReadWrite
64 : HistoryDatabase::kOpenReadOnly;
65 582 database_ = std::unique_ptr<HistoryDatabase>(
66 291 HistoryDatabase::Open(file_name, mode));
67
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 291 times.
291 if (database_.get() == nullptr) {
68 ✗ return false;
69 }
70
71
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 291 times.
291 if (!database_->HasProperty(HistoryDatabase::kFqrnKey)) {
72 ✗ LogCvmfs(kLogHistory, kLogDebug,
73 "opened history database does not provide "
74 "an FQRN under '%s'",
75 HistoryDatabase::kFqrnKey.c_str());
76 ✗ return false;
77 }
78
79
1/2
✓ Branch 3 taken 291 times.
✗ Branch 4 not taken.
291 set_fqrn(database_->GetProperty<std::string>(HistoryDatabase::kFqrnKey));
80 291 PrepareQueries();
81 291 return true;
82 }
83
84
85 1116 bool SqliteHistory::CreateDatabase(const std::string &file_name,
86 const std::string &repo_name) {
87
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1116 times.
1116 assert(database_.get() == nullptr);
88
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1116 times.
1116 assert(fqrn().empty());
89 1116 set_fqrn(repo_name);
90 2232 database_ = std::unique_ptr<HistoryDatabase>(
91 1116 HistoryDatabase::Create(file_name));
92 1116 if (database_.get() == nullptr
93
3/6
✓ Branch 0 taken 1116 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1116 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1116 times.
1116 || !database_->InsertInitialValues(repo_name)) {
94 ✗ LogCvmfs(kLogHistory, kLogDebug,
95 "failed to initialize empty database '%s', for repository '%s'",
96 file_name.c_str(), repo_name.c_str());
97 ✗ return false;
98 }
99
100 1116 PrepareQueries();
101 1116 return true;
102 }
103
104
105 1407 void SqliteHistory::PrepareQueries() {
106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1407 times.
1407 assert(database_.get() != nullptr);
107
108
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
1407 find_tag_ = std::unique_ptr<SqlFindTag>(new SqlFindTag(database_.get()));
109 2814 find_tag_by_date_ = std::unique_ptr<SqlFindTagByDate>(
110
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
2814 new SqlFindTagByDate(database_.get()));
111 2814 count_tags_ = std::unique_ptr<SqlCountTags>(
112
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
2814 new SqlCountTags(database_.get()));
113
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
1407 list_tags_ = std::unique_ptr<SqlListTags>(new SqlListTags(database_.get()));
114 2814 get_hashes_ = std::unique_ptr<SqlGetHashes>(
115
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
2814 new SqlGetHashes(database_.get()));
116 2814 list_rollback_tags_ = std::unique_ptr<SqlListRollbackTags>(
117
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
2814 new SqlListRollbackTags(database_.get()));
118 2814 list_branches_ = std::unique_ptr<SqlListBranches>(
119
1/2
✓ Branch 3 taken 1407 times.
✗ Branch 4 not taken.
2814 new SqlListBranches(database_.get()));
120
121
2/2
✓ Branch 2 taken 1381 times.
✓ Branch 3 taken 26 times.
1407 if (database_->ContainsRecycleBin()) {
122 2762 recycle_list_ = std::unique_ptr<SqlRecycleBinList>(
123
1/2
✓ Branch 3 taken 1381 times.
✗ Branch 4 not taken.
2762 new SqlRecycleBinList(database_.get()));
124 }
125
126
2/2
✓ Branch 1 taken 1220 times.
✓ Branch 2 taken 187 times.
1407 if (IsWritable()) {
127 2440 insert_tag_ = std::unique_ptr<SqlInsertTag>(
128
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlInsertTag(database_.get()));
129 2440 remove_tag_ = std::unique_ptr<SqlRemoveTag>(
130
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlRemoveTag(database_.get()));
131 2440 rollback_tag_ = std::unique_ptr<SqlRollbackTag>(
132
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlRollbackTag(database_.get()));
133 2440 recycle_empty_ = std::unique_ptr<SqlRecycleBinFlush>(
134
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlRecycleBinFlush(database_.get()));
135 2440 insert_branch_ = std::unique_ptr<SqlInsertBranch>(
136
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlInsertBranch(database_.get()));
137 2440 find_branch_head_ = std::unique_ptr<SqlFindBranchHead>(
138
1/2
✓ Branch 3 taken 1220 times.
✗ Branch 4 not taken.
2440 new SqlFindBranchHead(database_.get()));
139 }
140 1407 }
141
142
143 286 bool SqliteHistory::BeginTransaction() const {
144 286 return database_->BeginTransaction();
145 }
146
147
148 234 bool SqliteHistory::CommitTransaction() const {
149 234 return database_->CommitTransaction();
150 }
151
152
153 320 bool SqliteHistory::SetPreviousRevision(const shash::Any &history_hash) {
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 320 times.
320 assert(database_.get() != nullptr);
155
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 320 times.
320 assert(IsWritable());
156
1/2
✓ Branch 3 taken 320 times.
✗ Branch 4 not taken.
320 return database_->SetProperty(kPreviousRevisionKey, history_hash.ToString());
157 }
158
159
160 48 shash::Any SqliteHistory::previous_revision() const {
161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
48 assert(database_.get() != nullptr);
162 48 const std::string hash_str = database_->GetProperty<std::string>(
163
1/2
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
48 kPreviousRevisionKey);
164
1/2
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
96 return shash::MkFromHexPtr(shash::HexPtr(hash_str), shash::kSuffixHistory);
165 48 }
166
167
168 2109 bool SqliteHistory::IsWritable() const {
169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2109 times.
2109 assert(database_.get() != nullptr);
170 2109 return database_->read_write();
171 }
172
173 377 unsigned SqliteHistory::GetNumberOfTags() const {
174
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 377 times.
377 assert(database_.get() != nullptr);
175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 377 times.
377 assert(count_tags_.get() != nullptr);
176 377 bool retval = count_tags_->FetchRow();
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 377 times.
377 assert(retval);
178 377 const unsigned count = count_tags_->RetrieveCount();
179 377 retval = count_tags_->Reset();
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 377 times.
377 assert(retval);
181 377 return count;
182 }
183
184
185 55487 bool SqliteHistory::Insert(const History::Tag &tag) {
186
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 55487 times.
55487 assert(database_.get() != nullptr);
187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 55487 times.
55487 assert(insert_tag_.get() != nullptr);
188
189
2/2
✓ Branch 4 taken 55461 times.
✓ Branch 5 taken 26 times.
110974 return insert_tag_->BindTag(tag) && insert_tag_->Execute()
190
2/4
✓ Branch 0 taken 55487 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 55461 times.
✗ Branch 5 not taken.
110974 && insert_tag_->Reset();
191 }
192
193
194 169 bool SqliteHistory::Remove(const std::string &name) {
195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
169 assert(database_.get() != nullptr);
196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
169 assert(remove_tag_.get() != nullptr);
197
198
1/2
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
169 Tag condemned_tag;
199
3/4
✓ Branch 1 taken 169 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 156 times.
169 if (!GetByName(name, &condemned_tag)) {
200 13 return true;
201 }
202
203
3/8
✓ Branch 2 taken 156 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 156 times.
✗ Branch 9 not taken.
312 return remove_tag_->BindName(name) && remove_tag_->Execute()
204
3/6
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 156 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 156 times.
✗ Branch 7 not taken.
312 && remove_tag_->Reset();
205 169 }
206
207
208 299 bool SqliteHistory::Exists(const std::string &name) const {
209
1/2
✓ Branch 1 taken 299 times.
✗ Branch 2 not taken.
299 Tag existing_tag;
210
1/2
✓ Branch 1 taken 299 times.
✗ Branch 2 not taken.
598 return GetByName(name, &existing_tag);
211 299 }
212
213
214 762 bool SqliteHistory::GetByName(const std::string &name, Tag *tag) const {
215
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 762 times.
762 assert(database_.get() != nullptr);
216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 762 times.
762 assert(find_tag_.get() != nullptr);
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 762 times.
762 assert(NULL != tag);
218
219
5/6
✓ Branch 2 taken 762 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 160 times.
✓ Branch 7 taken 602 times.
✓ Branch 8 taken 160 times.
✓ Branch 9 taken 602 times.
762 if (!find_tag_->BindName(name) || !find_tag_->FetchRow()) {
220 160 find_tag_->Reset();
221 160 return false;
222 }
223
224 602 *tag = find_tag_->RetrieveTag();
225 602 return find_tag_->Reset();
226 }
227
228
229 60 bool SqliteHistory::GetByDate(const time_t timestamp, Tag *tag) const {
230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
60 assert(database_.get() != nullptr);
231
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
60 assert(find_tag_by_date_.get() != nullptr);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 assert(NULL != tag);
233
234 60 if (!find_tag_by_date_->BindTimestamp(timestamp)
235
5/6
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 17 times.
✓ Branch 7 taken 43 times.
60 || !find_tag_by_date_->FetchRow()) {
236 17 find_tag_by_date_->Reset();
237 17 return false;
238 }
239
240 43 *tag = find_tag_by_date_->RetrieveTag();
241 43 return find_tag_by_date_->Reset();
242 }
243
244
245 104 bool SqliteHistory::List(std::vector<Tag> *tags) const {
246
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 104 times.
104 assert(list_tags_.get() != nullptr);
247 104 return RunListing(tags, list_tags_.get());
248 }
249
250
251 template<class SqlListingT>
252 286 bool SqliteHistory::RunListing(std::vector<Tag> *list, SqlListingT *sql) const {
253
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
286 assert(database_.get() != nullptr);
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
286 assert(NULL != list);
255
256
2/2
✓ Branch 1 taken 15223 times.
✓ Branch 2 taken 143 times.
30732 while (sql->FetchRow()) {
257
1/2
✓ Branch 2 taken 15223 times.
✗ Branch 3 not taken.
30446 list->push_back(sql->RetrieveTag());
258 }
259
260 286 return sql->Reset();
261 }
262
263
264 39 bool SqliteHistory::GetBranchHead(const string &branch_name, Tag *tag) const {
265
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 assert(database_.get() != nullptr);
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 assert(find_branch_head_.get() != nullptr);
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 assert(tag != NULL);
268
269 39 if (!find_branch_head_->BindBranchName(branch_name)
270
5/6
✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 26 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 26 times.
39 || !find_branch_head_->FetchRow()) {
271 13 find_branch_head_->Reset();
272 13 return false;
273 }
274
275 26 *tag = find_branch_head_->RetrieveTag();
276 26 return find_branch_head_->Reset();
277 }
278
279
280 39 bool SqliteHistory::ExistsBranch(const string &branch_name) const {
281 39 vector<Branch> branches;
282
2/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
39 if (!ListBranches(&branches))
283 ✗ return false;
284
2/2
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 13 times.
104 for (unsigned i = 0; i < branches.size(); ++i) {
285
2/2
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 65 times.
91 if (branches[i].branch == branch_name)
286 26 return true;
287 }
288 13 return false;
289 39 }
290
291
292 234 bool SqliteHistory::InsertBranch(const Branch &branch) {
293
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
234 assert(database_.get() != nullptr);
294
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 234 times.
234 assert(insert_branch_.get() != nullptr);
295
296
2/2
✓ Branch 4 taken 208 times.
✓ Branch 5 taken 13 times.
455 return insert_branch_->BindBranch(branch) && insert_branch_->Execute()
297
3/4
✓ Branch 0 taken 221 times.
✓ Branch 1 taken 13 times.
✓ Branch 4 taken 208 times.
✗ Branch 5 not taken.
455 && insert_branch_->Reset();
298 }
299
300
301 13 bool SqliteHistory::PruneBranches() {
302 // Parent pointers might point to abandoned branches. Redirect them to the
303 // parent of the abandoned branch. This has to be repeated until the fix
304 // point is reached. It always works because we never delete the root branch
305 sqlite::Sql sql_fix_parent_pointers(
306 13 database_->sqlite_db(),
307 "INSERT OR REPLACE INTO branches (branch, parent, initial_revision) "
308 "SELECT branches.branch, abandoned_parent, branches.initial_revision "
309 " FROM branches "
310 " INNER JOIN (SELECT DISTINCT branches.branch AS abandoned_branch, "
311 " branches.parent AS abandoned_parent FROM branches "
312 " LEFT OUTER JOIN tags ON (branches.branch=tags.branch)"
313 " WHERE tags.branch IS NULL) "
314
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
39 " ON (branches.parent=abandoned_branch);");
315 // Detect if fix point is reached
316 sqlite::Sql sql_remaining_rows(
317 13 database_->sqlite_db(),
318 "SELECT count(*) FROM branches "
319 "INNER JOIN "
320 " (SELECT DISTINCT branches.branch AS abandoned_branch FROM branches "
321 " LEFT OUTER JOIN tags ON (branches.branch=tags.branch) "
322 " WHERE tags.branch IS NULL) "
323
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
39 "ON (branches.parent=abandoned_branch);");
324
325 bool retval;
326 do {
327
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 retval = sql_remaining_rows.FetchRow();
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 if (!retval)
329 ✗ return false;
330
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const int64_t count = sql_remaining_rows.RetrieveInt64(0);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 39 times.
39 assert(count >= 0);
332
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (count == 0)
333 13 break;
334
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 retval = sql_remaining_rows.Reset();
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 assert(retval);
336
337
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 retval = sql_fix_parent_pointers.Execute();
338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!retval)
339 ✗ return false;
340
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 retval = sql_fix_parent_pointers.Reset();
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 assert(retval);
342 26 } while (true);
343
344 sqlite::Sql sql_remove_branches(
345 13 database_->sqlite_db(),
346 "DELETE FROM branches "
347
3/6
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 13 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 13 times.
✗ Branch 9 not taken.
39 "WHERE branch NOT IN (SELECT DISTINCT branch FROM tags);");
348
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 retval = sql_remove_branches.Execute();
349 13 return retval;
350 13 }
351
352
353 130 bool SqliteHistory::ListBranches(vector<Branch> *branches) const {
354
2/2
✓ Branch 2 taken 351 times.
✓ Branch 3 taken 130 times.
481 while (list_branches_->FetchRow()) {
355
1/2
✓ Branch 3 taken 351 times.
✗ Branch 4 not taken.
351 branches->push_back(list_branches_->RetrieveBranch());
356 }
357
358 130 return list_branches_->Reset();
359 }
360
361
362 169 bool SqliteHistory::ListRecycleBin(std::vector<shash::Any> *hashes) const {
363
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
169 assert(database_.get() != nullptr);
364
365
2/2
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 143 times.
169 if (!database_->ContainsRecycleBin()) {
366 26 return false;
367 }
368
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 assert(NULL != hashes);
370 143 hashes->clear();
371
2/2
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 143 times.
156 while (recycle_list_->FetchRow()) {
372
1/2
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
13 hashes->push_back(recycle_list_->RetrieveHash());
373 }
374
375 143 return recycle_list_->Reset();
376 }
377
378
379 52 bool SqliteHistory::EmptyRecycleBin() {
380
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
52 assert(database_.get() != nullptr);
381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
52 assert(IsWritable());
382
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
52 assert(recycle_empty_.get() != nullptr);
383
2/4
✓ Branch 2 taken 52 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 52 times.
✗ Branch 7 not taken.
52 return recycle_empty_->Execute() && recycle_empty_->Reset();
384 }
385
386
387 39 bool SqliteHistory::Rollback(const Tag &updated_target_tag) {
388
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 assert(database_.get() != nullptr);
389
2/4
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
39 assert(IsWritable());
390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
39 assert(rollback_tag_.get() != nullptr);
391
392
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 Tag old_target_tag;
393 39 bool success = false;
394
395 // open a transaction (if non open yet)
396
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 const bool need_to_commit = BeginTransaction();
397
398 // retrieve the old version of the target tag from the history
399
1/2
✓ Branch 1 taken 39 times.
✗ Branch 2 not taken.
39 success = GetByName(updated_target_tag.name, &old_target_tag);
400
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 26 times.
39 if (!success) {
401
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve old target tag '%s'",
402 updated_target_tag.name.c_str());
403 13 return false;
404 }
405
406 // sanity checks
407
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 assert(old_target_tag.description == updated_target_tag.description);
408
409 // rollback the history to the target tag
410 // (essentially removing all intermediate tags + the old target tag)
411
1/2
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
26 success = rollback_tag_->BindTargetTag(old_target_tag)
412
5/12
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 26 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 26 times.
✗ Branch 13 not taken.
26 && rollback_tag_->Execute() && rollback_tag_->Reset();
413
4/8
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
26 if (!success || Exists(old_target_tag.name)) {
414 ✗ LogCvmfs(kLogHistory, kLogDebug,
415 "failed to remove intermediate tags "
416 "until '%s' - '%" PRIu64 "'",
417 old_target_tag.name.c_str(), old_target_tag.revision);
418 ✗ return false;
419 }
420
421 // insert the provided updated target tag into the history concluding the
422 // rollback operation
423
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 success = Insert(updated_target_tag);
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!success) {
425 ✗ LogCvmfs(kLogHistory, kLogDebug, "failed to insert updated target tag '%s'",
426 updated_target_tag.name.c_str());
427 ✗ return false;
428 }
429
430
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (need_to_commit) {
431 ✗ success = CommitTransaction();
432 ✗ assert(success);
433 }
434
435 26 return true;
436 39 }
437
438
439 52 bool SqliteHistory::ListTagsAffectedByRollback(
440 const std::string &target_tag_name, std::vector<Tag> *tags) const {
441 // retrieve the old version of the target tag from the history
442
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
52 Tag target_tag;
443
3/4
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 39 times.
52 if (!GetByName(target_tag_name, &target_tag)) {
444
1/2
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
13 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve target tag '%s'",
445 target_tag_name.c_str());
446 13 return false;
447 }
448
449 // prepage listing command to find affected tags for a potential rollback
450
2/4
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 39 times.
39 if (!list_rollback_tags_->BindTargetTag(target_tag)) {
451 ✗ LogCvmfs(kLogHistory, kLogDebug,
452 "failed to prepare rollback listing query");
453 ✗ return false;
454 }
455
456 // run the listing and return the results
457
1/2
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
39 return RunListing(tags, list_rollback_tags_.get());
458 52 }
459
460
461 26 bool SqliteHistory::GetHashes(std::vector<shash::Any> *hashes) const {
462
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 assert(database_.get() != nullptr);
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 assert(NULL != hashes);
464
465
2/2
✓ Branch 2 taken 26013 times.
✓ Branch 3 taken 26 times.
26039 while (get_hashes_->FetchRow()) {
466
1/2
✓ Branch 3 taken 26013 times.
✗ Branch 4 not taken.
26013 hashes->push_back(get_hashes_->RetrieveHash());
467 }
468
469 26 return get_hashes_->Reset();
470 }
471
472
473 80 void SqliteHistory::TakeDatabaseFileOwnership() {
474
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
80 assert(database_.get() != nullptr);
475 80 database_->TakeFileOwnership();
476 80 }
477
478
479 ✗ void SqliteHistory::DropDatabaseFileOwnership() {
480 ✗ assert(database_.get() != nullptr);
481 ✗ database_->DropFileOwnership();
482 }
483
484 } // namespace history
485