Skip to content

Commit

Permalink
fs: add garbage collection
Browse files Browse the repository at this point in the history
Add automatic garbage collection in zenfs.

The garbage collection, if enabled, kicks in under 30% capacity left and
cleans out zones with 1% valid data in them to start off with, increasing
to 58% at 99% capacity.

This scheme reduces space amplification down to as little as 5%
(from ~10-15%) in my testing.

Signed-off-by: Hans Holmberg <[email protected]>
  • Loading branch information
yhr committed Oct 7, 2022
1 parent 35b80b8 commit 724cfc5
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
63 changes: 63 additions & 0 deletions fs/fs_zenfs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <string.h>
#include <unistd.h>

#include <set>
#include <sstream>
#include <utility>
#include <vector>
Expand Down Expand Up @@ -258,11 +259,67 @@ ZenFS::~ZenFS() {
zbd_->LogZoneUsage();
LogFiles();

if (gc_worker_) {
run_gc_worker_ = false;
gc_worker_->join();
}

meta_log_.reset(nullptr);
ClearFiles();
delete zbd_;
}

void ZenFS::GCWorker() {
while (run_gc_worker_) {
usleep(1000 * 1000 * 10);

uint64_t non_free = zbd_->GetUsedSpace() + zbd_->GetReclaimableSpace();
uint64_t free = zbd_->GetFreeSpace();
uint64_t free_percent = (100 * free) / (free + non_free);
ZenFSSnapshot snapshot;
ZenFSSnapshotOptions options;

if (free_percent > GC_START_LEVEL) continue;

options.zone_ = 1;
options.zone_file_ = 1;
options.log_garbage_ = 1;

GetZenFSSnapshot(snapshot, options);

uint64_t threshold = (100 - GC_SLOPE * (GC_START_LEVEL - free_percent));
std::set<uint64_t> migrate_zones_start;
for (const auto& zone : snapshot.zones_) {
if (zone.capacity == 0) {
uint64_t garbage_percent_approx =
100 - 100 * zone.used_capacity / zone.max_capacity;
if (garbage_percent_approx > threshold &&
garbage_percent_approx < 100) {
migrate_zones_start.emplace(zone.start);
}
}
}

std::vector<ZoneExtentSnapshot*> migrate_exts;
for (auto& ext : snapshot.extents_) {
if (migrate_zones_start.find(ext.zone_start) !=
migrate_zones_start.end()) {
migrate_exts.push_back(&ext);
}
}

if (migrate_exts.size() > 0) {
IOStatus s;
Info(logger_, "Garbage collecting %d extents \n",
(int)migrate_exts.size());
s = MigrateExtents(migrate_exts);
if (!s.ok()) {
Error(logger_, "Garbage collection failed");
}
}
}
}

IOStatus ZenFS::Repair() {
std::map<std::string, std::shared_ptr<ZoneFile>>::iterator it;
for (it = files_.begin(); it != files_.end(); it++) {
Expand Down Expand Up @@ -1421,6 +1478,12 @@ Status ZenFS::Mount(bool readonly) {
IOStatus status = zbd_->ResetUnusedIOZones();
if (!status.ok()) return status;
Info(logger_, " Done");

if (superblock_->IsGCEnabled()) {
Info(logger_, "Starting garbage collection worker");
run_gc_worker_ = true;
gc_worker_.reset(new std::thread(&ZenFS::GCWorker, this));
}
}

LogFiles();
Expand Down
10 changes: 10 additions & 0 deletions fs/fs_zenfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace fs = std::filesystem;
#endif

#include <memory>
#include <thread>

#include "io_zenfs.h"
#include "metrics.h"
Expand Down Expand Up @@ -145,6 +146,9 @@ class ZenFS : public FileSystemWrapper {

std::shared_ptr<Logger> GetLogger() { return logger_; }

std::unique_ptr<std::thread> gc_worker_ = nullptr;
bool run_gc_worker_ = false;

struct ZenFSMetadataWriter : public MetadataWriter {
ZenFS* zenFS;
IOStatus Persist(ZoneFile* zoneFile) {
Expand Down Expand Up @@ -452,6 +456,12 @@ class ZenFS : public FileSystemWrapper {
IOStatus MigrateFileExtents(
const std::string& fname,
const std::vector<ZoneExtentSnapshot*>& migrate_exts);

private:
const uint64_t GC_START_LEVEL =
20; /* Enable GC when < 20% free space available */
const uint64_t GC_SLOPE = 3; /* GC agressiveness */
void GCWorker();
};
#endif // !defined(ROCKSDB_LITE) && defined(OS_LINUX)

Expand Down

0 comments on commit 724cfc5

Please sign in to comment.