diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index a67d2c470..76d510efe 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -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) { ++i; diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 62f505189..c38eeaf48 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -26,6 +26,9 @@ namespace nix { Path makeRootName(const Path & gcRoot, int & counter); void printGCWarning(); +unsigned int getIntArg(const string & opt, + Strings::iterator & i, const Strings::iterator & end); + /* Whether we're running setuid. */ extern bool setuidMode; diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 0caf1ce4e..8f5a1b6e5 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -439,6 +439,9 @@ Paths topoSortPaths(const PathSet & paths) } +struct GCLimitReached { }; + + void LocalStore::tryToDelete(const GCOptions & options, GCResults & results, const PathSet & livePaths, const PathSet & tempRootsClosed, PathSet & done, const Path & path) @@ -512,6 +515,21 @@ void LocalStore::tryToDelete(const GCOptions & options, GCResults & results, results.bytesFreed += bytesFreed; 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__ if (fdLock != -1) /* Write token to stale (deleted) lock file. */ @@ -650,8 +668,11 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) : format("deleting garbage...")); PathSet done; - foreach (PathSet::iterator, i, storePaths) - tryToDelete(options, results, livePaths, tempRootsClosed, done, *i); + try { + foreach (PathSet::iterator, i, storePaths) + tryToDelete(options, results, livePaths, tempRootsClosed, done, *i); + } catch (GCLimitReached & e) { + } } diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index 0d516c198..ac31601be 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -2,10 +2,21 @@ #include "globals.hh" #include "util.hh" +#include + namespace nix { +GCOptions::GCOptions() +{ + action = gcDeleteDead; + ignoreLiveness = false; + maxFreed = ULLONG_MAX; + maxLinks = 0; +} + + bool StoreAPI::hasSubstitutes(const Path & path) { PathSet paths = querySubstitutablePaths(); diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 760e71adc..b2a2dc7a5 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -60,16 +60,10 @@ struct GCOptions unsigned long long maxFreed; /* 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; - GCOptions() - { - action = gcDeleteDead; - ignoreLiveness = false; - maxFreed = ULLONG_MAX; - maxLinks = UINT_MAX; - } + GCOptions(); }; diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 9618823ea..b59ff27bb 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -528,6 +528,8 @@ static void opGC(Strings opFlags, Strings opArgs) else if (*i == "--print-live") options.action = GCOptions::gcReturnLive; else if (*i == "--print-dead") options.action = GCOptions::gcReturnDead; 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); PrintFreed freed( @@ -744,8 +746,12 @@ void run(Strings args) } else if (arg == "--indirect") indirectRoot = true; - else if (arg[0] == '-') + else if (arg[0] == '-') { opFlags.push_back(arg); + if (arg == "--max-freed" || arg == "--max-links") { /* !!! hack */ + if (i != args.end()) opFlags.push_back(*i++); + } + } else opArgs.push_back(arg);