GCC Code Coverage Report


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