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 |