GCC Code Coverage Report


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