about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2008-06-18T14·20+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2008-06-18T14·20+0000
commitd3aa183beb774c20cb77052248cf45e684d134fb (patch)
treedff630ec4a8a0af08added558a1f6b753edfd5dd
parenta8f3b02092fcc08fb25fb327d0188ffc888120bb (diff)
* 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).

-rw-r--r--src/libmain/shared.cc2
-rw-r--r--src/libmain/shared.hh3
-rw-r--r--src/libstore/gc.cc25
-rw-r--r--src/libstore/store-api.cc11
-rw-r--r--src/libstore/store-api.hh10
-rw-r--r--src/nix-store/nix-store.cc8
6 files changed, 47 insertions, 12 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index a67d2c47085c..76d510efebfc 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 62f505189f83..c38eeaf48131 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 0caf1ce4e627..8f5a1b6e5c99 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 0d516c198d3b..ac31601bef77 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -2,10 +2,21 @@
 #include "globals.hh"
 #include "util.hh"
 
+#include <stdint.h>
+
 
 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 760e71adc70b..b2a2dc7a53ec 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 9618823ea681..b59ff27bb30c 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);