GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/catalog_rw.cc
Date: 2026-05-19 11:45:12
Exec Total Coverage
Lines: 308 393 78.4%
Branches: 266 723 36.8%

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