1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-07-06 21:41:48 +02:00

Add automatic garbage collection

Nix can now automatically run the garbage collector during builds or
while adding paths to the store. The option "min-free = <bytes>"
specifies that Nix should run the garbage collector whenever free
space in the Nix store drops below <bytes>. It will then delete
garbage until "max-free" bytes are available.

Garbage collection during builds is asynchronous; running builds are
not paused and new builds are not blocked. However, there also is a
synchronous GC run prior to the first build/substitution.

Currently, no old GC roots are deleted (as in "nix-collect-garbage
-d").
This commit is contained in:
Eelco Dolstra 2017-09-05 20:43:42 +02:00
parent b932ea58ec
commit 0b606aad46
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
6 changed files with 127 additions and 1 deletions

View file

@ -1,6 +1,7 @@
#include "derivations.hh"
#include "globals.hh"
#include "local-store.hh"
#include "finally.hh"
#include <functional>
#include <queue>
@ -9,6 +10,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
@ -845,4 +847,72 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
}
void LocalStore::autoGC(bool sync)
{
auto getAvail = [this]() {
struct statvfs st;
if (statvfs(realStoreDir.c_str(), &st))
throw SysError("getting filesystem info about '%s'", realStoreDir);
return (uint64_t) st.f_bavail * st.f_bsize;
};
std::shared_future<void> future;
{
auto state(_state.lock());
if (state->gcRunning) {
future = state->gcFuture;
debug("waiting for auto-GC to finish");
goto sync;
}
auto now = std::chrono::steady_clock::now();
if (now < state->lastGCCheck + std::chrono::seconds(5)) return;
auto avail = getAvail();
state->lastGCCheck = now;
if (avail >= settings.minFree || avail >= settings.maxFree) return;
if (avail > state->availAfterGC * 0.97) return;
state->gcRunning = true;
std::promise<void> promise;
future = state->gcFuture = promise.get_future().share();
std::thread([promise{std::move(promise)}, this, avail, getAvail]() mutable {
/* Wake up any threads waiting for the auto-GC to finish. */
Finally wakeup([&]() {
auto state(_state.lock());
state->gcRunning = false;
state->lastGCCheck = std::chrono::steady_clock::now();
promise.set_value();
});
printInfo("running auto-GC to free %d bytes", settings.maxFree - avail);
GCOptions options;
options.maxFreed = settings.maxFree - avail;
GCResults results;
collectGarbage(options, results);
_state.lock()->availAfterGC = getAvail();
}).detach();
}
sync:
// Wait for the future outside of the state lock.
if (sync) future.get();
}
}