* Register GC roots properly.

This commit is contained in:
Eelco Dolstra 2009-03-15 11:56:11 +00:00
parent 32f0665d2c
commit d2fc382498
5 changed files with 38 additions and 20 deletions

View file

@ -19,6 +19,9 @@ void printHelp()
} }
static Path gcRootsDir;
Expr evalAttr(EvalState & state, Expr e) Expr evalAttr(EvalState & state, Expr e)
{ {
return e ? evalExpr(state, e) : e; return e ? evalExpr(state, e) : e;
@ -97,12 +100,12 @@ static void findJobsWrapped(EvalState & state, XMLWriter & doc,
if (getDerivation(state, e, drv)) { if (getDerivation(state, e, drv)) {
XMLAttrs xmlAttrs; XMLAttrs xmlAttrs;
Path outPath, drvPath; Path drvPath;
xmlAttrs["jobName"] = attrPath; xmlAttrs["jobName"] = attrPath;
xmlAttrs["nixName"] = drv.name; xmlAttrs["nixName"] = drv.name;
xmlAttrs["system"] = drv.system; xmlAttrs["system"] = drv.system;
xmlAttrs["drvPath"] = drv.queryDrvPath(state); xmlAttrs["drvPath"] = drvPath = drv.queryDrvPath(state);
xmlAttrs["outPath"] = drv.queryOutPath(state); xmlAttrs["outPath"] = drv.queryOutPath(state);
xmlAttrs["description"] = drv.queryMetaInfo(state, "description"); xmlAttrs["description"] = drv.queryMetaInfo(state, "description");
xmlAttrs["longDescription"] = drv.queryMetaInfo(state, "longDescription"); xmlAttrs["longDescription"] = drv.queryMetaInfo(state, "longDescription");
@ -110,6 +113,12 @@ static void findJobsWrapped(EvalState & state, XMLWriter & doc,
xmlAttrs["homepage"] = drv.queryMetaInfo(state, "homepage"); xmlAttrs["homepage"] = drv.queryMetaInfo(state, "homepage");
xmlAttrs["schedulingPriority"] = drv.queryMetaInfo(state, "schedulingPriority"); xmlAttrs["schedulingPriority"] = drv.queryMetaInfo(state, "schedulingPriority");
/* Register the derivation as a GC root. !!! This
registers roots for jobs that we may have already
done. */
Path root = gcRootsDir + "/" + baseNameOf(drvPath);
if (!pathExists(root)) addPermRoot(drvPath, root, false);
XMLOpenElement _(doc, "job", xmlAttrs); XMLOpenElement _(doc, "job", xmlAttrs);
showArgsUsed(doc, argsUsed); showArgsUsed(doc, argsUsed);
} }
@ -170,6 +179,10 @@ void run(Strings args)
? (ATermList) autoArgs.get(toATerm(name)) ? (ATermList) autoArgs.get(toATerm(name))
: ATempty, e)); : ATempty, e));
} }
else if (arg == "--gc-roots-dir") {
if (i == args.end()) throw UsageError("missing argument");
gcRootsDir = *i++;
}
else if (arg[0] == '-') else if (arg[0] == '-')
throw UsageError(format("unknown flag `%1%'") % arg); throw UsageError(format("unknown flag `%1%'") % arg);
else else
@ -178,6 +191,8 @@ void run(Strings args)
if (releaseExpr == "") throw UsageError("no expression specified"); if (releaseExpr == "") throw UsageError("no expression specified");
if (gcRootsDir == "") throw UsageError("--gc-roots-dir not specified");
store = openStore(); store = openStore();
Expr e = parseExprFromFile(state, releaseExpr); Expr e = parseExprFromFile(state, releaseExpr);

View file

@ -9,7 +9,7 @@ our @ISA = qw(Exporter);
our @EXPORT = qw( our @EXPORT = qw(
isValidPath queryPathInfo isValidPath queryPathInfo
getHydraPath getHydraDBPath openHydraDB getHydraPath getHydraDBPath openHydraDB
registerRoot getGCRootsDir registerRoot getGCRootsDir gcRootFor
getPrimaryBuildsForReleaseSet getRelease getLatestSuccessfulRelease ); getPrimaryBuildsForReleaseSet getRelease getLatestSuccessfulRelease );
@ -80,22 +80,26 @@ sub openHydraDB {
sub getGCRootsDir { sub getGCRootsDir {
die unless defined $ENV{LOGNAME}; die unless defined $ENV{LOGNAME};
return "/nix/var/nix/gcroots/per-user/$ENV{LOGNAME}/hydra-roots"; my $dir = "/nix/var/nix/gcroots/per-user/$ENV{LOGNAME}/hydra-roots";
mkpath $dir if !-e $dir;
return $dir;
}
sub gcRootFor {
my ($path) = @_;
return getGCRootsDir . basename $path;
} }
sub registerRoot { sub registerRoot {
my ($path) = @_; my ($path) = @_;
my $gcRootsDir = getGCRootsDir; my $link = gcRootFor $path;
mkpath($gcRootsDir) if !-e $gcRootsDir;
my $link = "$gcRootsDir/" . basename $path;
if (!-l $link) { if (!-l $link) {
symlink($path, $link) symlink($path, $link)
or die "cannot create symlink in $gcRootsDir to $path"; or die "cannot create GC root `$link' to `$path'";
} }
} }

View file

@ -28,8 +28,6 @@ sub doBuild {
my $failedDepBuild; my $failedDepBuild;
my $failedDepStepNr; my $failedDepStepNr;
registerRoot $outPath;
if (!isValidPath($outPath)) { if (!isValidPath($outPath)) {
$isCachedBuild = 0; $isCachedBuild = 0;
@ -75,7 +73,8 @@ sub doBuild {
# to get notifications about specific build steps, the # to get notifications about specific build steps, the
# associated log files, etc. # associated log files, etc.
my $cmd = "nix-store --max-silent-time 1800 --keep-going --no-build-output " . my $cmd = "nix-store --max-silent-time 1800 --keep-going --no-build-output " .
"--log-type flat --print-build-trace --realise $drvPath 2>&1"; "--log-type flat --print-build-trace --realise $drvPath " .
"--add-root " . gcRootFor $outPath . " 2>&1";
my $buildStepNr = 1; my $buildStepNr = 1;

View file

@ -267,9 +267,6 @@ sub checkJob {
, sha256hash => $input->{sha256hash} , sha256hash => $input->{sha256hash}
}); });
} }
# !!! this should really by done by nix-instantiate to prevent a GC race.
registerRoot $drvPath;
}); });
}; };
@ -330,9 +327,12 @@ sub checkJobSet {
$nixExprPath .= "/" . $jobset->nixexprpath; $nixExprPath .= "/" . $jobset->nixexprpath;
(my $res, my $jobsXml, my $stderr) = captureStdoutStderr( (my $res, my $jobsXml, my $stderr) = captureStdoutStderr(
"hydra_eval_jobs", $nixExprPath, inputsToArgs($inputInfo)); "hydra_eval_jobs", $nixExprPath, "--gc-roots-dir", getGCRootsDir,
inputsToArgs($inputInfo));
die "cannot evaluate the Nix expression containing the jobs:\n$stderr" unless $res; die "cannot evaluate the Nix expression containing the jobs:\n$stderr" unless $res;
print STDERR "$stderr";
my $jobs = XMLin($jobsXml, my $jobs = XMLin($jobsXml,
ForceArray => ['error', 'job', 'arg'], ForceArray => ['error', 'job', 'arg'],
KeyAttr => [], KeyAttr => [],

View file

@ -83,14 +83,14 @@ my @buildsToKeep = $db->resultset('Builds')->search({finished => 1, keep => 1},
keepBuild $_ foreach @buildsToKeep; keepBuild $_ foreach @buildsToKeep;
# For scheduled builds, we register the derivation and the output as a GC root. # For scheduled builds, we register the derivation as a GC root.
print STDERR "*** looking for scheduled builds\n"; print STDERR "*** looking for scheduled builds\n";
foreach my $build ($db->resultset('Builds')->search({finished => 0}, {join => 'schedulingInfo'})) { foreach my $build ($db->resultset('Builds')->search({finished => 0}, {join => 'schedulingInfo'})) {
if (isValidPath($build->drvpath)) { if (isValidPath($build->drvpath)) {
print STDERR "keeping scheduled build ", $build->id, " (", print STDERR "keeping scheduled build ", $build->id, " (",
strftime("%Y-%m-%d %H:%M:%S", localtime($build->timestamp)), ")\n"; strftime("%Y-%m-%d %H:%M:%S", localtime($build->timestamp)), ")\n";
registerRoot $build->drvpath; registerRoot $build->drvpath;
registerRoot $build->outpath; registerRoot $build->outpath if -e $build->outpath;
} else { } else {
print STDERR "warning: derivation ", $build->drvpath, " has disappeared\n"; print STDERR "warning: derivation ", $build->drvpath, " has disappeared\n";
} }