about summary refs log tree commit diff
diff options
context:
space:
mode:
-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 f04436b7f6..1ce62aeafc 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 8e3cbe5ce1..0ff3e7b39f 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 0fd759b07b..cbcf860543 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 c5853ef536..823e694dd3 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 19bc048abd..b64988268c 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 a62a648168..fa766d12e1 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 6e0aadad4a..c1ea7f7584 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 fa96725b1b..36c0416825 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 c69b9de506..b7bce20bd4 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();