about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/libstore/build.cc4
-rw-r--r--src/libstore/gc.cc17
-rw-r--r--src/libstore/gc.hh6
-rw-r--r--src/libstore/local-store.hh4
-rw-r--r--src/libstore/remote-store.cc15
-rw-r--r--src/libstore/remote-store.hh4
-rw-r--r--src/libstore/store-api.hh25
-rw-r--r--src/libstore/worker-protocol.hh2
-rw-r--r--src/libutil/util.cc4
-rw-r--r--src/nix-env/main.cc4
-rw-r--r--src/nix-worker/main.cc13
11 files changed, 81 insertions, 17 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index ab1011981c..71560b2d0c 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -642,7 +642,7 @@ void DerivationGoal::haveStoreExpr()
 
     for (DerivationOutputs::iterator i = drv.outputs.begin();
          i != drv.outputs.end(); ++i)
-        addTempRoot(i->second.path);
+        store->addTempRoot(i->second.path);
 
     /* Check what outputs paths are not already valid. */
     PathSet invalidOutputs = checkPathValidity(false);
@@ -1714,7 +1714,7 @@ void SubstitutionGoal::init()
 {
     trace("init");
 
-    addTempRoot(storePath);
+    store->addTempRoot(storePath);
     
     /* If the path already exists we're done. */
     if (store->isValidPath(storePath)) {
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 3e4150d898..56e64369a7 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -76,6 +76,12 @@ void createSymlink(const Path & link, const Path & target, bool careful)
 }
 
 
+void LocalStore::syncWithGC()
+{
+    AutoCloseFD fdGCLock = openGCLock(ltRead);
+}
+
+
 Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
     bool indirect, bool allowOutsideRootsDir)
 {
@@ -83,10 +89,6 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
     Path gcRoot(canonPath(_gcRoot));
     assertStorePath(storePath);
 
-    /* Grab the global GC root.  This prevents the set of permanent
-       roots from increasing while a GC is in progress. */
-    AutoCloseFD fdGCLock = openGCLock(ltRead);
-
     if (indirect) {
         string hash = printHash32(hashString(htSHA1, gcRoot));
         Path realRoot = canonPath((format("%1%/%2%/auto/%3%")
@@ -110,6 +112,11 @@ Path addPermRoot(const Path & _storePath, const Path & _gcRoot,
         createSymlink(gcRoot, storePath, false);
     }
 
+    /* Grab the global GC root, causing us to block while a GC is in
+       progress.  This prevents the set of permanent roots from
+       increasing while a GC is in progress. */
+    store->syncWithGC();
+    
     return gcRoot;
 }
 
@@ -119,7 +126,7 @@ static Path fnTempRoots;
 static AutoCloseFD fdTempRoots;
 
 
-void addTempRoot(const Path & path)
+void LocalStore::addTempRoot(const Path & path)
 {
     /* Create the temporary roots file for this process. */
     if (fdTempRoots == -1) {
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index 3f7242884b..d4f40afa2a 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -26,12 +26,6 @@ typedef enum {
 void collectGarbage(GCAction action, const PathSet & pathsToDelete,
     bool ignoreLiveness, PathSet & result, unsigned long long & bytesFreed);
 
-/* Register a temporary GC root.  This root will automatically
-   disappear when this process exits.  WARNING: this function should
-   not be called inside a BDB transaction, otherwise we can
-   deadlock. */
-void addTempRoot(const Path & path);
-
 /* Remove the temporary roots file for this process.  Any temporary
    root becomes garbage after this point unless it has been registered
    as a (permanent) root. */
diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh
index 3a7b22048e..389be33a37 100644
--- a/src/libstore/local-store.hh
+++ b/src/libstore/local-store.hh
@@ -58,6 +58,10 @@ public:
     void buildDerivations(const PathSet & drvPaths);
 
     void ensurePath(const Path & path);
+
+    void addTempRoot(const Path & path);
+
+    void syncWithGC();
 };
 
 
diff --git a/src/libstore/remote-store.cc b/src/libstore/remote-store.cc
index 2391fd9e87..9b9d74f7e8 100644
--- a/src/libstore/remote-store.cc
+++ b/src/libstore/remote-store.cc
@@ -170,4 +170,19 @@ void RemoteStore::ensurePath(const Path & path)
 }
 
 
+void RemoteStore::addTempRoot(const Path & path)
+{
+    writeInt(wopAddTempRoot, to);
+    writeString(path, to);
+    readInt(from);
+}
+
+
+void RemoteStore::syncWithGC()
+{
+    writeInt(wopSyncWithGC, to);
+    readInt(from);
+}
+
+
 }
diff --git a/src/libstore/remote-store.hh b/src/libstore/remote-store.hh
index 62feee0eac..b11191c09d 100644
--- a/src/libstore/remote-store.hh
+++ b/src/libstore/remote-store.hh
@@ -47,6 +47,10 @@ public:
 
     void ensurePath(const Path & path);
 
+    void addTempRoot(const Path & path);
+
+    void syncWithGC();
+    
 private:
     Pipe toChild;
     Pipe fromChild;
diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh
index 6fbe979316..67d230ca77 100644
--- a/src/libstore/store-api.hh
+++ b/src/libstore/store-api.hh
@@ -86,6 +86,31 @@ public:
        may be made valid by running a substitute (if defined for the
        path). */
     virtual void ensurePath(const Path & path) = 0;
+
+    /* Add a store path as a temporary root of the garbage collector.
+       The root disappears as soon as we exit. */
+    virtual void addTempRoot(const Path & path) = 0;
+
+    /* Acquire the global GC lock, then immediately release it.  This
+       function must be called after registering a new permanent root,
+       but before exiting.  Otherwise, it is possible that a running
+       garbage collector doesn't see the new root and deletes the
+       stuff we've just built.  By acquiring the lock briefly, we
+       ensure that either:
+
+       - The collector is already running, and so we block until the
+         collector is finished.  The collector will know about our
+         *temporary* locks, which should include whatever it is we
+         want to register as a permanent lock.
+
+       - The collector isn't running, or it's just started but hasn't
+         acquired the GC lock yet.  In that case we get and release
+         the lock right away, then exit.  The collector scans the
+         permanent root and sees our's.
+
+       In either case the permanent root is seen by the collector. */
+    virtual void syncWithGC() = 0;
+
 };
 
 
diff --git a/src/libstore/worker-protocol.hh b/src/libstore/worker-protocol.hh
index 65f5fc100a..2700b67197 100644
--- a/src/libstore/worker-protocol.hh
+++ b/src/libstore/worker-protocol.hh
@@ -18,6 +18,8 @@ typedef enum {
     wopAddTextToStore,
     wopBuildDerivations,
     wopEnsurePath,
+    wopAddTempRoot,
+    wopSyncWithGC
 } WorkerOp;
 
 
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 5623b01312..6d96310dad 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -122,7 +122,7 @@ Path dirOf(const Path & path)
 {
     Path::size_type pos = path.rfind('/');
     if (pos == string::npos)
-        throw Error(format("invalid file name: %1%") % path);
+        throw Error(format("invalid file name `%1%'") % path);
     return pos == 0 ? "/" : Path(path, 0, pos);
 }
 
@@ -131,7 +131,7 @@ string baseNameOf(const Path & path)
 {
     Path::size_type pos = path.rfind('/');
     if (pos == string::npos)
-        throw Error(format("invalid file name %1% ") % path);
+        throw Error(format("invalid file name `%1%'") % path);
     return string(path, pos + 1);
 }
 
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
index 4f0b5eca90..f2988485cd 100644
--- a/src/nix-env/main.cc
+++ b/src/nix-env/main.cc
@@ -182,7 +182,7 @@ static void createUserEnv(EvalState & state, const DrvInfos & elems,
 
         /* This is only necessary when installing store paths, e.g.,
            `nix-env -i /nix/store/abcd...-foo'. */
-        addTempRoot(i->queryOutPath(state));
+        store->addTempRoot(i->queryOutPath(state));
         store->ensurePath(i->queryOutPath(state));
         
         references.insert(i->queryOutPath(state));
@@ -940,7 +940,7 @@ static void opSwitchProfile(Globals & globals,
     if (opArgs.size() != 1)
         throw UsageError(format("exactly one argument expected"));
 
-    Path profile = opArgs.front();
+    Path profile = absPath(opArgs.front());
     Path profileLink = getHomeDir() + "/.nix-profile";
 
     switchLink(profileLink, profile);
diff --git a/src/nix-worker/main.cc b/src/nix-worker/main.cc
index 95077e6531..fef2c2958a 100644
--- a/src/nix-worker/main.cc
+++ b/src/nix-worker/main.cc
@@ -127,6 +127,19 @@ void processConnection(Source & from, Sink & to)
             break;
         }
 
+        case wopAddTempRoot: {
+            Path path = readStorePath(from);
+            store->addTempRoot(path);
+            writeInt(1, to);
+            break;
+        }
+
+        case wopSyncWithGC: {
+            store->syncWithGC();
+            writeInt(1, to);
+            break;
+        }
+
         default:
             throw Error(format("invalid operation %1%") % op);
         }