GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/history_sqlite.cc
Date: 2026-09-20 02:39:58
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 915 SqliteHistory *SqliteHistory::Open(const std::string &file_name) {
15 915 const bool read_write = false;
16 915 return Open(file_name, read_write);
17 }
18
19
20 328 SqliteHistory *SqliteHistory::OpenWritable(const std::string &file_name) {
21 328 const bool read_write = true;
22 328 return Open(file_name, read_write);
23 }
24
25
26 1243 SqliteHistory *SqliteHistory::Open(const std::string &file_name,
27 const bool read_write) {
28 1243 SqliteHistory *history = new SqliteHistory();
29
3/6
✓ Branch 0 taken 1243 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1243 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1243 times.
1243 if (NULL == history || !history->OpenDatabase(file_name, read_write)) {
30 delete history;
31 return NULL;
32 }
33
34 2486 LogCvmfs(kLogHistory, kLogDebug,
35 "opened history database '%s' for repository '%s' %s",
36 1243 file_name.c_str(), history->fqrn().c_str(),
37
2/2
✓ Branch 1 taken 328 times.
✓ Branch 2 taken 915 times.
1243 ((history->IsWritable()) ? "(writable)" : ""));
38
39 1243 return history;
40 }
41
42
43 3659 SqliteHistory *SqliteHistory::Create(const std::string &file_name,
44 const std::string &fqrn) {
45 3659 SqliteHistory *history = new SqliteHistory();
46
3/6
✓ Branch 0 taken 3659 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3659 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3659 times.
3659 if (NULL == history || !history->CreateDatabase(file_name, fqrn)) {
47 delete history;
48 return NULL;
49 }
50
51 3659 LogCvmfs(kLogHistory, kLogDebug,
52 "created empty history database '%s' for"
53 "repository '%s'",
54 file_name.c_str(), fqrn.c_str());
55 3659 return history;
56 }
57
58
59 1243 bool SqliteHistory::OpenDatabase(const std::string &file_name,
60 const bool read_write) {
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1243 times.
1243 assert(database_.get() == nullptr);
62 1243 const HistoryDatabase::OpenMode mode = (read_write)
63
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 915 times.
1243 ? HistoryDatabase::kOpenReadWrite
64 : HistoryDatabase::kOpenReadOnly;
65 2486 database_ = std::unique_ptr<HistoryDatabase>(
66 1243 HistoryDatabase::Open(file_name, mode));
67
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1243 times.
1243 if (database_.get() == nullptr) {
68 return false;
69 }
70
71
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 1243 times.
1243 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 1243 times.
✗ Branch 4 not taken.
1243 set_fqrn(database_->GetProperty<std::string>(HistoryDatabase::kFqrnKey));
80 1243 PrepareQueries();
81 1243 return true;
82 }
83
84
85 3659 bool SqliteHistory::CreateDatabase(const std::string &file_name,
86 const std::string &repo_name) {
87
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3659 times.
3659 assert(database_.get() == nullptr);
88
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3659 times.
3659 assert(fqrn().empty());
89 3659 set_fqrn(repo_name);
90 7318 database_ = std::unique_ptr<HistoryDatabase>(
91 3659 HistoryDatabase::Create(file_name));
92 3659 if (database_.get() == nullptr
93
3/6
✓ Branch 0 taken 3659 times.
✗ Branch 1 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3659 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3659 times.
3659 || !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 3659 PrepareQueries();
101 3659 return true;
102 }
103
104
105 4902 void SqliteHistory::PrepareQueries() {
106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4902 times.
4902 assert(database_.get() != nullptr);
107
108
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
4902 find_tag_ = std::unique_ptr<SqlFindTag>(new SqlFindTag(database_.get()));
109 9804 find_tag_by_date_ = std::unique_ptr<SqlFindTagByDate>(
110
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
9804 new SqlFindTagByDate(database_.get()));
111 9804 count_tags_ = std::unique_ptr<SqlCountTags>(
112
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
9804 new SqlCountTags(database_.get()));
113
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
4902 list_tags_ = std::unique_ptr<SqlListTags>(new SqlListTags(database_.get()));
114 9804 get_hashes_ = std::unique_ptr<SqlGetHashes>(
115
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
9804 new SqlGetHashes(database_.get()));
116 9804 list_rollback_tags_ = std::unique_ptr<SqlListRollbackTags>(
117
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
9804 new SqlListRollbackTags(database_.get()));
118 9804 list_branches_ = std::unique_ptr<SqlListBranches>(
119
1/2
✓ Branch 3 taken 4902 times.
✗ Branch 4 not taken.
9804 new SqlListBranches(database_.get()));
120
121
2/2
✓ Branch 2 taken 4820 times.
✓ Branch 3 taken 82 times.
4902 if (database_->ContainsRecycleBin()) {
122 9640 recycle_list_ = std::unique_ptr<SqlRecycleBinList>(
123
1/2
✓ Branch 3 taken 4820 times.
✗ Branch 4 not taken.
9640 new SqlRecycleBinList(database_.get()));
124 }
125
126
2/2
✓ Branch 1 taken 3987 times.
✓ Branch 2 taken 915 times.
4902 if (IsWritable()) {
127 7974 insert_tag_ = std::unique_ptr<SqlInsertTag>(
128
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlInsertTag(database_.get()));
129 7974 remove_tag_ = std::unique_ptr<SqlRemoveTag>(
130
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlRemoveTag(database_.get()));
131 7974 rollback_tag_ = std::unique_ptr<SqlRollbackTag>(
132
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlRollbackTag(database_.get()));
133 7974 recycle_empty_ = std::unique_ptr<SqlRecycleBinFlush>(
134
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlRecycleBinFlush(database_.get()));
135 7974 insert_branch_ = std::unique_ptr<SqlInsertBranch>(
136
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlInsertBranch(database_.get()));
137 7974 find_branch_head_ = std::unique_ptr<SqlFindBranchHead>(
138
1/2
✓ Branch 3 taken 3987 times.
✗ Branch 4 not taken.
7974 new SqlFindBranchHead(database_.get()));
139 }
140 4902 }
141
142
143 902 bool SqliteHistory::BeginTransaction() const {
144 902 return database_->BeginTransaction();
145 }
146
147
148 738 bool SqliteHistory::CommitTransaction() const {
149 738 return database_->CommitTransaction();
150 }
151
152
153 1760 bool SqliteHistory::SetPreviousRevision(const shash::Any &history_hash) {
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1760 times.
1760 assert(database_.get() != nullptr);
155
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1760 times.
1760 assert(IsWritable());
156
1/2
✓ Branch 3 taken 1760 times.
✗ Branch 4 not taken.
1760 return database_->SetProperty(kPreviousRevisionKey, history_hash.ToString());
157 }
158
159
160 264 shash::Any SqliteHistory::previous_revision() const {
161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 264 times.
264 assert(database_.get() != nullptr);
162 264 const std::string hash_str = database_->GetProperty<std::string>(
163
1/2
✓ Branch 1 taken 264 times.
✗ Branch 2 not taken.
264 kPreviousRevisionKey);
164
1/2
✓ Branch 2 taken 264 times.
✗ Branch 3 not taken.
528 return shash::MkFromHexPtr(shash::HexPtr(hash_str), shash::kSuffixHistory);
165 264 }
166
167
168 8192 bool SqliteHistory::IsWritable() const {
169
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8192 times.
8192 assert(database_.get() != nullptr);
170 8192 return database_->read_write();
171 }
172
173 1189 unsigned SqliteHistory::GetNumberOfTags() const {
174
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1189 times.
1189 assert(database_.get() != nullptr);
175
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1189 times.
1189 assert(count_tags_.get() != nullptr);
176 1189 bool retval = count_tags_->FetchRow();
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1189 times.
1189 assert(retval);
178 1189 const unsigned count = count_tags_->RetrieveCount();
179 1189 retval = count_tags_->Reset();
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1189 times.
1189 assert(retval);
181 1189 return count;
182 }
183
184
185 174386 bool SqliteHistory::Insert(const History::Tag &tag) {
186
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174386 times.
174386 assert(database_.get() != nullptr);
187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 174386 times.
174386 assert(insert_tag_.get() != nullptr);
188
189
2/2
✓ Branch 4 taken 174304 times.
✓ Branch 5 taken 82 times.
348772 return insert_tag_->BindTag(tag) && insert_tag_->Execute()
190
2/4
✓ Branch 0 taken 174386 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 174304 times.
✗ Branch 5 not taken.
348772 && insert_tag_->Reset();
191 }
192
193
194 533 bool SqliteHistory::Remove(const std::string &name) {
195
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 533 times.
533 assert(database_.get() != nullptr);
196
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 533 times.
533 assert(remove_tag_.get() != nullptr);
197
198
1/2
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
533 Tag condemned_tag;
199
3/4
✓ Branch 1 taken 533 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 492 times.
533 if (!GetByName(name, &condemned_tag)) {
200 41 return true;
201 }
202
203
3/8
✓ Branch 2 taken 492 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 492 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 492 times.
✗ Branch 9 not taken.
984 return remove_tag_->BindName(name) && remove_tag_->Execute()
204
3/6
✓ Branch 0 taken 492 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 492 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 492 times.
✗ Branch 7 not taken.
984 && remove_tag_->Reset();
205 533 }
206
207
208 943 bool SqliteHistory::Exists(const std::string &name) const {
209
1/2
✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
943 Tag existing_tag;
210
1/2
✓ Branch 1 taken 943 times.
✗ Branch 2 not taken.
1886 return GetByName(name, &existing_tag);
211 943 }
212
213
214 2472 bool SqliteHistory::GetByName(const std::string &name, Tag *tag) const {
215
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2472 times.
2472 assert(database_.get() != nullptr);
216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2472 times.
2472 assert(find_tag_.get() != nullptr);
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2472 times.
2472 assert(NULL != tag);
218
219
5/6
✓ Branch 2 taken 2472 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 539 times.
✓ Branch 7 taken 1933 times.
✓ Branch 8 taken 539 times.
✓ Branch 9 taken 1933 times.
2472 if (!find_tag_->BindName(name) || !find_tag_->FetchRow()) {
220 539 find_tag_->Reset();
221 539 return false;
222 }
223
224 1933 *tag = find_tag_->RetrieveTag();
225 1933 return find_tag_->Reset();
226 }
227
228
229 258 bool SqliteHistory::GetByDate(const time_t timestamp, Tag *tag) const {
230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 258 times.
258 assert(database_.get() != nullptr);
231
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 258 times.
258 assert(find_tag_by_date_.get() != nullptr);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 258 times.
258 assert(NULL != tag);
233
234 258 if (!find_tag_by_date_->BindTimestamp(timestamp)
235
5/6
✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 88 times.
✓ Branch 5 taken 170 times.
✓ Branch 6 taken 88 times.
✓ Branch 7 taken 170 times.
258 || !find_tag_by_date_->FetchRow()) {
236 88 find_tag_by_date_->Reset();
237 88 return false;
238 }
239
240 170 *tag = find_tag_by_date_->RetrieveTag();
241 170 return find_tag_by_date_->Reset();
242 }
243
244
245 328 bool SqliteHistory::List(std::vector<Tag> *tags) const {
246
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 328 times.
328 assert(list_tags_.get() != nullptr);
247 328 return RunListing(tags, list_tags_.get());
248 }
249
250
251 template<class SqlListingT>
252 902 bool SqliteHistory::RunListing(std::vector<Tag> *list, SqlListingT *sql) const {
253
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 451 times.
902 assert(database_.get() != nullptr);
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 451 times.
902 assert(NULL != list);
255
256
2/2
✓ Branch 1 taken 48011 times.
✓ Branch 2 taken 451 times.
96924 while (sql->FetchRow()) {
257
1/2
✓ Branch 2 taken 48011 times.
✗ Branch 3 not taken.
96022 list->push_back(sql->RetrieveTag());
258 }
259
260 902 return sql->Reset();
261 }
262
263
264 123 bool SqliteHistory::GetBranchHead(const string &branch_name, Tag *tag) const {
265
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 assert(database_.get() != nullptr);
266
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 assert(find_branch_head_.get() != nullptr);
267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 assert(tag != NULL);
268
269 123 if (!find_branch_head_->BindBranchName(branch_name)
270
5/6
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 82 times.
✓ Branch 6 taken 41 times.
✓ Branch 7 taken 82 times.
123 || !find_branch_head_->FetchRow()) {
271 41 find_branch_head_->Reset();
272 41 return false;
273 }
274
275 82 *tag = find_branch_head_->RetrieveTag();
276 82 return find_branch_head_->Reset();
277 }
278
279
280 123 bool SqliteHistory::ExistsBranch(const string &branch_name) const {
281 123 vector<Branch> branches;
282
2/4
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 123 times.
123 if (!ListBranches(&branches))
283 return false;
284
2/2
✓ Branch 1 taken 287 times.
✓ Branch 2 taken 41 times.
328 for (unsigned i = 0; i < branches.size(); ++i) {
285
2/2
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 205 times.
287 if (branches[i].branch == branch_name)
286 82 return true;
287 }
288 41 return false;
289 123 }
290
291
292 738 bool SqliteHistory::InsertBranch(const Branch &branch) {
293
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738 times.
738 assert(database_.get() != nullptr);
294
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 738 times.
738 assert(insert_branch_.get() != nullptr);
295
296
2/2
✓ Branch 4 taken 656 times.
✓ Branch 5 taken 41 times.
1435 return insert_branch_->BindBranch(branch) && insert_branch_->Execute()
297
3/4
✓ Branch 0 taken 697 times.
✓ Branch 1 taken 41 times.
✓ Branch 4 taken 656 times.
✗ Branch 5 not taken.
1435 && insert_branch_->Reset();
298 }
299
300
301 41 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 41 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 41 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 41 times.
✗ Branch 9 not taken.
123 " ON (branches.parent=abandoned_branch);");
315 // Detect if fix point is reached
316 sqlite::Sql sql_remaining_rows(
317 41 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 41 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 41 times.
✗ Branch 9 not taken.
123 "ON (branches.parent=abandoned_branch);");
324
325 bool retval;
326 do {
327
1/2
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
123 retval = sql_remaining_rows.FetchRow();
328
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 if (!retval)
329 return false;
330
1/2
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
123 const int64_t count = sql_remaining_rows.RetrieveInt64(0);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
123 assert(count >= 0);
332
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 82 times.
123 if (count == 0)
333 41 break;
334
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 retval = sql_remaining_rows.Reset();
335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 assert(retval);
336
337
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 retval = sql_fix_parent_pointers.Execute();
338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (!retval)
339 return false;
340
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 retval = sql_fix_parent_pointers.Reset();
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 assert(retval);
342 82 } while (true);
343
344 sqlite::Sql sql_remove_branches(
345 41 database_->sqlite_db(),
346 "DELETE FROM branches "
347
3/6
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 41 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 41 times.
✗ Branch 9 not taken.
123 "WHERE branch NOT IN (SELECT DISTINCT branch FROM tags);");
348
1/2
✓ Branch 1 taken 41 times.
✗ Branch 2 not taken.
41 retval = sql_remove_branches.Execute();
349 41 return retval;
350 41 }
351
352
353 410 bool SqliteHistory::ListBranches(vector<Branch> *branches) const {
354
2/2
✓ Branch 2 taken 1107 times.
✓ Branch 3 taken 410 times.
1517 while (list_branches_->FetchRow()) {
355
1/2
✓ Branch 3 taken 1107 times.
✗ Branch 4 not taken.
1107 branches->push_back(list_branches_->RetrieveBranch());
356 }
357
358 410 return list_branches_->Reset();
359 }
360
361
362 533 bool SqliteHistory::ListRecycleBin(std::vector<shash::Any> *hashes) const {
363
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 533 times.
533 assert(database_.get() != nullptr);
364
365
2/2
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 451 times.
533 if (!database_->ContainsRecycleBin()) {
366 82 return false;
367 }
368
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 451 times.
451 assert(NULL != hashes);
370 451 hashes->clear();
371
2/2
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 451 times.
492 while (recycle_list_->FetchRow()) {
372
1/2
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
41 hashes->push_back(recycle_list_->RetrieveHash());
373 }
374
375 451 return recycle_list_->Reset();
376 }
377
378
379 164 bool SqliteHistory::EmptyRecycleBin() {
380
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
164 assert(database_.get() != nullptr);
381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
164 assert(IsWritable());
382
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164 times.
164 assert(recycle_empty_.get() != nullptr);
383
2/4
✓ Branch 2 taken 164 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 164 times.
✗ Branch 7 not taken.
164 return recycle_empty_->Execute() && recycle_empty_->Reset();
384 }
385
386
387 123 bool SqliteHistory::Rollback(const Tag &updated_target_tag) {
388
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 assert(database_.get() != nullptr);
389
2/4
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 123 times.
123 assert(IsWritable());
390
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 123 times.
123 assert(rollback_tag_.get() != nullptr);
391
392
1/2
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
123 Tag old_target_tag;
393 123 bool success = false;
394
395 // open a transaction (if non open yet)
396
1/2
✓ Branch 1 taken 123 times.
✗ Branch 2 not taken.
123 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 123 times.
✗ Branch 2 not taken.
123 success = GetByName(updated_target_tag.name, &old_target_tag);
400
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 82 times.
123 if (!success) {
401
1/2
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
41 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve old target tag '%s'",
402 updated_target_tag.name.c_str());
403 41 return false;
404 }
405
406 // sanity checks
407
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
82 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 82 times.
✗ Branch 3 not taken.
82 success = rollback_tag_->BindTargetTag(old_target_tag)
412
5/12
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 82 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 82 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 82 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 82 times.
✗ Branch 13 not taken.
82 && rollback_tag_->Execute() && rollback_tag_->Reset();
413
4/8
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 82 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 82 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 82 times.
82 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 82 times.
✗ Branch 2 not taken.
82 success = Insert(updated_target_tag);
424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 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 82 times.
82 if (need_to_commit) {
431 success = CommitTransaction();
432 assert(success);
433 }
434
435 82 return true;
436 123 }
437
438
439 164 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 164 times.
✗ Branch 2 not taken.
164 Tag target_tag;
443
3/4
✓ Branch 1 taken 164 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 123 times.
164 if (!GetByName(target_tag_name, &target_tag)) {
444
1/2
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
41 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve target tag '%s'",
445 target_tag_name.c_str());
446 41 return false;
447 }
448
449 // prepage listing command to find affected tags for a potential rollback
450
2/4
✓ Branch 2 taken 123 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 123 times.
123 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 123 times.
✗ Branch 3 not taken.
123 return RunListing(tags, list_rollback_tags_.get());
458 164 }
459
460
461 82 bool SqliteHistory::GetHashes(std::vector<shash::Any> *hashes) const {
462
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
82 assert(database_.get() != nullptr);
463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 assert(NULL != hashes);
464
465
2/2
✓ Branch 2 taken 82041 times.
✓ Branch 3 taken 82 times.
82123 while (get_hashes_->FetchRow()) {
466
1/2
✓ Branch 3 taken 82041 times.
✗ Branch 4 not taken.
82041 hashes->push_back(get_hashes_->RetrieveHash());
467 }
468
469 82 return get_hashes_->Reset();
470 }
471
472
473 440 void SqliteHistory::TakeDatabaseFileOwnership() {
474
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 440 times.
440 assert(database_.get() != nullptr);
475 440 database_->TakeFileOwnership();
476 440 }
477
478
479 void SqliteHistory::DropDatabaseFileOwnership() {
480 assert(database_.get() != nullptr);
481 database_->DropFileOwnership();
482 }
483
484 } // namespace history
485