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