* Garbage collector: option `--max-freed' to stop after at least N

bytes have been freed, `--max-links' to stop when the Nix store
  directory has fewer than N hard links (the latter being important
  for very large Nix stores on filesystems with a 32000 subdirectories
  limit).
This commit is contained in:
Eelco Dolstra 2008-06-18 14:20:16 +00:00
parent a8f3b02092
commit d3aa183beb
6 changed files with 47 additions and 12 deletions

View file

@ -58,7 +58,7 @@ static void setLogType(string lt)
} }
static unsigned int getIntArg(const string & opt, unsigned int getIntArg(const string & opt,
Strings::iterator & i, const Strings::iterator & end) Strings::iterator & i, const Strings::iterator & end)
{ {
++i; ++i;

View file

@ -26,6 +26,9 @@ namespace nix {
Path makeRootName(const Path & gcRoot, int & counter); Path makeRootName(const Path & gcRoot, int & counter);
void printGCWarning(); void printGCWarning();
unsigned int getIntArg(const string & opt,
Strings::iterator & i, const Strings::iterator & end);
/* Whether we're running setuid. */ /* Whether we're running setuid. */
extern bool setuidMode; extern bool setuidMode;

View file

@ -439,6 +439,9 @@ Paths topoSortPaths(const PathSet & paths)
} }
struct GCLimitReached { };
void LocalStore::tryToDelete(const GCOptions & options, GCResults & results, void LocalStore::tryToDelete(const GCOptions & options, GCResults & results,
const PathSet & livePaths, const PathSet & tempRootsClosed, PathSet & done, const PathSet & livePaths, const PathSet & tempRootsClosed, PathSet & done,
const Path & path) const Path & path)
@ -512,6 +515,21 @@ void LocalStore::tryToDelete(const GCOptions & options, GCResults & results,
results.bytesFreed += bytesFreed; results.bytesFreed += bytesFreed;
results.blocksFreed += blocksFreed; results.blocksFreed += blocksFreed;
if (results.bytesFreed > options.maxFreed) {
printMsg(lvlInfo, format("deleted more than %1% bytes; stopping") % options.maxFreed);
throw GCLimitReached();
}
if (options.maxLinks) {
struct stat st;
if (stat(nixStore.c_str(), &st) == -1)
throw SysError(format("statting `%1%'") % nixStore);
if (st.st_nlink < options.maxLinks) {
printMsg(lvlInfo, format("link count on the store has dropped below %1%; stopping") % options.maxLinks);
throw GCLimitReached();
}
}
#ifndef __CYGWIN__ #ifndef __CYGWIN__
if (fdLock != -1) if (fdLock != -1)
/* Write token to stale (deleted) lock file. */ /* Write token to stale (deleted) lock file. */
@ -650,8 +668,11 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results)
: format("deleting garbage...")); : format("deleting garbage..."));
PathSet done; PathSet done;
try {
foreach (PathSet::iterator, i, storePaths) foreach (PathSet::iterator, i, storePaths)
tryToDelete(options, results, livePaths, tempRootsClosed, done, *i); tryToDelete(options, results, livePaths, tempRootsClosed, done, *i);
} catch (GCLimitReached & e) {
}
} }

View file

@ -2,10 +2,21 @@
#include "globals.hh" #include "globals.hh"
#include "util.hh" #include "util.hh"
#include <stdint.h>
namespace nix { namespace nix {
GCOptions::GCOptions()
{
action = gcDeleteDead;
ignoreLiveness = false;
maxFreed = ULLONG_MAX;
maxLinks = 0;
}
bool StoreAPI::hasSubstitutes(const Path & path) bool StoreAPI::hasSubstitutes(const Path & path)
{ {
PathSet paths = querySubstitutablePaths(); PathSet paths = querySubstitutablePaths();

View file

@ -60,16 +60,10 @@ struct GCOptions
unsigned long long maxFreed; unsigned long long maxFreed;
/* Stop after the number of hard links to the Nix store directory /* Stop after the number of hard links to the Nix store directory
has dropped to at least `maxLinks'. */ has dropped below `maxLinks'. */
unsigned int maxLinks; unsigned int maxLinks;
GCOptions() GCOptions();
{
action = gcDeleteDead;
ignoreLiveness = false;
maxFreed = ULLONG_MAX;
maxLinks = UINT_MAX;
}
}; };

View file

@ -528,6 +528,8 @@ static void opGC(Strings opFlags, Strings opArgs)
else if (*i == "--print-live") options.action = GCOptions::gcReturnLive; else if (*i == "--print-live") options.action = GCOptions::gcReturnLive;
else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead; else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead;
else if (*i == "--delete") options.action = GCOptions::gcDeleteDead; else if (*i == "--delete") options.action = GCOptions::gcDeleteDead;
else if (*i == "--max-freed") options.maxFreed = getIntArg(*i, i, opFlags.end());
else if (*i == "--max-links") options.maxLinks = getIntArg(*i, i, opFlags.end());
else throw UsageError(format("bad sub-operation `%1%' in GC") % *i); else throw UsageError(format("bad sub-operation `%1%' in GC") % *i);
PrintFreed freed( PrintFreed freed(
@ -744,8 +746,12 @@ void run(Strings args)
} }
else if (arg == "--indirect") else if (arg == "--indirect")
indirectRoot = true; indirectRoot = true;
else if (arg[0] == '-') else if (arg[0] == '-') {
opFlags.push_back(arg); opFlags.push_back(arg);
if (arg == "--max-freed" || arg == "--max-links") { /* !!! hack */
if (i != args.end()) opFlags.push_back(*i++);
}
}
else else
opArgs.push_back(arg); opArgs.push_back(arg);