GCC Code Coverage Report


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