GCC Code Coverage Report


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