GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/history_sqlite.cc
Date: 2025-09-28 02:35:26
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 480 SqliteHistory *SqliteHistory::Open(const std::string &file_name) {
15 480 const bool read_write = false;
16 480 return Open(file_name, read_write);
17 }
18
19
20 392 SqliteHistory *SqliteHistory::OpenWritable(const std::string &file_name) {
21 392 const bool read_write = true;
22 392 return Open(file_name, read_write);
23 }
24
25
26 872 SqliteHistory *SqliteHistory::Open(const std::string &file_name,
27 const bool read_write) {
28
1/2
✓ Branch 2 taken 872 times.
✗ Branch 3 not taken.
872 SqliteHistory *history = new SqliteHistory();
29
3/6
✓ Branch 0 taken 872 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 872 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 872 times.
872 if (NULL == history || !history->OpenDatabase(file_name, read_write)) {
30 delete history;
31 return NULL;
32 }
33
34 1744 LogCvmfs(kLogHistory, kLogDebug,
35 "opened history database '%s' for repository '%s' %s",
36 872 file_name.c_str(), history->fqrn().c_str(),
37
2/2
✓ Branch 1 taken 392 times.
✓ Branch 2 taken 480 times.
872 ((history->IsWritable()) ? "(writable)" : ""));
38
39 872 return history;
40 }
41
42
43 2061 SqliteHistory *SqliteHistory::Create(const std::string &file_name,
44 const std::string &fqrn) {
45
1/2
✓ Branch 2 taken 2061 times.
✗ Branch 3 not taken.
2061 SqliteHistory *history = new SqliteHistory();
46
3/6
✓ Branch 0 taken 2061 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2061 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2061 times.
2061 if (NULL == history || !history->CreateDatabase(file_name, fqrn)) {
47 delete history;
48 return NULL;
49 }
50
51 2061 LogCvmfs(kLogHistory, kLogDebug,
52 "created empty history database '%s' for"
53 "repository '%s'",
54 file_name.c_str(), fqrn.c_str());
55 2061 return history;
56 }
57
58
59 872 bool SqliteHistory::OpenDatabase(const std::string &file_name,
60 const bool read_write) {
61
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 872 times.
872 assert(!database_.IsValid());
62 872 const HistoryDatabase::OpenMode mode = (read_write)
63
2/2
✓ Branch 0 taken 392 times.
✓ Branch 1 taken 480 times.
872 ? HistoryDatabase::kOpenReadWrite
64 : HistoryDatabase::kOpenReadOnly;
65 872 database_ = HistoryDatabase::Open(file_name, mode);
66
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 872 times.
872 if (!database_.IsValid()) {
67 return false;
68 }
69
70
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 872 times.
872 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 872 times.
✗ Branch 4 not taken.
872 set_fqrn(database_->GetProperty<std::string>(HistoryDatabase::kFqrnKey));
79 872 PrepareQueries();
80 872 return true;
81 }
82
83
84 2061 bool SqliteHistory::CreateDatabase(const std::string &file_name,
85 const std::string &repo_name) {
86
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2061 times.
2061 assert(!database_.IsValid());
87
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 2061 times.
2061 assert(fqrn().empty());
88 2061 set_fqrn(repo_name);
89 2061 database_ = HistoryDatabase::Create(file_name);
90
3/6
✓ Branch 1 taken 2061 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2061 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2061 times.
2061 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 2061 PrepareQueries();
98 2061 return true;
99 }
100
101
102 2933 void SqliteHistory::PrepareQueries() {
103
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2933 times.
2933 assert(database_.IsValid());
104
105
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 find_tag_ = new SqlFindTag(database_.weak_ref());
106
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 find_tag_by_date_ = new SqlFindTagByDate(database_.weak_ref());
107
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 count_tags_ = new SqlCountTags(database_.weak_ref());
108
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 list_tags_ = new SqlListTags(database_.weak_ref());
109
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 get_hashes_ = new SqlGetHashes(database_.weak_ref());
110
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 list_rollback_tags_ = new SqlListRollbackTags(database_.weak_ref());
111
1/2
✓ Branch 3 taken 2933 times.
✗ Branch 4 not taken.
2933 list_branches_ = new SqlListBranches(database_.weak_ref());
112
113
2/2
✓ Branch 2 taken 2835 times.
✓ Branch 3 taken 98 times.
2933 if (database_->ContainsRecycleBin()) {
114
1/2
✓ Branch 3 taken 2835 times.
✗ Branch 4 not taken.
2835 recycle_list_ = new SqlRecycleBinList(database_.weak_ref());
115 }
116
117
2/2
✓ Branch 1 taken 2453 times.
✓ Branch 2 taken 480 times.
2933 if (IsWritable()) {
118
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 insert_tag_ = new SqlInsertTag(database_.weak_ref());
119
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 remove_tag_ = new SqlRemoveTag(database_.weak_ref());
120
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 rollback_tag_ = new SqlRollbackTag(database_.weak_ref());
121
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 recycle_empty_ = new SqlRecycleBinFlush(database_.weak_ref());
122
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 insert_branch_ = new SqlInsertBranch(database_.weak_ref());
123
1/2
✓ Branch 3 taken 2453 times.
✗ Branch 4 not taken.
2453 find_branch_head_ = new SqlFindBranchHead(database_.weak_ref());
124 }
125 2933 }
126
127
128 1078 bool SqliteHistory::BeginTransaction() const {
129 1078 return database_->BeginTransaction();
130 }
131
132
133 882 bool SqliteHistory::CommitTransaction() const {
134 882 return database_->CommitTransaction();
135 }
136
137
138 500 bool SqliteHistory::SetPreviousRevision(const shash::Any &history_hash) {
139
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
500 assert(database_.IsValid());
140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 500 times.
500 assert(IsWritable());
141
1/2
✓ Branch 3 taken 500 times.
✗ Branch 4 not taken.
500 return database_->SetProperty(kPreviousRevisionKey, history_hash.ToString());
142 }
143
144
145 75 shash::Any SqliteHistory::previous_revision() const {
146
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
75 assert(database_.IsValid());
147 75 const std::string hash_str = database_->GetProperty<std::string>(
148
1/2
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
75 kPreviousRevisionKey);
149
1/2
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
150 return shash::MkFromHexPtr(shash::HexPtr(hash_str), shash::kSuffixHistory);
150 75 }
151
152
153 4648 bool SqliteHistory::IsWritable() const {
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4648 times.
4648 assert(database_.IsValid());
155 4648 return database_->read_write();
156 }
157
158 1421 unsigned SqliteHistory::GetNumberOfTags() const {
159
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1421 times.
1421 assert(database_.IsValid());
160
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1421 times.
1421 assert(count_tags_.IsValid());
161 1421 bool retval = count_tags_->FetchRow();
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1421 times.
1421 assert(retval);
163 1421 const unsigned count = count_tags_->RetrieveCount();
164 1421 retval = count_tags_->Reset();
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1421 times.
1421 assert(retval);
166 1421 return count;
167 }
168
169
170 207704 bool SqliteHistory::Insert(const History::Tag &tag) {
171
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 207704 times.
207704 assert(database_.IsValid());
172
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 207704 times.
207704 assert(insert_tag_.IsValid());
173
174
2/2
✓ Branch 4 taken 207606 times.
✓ Branch 5 taken 98 times.
415408 return insert_tag_->BindTag(tag) && insert_tag_->Execute()
175
2/4
✓ Branch 0 taken 207704 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 207606 times.
✗ Branch 5 not taken.
415408 && insert_tag_->Reset();
176 }
177
178
179 637 bool SqliteHistory::Remove(const std::string &name) {
180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 637 times.
637 assert(database_.IsValid());
181
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 637 times.
637 assert(remove_tag_.IsValid());
182
183
1/2
✓ Branch 1 taken 637 times.
✗ Branch 2 not taken.
637 Tag condemned_tag;
184
3/4
✓ Branch 1 taken 637 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 588 times.
637 if (!GetByName(name, &condemned_tag)) {
185 49 return true;
186 }
187
188
3/8
✓ Branch 2 taken 588 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 588 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 588 times.
✗ Branch 9 not taken.
1176 return remove_tag_->BindName(name) && remove_tag_->Execute()
189
3/6
✓ Branch 0 taken 588 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 588 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 588 times.
✗ Branch 7 not taken.
1176 && remove_tag_->Reset();
190 637 }
191
192
193 1127 bool SqliteHistory::Exists(const std::string &name) const {
194
1/2
✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
1127 Tag existing_tag;
195
1/2
✓ Branch 1 taken 1127 times.
✗ Branch 2 not taken.
2254 return GetByName(name, &existing_tag);
196 1127 }
197
198
199 2848 bool SqliteHistory::GetByName(const std::string &name, Tag *tag) const {
200
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2848 times.
2848 assert(database_.IsValid());
201
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2848 times.
2848 assert(find_tag_.IsValid());
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2848 times.
2848 assert(NULL != tag);
203
204
5/6
✓ Branch 2 taken 2848 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 591 times.
✓ Branch 7 taken 2257 times.
✓ Branch 8 taken 591 times.
✓ Branch 9 taken 2257 times.
2848 if (!find_tag_->BindName(name) || !find_tag_->FetchRow()) {
205 591 find_tag_->Reset();
206 591 return false;
207 }
208
209 2257 *tag = find_tag_->RetrieveTag();
210 2257 return find_tag_->Reset();
211 }
212
213
214 202 bool SqliteHistory::GetByDate(const time_t timestamp, Tag *tag) const {
215
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
202 assert(database_.IsValid());
216
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
202 assert(find_tag_by_date_.IsValid());
217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 202 times.
202 assert(NULL != tag);
218
219 202 if (!find_tag_by_date_->BindTimestamp(timestamp)
220
5/6
✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 52 times.
✓ Branch 5 taken 150 times.
✓ Branch 6 taken 52 times.
✓ Branch 7 taken 150 times.
202 || !find_tag_by_date_->FetchRow()) {
221 52 find_tag_by_date_->Reset();
222 52 return false;
223 }
224
225 150 *tag = find_tag_by_date_->RetrieveTag();
226 150 return find_tag_by_date_->Reset();
227 }
228
229
230 392 bool SqliteHistory::List(std::vector<Tag> *tags) const {
231
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 392 times.
392 assert(list_tags_.IsValid());
232 392 return RunListing(tags, list_tags_.weak_ref());
233 }
234
235
236 template<class SqlListingT>
237 1078 bool SqliteHistory::RunListing(std::vector<Tag> *list, SqlListingT *sql) const {
238
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 539 times.
1078 assert(database_.IsValid());
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 539 times.
1078 assert(NULL != list);
240
241
2/2
✓ Branch 1 taken 57379 times.
✓ Branch 2 taken 539 times.
115836 while (sql->FetchRow()) {
242
1/2
✓ Branch 2 taken 57379 times.
✗ Branch 3 not taken.
114758 list->push_back(sql->RetrieveTag());
243 }
244
245 1078 return sql->Reset();
246 }
247
248
249 147 bool SqliteHistory::GetBranchHead(const string &branch_name, Tag *tag) const {
250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
147 assert(database_.IsValid());
251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
147 assert(find_branch_head_.IsValid());
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 assert(tag != NULL);
253
254 147 if (!find_branch_head_->BindBranchName(branch_name)
255
5/6
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 49 times.
✓ Branch 5 taken 98 times.
✓ Branch 6 taken 49 times.
✓ Branch 7 taken 98 times.
147 || !find_branch_head_->FetchRow()) {
256 49 find_branch_head_->Reset();
257 49 return false;
258 }
259
260 98 *tag = find_branch_head_->RetrieveTag();
261 98 return find_branch_head_->Reset();
262 }
263
264
265 147 bool SqliteHistory::ExistsBranch(const string &branch_name) const {
266 147 vector<Branch> branches;
267
2/4
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 147 times.
147 if (!ListBranches(&branches))
268 return false;
269
2/2
✓ Branch 1 taken 343 times.
✓ Branch 2 taken 49 times.
392 for (unsigned i = 0; i < branches.size(); ++i) {
270
2/2
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 245 times.
343 if (branches[i].branch == branch_name)
271 98 return true;
272 }
273 49 return false;
274 147 }
275
276
277 882 bool SqliteHistory::InsertBranch(const Branch &branch) {
278
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 882 times.
882 assert(database_.IsValid());
279
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 882 times.
882 assert(insert_branch_.IsValid());
280
281
2/2
✓ Branch 4 taken 784 times.
✓ Branch 5 taken 49 times.
1715 return insert_branch_->BindBranch(branch) && insert_branch_->Execute()
282
3/4
✓ Branch 0 taken 833 times.
✓ Branch 1 taken 49 times.
✓ Branch 4 taken 784 times.
✗ Branch 5 not taken.
1715 && insert_branch_->Reset();
283 }
284
285
286 49 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 49 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 49 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 49 times.
✗ Branch 9 not taken.
147 " ON (branches.parent=abandoned_branch);");
300 // Detect if fix point is reached
301 sqlite::Sql sql_remaining_rows(
302 49 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 49 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 49 times.
✗ Branch 9 not taken.
147 "ON (branches.parent=abandoned_branch);");
309
310 bool retval;
311 do {
312
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 retval = sql_remaining_rows.FetchRow();
313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 if (!retval)
314 return false;
315
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 const int64_t count = sql_remaining_rows.RetrieveInt64(0);
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 assert(count >= 0);
317
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 98 times.
147 if (count == 0)
318 49 break;
319
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 retval = sql_remaining_rows.Reset();
320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 assert(retval);
321
322
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 retval = sql_fix_parent_pointers.Execute();
323
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 if (!retval)
324 return false;
325
1/2
✓ Branch 1 taken 98 times.
✗ Branch 2 not taken.
98 retval = sql_fix_parent_pointers.Reset();
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 assert(retval);
327 98 } while (true);
328
329 sqlite::Sql sql_remove_branches(
330 49 database_->sqlite_db(),
331 "DELETE FROM branches "
332
3/6
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 49 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 49 times.
✗ Branch 9 not taken.
147 "WHERE branch NOT IN (SELECT DISTINCT branch FROM tags);");
333
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 retval = sql_remove_branches.Execute();
334 49 return retval;
335 49 }
336
337
338 490 bool SqliteHistory::ListBranches(vector<Branch> *branches) const {
339
2/2
✓ Branch 2 taken 1323 times.
✓ Branch 3 taken 490 times.
1813 while (list_branches_->FetchRow()) {
340
1/2
✓ Branch 3 taken 1323 times.
✗ Branch 4 not taken.
1323 branches->push_back(list_branches_->RetrieveBranch());
341 }
342
343 490 return list_branches_->Reset();
344 }
345
346
347 637 bool SqliteHistory::ListRecycleBin(std::vector<shash::Any> *hashes) const {
348
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 637 times.
637 assert(database_.IsValid());
349
350
2/2
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 539 times.
637 if (!database_->ContainsRecycleBin()) {
351 98 return false;
352 }
353
354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 539 times.
539 assert(NULL != hashes);
355 539 hashes->clear();
356
2/2
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 539 times.
588 while (recycle_list_->FetchRow()) {
357
1/2
✓ Branch 3 taken 49 times.
✗ Branch 4 not taken.
49 hashes->push_back(recycle_list_->RetrieveHash());
358 }
359
360 539 return recycle_list_->Reset();
361 }
362
363
364 196 bool SqliteHistory::EmptyRecycleBin() {
365
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
196 assert(database_.IsValid());
366
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
196 assert(IsWritable());
367
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 196 times.
196 assert(recycle_empty_.IsValid());
368
2/4
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 196 times.
✗ Branch 7 not taken.
196 return recycle_empty_->Execute() && recycle_empty_->Reset();
369 }
370
371
372 147 bool SqliteHistory::Rollback(const Tag &updated_target_tag) {
373
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
147 assert(database_.IsValid());
374
2/4
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 147 times.
147 assert(IsWritable());
375
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 147 times.
147 assert(rollback_tag_.IsValid());
376
377
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 Tag old_target_tag;
378 147 bool success = false;
379
380 // open a transaction (if non open yet)
381
1/2
✓ Branch 1 taken 147 times.
✗ Branch 2 not taken.
147 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 147 times.
✗ Branch 2 not taken.
147 success = GetByName(updated_target_tag.name, &old_target_tag);
385
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 98 times.
147 if (!success) {
386
1/2
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
49 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve old target tag '%s'",
387 updated_target_tag.name.c_str());
388 49 return false;
389 }
390
391 // sanity checks
392
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
98 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 98 times.
✗ Branch 3 not taken.
98 success = rollback_tag_->BindTargetTag(old_target_tag)
397
5/12
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 98 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 98 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 98 times.
✗ Branch 13 not taken.
98 && rollback_tag_->Execute() && rollback_tag_->Reset();
398
4/8
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 98 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 98 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 98 times.
98 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 98 times.
✗ Branch 2 not taken.
98 success = Insert(updated_target_tag);
409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 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 98 times.
98 if (need_to_commit) {
416 success = CommitTransaction();
417 assert(success);
418 }
419
420 98 return true;
421 147 }
422
423
424 196 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 196 times.
✗ Branch 2 not taken.
196 Tag target_tag;
428
3/4
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
✓ Branch 4 taken 147 times.
196 if (!GetByName(target_tag_name, &target_tag)) {
429
1/2
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
49 LogCvmfs(kLogHistory, kLogDebug, "failed to retrieve target tag '%s'",
430 target_tag_name.c_str());
431 49 return false;
432 }
433
434 // prepage listing command to find affected tags for a potential rollback
435
2/4
✓ Branch 2 taken 147 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 147 times.
147 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 147 times.
✗ Branch 3 not taken.
147 return RunListing(tags, list_rollback_tags_.weak_ref());
443 196 }
444
445
446 98 bool SqliteHistory::GetHashes(std::vector<shash::Any> *hashes) const {
447
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 98 times.
98 assert(database_.IsValid());
448
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 98 times.
98 assert(NULL != hashes);
449
450
2/2
✓ Branch 2 taken 98049 times.
✓ Branch 3 taken 98 times.
98147 while (get_hashes_->FetchRow()) {
451
1/2
✓ Branch 3 taken 98049 times.
✗ Branch 4 not taken.
98049 hashes->push_back(get_hashes_->RetrieveHash());
452 }
453
454 98 return get_hashes_->Reset();
455 }
456
457
458 125 void SqliteHistory::TakeDatabaseFileOwnership() {
459
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 125 times.
125 assert(database_.IsValid());
460 125 database_->TakeFileOwnership();
461 125 }
462
463
464 void SqliteHistory::DropDatabaseFileOwnership() {
465 assert(database_.IsValid());
466 database_->DropFileOwnership();
467 }
468
469 } // namespace history
470