diff options
author | Eelco Dolstra <e.dolstra@tudelft.nl> | 2005-02-01 12:36:25 +0000 |
---|---|---|
committer | Eelco Dolstra <e.dolstra@tudelft.nl> | 2005-02-01 12:36:25 +0000 |
commit | dcc37c236c66ba463bd61fec23d046485d8a412f (patch) | |
tree | b1a34feaf2a9a0ca0e0bad89c1671289de9e19d2 /src/libstore | |
parent | a6b65fd5e107416588a6572a88518d8816abcb12 (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.cc | 46 | ||||
-rw-r--r-- | src/libstore/gc.hh | 3 | ||||
-rw-r--r-- | src/libstore/store.cc | 6 | ||||
-rw-r--r-- | src/libstore/store.hh | 2 |
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., |