about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2012-05-30T02·59-0400
committerEelco Dolstra <eelco.dolstra@logicblox.com>2012-05-30T02·59-0400
commit4bc4da331aae13be8a39e768524a854597addd8a (patch)
tree5fccb805c1d27bd82c935f87a97f1a6cd3b29176
parent2c26985835cf82ed5d2979c3a400f72f6aeba32f (diff)
Reserve some disk space for the garbage collector
We can't open a SQLite database if the disk is full.  Since this
prevents the garbage collector from running when it's most needed, we
reserve some dummy space that we can free just before doing a garbage
collection.  This actually revives some old code from the Berkeley DB
days.

Fixes #27.
-rw-r--r--src/libstore/local-store.cc20
-rw-r--r--src/libstore/local-store.hh2
-rw-r--r--src/libstore/remote-store.cc6
-rw-r--r--src/libstore/remote-store.hh2
-rw-r--r--src/libstore/store-api.cc4
-rw-r--r--src/libstore/store-api.hh2
-rw-r--r--src/libstore/worker-protocol.hh2
-rw-r--r--src/nix-store/nix-store.cc2
-rw-r--r--src/nix-worker/nix-worker.cc6
9 files changed, 35 insertions, 11 deletions
diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc
index f04436b7f659..1ce62aeafcef 100644
--- a/src/libstore/local-store.cc
+++ b/src/libstore/local-store.cc
@@ -195,7 +195,7 @@ void checkStoreNotSymlink()
 }
 
 
-LocalStore::LocalStore()
+LocalStore::LocalStore(bool reserveSpace)
 {
     substitutablePathsLoaded = false;
     
@@ -221,6 +221,24 @@ LocalStore::LocalStore()
   
     checkStoreNotSymlink();
 
+    /* We can't open a SQLite database if the disk is full.  Since
+       this prevents the garbage collector from running when it's most
+       needed, we reserve some dummy space that we can free just
+       before doing a garbage collection. */
+    try {
+        Path reservedPath = nixDBPath + "/reserved";
+        if (reserveSpace) {
+            int reservedSize = queryIntSetting("gc-reserved-space", 1024 * 1024);
+            struct stat st;
+            if (stat(reservedPath.c_str(), &st) == -1 ||
+                st.st_size != reservedSize)
+                writeFile(reservedPath, string(reservedSize, 'X'));
+        }
+        else
+            deletePath(reservedPath);
+    } catch (SysError & e) { /* don't care about errors */
+    }
+
     /* Acquire the big fat lock in shared mode to make sure that no
        schema upgrade is in progress. */
     try {
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 8e3cbe5ce11b..0ff3e7b39ff6 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -91,7 +91,7 @@ public:
 
     /* Initialise the local store, upgrading the schema if
        necessary. */
-    LocalStore();
+    LocalStore(bool reserveSpace = true);
 
     ~LocalStore();
     
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 0fd759b07b4b..cbcf860543e2 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -43,7 +43,7 @@ RemoteStore::RemoteStore()
 }
 
 
-void RemoteStore::openConnection()
+void RemoteStore::openConnection(bool reserveSpace)
 {
     if (initialised) return;
     initialised = true;
@@ -75,6 +75,8 @@ void RemoteStore::openConnection()
         if (GET_PROTOCOL_MAJOR(daemonVersion) != GET_PROTOCOL_MAJOR(PROTOCOL_VERSION))
             throw Error("Nix daemon protocol version not supported");
         writeInt(PROTOCOL_VERSION, to);
+        if (GET_PROTOCOL_MINOR(daemonVersion) >= 11)
+            writeInt(reserveSpace, to);
         processStderr();
     }
     catch (Error & e) {
@@ -462,7 +464,7 @@ Roots RemoteStore::findRoots()
 
 void RemoteStore::collectGarbage(const GCOptions & options, GCResults & results)
 {
-    openConnection();
+    openConnection(false);
     
     writeInt(wopCollectGarbage, to);
     writeInt(options.action, to);
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index c5853ef53646..823e694dd379 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -86,7 +86,7 @@ private:
     unsigned int daemonVersion;
     bool initialised;
 
-    void openConnection();
+    void openConnection(bool reserveSpace = true);
 
     void processStderr(Sink * sink = 0, Source * source = 0);
 
diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc
index 19bc048abd02..b64988268cdb 100644
--- a/src/libstore/store-api.cc
+++ b/src/libstore/store-api.cc
@@ -322,10 +322,10 @@ namespace nix {
 boost::shared_ptr<StoreAPI> store;
 
 
-boost::shared_ptr<StoreAPI> openStore()
+boost::shared_ptr<StoreAPI> openStore(bool reserveSpace)
 {
     if (getEnv("NIX_REMOTE") == "")
-        return boost::shared_ptr<StoreAPI>(new LocalStore());
+        return boost::shared_ptr<StoreAPI>(new LocalStore(reserveSpace));
     else
         return boost::shared_ptr<StoreAPI>(new RemoteStore());
 }
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index a62a648168f9..fa766d12e119 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -327,7 +327,7 @@ extern boost::shared_ptr<StoreAPI> store;
 
 /* Factory method: open the Nix database, either through the local or
    remote implementation. */
-boost::shared_ptr<StoreAPI> openStore();
+boost::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
 
 
 /* Display a set of paths in human-readable form (i.e., between quotes
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 6e0aadad4ae0..c1ea7f758470 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -8,7 +8,7 @@ namespace nix {
 #define WORKER_MAGIC_1 0x6e697863
 #define WORKER_MAGIC_2 0x6478696f
 
-#define PROTOCOL_VERSION 0x10a
+#define PROTOCOL_VERSION 0x10b
 #define GET_PROTOCOL_MAJOR(x) ((x) & 0xff00)
 #define GET_PROTOCOL_MINOR(x) ((x) & 0x00ff)
 
diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc
index fa96725b1b48..36c04168259c 100644
--- a/src/nix-store/nix-store.cc
+++ b/src/nix-store/nix-store.cc
@@ -843,7 +843,7 @@ void run(Strings args)
     if (!op) throw UsageError("no operation specified");
 
     if (op != opDump && op != opRestore) /* !!! hack */
-        store = openStore();
+        store = openStore(op != opGC);
 
     op(opFlags, opArgs);
 }
diff --git a/src/nix-worker/nix-worker.cc b/src/nix-worker/nix-worker.cc
index c69b9de506d6..b7bce20bd412 100644
--- a/src/nix-worker/nix-worker.cc
+++ b/src/nix-worker/nix-worker.cc
@@ -625,8 +625,12 @@ static void processConnection()
             throw Error("if you run `nix-worker' as root, then you MUST set `build-users-group'!");
 #endif
 
+        bool reserveSpace = true;
+        if (GET_PROTOCOL_MINOR(clientVersion) >= 11)
+            reserveSpace = readInt(from) != 0;
+
         /* Open the store. */
-        store = boost::shared_ptr<StoreAPI>(new LocalStore());
+        store = boost::shared_ptr<StoreAPI>(new LocalStore(reserveSpace));
 
         stopWork();
         to.flush();