GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_rw.cc
Date: 2025-06-22 02:36:02
Exec Total Coverage
Lines: 305 390 78.2%
Branches: 266 725 36.7%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #define __STDC_FORMAT_MACROS
6
7 #include "catalog_rw.h"
8
9 #include <inttypes.h>
10
11 #include <cstdio>
12 #include <cstdlib>
13
14 #include "util/concurrency.h"
15 #include "util/exception.h"
16 #include "util/logging.h"
17 #include "xattr.h"
18
19 using namespace std; // NOLINT
20
21 namespace catalog {
22
23 const double WritableCatalog::kMaximalFreePageRatio = 0.20;
24 const double WritableCatalog::kMaximalRowIdWasteRatio = 0.25;
25
26
27 2611 WritableCatalog::WritableCatalog(const string &path,
28 const shash::Any &catalog_hash,
29 Catalog *parent,
30 2611 const bool is_not_root)
31 5222 : Catalog(PathString(path.data(), path.length()),
32 catalog_hash, // This is 0 for a newly created catalog!
33 parent,
34 is_not_root)
35 2611 , sql_insert_(NULL)
36 2611 , sql_unlink_(NULL)
37 2611 , sql_touch_(NULL)
38 2611 , sql_update_(NULL)
39 2611 , sql_chunk_insert_(NULL)
40 2611 , sql_chunks_remove_(NULL)
41 2611 , sql_chunks_count_(NULL)
42 2611 , sql_max_link_id_(NULL)
43 2611 , sql_inc_linkcount_(NULL)
44
2/4
✓ Branch 2 taken 2611 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2611 times.
✗ Branch 6 not taken.
7833 , dirty_(false) {
45 2611 atomic_init32(&dirty_children_);
46 2611 }
47
48
49 150 WritableCatalog *WritableCatalog::AttachFreely(const string &root_path,
50 const string &file,
51 const shash::Any &catalog_hash,
52 Catalog *parent,
53 const bool is_not_root) {
54 WritableCatalog *catalog = new WritableCatalog(root_path, catalog_hash,
55
1/2
✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
150 parent, is_not_root);
56 150 const bool successful_init = catalog->InitStandalone(file);
57
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 150 times.
150 if (!successful_init) {
58 delete catalog;
59 return NULL;
60 }
61 150 return catalog;
62 }
63
64
65 10376 WritableCatalog::~WritableCatalog() {
66 // CAUTION HOT!
67 // (see Catalog.h - near the definition of FinalizePreparedStatements)
68 5188 FinalizePreparedStatements();
69 10376 }
70
71
72 2225 void WritableCatalog::Transaction() {
73
1/3
✓ Branch 2 taken 2225 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2225 LogCvmfs(kLogCatalog, kLogVerboseMsg, "opening SQLite transaction for '%s'",
74 4450 mountpoint().c_str());
75 2225 const bool retval = database().BeginTransaction();
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2225 times.
2225 assert(retval == true);
77 2225 }
78
79
80 2066 void WritableCatalog::Commit() {
81
1/3
✓ Branch 2 taken 2066 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2066 LogCvmfs(kLogCatalog, kLogVerboseMsg, "closing SQLite transaction for '%s'",
82 4132 mountpoint().c_str());
83 2066 const bool retval = database().CommitTransaction();
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2066 times.
2066 assert(retval == true);
85 2066 dirty_ = false;
86 2066 }
87
88
89 2611 void WritableCatalog::InitPreparedStatements() {
90 2611 Catalog::InitPreparedStatements(); // polymorphism: up call
91
92 const bool retval =
93
3/6
✓ Branch 2 taken 2611 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 2611 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 2611 times.
✗ Branch 10 not taken.
2611 SqlCatalog(database(), "PRAGMA foreign_keys = ON;").Execute();
94
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2611 times.
2611 assert(retval);
95
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_insert_ = new SqlDirentInsert(database());
96
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_unlink_ = new SqlDirentUnlink(database());
97
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_touch_ = new SqlDirentTouch(database());
98
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_update_ = new SqlDirentUpdate(database());
99
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_chunk_insert_ = new SqlChunkInsert(database());
100
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_chunks_remove_ = new SqlChunksRemove(database());
101
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_chunks_count_ = new SqlChunksCount(database());
102
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_max_link_id_ = new SqlMaxHardlinkGroup(database());
103
1/2
✓ Branch 3 taken 2611 times.
✗ Branch 4 not taken.
2611 sql_inc_linkcount_ = new SqlIncLinkcount(database());
104 2611 }
105
106
107 2594 void WritableCatalog::FinalizePreparedStatements() {
108 // no polymorphism: no up call (see Catalog.h -
109 // near the definition of this method)
110
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_insert_;
111
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_unlink_;
112
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_touch_;
113
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_update_;
114
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_chunk_insert_;
115
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_chunks_remove_;
116
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_chunks_count_;
117
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_max_link_id_;
118
1/2
✓ Branch 0 taken 2594 times.
✗ Branch 1 not taken.
2594 delete sql_inc_linkcount_;
119 2594 }
120
121
122 /**
123 * Find out the maximal hardlink group id in this catalog.
124 */
125 79 uint32_t WritableCatalog::GetMaxLinkId() const {
126 79 int result = -1;
127
128
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 if (sql_max_link_id_->FetchRow()) {
129 79 result = sql_max_link_id_->GetMaxGroupId();
130 }
131 79 sql_max_link_id_->Reset();
132
133 79 return result;
134 }
135
136
137 /**
138 * Adds a directory entry.
139 * @param entry the DirectoryEntry to add to the catalog
140 * @param entry_path the full path of the DirectoryEntry to add
141 * @param parent_path the full path of the containing directory
142 */
143 14127 void WritableCatalog::AddEntry(const DirectoryEntry &entry,
144 const XattrList &xattrs,
145 const string &entry_path,
146 const string &parent_path) {
147
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 SetDirty();
148
149
1/6
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14127 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
14127 LogCvmfs(kLogCatalog, kLogVerboseMsg, "add entry '%s' to '%s'",
150
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
28254 entry_path.c_str(), mountpoint().c_str());
151
152
1/2
✓ Branch 2 taken 14127 times.
✗ Branch 3 not taken.
14127 const shash::Md5 path_hash((shash::AsciiPtr(entry_path)));
153
1/2
✓ Branch 2 taken 14127 times.
✗ Branch 3 not taken.
14127 const shash::Md5 parent_hash((shash::AsciiPtr(parent_path)));
154
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 DirectoryEntry effective_entry(entry);
155 14127 effective_entry.set_has_xattrs(!xattrs.IsEmpty());
156
157
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 bool retval = sql_insert_->BindPathHash(path_hash)
158
2/4
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 14127 times.
✗ Branch 4 not taken.
14127 && sql_insert_->BindParentPathHash(parent_hash)
159
3/6
✓ Branch 0 taken 14127 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 14127 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 14127 times.
✗ Branch 6 not taken.
28254 && sql_insert_->BindDirent(effective_entry);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14127 times.
14127 assert(retval);
161
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 if (xattrs.IsEmpty()) {
162
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 retval = sql_insert_->BindXattrEmpty();
163 } else {
164 retval = sql_insert_->BindXattr(xattrs);
165 }
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14127 times.
14127 assert(retval);
167
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 retval = sql_insert_->Execute();
168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14127 times.
14127 assert(retval);
169
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 sql_insert_->Reset();
170
171
1/2
✓ Branch 1 taken 14127 times.
✗ Branch 2 not taken.
14127 delta_counters_.Increment(effective_entry);
172 14127 }
173
174
175 /**
176 * Removes the specified entry from the catalog.
177 * Note: removing a directory which is non-empty results in dangling entries.
178 * (this should be treated in upper layers)
179 * @param entry_path the full path of the DirectoryEntry to delete
180 */
181 4129 void WritableCatalog::RemoveEntry(const string &file_path) {
182
1/2
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
4129 DirectoryEntry entry;
183
2/4
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4129 times.
✗ Branch 5 not taken.
4129 bool retval = LookupPath(PathString(file_path), &entry);
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4129 times.
4129 assert(retval);
185
186
1/2
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
4129 SetDirty();
187
188 // If the entry used to be a chunked file... remove the chunks
189
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4129 times.
4129 if (entry.IsChunkedFile()) {
190 RemoveFileChunks(file_path);
191 }
192
193 // remove the entry itself
194
1/2
✓ Branch 2 taken 4129 times.
✗ Branch 3 not taken.
4129 const shash::Md5 path_hash = shash::Md5(shash::AsciiPtr(file_path));
195
4/9
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4129 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4129 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4129 times.
✗ Branch 9 not taken.
4129 retval = sql_unlink_->BindPathHash(path_hash) && sql_unlink_->Execute();
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4129 times.
4129 assert(retval);
197
1/2
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
4129 sql_unlink_->Reset();
198
199
1/2
✓ Branch 1 taken 4129 times.
✗ Branch 2 not taken.
4129 delta_counters_.Decrement(entry);
200 4129 }
201
202
203 void WritableCatalog::IncLinkcount(const string &path_within_group,
204 const int delta) {
205 SetDirty();
206
207 const shash::Md5 path_hash = shash::Md5(shash::AsciiPtr(path_within_group));
208
209 const bool retval = sql_inc_linkcount_->BindPathHash(path_hash) &&
210 sql_inc_linkcount_->BindDelta(delta) &&
211 sql_inc_linkcount_->Execute();
212 assert(retval);
213 sql_inc_linkcount_->Reset();
214 }
215
216
217 91 void WritableCatalog::TouchEntry(const DirectoryEntryBase &entry,
218 const XattrList &xattrs,
219 const shash::Md5 &path_hash) {
220
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 SetDirty();
221
222
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 catalog::DirectoryEntry prev_entry;
223
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 bool retval = LookupMd5Path(path_hash, &prev_entry);
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 assert(retval);
225
226
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 retval = sql_touch_->BindPathHash(path_hash)
227
3/6
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 91 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 91 times.
✗ Branch 6 not taken.
91 && sql_touch_->BindDirentBase(entry);
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 assert(retval);
229
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 if (xattrs.IsEmpty()) {
230
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 retval = sql_touch_->BindXattrEmpty();
231
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
91 if (prev_entry.HasXattrs())
232 delta_counters_.self.xattrs--;
233 } else {
234 retval = sql_touch_->BindXattr(xattrs);
235 if (!prev_entry.HasXattrs())
236 delta_counters_.self.xattrs++;
237 }
238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 assert(retval);
239
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 retval = sql_touch_->Execute();
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 assert(retval);
241
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 sql_touch_->Reset();
242 91 }
243
244
245 6520 void WritableCatalog::UpdateEntry(const DirectoryEntry &entry,
246 const shash::Md5 &path_hash) {
247 6520 SetDirty();
248
249
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
6520 const bool retval = sql_update_->BindPathHash(path_hash) &&
250
3/7
✓ Branch 0 taken 6520 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 6520 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 6520 times.
✗ Branch 7 not taken.
6520 sql_update_->BindDirent(entry) && sql_update_->Execute();
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6520 times.
6520 assert(retval);
252 6520 sql_update_->Reset();
253 6520 }
254
255 68 void WritableCatalog::AddFileChunk(const std::string &entry_path,
256 const FileChunk &chunk) {
257
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 SetDirty();
258
259
1/2
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 const shash::Md5 path_hash((shash::AsciiPtr(entry_path)));
260
261
1/4
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
68 LogCvmfs(kLogCatalog, kLogVerboseMsg,
262 "adding chunk for %s from offset %ld "
263 "and chunk size: %ld bytes",
264 68 entry_path.c_str(), chunk.offset(), chunk.offset() + chunk.size());
265
266 68 delta_counters_.self.file_chunks++;
267
268
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 const bool retval = sql_chunk_insert_->BindPathHash(path_hash) &&
269
3/6
✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
✗ Branch 6 not taken.
136 sql_chunk_insert_->BindFileChunk(chunk) &&
270
2/4
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 68 times.
✗ Branch 4 not taken.
68 sql_chunk_insert_->Execute();
271
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
68 assert(retval);
272
1/2
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
68 sql_chunk_insert_->Reset();
273 68 }
274
275
276 /**
277 * Removes the file chunks for a given file path
278 * @param entry_path the file path to clear from it's file chunks
279 */
280 void WritableCatalog::RemoveFileChunks(const std::string &entry_path) {
281 const shash::Md5 path_hash((shash::AsciiPtr(entry_path)));
282 bool retval;
283
284 // subtract the number of chunks from the statistics counters
285 retval = sql_chunks_count_->BindPathHash(path_hash)
286 && sql_chunks_count_->Execute();
287 assert(retval);
288 const int chunks_count = sql_chunks_count_->GetChunkCount();
289 delta_counters_.self.file_chunks -= chunks_count;
290 sql_chunks_count_->Reset();
291
292 // remove the chunks associated to `entry_path`
293 retval = sql_chunks_remove_->BindPathHash(path_hash)
294 && sql_chunks_remove_->Execute();
295 assert(retval);
296 sql_chunks_remove_->Reset();
297 }
298
299
300 /**
301 * Sets the last modified time stamp of this catalog to current time.
302 */
303 2482 void WritableCatalog::UpdateLastModified() {
304
2/4
✓ Branch 4 taken 2482 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 2482 times.
✗ Branch 8 not taken.
2482 database().SetProperty("last_modified", static_cast<uint64_t>(time(NULL)));
305 2482 }
306
307
308 /**
309 * Increments the revision of the catalog in the database.
310 */
311 1802 void WritableCatalog::IncrementRevision() { SetRevision(GetRevision() + 1); }
312
313
314 1802 void WritableCatalog::SetRevision(const uint64_t new_revision) {
315
2/4
✓ Branch 3 taken 1802 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 1802 times.
✗ Branch 7 not taken.
1802 database().SetProperty("revision", new_revision);
316 1802 }
317
318
319 void WritableCatalog::SetBranch(const std::string &branch_name) {
320 database().SetProperty("branch", branch_name);
321 }
322
323
324 void WritableCatalog::SetTTL(const uint64_t new_ttl) {
325 database().SetProperty("TTL", new_ttl);
326 }
327
328
329 bool WritableCatalog::SetVOMSAuthz(const std::string &voms_authz) {
330 return database().SetVOMSAuthz(voms_authz);
331 }
332
333
334 /**
335 * Sets the content hash of the previous catalog revision.
336 */
337 1802 void WritableCatalog::SetPreviousRevision(const shash::Any &hash) {
338
2/4
✓ Branch 4 taken 1802 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1802 times.
✗ Branch 8 not taken.
1802 database().SetProperty("previous_revision", hash.ToString());
339 1802 }
340
341
342 /**
343 * Moves a subtree from this catalog into a just created nested catalog.
344 */
345 981 void WritableCatalog::Partition(WritableCatalog *new_nested_catalog) {
346 // Create connection between parent and child catalogs
347
3/6
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 981 times.
✗ Branch 8 not taken.
981 MakeTransitionPoint(new_nested_catalog->mountpoint().ToString());
348
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 new_nested_catalog->MakeNestedRoot();
349 981 delta_counters_.subtree.directories++; // Root directory in nested catalog
350
351 // Move the present directory tree into the newly created nested catalog
352 // if we hit nested catalog mountpoints on the way, we return them through
353 // the passed list
354 981 vector<string> GrandChildMountpoints;
355
3/6
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 981 times.
✗ Branch 8 not taken.
981 MoveToNested(new_nested_catalog->mountpoint().ToString(), new_nested_catalog,
356 &GrandChildMountpoints);
357
358 // Nested catalog mountpoints found in the moved directory structure are now
359 // links to nested catalogs of the newly created nested catalog.
360 // Move these references into the new nested catalog
361
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 MoveCatalogsToNested(GrandChildMountpoints, new_nested_catalog);
362 981 }
363
364
365 981 void WritableCatalog::MakeTransitionPoint(const string &mountpoint) {
366 // Find the directory entry to edit
367
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 DirectoryEntry transition_entry;
368
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 const bool retval = LookupPath(
369
1/2
✓ Branch 3 taken 981 times.
✗ Branch 4 not taken.
1962 PathString(mountpoint.data(), mountpoint.length()), &transition_entry);
370
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 981 times.
981 assert(retval);
371
372
2/4
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
981 assert(transition_entry.IsDirectory()
373 && !transition_entry.IsNestedCatalogRoot());
374
375 981 transition_entry.set_is_nested_catalog_mountpoint(true);
376
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 UpdateEntry(transition_entry, mountpoint);
377 981 }
378
379
380 981 void WritableCatalog::MakeNestedRoot() {
381
1/2
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
981 DirectoryEntry root_entry;
382
2/4
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
981 const bool retval = LookupPath(mountpoint(), &root_entry);
383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 981 times.
981 assert(retval);
384
385
2/4
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
981 assert(root_entry.IsDirectory() && !root_entry.IsNestedCatalogMountpoint());
386
387 981 root_entry.set_is_nested_catalog_root(true);
388
3/6
✓ Branch 1 taken 981 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 981 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 981 times.
✗ Branch 8 not taken.
981 UpdateEntry(root_entry, mountpoint().ToString());
389 981 }
390
391
392 1679 void WritableCatalog::MoveToNestedRecursively(
393 const string directory,
394 WritableCatalog *new_nested_catalog,
395 vector<string> *grand_child_mountpoints) {
396 // After creating a new nested catalog we have to move all elements
397 // now contained by the new one. List and move them recursively.
398 1679 DirectoryEntryList listing;
399 1679 const bool resolve_magic_symlinks = false;
400
2/4
✓ Branch 1 taken 1679 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1679 times.
✗ Branch 5 not taken.
1679 bool retval = ListingPath(PathString(directory), &listing,
401 resolve_magic_symlinks);
402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1679 times.
1679 assert(retval);
403
404 // Go through the listing
405 1679 const XattrList empty_xattrs;
406 1679 for (DirectoryEntryList::const_iterator i = listing.begin(),
407 1679 iEnd = listing.end();
408
2/2
✓ Branch 1 taken 3745 times.
✓ Branch 2 taken 1679 times.
5424 i != iEnd;
409 3745 ++i) {
410
1/2
✓ Branch 2 taken 3745 times.
✗ Branch 3 not taken.
3745 const string full_path = i->GetFullPath(directory);
411
412 // The entries are first inserted into the new catalog
413
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3745 times.
3745 if (i->HasXattrs()) {
414 XattrList xattrs;
415 retval = LookupXattrsPath(PathString(full_path), &xattrs);
416 assert(retval);
417 assert(!xattrs.IsEmpty());
418 new_nested_catalog->AddEntry(*i, xattrs, full_path);
419 } else {
420
1/2
✓ Branch 2 taken 3745 times.
✗ Branch 3 not taken.
3745 new_nested_catalog->AddEntry(*i, empty_xattrs, full_path);
421 }
422
423 // Then we check if we have some special cases:
424
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3745 times.
3745 if (i->IsNestedCatalogMountpoint()) {
425 grand_child_mountpoints->push_back(full_path);
426
2/2
✓ Branch 2 taken 698 times.
✓ Branch 3 taken 3047 times.
3745 } else if (i->IsDirectory()) {
427 // Recurse deeper into the directory tree
428
2/4
✓ Branch 1 taken 698 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 698 times.
✗ Branch 5 not taken.
698 MoveToNestedRecursively(full_path, new_nested_catalog,
429 grand_child_mountpoints);
430
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 3047 times.
3047 } else if (i->IsChunkedFile()) {
431 MoveFileChunksToNested(full_path, i->hash_algorithm(),
432 new_nested_catalog);
433 }
434
435 // Remove the entry from the current catalog
436
1/2
✓ Branch 1 taken 3745 times.
✗ Branch 2 not taken.
3745 RemoveEntry(full_path);
437 3745 }
438 1679 }
439
440
441 981 void WritableCatalog::MoveCatalogsToNested(
442 const vector<string> &nested_catalogs,
443 WritableCatalog *new_nested_catalog) {
444 1962 for (vector<string>::const_iterator i = nested_catalogs.begin(),
445 981 iEnd = nested_catalogs.end();
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 981 times.
981 i != iEnd;
447 ++i) {
448 shash::Any hash_nested;
449 uint64_t size_nested;
450 const bool retval = FindNested(PathString(*i), &hash_nested, &size_nested);
451 assert(retval);
452
453 Catalog *attached_reference = NULL;
454 RemoveNestedCatalog(*i, &attached_reference);
455
456 new_nested_catalog->InsertNestedCatalog(*i, attached_reference, hash_nested,
457 size_nested);
458 }
459 981 }
460
461
462 void WritableCatalog::MoveFileChunksToNested(
463 const std::string &full_path,
464 const shash::Algorithms algorithm,
465 WritableCatalog *new_nested_catalog) {
466 FileChunkList chunks;
467 ListPathChunks(PathString(full_path), algorithm, &chunks);
468 assert(chunks.size() > 0);
469
470 for (unsigned i = 0; i < chunks.size(); ++i) {
471 new_nested_catalog->AddFileChunk(full_path, *chunks.AtPtr(i));
472 }
473 }
474
475
476 /**
477 * Insert a nested catalog reference into this catalog.
478 * The attached catalog object of this mountpoint can be specified (optional)
479 * This way, the in-memory representation of the catalog tree is updated, too
480 * @param mountpoint the path to the catalog to add a reference to
481 * @param attached_reference can contain a reference to the attached catalog
482 * object of mountpoint
483 * @param content_hash can be set to safe a content hash together with the
484 * reference
485 */
486 1106 void WritableCatalog::InsertNestedCatalog(const string &mountpoint,
487 Catalog *attached_reference,
488 const shash::Any content_hash,
489 const uint64_t size) {
490 1106 const string hash_string = (!content_hash.IsNull()) ? content_hash.ToString()
491
6/12
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 981 times.
✓ Branch 3 taken 125 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 981 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 981 times.
✓ Branch 10 taken 125 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
1106 : "";
492
493 1106 SqlCatalog stmt(database(), "INSERT INTO nested_catalogs (path, sha1, size) "
494
2/4
✓ Branch 2 taken 1106 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1106 times.
✗ Branch 6 not taken.
3318 "VALUES (:p, :sha1, :size);");
495
1/2
✓ Branch 1 taken 1106 times.
✗ Branch 2 not taken.
1106 const bool retval = stmt.BindText(1, mountpoint) &&
496
2/4
✓ Branch 1 taken 1106 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106 times.
✗ Branch 4 not taken.
1106 stmt.BindText(2, hash_string) &&
497
5/10
✓ Branch 0 taken 1106 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1106 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1106 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1106 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1106 times.
✗ Branch 11 not taken.
2212 stmt.BindInt64(3, size) && stmt.Execute();
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
1106 assert(retval);
499
500 // If a reference of the in-memory object of the newly referenced
501 // catalog was passed, we add this to our own children
502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
1106 if (attached_reference != NULL)
503 AddChild(attached_reference);
504
505
1/2
✓ Branch 1 taken 1106 times.
✗ Branch 2 not taken.
1106 ResetNestedCatalogCacheUnprotected();
506
507 1106 delta_counters_.self.nested_catalogs++;
508 1106 }
509
510
511 /**
512 * Registers a snapshot in /.cvmfs/snapshots. Note that bind mountpoints are
513 * not universally handled: in Partition and MergeIntoParent, bind mountpoint
514 * handling is missing!
515 */
516 void WritableCatalog::InsertBindMountpoint(const string &mountpoint,
517 const shash::Any content_hash,
518 const uint64_t size) {
519 SqlCatalog stmt(database(),
520 "INSERT INTO bind_mountpoints (path, sha1, size) "
521 "VALUES (:p, :sha1, :size);");
522 const bool retval = stmt.BindText(1, mountpoint) &&
523 stmt.BindText(2, content_hash.ToString()) &&
524 stmt.BindInt64(3, size) && stmt.Execute();
525 assert(retval);
526 }
527
528
529 /**
530 * Remove a nested catalog reference from the database.
531 * If the catalog 'mountpoint' is currently attached as a child, it will be
532 * removed, too (but not detached).
533 * @param[in] mountpoint the mountpoint of the nested catalog to dereference in
534 the database
535 * @param[out] attached_reference is set to the object of the attached child or
536 * to NULL
537 */
538 121 void WritableCatalog::RemoveNestedCatalog(const string &mountpoint,
539 Catalog **attached_reference) {
540
1/2
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
121 shash::Any dummy;
541 uint64_t dummy_size;
542
2/4
✓ Branch 3 taken 121 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
121 bool retval = FindNested(PathString(mountpoint.data(), mountpoint.length()),
543 &dummy, &dummy_size);
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 assert(retval);
545
546
2/4
✓ Branch 2 taken 121 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
242 SqlCatalog stmt(database(), "DELETE FROM nested_catalogs WHERE path = :p;");
547
4/9
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 121 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 121 times.
✗ Branch 9 not taken.
121 retval = stmt.BindText(1, mountpoint) && stmt.Execute();
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 assert(retval);
549
550 // If the reference was successfully deleted, we also have to check whether
551 // there is also an attached reference in our in-memory data.
552 // In this case we remove the child and return it through **attached_reference
553
2/4
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 121 times.
✗ Branch 5 not taken.
121 Catalog *child = FindChild(PathString(mountpoint));
554
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 42 times.
121 if (child != NULL)
555
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 RemoveChild(child);
556
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
121 if (attached_reference != NULL)
557 *attached_reference = child;
558
559
1/2
✓ Branch 1 taken 121 times.
✗ Branch 2 not taken.
121 ResetNestedCatalogCacheUnprotected();
560
561 121 delta_counters_.self.nested_catalogs--;
562 121 }
563
564
565 /**
566 * Unregisters a snapshot from /.cvmfs/snapshots. Note that bind mountpoints
567 * are not universally handled: in Partition and MergeIntoParent, bind
568 * mountpoint handling is missing!
569 */
570 void WritableCatalog::RemoveBindMountpoint(const std::string &mountpoint) {
571 shash::Any dummy;
572 uint64_t dummy_size;
573 bool retval = FindNested(PathString(mountpoint.data(), mountpoint.length()),
574 &dummy, &dummy_size);
575 assert(retval);
576
577 SqlCatalog stmt(database(), "DELETE FROM bind_mountpoints WHERE path = :p;");
578 retval = stmt.BindText(1, mountpoint) && stmt.Execute();
579 assert(retval);
580 }
581
582
583 /**
584 * Updates the link to a nested catalog in the database.
585 * @param path the path of the nested catalog to update
586 * @param hash the hash to set the given nested catalog link to
587 * @param size the uncompressed catalog database file size
588 * @param child_counters the statistics counters of the nested catalog
589 */
590 939 void WritableCatalog::UpdateNestedCatalog(const std::string &path,
591 const shash::Any &hash,
592 const uint64_t size,
593 const DeltaCounters &child_counters) {
594 939 const MutexLockGuard guard(lock_);
595
1/2
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
939 SetDirty();
596
597
1/2
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
939 child_counters.PopulateToParent(&delta_counters_);
598
599
1/2
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
939 const string hash_str = hash.ToString();
600 const string sql = "UPDATE nested_catalogs SET sha1 = :sha1, size = :size "
601
1/2
✓ Branch 2 taken 939 times.
✗ Branch 3 not taken.
939 "WHERE path = :path;";
602
1/2
✓ Branch 2 taken 939 times.
✗ Branch 3 not taken.
939 SqlCatalog stmt(database(), sql);
603
604
3/7
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 939 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 939 times.
✗ Branch 7 not taken.
1878 const bool retval = stmt.BindText(1, hash_str) && stmt.BindInt64(2, size) &&
605
5/10
✓ Branch 0 taken 939 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 939 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 939 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 939 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 939 times.
✗ Branch 11 not taken.
1878 stmt.BindText(3, path) && stmt.Execute();
606
607
1/2
✓ Branch 1 taken 939 times.
✗ Branch 2 not taken.
939 ResetNestedCatalogCacheUnprotected();
608
609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 939 times.
939 assert(retval);
610 939 }
611
612
613 79 void WritableCatalog::MergeIntoParent() {
614
2/4
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
79 assert(!IsRoot() && HasParent());
615 79 WritableCatalog *parent = GetWritableParent();
616
617 79 CopyToParent();
618
619 // Copy the nested catalog references
620 79 CopyCatalogsToParent();
621
622 // Fix counters in parent
623 79 delta_counters_.PopulateToParent(&parent->delta_counters_);
624 79 Counters &counters = GetWritableCounters();
625 79 counters.ApplyDelta(delta_counters_);
626 79 counters.MergeIntoParent(&parent->delta_counters_);
627
628 // Remove the nested catalog reference for this nested catalog.
629 // From now on this catalog will be dangling!
630
2/4
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 79 times.
✗ Branch 6 not taken.
79 parent->RemoveNestedCatalog(this->mountpoint().ToString(), NULL);
631 79 }
632
633
634 void WritableCatalog::RemoveFromParent() {
635 assert(!IsRoot() && HasParent());
636 WritableCatalog *parent = GetWritableParent();
637
638 // Remove the nested catalog reference for this nested catalog.
639 // From now on this catalog will be dangling!
640 parent->RemoveNestedCatalog(this->mountpoint().ToString(), NULL);
641 parent->delta_counters_.RemoveFromSubtree(
642 Counters::Diff(Counters(), GetCounters()));
643 }
644
645
646 79 void WritableCatalog::CopyCatalogsToParent() {
647
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 WritableCatalog *parent = GetWritableParent();
648
649 // Obtain a list of all nested catalog references
650
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 const NestedCatalogList nested_catalog_references = ListOwnNestedCatalogs();
651
652 // Go through the list and update the databases
653 // simultaneously we are checking if the referenced catalogs are currently
654 // attached and update the in-memory data structures as well
655 158 for (NestedCatalogList::const_iterator i = nested_catalog_references.begin(),
656 79 iEnd = nested_catalog_references.end();
657
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 79 times.
79 i != iEnd;
658 ++i) {
659 Catalog *child = FindChild(i->mountpoint);
660 parent->InsertNestedCatalog(i->mountpoint.ToString(), child, i->hash,
661 i->size);
662 parent->delta_counters_.self.nested_catalogs--; // Will be fixed later
663 }
664 79 }
665
666 79 void WritableCatalog::CopyToParent() {
667 // We could simply copy all entries from this database to the 'other' database
668 // BUT: 1. this would create collisions in hardlink group IDs.
669 // therefore we first update all hardlink group IDs to fit behind the
670 // ones in the 'other' database
671 // 2. the root entry of the nested catalog is present twice:
672 // 1. in the parent directory (as mount point) and
673 // 2. in the nested catalog (as root entry)
674 // therefore we delete the mount point from the parent before merging
675
676
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 WritableCatalog *parent = GetWritableParent();
677
678 // Update hardlink group IDs in this nested catalog.
679 // To avoid collisions we add the maximal present hardlink group ID in parent
680 // to all hardlink group IDs in the nested catalog.
681
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 const uint64_t offset = static_cast<uint64_t>(parent->GetMaxLinkId()) << 32;
682 const string update_link_ids = "UPDATE catalog SET hardlinks = hardlinks + "
683
2/4
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
158 + StringifyInt(offset)
684
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 + " WHERE hardlinks > (1 << 32);";
685
686
1/2
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
79 SqlCatalog sql_update_link_ids(database(), update_link_ids);
687
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 bool retval = sql_update_link_ids.Execute();
688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
689
690 // Remove the nested catalog root.
691 // It is already present in the parent.
692
3/6
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 79 times.
✗ Branch 8 not taken.
79 RemoveEntry(this->mountpoint().ToString());
693
694 // Now copy all DirectoryEntries to the 'other' catalog.
695 // There will be no data collisions, as we resolved them beforehand
696
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if (dirty_)
697
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 Commit();
698
2/2
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 30 times.
79 if (parent->dirty_)
699
1/2
✓ Branch 1 taken 49 times.
✗ Branch 2 not taken.
49 parent->Commit();
700
2/4
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
237 SqlCatalog sql_attach(database(), "ATTACH '" + parent->database_path()
701
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
158 + "' "
702
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 "AS other;");
703
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 retval = sql_attach.Execute();
704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
705
2/4
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 79 times.
✗ Branch 7 not taken.
158 retval = SqlCatalog(database(), "INSERT INTO other.catalog "
706 "SELECT * FROM main.catalog;")
707
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 .Execute();
708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
709
2/4
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 79 times.
✗ Branch 7 not taken.
158 retval = SqlCatalog(database(), "INSERT INTO other.chunks "
710 "SELECT * FROM main.chunks;")
711
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 .Execute();
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
713
3/6
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 79 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 79 times.
✗ Branch 10 not taken.
79 retval = SqlCatalog(database(), "DETACH other;").Execute();
714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
715
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 parent->SetDirty();
716
717 // Change the just copied nested catalog root to an ordinary directory
718 // (the nested catalog is merged into it's parent)
719
1/2
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
79 DirectoryEntry old_root_entry;
720
2/4
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
79 retval = parent->LookupPath(this->mountpoint(), &old_root_entry);
721
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 assert(retval);
722
723
3/6
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 79 times.
✗ Branch 8 not taken.
79 assert(old_root_entry.IsDirectory()
724 && old_root_entry.IsNestedCatalogMountpoint()
725 && !old_root_entry.IsNestedCatalogRoot());
726
727 // Remove the nested catalog root mark
728 79 old_root_entry.set_is_nested_catalog_mountpoint(false);
729
3/6
✓ Branch 1 taken 79 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 79 times.
✗ Branch 8 not taken.
79 parent->UpdateEntry(old_root_entry, this->mountpoint().ToString());
730 79 }
731
732
733 /**
734 * Writes delta_counters_ to the database.
735 */
736 2783 void WritableCatalog::UpdateCounters() {
737 2783 const bool retval = delta_counters_.WriteToDatabase(database())
738
2/4
✓ Branch 0 taken 2783 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2783 times.
✗ Branch 4 not taken.
2783 && ReadCatalogCounters();
739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2783 times.
2783 assert(retval);
740 2783 }
741
742
743 /**
744 * Checks if the database of this catalogs needs cleanup and defragments it
745 * if necessary
746 */
747 1802 void WritableCatalog::VacuumDatabaseIfNecessary() {
748 1802 const CatalogDatabase &db = database();
749 1802 bool needs_defragmentation = false;
750 1802 double ratio = 0.0;
751 1802 std::string reason;
752
753
2/4
✓ Branch 1 taken 1802 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1802 times.
1802 if ((ratio = db.GetFreePageRatio()) > kMaximalFreePageRatio) {
754 needs_defragmentation = true;
755 reason = "free pages";
756
3/4
✓ Branch 1 taken 1802 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 475 times.
✓ Branch 4 taken 1327 times.
1802 } else if ((ratio = db.GetRowIdWasteRatio()) > kMaximalRowIdWasteRatio) {
757 475 needs_defragmentation = true;
758
1/2
✓ Branch 1 taken 475 times.
✗ Branch 2 not taken.
475 reason = "wasted row IDs";
759 }
760
761
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 1327 times.
1802 if (needs_defragmentation) {
762
3/14
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 145 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 475 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
1095 LogCvmfs(kLogCatalog, kLogStdout | kLogNoLinebreak,
763 "Note: Catalog at %s gets defragmented (%.2f%% %s)... ",
764
3/6
✓ Branch 2 taken 145 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 145 times.
✓ Branch 6 taken 330 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
1095 (IsRoot()) ? "/" : mountpoint().c_str(), ratio * 100.0,
765 reason.c_str());
766
2/4
✓ Branch 1 taken 475 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 475 times.
475 if (!db.Vacuum()) {
767 PANIC(kLogStderr, "failed (SQLite: %s)", db.GetLastErrorMsg().c_str());
768 }
769
1/2
✓ Branch 1 taken 475 times.
✗ Branch 2 not taken.
475 LogCvmfs(kLogCatalog, kLogStdout, "done");
770 }
771 1802 }
772
773 } // namespace catalog
774