GCC Code Coverage Report


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