GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/garbage_collection/garbage_collector_impl.h
Date: 2026-11-08 02:41:18
Exec Total Coverage
Lines: 167 209 79.9%
Branches: 125 314 39.8%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #ifndef CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_IMPL_H_
6 #define CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_IMPL_H_
7
8 #include <algorithm>
9 #include <ctime>
10 #include <limits>
11 #include <string>
12 #include <vector>
13
14 #include "garbage_collection/garbage_collector.h"
15 #include "util/logging.h"
16 #include "util/string.h"
17
18 template<class CatalogTraversalT, class HashFilterT>
19 const uint64_t GarbageCollector<CatalogTraversalT, HashFilterT>::Configuration::
20 kFullHistory = std::numeric_limits<uint64_t>::max();
21
22 template<class CatalogTraversalT, class HashFilterT>
23 const uint64_t GarbageCollector<CatalogTraversalT,
24 HashFilterT>::Configuration::kNoHistory = 0;
25
26 template<class CatalogTraversalT, class HashFilterT>
27 const time_t GarbageCollector<CatalogTraversalT,
28 HashFilterT>::Configuration::kNoTimestamp = 0;
29
30
31 template<class CatalogTraversalT, class HashFilterT>
32 1944 GarbageCollector<CatalogTraversalT, HashFilterT>::GarbageCollector(
33 const Configuration &configuration)
34 1944 : configuration_(configuration)
35 1944 , catalog_info_shim_(configuration.reflog)
36
1/2
✓ Branch 1 taken 972 times.
✗ Branch 2 not taken.
1944 , traversal_(
37
1/2
✓ Branch 1 taken 972 times.
✗ Branch 2 not taken.
1944 GarbageCollector<CatalogTraversalT, HashFilterT>::GetTraversalParams(
38 configuration))
39 1944 , hash_filter_()
40 1944 , hash_map_delete_requests_()
41 1944 , use_reflog_timestamps_(false)
42 1944 , oldest_trunk_catalog_(static_cast<uint64_t>(-1))
43 1944 , oldest_trunk_catalog_found_(false)
44 1944 , preserved_catalogs_(0)
45 1944 , unreferenced_trees_(0)
46 1944 , condemned_trees_(0)
47 1944 , condemned_catalogs_(0)
48 1944 , last_reported_status_(0.0)
49 1944 , condemned_objects_(0)
50 1944 , condemned_bytes_(0)
51 1944 , duplicate_delete_requests_(0) {
52
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 972 times.
1944 assert(configuration_.uploader != NULL);
53 1944 }
54
55
56 template<class CatalogTraversalT, class HashFilterT>
57 72 void GarbageCollector<CatalogTraversalT, HashFilterT>::UseReflogTimestamps() {
58 72 traversal_.SetCatalogInfoShim(&catalog_info_shim_);
59 72 use_reflog_timestamps_ = true;
60 72 }
61
62
63 template<class CatalogTraversalT, class HashFilterT>
64 typename GarbageCollector<CatalogTraversalT, HashFilterT>::TraversalParameters
65 2160 GarbageCollector<CatalogTraversalT, HashFilterT>::GetTraversalParams(
66 const GarbageCollector<CatalogTraversalT, HashFilterT>::Configuration
67 &config) {
68 2160 TraversalParameters params;
69 2160 params.object_fetcher = config.object_fetcher;
70 2160 params.history = config.keep_history_depth;
71 2160 params.timestamp = config.keep_history_timestamp;
72 2160 params.no_repeat_history = true;
73 2160 params.ignore_load_failure = true;
74 2160 params.quiet = !config.verbose;
75 2160 params.num_threads = config.num_threads;
76 2160 return params;
77 }
78
79
80 template<class CatalogTraversalT, class HashFilterT>
81 21384 void GarbageCollector<CatalogTraversalT, HashFilterT>::PreserveDataObjects(
82 const GarbageCollector<CatalogTraversalT,
83 HashFilterT>::TraversalCallbackDataTN
84 &data // NOLINT(runtime/references)
85 ) {
86 // A partial replica cannot serve excluded subtrees, even if their objects
87 // are still on disk from an earlier full snapshot. Do not mark them live.
88 // As in snapshot, exclusion is per nested catalog, not per directory.
89 42768 if (configuration_.prune_partial_replica
90
12/20
✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 8964 times.
✓ Branch 3 taken 1728 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1728 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 504 times.
✓ Branch 9 taken 1224 times.
✓ Branch 10 taken 1728 times.
✓ Branch 11 taken 8964 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1728 times.
✓ Branch 14 taken 8964 times.
✓ Branch 16 taken 504 times.
✓ Branch 17 taken 10188 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
24840 && configuration_.inclusion_spec->IsExcluded(
91
1/2
✓ Branch 1 taken 1728 times.
✗ Branch 2 not taken.
3456 data.catalog->mountpoint().ToString())) {
92 1008 return;
93 }
94 20376 ++preserved_catalogs_;
95
96
2/2
✓ Branch 1 taken 3060 times.
✓ Branch 2 taken 7128 times.
20376 if (data.catalog->IsRoot()) {
97 12240 const uint64_t mtime = use_reflog_timestamps_
98
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 2880 times.
6480 ? catalog_info_shim_.GetLastModified(
99
1/2
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
360 data.catalog)
100 5760 : data.catalog->GetLastModified();
101
2/2
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 684 times.
6120 if (!oldest_trunk_catalog_found_)
102 4752 oldest_trunk_catalog_ = std::min(oldest_trunk_catalog_, mtime);
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3060 times.
6120 if (configuration_.verbose) {
104 ✗ const uint64_t rev = data.catalog->revision();
105 ✗ LogCvmfs(
106 kLogGc, kLogStdout | kLogDebug,
107 "Preserving Revision %" PRIu64 " (%s / added @ %s)", rev,
108 ✗ StringifyTime(data.catalog->GetLastModified(), true).c_str(),
109 ✗ StringifyTime(catalog_info_shim_.GetLastModified(data.catalog), true)
110 .c_str());
111 ✗ PrintCatalogTreeEntry(data.tree_level, data.catalog);
112 }
113
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3060 times.
6120 if (data.catalog->schema() < 0.99) {
114 ✗ LogCvmfs(
115 kLogGc, kLogStdout | kLogDebug,
116 "Warning: "
117 "legacy catalog does not provide access to nested catalog "
118 "hierarchy.\n"
119 " Some unreferenced objects may remain in the repository.");
120 }
121 }
122
123 // the hash of the actual catalog needs to preserved
124
1/2
✓ Branch 2 taken 10188 times.
✗ Branch 3 not taken.
20376 hash_filter_.Fill(data.catalog->hash());
125
126 // all the objects referenced from this catalog need to be preserved
127
1/2
✓ Branch 1 taken 10188 times.
✗ Branch 2 not taken.
20376 const HashVector &referenced_hashes = data.catalog->GetReferencedObjects();
128 20376 typename HashVector::const_iterator i = referenced_hashes.begin();
129 20376 const typename HashVector::const_iterator iend = referenced_hashes.end();
130
2/2
✓ Branch 2 taken 52848 times.
✓ Branch 3 taken 10188 times.
126072 for (; i != iend; ++i) {
131
1/2
✓ Branch 2 taken 52848 times.
✗ Branch 3 not taken.
105696 hash_filter_.Fill(*i);
132 }
133 }
134
135
136 template<class CatalogTraversalT, class HashFilterT>
137 4752 void GarbageCollector<CatalogTraversalT, HashFilterT>::SweepDataObjects(
138 const GarbageCollector<CatalogTraversalT,
139 HashFilterT>::TraversalCallbackDataTN
140 &data // NOLINT(runtime/references)
141 ) {
142 4752 ++condemned_catalogs_;
143
2/2
✓ Branch 1 taken 900 times.
✓ Branch 2 taken 1476 times.
4752 if (data.catalog->IsRoot())
144 1800 ++condemned_trees_;
145
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2376 times.
4752 if (configuration_.verbose) {
147 ✗ if (data.catalog->IsRoot()) {
148 ✗ const uint64_t rev = data.catalog->revision();
149 ✗ const time_t mtime = static_cast<time_t>(data.catalog->GetLastModified());
150 ✗ LogCvmfs(kLogGc, kLogStdout | kLogDebug,
151 "Sweeping Revision %" PRIu64 " (%s)", rev,
152 StringifyTime(mtime, true).c_str());
153 }
154 ✗ PrintCatalogTreeEntry(data.tree_level, data.catalog);
155 }
156
157 // all the objects referenced from this catalog need to be checked against the
158 // the preserved hashes in the hash_filter_ and possibly deleted
159
1/2
✓ Branch 1 taken 2376 times.
✗ Branch 2 not taken.
4752 const HashVector &referenced_hashes = data.catalog->GetReferencedObjects();
160 4752 typename HashVector::const_iterator i = referenced_hashes.begin();
161 4752 const typename HashVector::const_iterator iend = referenced_hashes.end();
162
2/2
✓ Branch 2 taken 14364 times.
✓ Branch 3 taken 2376 times.
33480 for (; i != iend; ++i) {
163
1/2
✓ Branch 2 taken 14364 times.
✗ Branch 3 not taken.
28728 CheckAndSweep(*i);
164 }
165
166 // the catalog itself is also condemned and needs to be removed
167
1/2
✓ Branch 2 taken 2376 times.
✗ Branch 3 not taken.
4752 CheckAndSweep(data.catalog->hash());
168
169 4752 float threshold = static_cast<float>(condemned_trees_)
170 4752 / static_cast<float>(unreferenced_trees_);
171
2/2
✓ Branch 0 taken 900 times.
✓ Branch 1 taken 1476 times.
4752 if (threshold > last_reported_status_ + 0.1) {
172
1/4
✓ Branch 2 taken 900 times.
✗ Branch 3 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3600 LogCvmfs(kLogGc, kLogStdout | kLogDebug,
173 " - %02.0f%% %" PRIu64 " / %" PRIu64
174 " unreferenced revisions removed [%s]",
175
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
1800 100.0 * threshold, condemned_trees_, unreferenced_trees_,
176 StringifyLocalTime(time(NULL)).c_str());
177 1800 last_reported_status_ = threshold;
178 }
179 4752 }
180
181
182 template<class CatalogTraversalT, class HashFilterT>
183 3456 void GarbageCollector<CatalogTraversalT, HashFilterT>::SweepExcludedDataObjects(
184 const TraversalCallbackDataTN &data) {
185
4/6
✓ Branch 1 taken 1728 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1728 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 1224 times.
✓ Branch 9 taken 504 times.
3456 if (!configuration_.inclusion_spec->IsExcluded(
186 3456 data.catalog->mountpoint().ToString())) {
187 2448 return;
188 }
189
190 1008 const HashVector &hashes = data.catalog->GetReferencedObjects();
191 1008 for (typename HashVector::const_iterator i = hashes.begin();
192
2/2
✓ Branch 2 taken 2628 times.
✓ Branch 3 taken 504 times.
6264 i != hashes.end();
193 5256 ++i) {
194
1/2
✓ Branch 2 taken 2628 times.
✗ Branch 3 not taken.
5256 CheckAndSweep(*i);
195 }
196 1008 CheckAndSweep(data.catalog->hash());
197 }
198
199
200 template<class CatalogTraversalT, class HashFilterT>
201 39744 void GarbageCollector<CatalogTraversalT, HashFilterT>::CheckAndSweep(
202 const shash::Any &hash) {
203
2/2
✓ Branch 1 taken 9504 times.
✓ Branch 2 taken 10368 times.
39744 if (!hash_filter_.Contains(hash)) {
204
2/2
✓ Branch 1 taken 8208 times.
✓ Branch 2 taken 1296 times.
19008 if (!hash_map_delete_requests_.Contains(hash)) {
205 16416 hash_map_delete_requests_.Fill(hash);
206 16416 Sweep(hash);
207 } else {
208 2592 ++duplicate_delete_requests_;
209
1/2
✓ Branch 3 taken 1296 times.
✗ Branch 4 not taken.
2592 LogCvmfs(kLogGc, kLogDebug, "Hash %s already marked as to delete",
210 hash.ToString().c_str());
211 }
212 }
213 39744 }
214
215
216 template<class CatalogTraversalT, class HashFilterT>
217 16416 void GarbageCollector<CatalogTraversalT, HashFilterT>::Sweep(
218 const shash::Any &hash) {
219 16416 ++condemned_objects_;
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8208 times.
16416 if (configuration_.extended_stats) {
221 ✗ if (!hash.HasSuffix() || hash.suffix == shash::kSuffixPartial) {
222 ✗ int64_t condemned_bytes = configuration_.uploader->GetObjectSize(hash);
223 ✗ if (condemned_bytes > 0) {
224 ✗ condemned_bytes_ += condemned_bytes;
225 }
226 }
227 }
228
229 16416 LogDeletion(hash);
230
2/2
✓ Branch 0 taken 468 times.
✓ Branch 1 taken 7740 times.
16416 if (configuration_.dry_run) {
231 936 return;
232 }
233
234 15480 configuration_.uploader->RemoveAsync(hash);
235 }
236
237
238 template<class CatalogTraversalT, class HashFilterT>
239 1944 bool GarbageCollector<CatalogTraversalT, HashFilterT>::RemoveCatalogFromReflog(
240 const shash::Any &catalog) {
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 972 times.
1944 assert(catalog.suffix == shash::kSuffixCatalog);
242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 972 times.
1944 return (configuration_.dry_run) ? true
243 1944 : configuration_.reflog->Remove(catalog);
244 }
245
246
247 template<class CatalogTraversalT, class HashFilterT>
248 1872 bool GarbageCollector<CatalogTraversalT, HashFilterT>::Collect() {
249 3744 if (configuration_.prune_partial_replica
250
6/6
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 792 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 900 times.
2088 && (configuration_.inclusion_spec == NULL
251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
216 || !configuration_.inclusion_spec->IsValid())) {
252 72 LogCvmfs(kLogGc, kLogStderr,
253 "pruning a partial replica requires a valid inclusion spec");
254 72 return false;
255 }
256
3/6
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 900 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 900 times.
1800 if (!AnalyzePreservedCatalogTree() || !CheckPreservedRevisions())
257 ✗ return false;
258
2/4
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 900 times.
✗ Branch 5 not taken.
1800 const bool success = SweepReflog() && SweepExcludedCatalogs();
259
260 // TODO(jblomer): turn current counters into perf::Counters
261
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 900 times.
1800 if (configuration_.statistics) {
262 ✗ perf::Counter *ctr_preserved_catalogs = configuration_.statistics->Register(
263 "gc.n_preserved_catalogs", "number of live catalogs");
264 ✗ perf::Counter *ctr_condemned_catalogs = configuration_.statistics->Register(
265 "gc.n_condemned_catalogs", "number of dead catalogs");
266 ✗ perf::Counter *ctr_condemned_objects = configuration_.statistics->Register(
267 "gc.n_condemned_objects", "number of deleted objects");
268 ✗ perf::Counter *ctr_condemned_bytes = configuration_.statistics->Register(
269 "gc.sz_condemned_bytes", "number of deleted bytes");
270 perf::Counter
271 ✗ *ctr_duplicate_delete_requests = configuration_.statistics->Register(
272 "gc.n_duplicate_delete_requests",
273 "number of duplicated delete requests");
274 ✗ ctr_preserved_catalogs->Set(preserved_catalog_count());
275 ✗ ctr_condemned_catalogs->Set(condemned_catalog_count());
276 ✗ ctr_condemned_objects->Set(condemned_objects_count());
277 ✗ ctr_condemned_bytes->Set(condemned_bytes_count());
278 ✗ ctr_duplicate_delete_requests->Set(duplicate_delete_requests());
279 }
280 1800 return success;
281 }
282
283
284 template<class CatalogTraversalT, class HashFilterT>
285 1800 bool GarbageCollector<CatalogTraversalT,
286 HashFilterT>::AnalyzePreservedCatalogTree() {
287
1/2
✓ Branch 4 taken 900 times.
✗ Branch 5 not taken.
1800 LogCvmfs(kLogGc, kLogStdout, " --> marking unreferenced objects [%s]",
288 StringifyLocalTime(time(NULL)).c_str());
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 900 times.
1800 if (configuration_.verbose) {
290 ✗ LogCvmfs(kLogGc, kLogStdout | kLogDebug,
291 "Preserving data objects in latest revision");
292 }
293
294 typename CatalogTraversalT::CallbackTN
295 1800 *callback = traversal_.RegisterListener(
296 &GarbageCollector<CatalogTraversalT,
297 HashFilterT>::PreserveDataObjects,
298 this);
299
300 1800 bool success = traversal_.Traverse();
301 1800 oldest_trunk_catalog_found_ = true;
302
2/4
✓ Branch 0 taken 900 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 900 times.
✗ Branch 4 not taken.
1800 success = success && traversal_.TraverseNamedSnapshots();
303 1800 traversal_.UnregisterListener(callback);
304
305 1800 return success;
306 }
307
308
309 template<class CatalogTraversalT, class HashFilterT>
310 1800 bool GarbageCollector<CatalogTraversalT,
311 HashFilterT>::CheckPreservedRevisions() {
312 1800 const bool keeps_revisions = (preserved_catalog_count() > 0);
313
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1800 if (!keeps_revisions && configuration_.verbose) {
314 ✗ LogCvmfs(kLogGc, kLogStderr | kLogDebug,
315 "This would delete everything! Abort.");
316 }
317
318 1800 return keeps_revisions;
319 }
320
321
322 template<class CatalogTraversalT, class HashFilterT>
323 1800 bool GarbageCollector<CatalogTraversalT, HashFilterT>::SweepExcludedCatalogs() {
324
2/2
✓ Branch 0 taken 792 times.
✓ Branch 1 taken 108 times.
1800 if (!configuration_.prune_partial_replica)
325 1584 return true;
326
327
2/4
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
216 LogCvmfs(kLogGc, kLogStdout, " --> pruning excluded subtrees [%s]",
328 StringifyLocalTime(time(NULL)).c_str());
329 // Excluded catalogs listed in the reflog are already removed by SweepReflog.
330 // This pass covers those missing from the reflog. It needs a fresh traversal
331 // because the marking traversal remembers all visited catalogs.
332
2/4
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
216 CatalogTraversalT traversal(GetTraversalParams(configuration_));
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
216 if (use_reflog_timestamps_)
334 ✗ traversal.SetCatalogInfoShim(&catalog_info_shim_);
335
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 typename CatalogTraversalT::CallbackTN *callback = traversal.RegisterListener(
336 &GarbageCollector<CatalogTraversalT,
337 HashFilterT>::SweepExcludedDataObjects,
338 this);
339
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 bool success = traversal.Traverse();
340
3/6
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
216 success = success && traversal.TraverseNamedSnapshots();
341
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 traversal.UnregisterListener(callback);
342
1/2
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
216 configuration_.uploader->WaitForUpload();
343
3/6
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
216 return success && configuration_.uploader->GetNumberOfErrors() == 0;
344 216 }
345
346
347 template<class CatalogTraversalT, class HashFilterT>
348 1800 bool GarbageCollector<CatalogTraversalT, HashFilterT>::SweepReflog() {
349
2/4
✓ Branch 2 taken 900 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 900 times.
✗ Branch 7 not taken.
1800 LogCvmfs(kLogGc, kLogStdout, " --> sweeping unreferenced objects [%s]",
350 StringifyLocalTime(time(NULL)).c_str());
351
352 1800 const ReflogTN *reflog = configuration_.reflog;
353 1800 std::vector<shash::Any> catalogs;
354
4/8
✓ Branch 0 taken 900 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 900 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 900 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 900 times.
1800 if (NULL == reflog || !reflog->List(SqlReflog::kRefCatalog, &catalogs)) {
355 ✗ LogCvmfs(kLogGc, kLogStderr, "Failed to list catalog reference log");
356 ✗ return false;
357 }
358
359 typename CatalogTraversalT::CallbackTN
360
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
1800 *callback = traversal_.RegisterListener(
361 &GarbageCollector<CatalogTraversalT, HashFilterT>::SweepDataObjects,
362 this);
363
364 1800 std::vector<shash::Any> to_sweep;
365 1800 std::vector<shash::Any>::const_iterator i = catalogs.begin();
366 1800 std::vector<shash::Any>::const_iterator iend = catalogs.end();
367
2/2
✓ Branch 2 taken 4032 times.
✓ Branch 3 taken 900 times.
9864 for (; i != iend; ++i) {
368
3/4
✓ Branch 2 taken 4032 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 972 times.
✓ Branch 5 taken 3060 times.
8064 if (!hash_filter_.Contains(*i)) {
369
1/2
✓ Branch 2 taken 972 times.
✗ Branch 3 not taken.
1944 to_sweep.push_back(*i);
370 }
371 }
372 1800 unreferenced_trees_ = to_sweep.size();
373
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
1800 bool success = traversal_.TraverseList(to_sweep,
374 CatalogTraversalT::kDepthFirst);
375
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
1800 traversal_.UnregisterListener(callback);
376
377 1800 i = to_sweep.begin();
378 1800 iend = to_sweep.end();
379
2/2
✓ Branch 1 taken 972 times.
✓ Branch 2 taken 900 times.
3744 for (; i != iend; ++i) {
380
3/6
✓ Branch 0 taken 972 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 972 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 972 times.
✗ Branch 7 not taken.
1944 success = success && RemoveCatalogFromReflog(*i);
381 }
382
383
1/2
✓ Branch 1 taken 900 times.
✗ Branch 2 not taken.
1800 configuration_.uploader->WaitForUpload();
384
2/4
✓ Branch 2 taken 900 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 900 times.
✗ Branch 7 not taken.
1800 LogCvmfs(kLogGc, kLogStdout, " --> done garbage collecting [%s]",
385 StringifyLocalTime(time(NULL)).c_str());
386
3/6
✓ Branch 0 taken 900 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 900 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 900 times.
✗ Branch 6 not taken.
1800 return success && (configuration_.uploader->GetNumberOfErrors() == 0);
387 1800 }
388
389
390 template<class CatalogTraversalT, class HashFilterT>
391 ✗ void GarbageCollector<CatalogTraversalT, HashFilterT>::PrintCatalogTreeEntry(
392 const unsigned int tree_level, const CatalogTN *catalog) const {
393 ✗ std::string tree_indent;
394 ✗ for (unsigned int i = 0; i < tree_level; ++i) {
395 ✗ tree_indent += "\u2502 ";
396 }
397 ✗ tree_indent += "\u251C\u2500 ";
398
399 ✗ const std::string hash_string = catalog->hash().ToString();
400 ✗ const std::string path = (catalog->mountpoint().IsEmpty())
401 ? "/"
402 : catalog->mountpoint().ToString();
403
404 ✗ LogCvmfs(kLogGc, kLogStdout, "%s%s %s", tree_indent.c_str(),
405 hash_string.c_str(), path.c_str());
406 ✗ LogCvmfs(kLogGc, kLogDebug, "catalog tree entry: %s %s", hash_string.c_str(),
407 path.c_str());
408 }
409
410
411 template<class CatalogTraversalT, class HashFilterT>
412 16416 void GarbageCollector<CatalogTraversalT, HashFilterT>::LogDeletion(
413 const shash::Any &hash) const {
414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8208 times.
16416 if (configuration_.verbose) {
415 ✗ LogCvmfs(kLogGc, kLogStdout | kLogDebug, "Sweep: %s",
416 hash.ToStringWithSuffix().c_str());
417 }
418
419
2/2
✓ Branch 1 taken 396 times.
✓ Branch 2 taken 7812 times.
16416 if (configuration_.has_deletion_log()) {
420
1/2
✓ Branch 3 taken 396 times.
✗ Branch 4 not taken.
792 const int written = fprintf(configuration_.deleted_objects_logfile, "%s\n",
421 hash.ToStringWithSuffix().c_str());
422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 396 times.
792 if (written < 0) {
423 ✗ LogCvmfs(kLogGc, kLogStderr, "failed to write to deleted objects log");
424 }
425 }
426 16416 }
427
428 #endif // CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_IMPL_H_
429