aboutsummaryrefslogtreecommitdiff
path: root/src/libstore
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2005-02-01 12:36:25 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2005-02-01 12:36:25 +0000
commitdcc37c236c66ba463bd61fec23d046485d8a412f (patch)
treeb1a34feaf2a9a0ca0e0bad89c1671289de9e19d2 /src/libstore
parenta6b65fd5e107416588a6572a88518d8816abcb12 (diff)
* nix-store, nix-instantiate: added an option `--add-root' to
immediately add the result as a permanent GC root. This is the only way to prevent a race with the garbage collector. For instance, the old style ln -s $(nix-store -r $(nix-instantiate foo.nix)) \ /nix/var/nix/gcroots/result has two time windows in which the garbage collector can interfere (by GC'ing the derivation and the output, respectively). On the other hand, nix-store --add-root /nix/var/nix/gcroots/result -r \ $(nix-instantiate --add-root /nix/var/nix/gcroots/drv \ foo.nix) is safe. * nix-build: use `--add-root' to prevent GC races.
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/gc.cc46
-rw-r--r--src/libstore/gc.hh3
-rw-r--r--src/libstore/store.cc6
-rw-r--r--src/libstore/store.hh2
4 files changed, 54 insertions, 3 deletions
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index cff503784..ee9a369dc 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -39,6 +39,48 @@ static int openGCLock(LockType lockType)
}
+static void createDirs(const Path & path)
+{
+ if (path == "") return;
+ createDirs(dirOf(path));
+ if (!pathExists(path))
+ if (mkdir(path.c_str(), 0777) == -1)
+ throw SysError(format("creating directory `%1%'") % path);
+}
+
+
+Path addPermRoot(const Path & _storePath, const Path & _gcRoot)
+{
+ Path storePath(canonPath(_storePath));
+ Path gcRoot(canonPath(_gcRoot));
+
+ Path rootsDir = canonPath((format("%1%/%2%") % nixStateDir % "gcroots").str());
+
+ if (string(gcRoot, 0, rootsDir.size() + 1) != rootsDir + "/")
+ throw Error(format(
+ "path `%1%' is not a valid garbage collector root; "
+ "it's not in the `%1%' directory")
+ % gcRoot % rootsDir);
+
+ /* Grab the global GC root. This prevents the set of permanent
+ roots from increasing while a GC is in progress. */
+ AutoCloseFD fdGCLock = openGCLock(ltRead);
+
+ /* Create directories up to `gcRoot'. */
+ createDirs(dirOf(gcRoot));
+
+ /* Remove the old symlink. */
+ unlink(gcRoot.c_str());
+
+ /* And create the new own. */
+ if (symlink(storePath.c_str(), gcRoot.c_str()) == -1)
+ throw SysError(format("symlinking `%1%' to `%2%'")
+ % gcRoot % storePath);
+
+ return gcRoot;
+}
+
+
static string tempRootsDir = "temproots";
/* The file to which we write our temporary roots. */
@@ -210,6 +252,9 @@ void collectGarbage(const PathSet & roots, GCAction action,
b) Processes from creating new temporary root files. */
AutoCloseFD fdGCLock = openGCLock(ltWrite);
+ /* !!! Find the roots here, after we've grabbed the GC lock, since
+ the set of permanent roots cannot increase now. */
+
/* Determine the live paths which is just the closure of the
roots under the `references' relation. */
PathSet livePaths;
@@ -264,6 +309,7 @@ void collectGarbage(const PathSet & roots, GCAction action,
will not work anymore because we get cycles. */
storePaths = topoSort(storePaths2);
+ /* Try to delete store paths in the topologically sorted order. */
for (Paths::iterator i = storePaths.begin(); i != storePaths.end(); ++i) {
debug(format("considering deletion of `%1%'") % *i);
diff --git a/src/libstore/gc.hh b/src/libstore/gc.hh
index 91c5be914..03e1d7691 100644
--- a/src/libstore/gc.hh
+++ b/src/libstore/gc.hh
@@ -26,5 +26,8 @@ void addTempRoot(const Path & path);
as a (permanent) root. */
void removeTempRoots();
+/* Register a permanent GC root. */
+Path addPermRoot(const Path & storePath, const Path & gcRoot);
+
#endif /* !__GC_H */
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index c7b84e7c6..b915fce24 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -168,7 +168,7 @@ void copyPath(const Path & src, const Path & dst)
}
-static bool isInStore(const Path & path)
+bool isStorePath(const Path & path)
{
return path[0] == '/'
&& path.compare(0, nixStore.size(), nixStore) == 0
@@ -180,7 +180,7 @@ static bool isInStore(const Path & path)
void assertStorePath(const Path & path)
{
- if (!isInStore(path))
+ if (!isStorePath(path))
throw Error(format("path `%1%' is not in the Nix store") % path);
}
@@ -579,7 +579,7 @@ void verifyStore()
if (!pathExists(path)) {
printMsg(lvlError, format("path `%1%' disappeared") % path);
invalidatePath(path, txn);
- } else if (!isInStore(path)) {
+ } else if (!isStorePath(path)) {
printMsg(lvlError, format("path `%1%' is not in the Nix store") % path);
invalidatePath(path, txn);
} else
diff --git a/src/libstore/store.hh b/src/libstore/store.hh
index dce4eb1d6..3a0b7a713 100644
--- a/src/libstore/store.hh
+++ b/src/libstore/store.hh
@@ -62,6 +62,8 @@ void registerValidPath(const Transaction & txn,
/* Throw an exception if `path' is not directly in the Nix store. */
void assertStorePath(const Path & path);
+bool isStorePath(const Path & path);
+
/* "Fix", or canonicalise, the meta-data of the files in a store path
after it has been built. In particular:
- the last modification date on each file is set to 0 (i.e.,