* Build hooks: use nix-store --import. This prevents a redundant

scan for runtime dependencies (i.e. the local machine shouldn't do a
  scan that the remote machine has already done).  Also pipe directly
  into `nix-store --import': don't use a temporary file.
This commit is contained in:
Eelco Dolstra 2009-02-02 17:24:10 +00:00
parent 6f8c96d123
commit b682fae9d9
3 changed files with 29 additions and 22 deletions

View file

@ -192,7 +192,7 @@ my $buildFlags = "--max-silent-time $maxSilentTime";
# connection dies. Without it, the remote process might continue to # connection dies. Without it, the remote process might continue to
# run indefinitely (that is, until it next tries to write to # run indefinitely (that is, until it next tries to write to
# stdout/stderr). # stdout/stderr).
if (system("ssh -tt $sshOpts $hostName 'nix-store -rvvK $buildFlags $drvPath'") != 0) { if (system("ssh -tt $sshOpts $hostName 'nix-store --realise -K $buildFlags $drvPath > /dev/null'") != 0) {
# If we couldn't run ssh or there was an ssh problem (indicated by # If we couldn't run ssh or there was an ssh problem (indicated by
# exit code 255), then we return exit code 1; otherwise we assume # exit code 255), then we return exit code 1; otherwise we assume
# that the builder failed, which we indicated to Nix using exit # that the builder failed, which we indicated to Nix using exit
@ -209,17 +209,6 @@ foreach my $output (split '\n', $outputs) {
my $maybeSignRemote = ""; my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0; $maybeSignRemote = "--sign" if $UID != 0;
system("ssh $sshOpts $hostName 'nix-store --export $maybeSignRemote $output' > dump") == 0 system("ssh $sshOpts $hostName 'nix-store --export $maybeSignRemote $output' | @bindir@/nix-store --import > /dev/null") == 0
or die "cannot copy $output from $hostName: $?"; or die "cannot copy $output from $hostName: $?";
# This doesn't work yet, since the caller has a lock on the output
# path. We should move towards lock-free invocation of build
# hooks and substitutes.
#system("nix-store --import < dump") == 0
# or die "cannot import $output: $?";
# Hack: skip the first 8 bytes (the nix-store --export next
# archive marker). The archive follows.
system("(dd bs=1 count=8 of=/dev/null && cat) < dump | nix-store --restore $output") == 0
or die "cannot restore $output: $?";
} }

View file

@ -1240,6 +1240,12 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
initChild(); initChild();
string s;
foreach (DerivationOutputs::const_iterator, i, drv.outputs)
s += i->second.path + " ";
if (setenv("NIX_HELD_LOCKS", s.c_str(), 1))
throw SysError("setting an environment variable");
execl(buildHook.c_str(), buildHook.c_str(), execl(buildHook.c_str(), buildHook.c_str(),
(worker.canBuildMore() ? (string) "1" : "0").c_str(), (worker.canBuildMore() ? (string) "1" : "0").c_str(),
thisSystem.c_str(), thisSystem.c_str(),
@ -1945,13 +1951,21 @@ void DerivationGoal::computeClosure()
{ {
map<Path, PathSet> allReferences; map<Path, PathSet> allReferences;
map<Path, Hash> contentHashes; map<Path, Hash> contentHashes;
/* When using a build hook, the build hook can register the output
as valid (by doing `nix-store --import'). If so we don't have
to do anything here. */
if (usingBuildHook) {
bool allValid = true;
foreach (DerivationOutputs::iterator, i, drv.outputs)
if (!worker.store.isValidPath(i->second.path)) allValid = false;
if (allValid) return;
}
/* Check whether the output paths were created, and grep each /* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all output path to determine what other paths it references. Also make all
output paths read-only. */ output paths read-only. */
for (DerivationOutputs::iterator i = drv.outputs.begin(); foreach (DerivationOutputs::iterator, i, drv.outputs) {
i != drv.outputs.end(); ++i)
{
Path path = i->second.path; Path path = i->second.path;
if (!pathExists(path)) { if (!pathExists(path)) {
throw BuildError( throw BuildError(
@ -2043,14 +2057,11 @@ void DerivationGoal::computeClosure()
paths referenced by each of them. !!! this should be paths referenced by each of them. !!! this should be
atomic so that either all paths are registered as valid, or atomic so that either all paths are registered as valid, or
none are. */ none are. */
for (DerivationOutputs::iterator i = drv.outputs.begin(); foreach (DerivationOutputs::iterator, i, drv.outputs)
i != drv.outputs.end(); ++i)
{
worker.store.registerValidPath(i->second.path, worker.store.registerValidPath(i->second.path,
contentHashes[i->second.path], contentHashes[i->second.path],
allReferences[i->second.path], allReferences[i->second.path],
drvPath); drvPath);
}
/* It is now safe to delete the lock files, since all future /* It is now safe to delete the lock files, since all future
lockers will see that the output paths are valid; they will not lockers will see that the output paths are valid; they will not

View file

@ -924,7 +924,14 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
if (!isValidPath(dstPath)) { if (!isValidPath(dstPath)) {
PathLocks outputLock(singleton<PathSet, Path>(dstPath)); PathLocks outputLock;
/* Lock the output path. But don't lock if we're being called
from a build hook (whose parent process already acquired a
lock on this path). */
Strings locksHeld = tokenizeString(getEnv("NIX_HELD_LOCKS"));
if (find(locksHeld.begin(), locksHeld.end(), dstPath) == locksHeld.end())
outputLock.lockPaths(singleton<PathSet, Path>(dstPath));
if (!isValidPath(dstPath)) { if (!isValidPath(dstPath)) {