aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-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
8 files changed, 64 insertions, 13 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index ab1011981..71560b2d0 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 3e4150d89..56e64369a 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 3f7242884..d4f40afa2 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 3a7b22048..389be33a3 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 2391fd9e8..9b9d74f7e 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 62feee0ea..b11191c09 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 6fbe97931..67d230ca7 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 65f5fc100..2700b6719 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;