| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/garbage_collection/garbage_collector.h |
| Date: | 2026-10-25 02:40:14 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 28 | 31 | 90.3% |
| Branches: | 2 | 4 | 50.0% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | * | ||
| 4 | * The GarbageCollector class is figuring out which data objects (represented by | ||
| 5 | * their content hashes) can be deleted as outdated garbage. | ||
| 6 | * Garbage collection is performed on the granularity of catalog revisions, thus | ||
| 7 | * a complete repository revision is either considered to be outdated or active. | ||
| 8 | * This way, a mountable repository revision stays completely usable (no nested | ||
| 9 | * catalogs or data objects become unavailable). A revision is defined by it's | ||
| 10 | * root catalog; the revision numbers of nested catalogs are irrelevant, since | ||
| 11 | * they might be referenced by newer (preserved) repository revisions. | ||
| 12 | * Thus, garbage objects are those that are _not_ referenced by any of the pre- | ||
| 13 | * served root catalogs or their direct subordinate nested catalog try. | ||
| 14 | * | ||
| 15 | * We use a two-stage approach: | ||
| 16 | * | ||
| 17 | * 1st Stage - Initialization | ||
| 18 | * The GarbageCollector is reading all the catalogs that are meant | ||
| 19 | * to be preserved. It builds up a filter (HashFilterT) containing | ||
| 20 | * all content hashes that are _not_ to be deleted | ||
| 21 | * | ||
| 22 | * 2nd Stage - Sweeping | ||
| 23 | * The initialized HashFilterT is presented with all content | ||
| 24 | * hashes found in condemned catalogs and decides if they are | ||
| 25 | * referenced by the preserved catalog revisions or not. | ||
| 26 | * | ||
| 27 | * The GarbageCollector is templated with CatalogTraversalT mainly for | ||
| 28 | * testability and with HashFilterT as an instance of the Strategy Pattern to | ||
| 29 | * abstract from the actual hash filtering method to be used. | ||
| 30 | */ | ||
| 31 | |||
| 32 | #ifndef CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_H_ | ||
| 33 | #define CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_H_ | ||
| 34 | |||
| 35 | #include <inttypes.h> | ||
| 36 | |||
| 37 | #include <vector> | ||
| 38 | |||
| 39 | #include "catalog_traversal_parallel.h" | ||
| 40 | #include "garbage_collection/hash_filter.h" | ||
| 41 | #include "path_filters/inclusion_spec.h" | ||
| 42 | #include "statistics.h" | ||
| 43 | #include "upload_facility.h" | ||
| 44 | |||
| 45 | template<class CatalogTraversalT, class HashFilterT> | ||
| 46 | class GarbageCollector { | ||
| 47 | protected: | ||
| 48 | typedef typename CatalogTraversalT::ObjectFetcherTN ObjectFetcherTN; | ||
| 49 | typedef typename ObjectFetcherTN::HistoryTN HistoryTN; | ||
| 50 | typedef typename ObjectFetcherTN::ReflogTN ReflogTN; | ||
| 51 | typedef typename CatalogTraversalT::CatalogTN CatalogTN; | ||
| 52 | typedef typename CatalogTraversalT::CallbackDataTN TraversalCallbackDataTN; | ||
| 53 | typedef typename CatalogTraversalT::Parameters TraversalParameters; | ||
| 54 | typedef std::vector<shash::Any> HashVector; | ||
| 55 | |||
| 56 | public: | ||
| 57 | struct Configuration { | ||
| 58 | static const uint64_t kFullHistory; | ||
| 59 | static const uint64_t kNoHistory; | ||
| 60 | static const time_t kNoTimestamp; | ||
| 61 | static const shash::Any kLatestHistoryDatabase; | ||
| 62 | |||
| 63 | 2088 | Configuration() | |
| 64 | 2088 | : uploader(NULL) | |
| 65 | 2088 | , object_fetcher(NULL) | |
| 66 | 2088 | , reflog(NULL) | |
| 67 | 2088 | , keep_history_depth(kFullHistory) | |
| 68 | 2088 | , keep_history_timestamp(kNoTimestamp) | |
| 69 | 2088 | , dry_run(false) | |
| 70 | 2088 | , verbose(false) | |
| 71 | 2088 | , deleted_objects_logfile(NULL) | |
| 72 | 2088 | , statistics(NULL) | |
| 73 | 2088 | , extended_stats(false) | |
| 74 | 2088 | , num_threads(8) | |
| 75 | 2088 | , prune_partial_replica(false) | |
| 76 | 2088 | , inclusion_spec(NULL) { } | |
| 77 | |||
| 78 | 26448 | bool has_deletion_log() const { return deleted_objects_logfile != NULL; } | |
| 79 | |||
| 80 | upload::AbstractUploader *uploader; | ||
| 81 | ObjectFetcherTN *object_fetcher; | ||
| 82 | ReflogTN *reflog; | ||
| 83 | uint64_t keep_history_depth; | ||
| 84 | time_t keep_history_timestamp; | ||
| 85 | bool dry_run; | ||
| 86 | bool verbose; | ||
| 87 | FILE *deleted_objects_logfile; | ||
| 88 | perf::Statistics *statistics; | ||
| 89 | bool extended_stats; | ||
| 90 | unsigned int num_threads; | ||
| 91 | bool prune_partial_replica; | ||
| 92 | const catalog::InclusionSpec *inclusion_spec; | ||
| 93 | }; | ||
| 94 | |||
| 95 | public: | ||
| 96 | explicit GarbageCollector(const Configuration &configuration); | ||
| 97 | |||
| 98 | void UseReflogTimestamps(); | ||
| 99 | bool Collect(); | ||
| 100 | |||
| 101 | 5336 | uint64_t preserved_catalog_count() const { return preserved_catalogs_; } | |
| 102 | 1102 | uint64_t condemned_catalog_count() const { return condemned_catalogs_; } | |
| 103 | 290 | uint64_t condemned_objects_count() const { return condemned_objects_; } | |
| 104 | ✗ | uint64_t duplicate_delete_requests() const { | |
| 105 | ✗ | return duplicate_delete_requests_; | |
| 106 | } | ||
| 107 | ✗ | uint64_t condemned_bytes_count() const { return condemned_bytes_; } | |
| 108 | 1218 | uint64_t oldest_trunk_catalog() const { return oldest_trunk_catalog_; } | |
| 109 | |||
| 110 | protected: | ||
| 111 | TraversalParameters GetTraversalParams(const Configuration &configuration); | ||
| 112 | |||
| 113 | void PreserveDataObjects(const TraversalCallbackDataTN &data); | ||
| 114 | void SweepDataObjects(const TraversalCallbackDataTN &data); | ||
| 115 | void SweepExcludedDataObjects(const TraversalCallbackDataTN &data); | ||
| 116 | |||
| 117 | bool AnalyzePreservedCatalogTree(); | ||
| 118 | bool CheckPreservedRevisions(); | ||
| 119 | bool SweepReflog(); | ||
| 120 | bool SweepExcludedCatalogs(); | ||
| 121 | |||
| 122 | void CheckAndSweep(const shash::Any &hash); | ||
| 123 | void Sweep(const shash::Any &hash); | ||
| 124 | bool RemoveCatalogFromReflog(const shash::Any &catalog); | ||
| 125 | |||
| 126 | void PrintCatalogTreeEntry(const unsigned int tree_level, | ||
| 127 | const CatalogTN *catalog) const; | ||
| 128 | void LogDeletion(const shash::Any &hash) const; | ||
| 129 | |||
| 130 | private: | ||
| 131 | class ReflogBasedInfoShim | ||
| 132 | : public swissknife::CatalogTraversalInfoShim<CatalogTN> { | ||
| 133 | public: | ||
| 134 | 3132 | explicit ReflogBasedInfoShim(ReflogTN *reflog) : reflog_(reflog) { | |
| 135 | 3132 | pthread_mutex_init(&reflog_mutex_, NULL); | |
| 136 | 3132 | } | |
| 137 | 1566 | virtual ~ReflogBasedInfoShim() { pthread_mutex_destroy(&reflog_mutex_); } | |
| 138 | 522 | virtual uint64_t GetLastModified(const CatalogTN *catalog) { | |
| 139 | uint64_t timestamp; | ||
| 140 | 1044 | MutexLockGuard m(&reflog_mutex_); | |
| 141 |
1/2✓ Branch 2 taken 522 times.
✗ Branch 3 not taken.
|
1044 | bool retval = reflog_->GetCatalogTimestamp(catalog->hash(), ×tamp); |
| 142 |
1/2✓ Branch 0 taken 522 times.
✗ Branch 1 not taken.
|
2088 | return retval ? timestamp : catalog->GetLastModified(); |
| 143 | 1044 | } | |
| 144 | |||
| 145 | private: | ||
| 146 | ReflogTN *reflog_; | ||
| 147 | pthread_mutex_t reflog_mutex_; | ||
| 148 | }; | ||
| 149 | |||
| 150 | const Configuration configuration_; | ||
| 151 | ReflogBasedInfoShim catalog_info_shim_; | ||
| 152 | CatalogTraversalT traversal_; | ||
| 153 | HashFilterT hash_filter_; | ||
| 154 | HashFilterT hash_map_delete_requests_; | ||
| 155 | |||
| 156 | |||
| 157 | bool use_reflog_timestamps_; | ||
| 158 | /** | ||
| 159 | * A marker for the garbage collection grace period, the time span that is | ||
| 160 | * walked back from the current head catalog. There can be named snapshots | ||
| 161 | * older than this snapshot. The oldest_trunk_catalog_ is used as a marker | ||
| 162 | * for when to remove auxiliary files (meta info, history, ...). | ||
| 163 | */ | ||
| 164 | uint64_t oldest_trunk_catalog_; | ||
| 165 | bool oldest_trunk_catalog_found_; | ||
| 166 | uint64_t preserved_catalogs_; | ||
| 167 | /** | ||
| 168 | * Number of catalogs in the reflog that are to be deleted (in fact, some of | ||
| 169 | * them might not exist anymore). | ||
| 170 | */ | ||
| 171 | uint64_t unreferenced_trees_; | ||
| 172 | /** | ||
| 173 | * Number of root catalogs garbage collected, count grows as GC progresses | ||
| 174 | */ | ||
| 175 | uint64_t condemned_trees_; | ||
| 176 | /** | ||
| 177 | * Number of catalogs garbage collected, count grows as GC progresses | ||
| 178 | */ | ||
| 179 | uint64_t condemned_catalogs_; | ||
| 180 | /** | ||
| 181 | * Keeps track if the last status report issued, between 0 and 1 | ||
| 182 | */ | ||
| 183 | float last_reported_status_; | ||
| 184 | |||
| 185 | uint64_t condemned_objects_; | ||
| 186 | uint64_t condemned_bytes_; | ||
| 187 | uint64_t duplicate_delete_requests_; | ||
| 188 | }; | ||
| 189 | |||
| 190 | #include "garbage_collector_impl.h" | ||
| 191 | |||
| 192 | #endif // CVMFS_GARBAGE_COLLECTION_GARBAGE_COLLECTOR_H_ | ||
| 193 |