* Acquire a global GC lock to prevent new temporary root files from
being created after the garbage collector has read the temproots directory. This blocks the creation of new processes, but the garbage collector could periodically release the GC lock to allow them to run.
This commit is contained in:
parent
89c9bc11ab
commit
32fa82a56a
3 changed files with 36 additions and 19 deletions
|
@ -12,17 +12,30 @@
|
|||
#include <unistd.h>
|
||||
|
||||
|
||||
/* Acquire the global GC lock. */
|
||||
static AutoCloseFD openGCLock(LockType lockType)
|
||||
{
|
||||
#if 0
|
||||
Path fnGCLock = (format("%1%/%2%/%3%")
|
||||
% nixStateDir % tempRootsDir % getpid()).str();
|
||||
static string gcLockName = "gc.lock";
|
||||
|
||||
fdTempRoots = open(fnTempRoots.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (fdTempRoots == -1)
|
||||
throw SysError(format("opening temporary roots file `%1%'") % fnTempRoots);
|
||||
#endif
|
||||
|
||||
/* Acquire the global GC lock. This is used to prevent new Nix
|
||||
processes from starting after the temporary root files have been
|
||||
read. To be precise: when they try to create a new temporary root
|
||||
file, they will block until the garbage collector has finished /
|
||||
yielded the GC lock. */
|
||||
static int openGCLock(LockType lockType)
|
||||
{
|
||||
Path fnGCLock = (format("%1%/%2%")
|
||||
% nixStateDir % gcLockName).str();
|
||||
|
||||
AutoCloseFD fdGCLock = open(fnGCLock.c_str(), O_RDWR | O_CREAT, 0600);
|
||||
if (fdGCLock == -1)
|
||||
throw SysError(format("opening global GC lock `%1%'") % fnGCLock);
|
||||
|
||||
lockFile(fdGCLock, lockType, true);
|
||||
|
||||
/* !!! Restrict read permission on the GC root. Otherwise any
|
||||
process that can open the file for reading can DoS the
|
||||
collector. */
|
||||
|
||||
return fdGCLock.borrow();
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,10 +55,14 @@ void addTempRoot(const Path & path)
|
|||
fnTempRoots = (format("%1%/%2%/%3%")
|
||||
% nixStateDir % tempRootsDir % getpid()).str();
|
||||
|
||||
AutoCloseFD fdGCLock = openGCLock(ltRead);
|
||||
|
||||
fdTempRoots = open(fnTempRoots.c_str(), O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
if (fdTempRoots == -1)
|
||||
throw SysError(format("opening temporary roots file `%1%'") % fnTempRoots);
|
||||
|
||||
fdGCLock.close();
|
||||
|
||||
debug(format("acquiring read lock on `%1%'") % fnTempRoots);
|
||||
lockFile(fdTempRoots, ltRead, true);
|
||||
|
||||
|
@ -188,13 +205,10 @@ void collectGarbage(const PathSet & roots, GCAction action,
|
|||
{
|
||||
result.clear();
|
||||
|
||||
/* !!! TODO: Acquire the global GC root. This prevents
|
||||
/* Acquire the global GC root. This prevents
|
||||
a) New roots from being added.
|
||||
b) Processes from creating new temporary root files. */
|
||||
|
||||
/* !!! Restrict read permission on the GC root. Otherwise any
|
||||
process that can open the file for reading can DoS the
|
||||
collector. */
|
||||
AutoCloseFD fdGCLock = openGCLock(ltWrite);
|
||||
|
||||
/* Determine the live paths which is just the closure of the
|
||||
roots under the `references' relation. */
|
||||
|
|
|
@ -36,10 +36,10 @@ nix-pull.sh: dependencies.nix
|
|||
gc.sh: dependencies.nix
|
||||
gc-concurrent.sh: gc-concurrent.nix gc-concurrent2.nix
|
||||
|
||||
#TESTS = init.sh hash.sh lang.sh simple.sh dependencies.sh locking.sh parallel.sh \
|
||||
# build-hook.sh substitutes.sh substitutes2.sh fallback.sh nix-push.sh gc.sh \
|
||||
# gc-concurrent.sh verify.sh nix-pull.sh
|
||||
TESTS = init.sh gc-concurrent.sh
|
||||
TESTS = init.sh hash.sh lang.sh simple.sh dependencies.sh locking.sh parallel.sh \
|
||||
build-hook.sh substitutes.sh substitutes2.sh fallback.sh nix-push.sh gc.sh \
|
||||
gc-concurrent.sh verify.sh nix-pull.sh
|
||||
#TESTS = init.sh gc-concurrent.sh
|
||||
|
||||
XFAIL_TESTS =
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ outPath2=$($TOP/src/nix-store/nix-store -q $storeExpr2)
|
|||
|
||||
ls -l test-tmp/state/temproots
|
||||
|
||||
ln -s $storeExpr2 "$NIX_LOCALSTATE_DIR"/nix/gcroots/foo2
|
||||
|
||||
# Start build #1 in the background. It starts immediately.
|
||||
$TOP/src/nix-store/nix-store -rvv "$storeExpr1" &
|
||||
pid1=$!
|
||||
|
@ -31,4 +33,5 @@ wait $pid2
|
|||
cat $outPath1/foobar
|
||||
cat $outPath1/input-2/bar
|
||||
|
||||
# Build #2 should have failed because its derivation got garbage collected.
|
||||
cat $outPath2/foobar
|
||||
|
|
Loading…
Reference in a new issue