GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/garbage_collection/garbage_collector_impl.h
Date: 2026-11-01 02:41:19
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 4806 GarbageCollector<CatalogTraversalT, HashFilterT>::GarbageCollector(
32 const Configuration &configuration)
33 4806 : configuration_(configuration)
34 4806 , catalog_info_shim_(configuration.reflog)
35
1/2
✓ Branch 1 taken 2403 times.
✗ Branch 2 not taken.
4806 , traversal_(
36
1/2
✓ Branch 1 taken 2403 times.
✗ Branch 2 not taken.
4806 GarbageCollector<CatalogTraversalT, HashFilterT>::GetTraversalParams(
37 configuration))
38 4806 , hash_filter_()
39 4806 , hash_map_delete_requests_()
40 4806 , use_reflog_timestamps_(false)
41 4806 , oldest_trunk_catalog_(static_cast<uint64_t>(-1))
42 4806 , oldest_trunk_catalog_found_(false)
43 4806 , preserved_catalogs_(0)
44 4806 , unreferenced_trees_(0)
45 4806 , condemned_trees_(0)
46 4806 , condemned_catalogs_(0)
47 4806 , last_reported_status_(0.0)
48 4806 , condemned_objects_(0)
49 4806 , condemned_bytes_(0)
50 4806 , duplicate_delete_requests_(0) {
51
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2403 times.
4806 assert(configuration_.uploader != NULL);
52 4806 }
53
54
55 template<class CatalogTraversalT, class HashFilterT>
56 178 void GarbageCollector<CatalogTraversalT, HashFilterT>::UseReflogTimestamps() {
57 178 traversal_.SetCatalogInfoShim(&catalog_info_shim_);
58 178 use_reflog_timestamps_ = true;
59 178 }
60
61
62 template<class CatalogTraversalT, class HashFilterT>
63 typename GarbageCollector<CatalogTraversalT, HashFilterT>::TraversalParameters
64 5340 GarbageCollector<CatalogTraversalT, HashFilterT>::GetTraversalParams(
65 const GarbageCollector<CatalogTraversalT, HashFilterT>::Configuration
66 &config) {
67 5340 TraversalParameters params;
68 5340 params.object_fetcher = config.object_fetcher;
69 5340 params.history = config.keep_history_depth;
70 5340 params.timestamp = config.keep_history_timestamp;
71 5340 params.no_repeat_history = true;
72 5340 params.ignore_load_failure = true;
73 5340 params.quiet = !config.verbose;
74 5340 params.num_threads = config.num_threads;
75 5340 return params;
76 }
77
78
79 template<class CatalogTraversalT, class HashFilterT>
80 52866 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 105732 if (configuration_.prune_partial_replica
89
12/20
✓ Branch 0 taken 4272 times.
✓ Branch 1 taken 22161 times.
✓ Branch 3 taken 4272 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 4272 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1246 times.
✓ Branch 9 taken 3026 times.
✓ Branch 10 taken 4272 times.
✓ Branch 11 taken 22161 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4272 times.
✓ Branch 14 taken 22161 times.
✓ Branch 16 taken 1246 times.
✓ Branch 17 taken 25187 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
61410 && configuration_.inclusion_spec->IsExcluded(
90
1/2
✓ Branch 1 taken 4272 times.
✗ Branch 2 not taken.
8544 data.catalog->mountpoint().ToString())) {
91 2492 return;
92 }
93 50374 ++preserved_catalogs_;
94
95
2/2
✓ Branch 1 taken 7565 times.
✓ Branch 2 taken 17622 times.
50374 if (data.catalog->IsRoot()) {
96 30260 const uint64_t mtime = use_reflog_timestamps_
97
2/2
✓ Branch 0 taken 445 times.
✓ Branch 1 taken 7120 times.
16020 ? catalog_info_shim_.GetLastModified(
98
1/2
✓ Branch 1 taken 445 times.
✗ Branch 2 not taken.
890 data.catalog)
99 14240 : data.catalog->GetLastModified();
100
2/2
✓ Branch 0 taken 5874 times.
✓ Branch 1 taken 1691 times.
15130 if (!oldest_trunk_catalog_found_)
101 11748 oldest_trunk_catalog_ = std::min(oldest_trunk_catalog_, mtime);
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7565 times.
15130 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 7565 times.
15130 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 25187 times.
✗ Branch 3 not taken.
50374 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 25187 times.
✗ Branch 2 not taken.
50374 const HashVector &referenced_hashes = data.catalog->GetReferencedObjects();
127 50374 typename HashVector::const_iterator i = referenced_hashes.begin();
128 50374 const typename HashVector::const_iterator iend = referenced_hashes.end();
129
2/2
✓ Branch 2 taken 130652 times.
✓ Branch 3 taken 25187 times.
311678 for (; i != iend; ++i) {
130
1/2
✓ Branch 2 taken 130652 times.
✗ Branch 3 not taken.
261304 hash_filter_.Fill(*i);
131 }
132 }
133
134
135 template<class CatalogTraversalT, class HashFilterT>
136 11748 void GarbageCollector<CatalogTraversalT, HashFilterT>::SweepDataObjects(
137 const GarbageCollector<CatalogTraversalT,
138 HashFilterT>::TraversalCallbackDataTN
139 &data // NOLINT(runtime/references)
140 ) {
141 11748 ++condemned_catalogs_;
142
2/2
✓ Branch 1 taken 2225 times.
✓ Branch 2 taken 3649 times.
11748 if (data.catalog->IsRoot())
143 4450 ++condemned_trees_;
144
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5874 times.
11748 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 5874 times.
✗ Branch 2 not taken.
11748 const HashVector &referenced_hashes = data.catalog->GetReferencedObjects();
159 11748 typename HashVector::const_iterator i = referenced_hashes.begin();
160 11748 const typename HashVector::const_iterator iend = referenced_hashes.end();
161
2/2
✓ Branch 2 taken 35511 times.
✓ Branch 3 taken 5874 times.
82770 for (; i != iend; ++i) {
162
1/2
✓ Branch 2 taken 35511 times.
✗ Branch 3 not taken.
71022 CheckAndSweep(*i);
163 }
164
165 // the catalog itself is also condemned and needs to be removed
166
1/2
✓ Branch 2 taken 5874 times.
✗ Branch 3 not taken.
11748 CheckAndSweep(data.catalog->hash());
167
168 11748 float threshold = static_cast<float>(condemned_trees_)
169 11748 / static_cast<float>(unreferenced_trees_);
170
2/2
✓ Branch 0 taken 2225 times.
✓ Branch 1 taken 3649 times.
11748 if (threshold > last_reported_status_ + 0.1) {
171
1/4
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8900 LogCvmfs(kLogGc, kLogStdout | kLogDebug,
172 " - %02.0f%% %" PRIu64 " / %" PRIu64
173 " unreferenced revisions removed [%s]",
174
1/2
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
4450 100.0 * threshold, condemned_trees_, unreferenced_trees_,
175 RfcTimestamp().c_str());
176 4450 last_reported_status_ = threshold;
177 }
178 11748 }
179
180
181 template<class CatalogTraversalT, class HashFilterT>
182 8544 void GarbageCollector<CatalogTraversalT, HashFilterT>::SweepExcludedDataObjects(
183 const TraversalCallbackDataTN &data) {
184
4/6
✓ Branch 1 taken 4272 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4272 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 3026 times.
✓ Branch 9 taken 1246 times.
8544 if (!configuration_.inclusion_spec->IsExcluded(
185 8544 data.catalog->mountpoint().ToString())) {
186 6052 return;
187 }
188
189 2492 const HashVector &hashes = data.catalog->GetReferencedObjects();
190 2492 for (typename HashVector::const_iterator i = hashes.begin();
191
2/2
✓ Branch 2 taken 6497 times.
✓ Branch 3 taken 1246 times.
15486 i != hashes.end();
192 12994 ++i) {
193
1/2
✓ Branch 2 taken 6497 times.
✗ Branch 3 not taken.
12994 CheckAndSweep(*i);
194 }
195 2492 CheckAndSweep(data.catalog->hash());
196 }
197
198
199 template<class CatalogTraversalT, class HashFilterT>
200 98256 void GarbageCollector<CatalogTraversalT, HashFilterT>::CheckAndSweep(
201 const shash::Any &hash) {
202
2/2
✓ Branch 1 taken 23496 times.
✓ Branch 2 taken 25632 times.
98256 if (!hash_filter_.Contains(hash)) {
203
2/2
✓ Branch 1 taken 20292 times.
✓ Branch 2 taken 3204 times.
46992 if (!hash_map_delete_requests_.Contains(hash)) {
204 40584 hash_map_delete_requests_.Fill(hash);
205 40584 Sweep(hash);
206 } else {
207 6408 ++duplicate_delete_requests_;
208
1/2
✓ Branch 3 taken 3204 times.
✗ Branch 4 not taken.
6408 LogCvmfs(kLogGc, kLogDebug, "Hash %s already marked as to delete",
209 hash.ToString().c_str());
210 }
211 }
212 98256 }
213
214
215 template<class CatalogTraversalT, class HashFilterT>
216 40584 void GarbageCollector<CatalogTraversalT, HashFilterT>::Sweep(
217 const shash::Any &hash) {
218 40584 ++condemned_objects_;
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20292 times.
40584 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 40584 LogDeletion(hash);
229
2/2
✓ Branch 0 taken 1157 times.
✓ Branch 1 taken 19135 times.
40584 if (configuration_.dry_run) {
230 2314 return;
231 }
232
233 38270 configuration_.uploader->RemoveAsync(hash);
234 }
235
236
237 template<class CatalogTraversalT, class HashFilterT>
238 4806 bool GarbageCollector<CatalogTraversalT, HashFilterT>::RemoveCatalogFromReflog(
239 const shash::Any &catalog) {
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2403 times.
4806 assert(catalog.suffix == shash::kSuffixCatalog);
241
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2403 times.
4806 return (configuration_.dry_run) ? true
242 4806 : configuration_.reflog->Remove(catalog);
243 }
244
245
246 template<class CatalogTraversalT, class HashFilterT>
247 4628 bool GarbageCollector<CatalogTraversalT, HashFilterT>::Collect() {
248 9256 if (configuration_.prune_partial_replica
249
6/6
✓ Branch 0 taken 356 times.
✓ Branch 1 taken 1958 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 89 times.
✓ Branch 4 taken 89 times.
✓ Branch 5 taken 2225 times.
5162 && (configuration_.inclusion_spec == NULL
250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
534 || !configuration_.inclusion_spec->IsValid())) {
251 178 LogCvmfs(kLogGc, kLogStderr,
252 "pruning a partial replica requires a valid inclusion spec");
253 178 return false;
254 }
255
3/6
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2225 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2225 times.
4450 if (!AnalyzePreservedCatalogTree() || !CheckPreservedRevisions())
256 ✗ return false;
257
2/4
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2225 times.
✗ Branch 5 not taken.
4450 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 2225 times.
4450 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 4450 return success;
280 }
281
282
283 template<class CatalogTraversalT, class HashFilterT>
284 4450 bool GarbageCollector<CatalogTraversalT,
285 HashFilterT>::AnalyzePreservedCatalogTree() {
286
1/2
✓ Branch 3 taken 2225 times.
✗ Branch 4 not taken.
4450 LogCvmfs(kLogGc, kLogStdout, " --> marking unreferenced objects [%s]",
287 RfcTimestamp().c_str());
288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2225 times.
4450 if (configuration_.verbose) {
289 ✗ LogCvmfs(kLogGc, kLogStdout | kLogDebug,
290 "Preserving data objects in latest revision");
291 }
292
293 typename CatalogTraversalT::CallbackTN
294 4450 *callback = traversal_.RegisterListener(
295 &GarbageCollector<CatalogTraversalT,
296 HashFilterT>::PreserveDataObjects,
297 this);
298
299 4450 bool success = traversal_.Traverse();
300 4450 oldest_trunk_catalog_found_ = true;
301
2/4
✓ Branch 0 taken 2225 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2225 times.
✗ Branch 4 not taken.
4450 success = success && traversal_.TraverseNamedSnapshots();
302 4450 traversal_.UnregisterListener(callback);
303
304 4450 return success;
305 }
306
307
308 template<class CatalogTraversalT, class HashFilterT>
309 4450 bool GarbageCollector<CatalogTraversalT,
310 HashFilterT>::CheckPreservedRevisions() {
311 4450 const bool keeps_revisions = (preserved_catalog_count() > 0);
312
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4450 if (!keeps_revisions && configuration_.verbose) {
313 ✗ LogCvmfs(kLogGc, kLogStderr | kLogDebug,
314 "This would delete everything! Abort.");
315 }
316
317 4450 return keeps_revisions;
318 }
319
320
321 template<class CatalogTraversalT, class HashFilterT>
322 4450 bool GarbageCollector<CatalogTraversalT, HashFilterT>::SweepExcludedCatalogs() {
323
2/2
✓ Branch 0 taken 1958 times.
✓ Branch 1 taken 267 times.
4450 if (!configuration_.prune_partial_replica)
324 3916 return true;
325
326
2/4
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 267 times.
✗ Branch 6 not taken.
534 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 267 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 267 times.
✗ Branch 5 not taken.
534 CatalogTraversalT traversal(GetTraversalParams(configuration_));
332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
534 if (use_reflog_timestamps_)
333 ✗ traversal.SetCatalogInfoShim(&catalog_info_shim_);
334
1/2
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
534 typename CatalogTraversalT::CallbackTN *callback = traversal.RegisterListener(
335 &GarbageCollector<CatalogTraversalT,
336 HashFilterT>::SweepExcludedDataObjects,
337 this);
338
1/2
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
534 bool success = traversal.Traverse();
339
3/6
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 267 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 267 times.
✗ Branch 6 not taken.
534 success = success && traversal.TraverseNamedSnapshots();
340
1/2
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
534 traversal.UnregisterListener(callback);
341
1/2
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
534 configuration_.uploader->WaitForUpload();
342
3/6
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 267 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 267 times.
✗ Branch 6 not taken.
534 return success && configuration_.uploader->GetNumberOfErrors() == 0;
343 534 }
344
345
346 template<class CatalogTraversalT, class HashFilterT>
347 4450 bool GarbageCollector<CatalogTraversalT, HashFilterT>::SweepReflog() {
348
2/4
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2225 times.
✗ Branch 6 not taken.
4450 LogCvmfs(kLogGc, kLogStdout, " --> sweeping unreferenced objects [%s]",
349 RfcTimestamp().c_str());
350
351 4450 const ReflogTN *reflog = configuration_.reflog;
352 4450 std::vector<shash::Any> catalogs;
353
4/8
✓ Branch 0 taken 2225 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2225 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2225 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2225 times.
4450 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 2225 times.
✗ Branch 2 not taken.
4450 *callback = traversal_.RegisterListener(
360 &GarbageCollector<CatalogTraversalT, HashFilterT>::SweepDataObjects,
361 this);
362
363 4450 std::vector<shash::Any> to_sweep;
364 4450 std::vector<shash::Any>::const_iterator i = catalogs.begin();
365 4450 std::vector<shash::Any>::const_iterator iend = catalogs.end();
366
2/2
✓ Branch 2 taken 9968 times.
✓ Branch 3 taken 2225 times.
24386 for (; i != iend; ++i) {
367
3/4
✓ Branch 2 taken 9968 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2403 times.
✓ Branch 5 taken 7565 times.
19936 if (!hash_filter_.Contains(*i)) {
368
1/2
✓ Branch 2 taken 2403 times.
✗ Branch 3 not taken.
4806 to_sweep.push_back(*i);
369 }
370 }
371 4450 unreferenced_trees_ = to_sweep.size();
372
1/2
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
4450 bool success = traversal_.TraverseList(to_sweep,
373 CatalogTraversalT::kDepthFirst);
374
1/2
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
4450 traversal_.UnregisterListener(callback);
375
376 4450 i = to_sweep.begin();
377 4450 iend = to_sweep.end();
378
2/2
✓ Branch 1 taken 2403 times.
✓ Branch 2 taken 2225 times.
9256 for (; i != iend; ++i) {
379
3/6
✓ Branch 0 taken 2403 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 2403 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2403 times.
✗ Branch 7 not taken.
4806 success = success && RemoveCatalogFromReflog(*i);
380 }
381
382
1/2
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
4450 configuration_.uploader->WaitForUpload();
383
2/4
✓ Branch 1 taken 2225 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2225 times.
✗ Branch 6 not taken.
4450 LogCvmfs(kLogGc, kLogStdout, " --> done garbage collecting [%s]",
384 RfcTimestamp().c_str());
385
3/6
✓ Branch 0 taken 2225 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 2225 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2225 times.
✗ Branch 6 not taken.
4450 return success && (configuration_.uploader->GetNumberOfErrors() == 0);
386 4450 }
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 40584 void GarbageCollector<CatalogTraversalT, HashFilterT>::LogDeletion(
412 const shash::Any &hash) const {
413
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20292 times.
40584 if (configuration_.verbose) {
414 ✗ LogCvmfs(kLogGc, kLogStdout | kLogDebug, "Sweep: %s",
415 hash.ToStringWithSuffix().c_str());
416 }
417
418
2/2
✓ Branch 1 taken 979 times.
✓ Branch 2 taken 19313 times.
40584 if (configuration_.has_deletion_log()) {
419
1/2
✓ Branch 3 taken 979 times.
✗ Branch 4 not taken.
1958 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 979 times.
1958 if (written < 0) {
422 ✗ LogCvmfs(kLogGc, kLogStderr, "failed to write to deleted objects log");
423 }
424 }
425 40584 }
426
427 #endif // CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_IMPL_H_
428