* hydra_scheduler: use eval-jobs.
[?]
Mar 9, 2009, 1:04 PM
POPU2ATH2HHBTGHKRAV3EY2K55P664IARI3YJGLDKVJ6PQPXBQ4ACDependencies
- [2]
N6E7R424 - [3]
XNCWZ7OT* Get the job priority from the meta.schedulingPriority attribute. - [4]
M3WSK4CB - [5]
2T42QGZD* Register builds as GC roots so they don't get deleted. - [6]
CN5LSNJN* Pass the version of dependencies to the Nix expression. - [7]
BHZXGT2H* Channels: provide an index page that lists all the packages in the - [8]
KD5237CU* eval-jobs now efficiently evaluates all Hydra jobs from a - [9]
YAPITGB3* Boolean inputs. - [10]
PHX2HIVG* Store info about the build inputs in the build record. - [11]
CMU3YKOU* Store the release name. - [12]
M552HLIA* Support variant builds. - [13]
67P45PY4 - [14]
HJLYC753* Adding input value alternatives. - [15]
BVOPAMLS - [16]
6BLUKEQ2* Caching of "path" inputs, and fake a revision number for those. - [17]
3ZCEPLNO - [18]
VJHIHMEH* Store the meta.longDescription and meta.license attributes in the - [19]
H7CNGK4O* Log evaluation errors etc. in the DB. - [20]
HOVPJBFF* Require every argument to be specified. - [21]
FMJMW4PU - [22]
YGRLM2SK* Export all relevant info about the derivation. - [23]
FDE3BJAP* Refactoring. - [24]
TLZ2SPBR - [25]
ZVTSOVHN* Support Subversion checkouts. - [26]
5QJP6JHS* Get dependencies from the database. - [27]
ECBA3GQO* Make the schema class names match the case of the SQL table names. - [28]
L2E6EVE2* Merged the Build and Job tables. - [29]
7YBYT2LQ - [30]
TWURROKC - [31]
N22GPKYT* Put info about logs / build products in the DB. - [32]
KOTB7BKV - [33]
X27GNHDV* Basic job info in the database. - [34]
4LWGZL33 - [*]
4N5APGRG* Start of a helper tool to evaluate job expressions efficiently.
Change contents
- edit in src/c/eval-jobs.cc at line 48
- edit in src/c/eval-jobs.cc at line 58
- edit in src/c/eval-jobs.cc at line 59
- replacement in src/c/eval-jobs.cc at line 102
xmlAttrs["name"] = attrPath;xmlAttrs["jobName"] = attrPath;xmlAttrs["nixName"] = drv.name; - edit in src/c/eval-jobs.cc at line 111
xmlAttrs["schedulingPriority"] = drv.queryMetaInfo(state, "schedulingPriority"); - edit in src/c/eval-jobs.cc at line 179[36.855][36.855]
if (releaseExpr == "") throw UsageError("no expression specified"); - edit in src/script/hydra_scheduler.pl at line 4
use feature 'switch'; - replacement in src/script/hydra_scheduler.pl at line 36
sub fetchInput {my ($input, $alt, $inputInfo) = @_;sub fetchInputAlt {my ($input, $alt) = @_; - replacement in src/script/hydra_scheduler.pl at line 93
$$inputInfo{$input->name} =return - replacement in src/script/hydra_scheduler.pl at line 144
$$inputInfo{$input->name} =return - replacement in src/script/hydra_scheduler.pl at line 156
$$inputInfo{$input->name} = {type => $type, value => $alt->value};return {type => $type, value => $alt->value}; - replacement in src/script/hydra_scheduler.pl at line 161
$$inputInfo{$input->name} = {type => $type, value => $alt->value};return {type => $type, value => $alt->value}; - replacement in src/script/hydra_scheduler.pl at line 170[9.7161]→[9.51:157](∅→∅),[9.157]→[9.5669:5674](∅→∅),[9.5669]→[9.5669:5674](∅→∅),[9.5674]→[9.158:198](∅→∅),[9.198]→[9.2247:2473](∅→∅),[9.2473]→[9.362:382](∅→∅),[9.362]→[9.362:382](∅→∅)
sub checkJob {my ($project, $jobset, $inputInfo, $nixExprPath, $jobName, $jobExpr, $extraArgs) = @_;# Instantiate the store derivation.(my $res, my $drvPath, my $stderr) = captureStdoutStderr("nix-instantiate", $nixExprPath, "--attr", $jobName, @{$extraArgs});die "cannot evaluate the Nix expression for job `$jobName':\n$stderr" unless $res;chomp $drvPath;sub fetchInputs {my ($jobset, $inputInfo) = @_;foreach my $input ($jobset->jobsetinputs->all) {foreach my $alt ($input->jobsetinputalts->all) {push @{$$inputInfo{$input->name}}, fetchInputAlt($input, $alt);}}} - edit in src/script/hydra_scheduler.pl at line 179
# Call nix-env --xml to get info about this job (drvPath, outPath, meta attributes, ...).($res, my $infoXml, $stderr) = captureStdoutStderr(qw(nix-env --query --available * --attr-path --out-path --drv-path --meta --xml --system-filter *),"-f", $nixExprPath, "--attr", $jobName, @{$extraArgs});die "cannot get information about the job `$jobName':\n$stderr" unless $res; - replacement in src/script/hydra_scheduler.pl at line 180
my $info = XMLin($infoXml, ForceArray => 1, KeyAttr => ['attrPath', 'name'])or die "cannot parse XML output";sub checkJob {my ($project, $jobset, $inputInfo, $job) = @_; - replacement in src/script/hydra_scheduler.pl at line 183[9.806]→[9.5621:5688](∅→∅),[9.5688]→[9.893:1005](∅→∅),[9.893]→[9.893:1005](∅→∅),[9.1005]→[9.3190:3396](∅→∅),[9.3396]→[7.4646:4740](∅→∅),[7.4740]→[9.3396:3401](∅→∅),[9.3396]→[9.3396:3401](∅→∅),[9.3401]→[9.1005:1049](∅→∅),[9.1005]→[9.1005:1049](∅→∅)
my $job = $info->{item}->{$jobName};die if !defined $job;my $description = defined $job->{meta}->{description} ? $job->{meta}->{description}->{value} : "";my $longDescription = defined $job->{meta}->{longDescription} ? $job->{meta}->{longDescription}->{value} : "";my $license = defined $job->{meta}->{license} ? $job->{meta}->{license}->{value} : "";my $homepage = defined $job->{meta}->{homepage} ? $job->{meta}->{homepage}->{value} : "";die unless $job->{drvPath} eq $drvPath;my $jobName = $job->{jobName};my $drvPath = $job->{drvPath}; - replacement in src/script/hydra_scheduler.pl at line 188
if (defined $job->{meta}->{schedulingPriority} &&$job->{meta}->{schedulingPriority}->{value} =~ /^\d+$/){$priority = int($job->{meta}->{schedulingPriority}->{value});}$priority = int($job->{schedulingPriority})if $job->{schedulingPriority} =~ /^\d+$/; - replacement in src/script/hydra_scheduler.pl at line 208[9.10276]→[9.10276:10318](∅→∅),[9.10318]→[9.3402:3486](∅→∅),[9.3486]→[9.2969:3007](∅→∅),[9.10318]→[9.2969:3007](∅→∅)
, description => $description, longdescription => $longDescription, license => $license, nixname => $job->{name}, description => $job->{description}, longdescription => $job->{longDescription}, license => $job->{license}, nixname => $job->{nixName} - replacement in src/script/hydra_scheduler.pl at line 224
foreach my $inputName (keys %{$inputInfo}) {my $input = $inputInfo->{$inputName};foreach my $arg (@{$job->{arg}}) {my $input = $inputInfo->{$arg->{name}}->[$arg->{altnr}] or die "invalid input"; - replacement in src/script/hydra_scheduler.pl at line 228
, name => $inputName, name => $arg->{name} - replacement in src/script/hydra_scheduler.pl at line 238
- replacement in src/script/hydra_scheduler.pl at line 257
sub checkJobAlternatives {my ($project, $jobset, $inputInfo, $nixExprPath, $jobName, $jobExpr, $extraArgs, $argsNeeded, $n) = @_;sub inputsToArgs {my ($inputInfo) = @_;my @res = (); - replacement in src/script/hydra_scheduler.pl at line 261[9.1317]→[9.1317:1356](∅→∅),[9.1356]→[9.6101:6226](∅→∅),[9.6226]→[9.3187:3319](∅→∅),[9.3319]→[9.1451:1512](∅→∅),[9.6249]→[9.1451:1512](∅→∅),[9.1451]→[9.1451:1512](∅→∅),[9.1512]→[9.3320:3379](∅→∅),[9.3379]→[9.1576:1647](∅→∅),[9.1576]→[9.1576:1647](∅→∅),[9.1647]→[9.457:533](∅→∅),[9.533]→[9.1647:1734](∅→∅),[9.1647]→[9.1647:1734](∅→∅),[9.1734]→[9.3380:3477](∅→∅),[9.3477]→[9.3902:3952](∅→∅),[9.3952]→[9.3478:3519](∅→∅),[9.1902]→[9.3478:3519](∅→∅),[9.3519]→[9.1932:1995](∅→∅),[9.1932]→[9.1932:1995](∅→∅),[9.1995]→[9.3953:4003](∅→∅),[9.4003]→[9.1955:2051](∅→∅),[9.2051]→[6.0:99](∅→∅),[6.99]→[9.4080:4159](∅→∅),[9.2051]→[9.4080:4159](∅→∅),[9.4080]→[9.4080:4159](∅→∅),[9.4159]→[9.2437:2504](∅→∅),[9.2504]→[9.3628:3714](∅→∅),[9.2192]→[9.3628:3714](∅→∅),[9.3714]→[9.2505:2656](∅→∅)
if ($n >= scalar @{$argsNeeded}) {eval {checkJob($project, $jobset, $inputInfo, $nixExprPath, $jobName, $jobExpr, $extraArgs);};if ($@) {print "error evaluating job `", $jobName, "': $@";setJobsetError($jobset, $@);}return;}my $argName = @{$argsNeeded}[$n];#print "finding alternatives for argument $argName\n";my ($input) = $jobset->jobsetinputs->search({name => $argName});my %newInputInfo = %{$inputInfo}; $inputInfo = \%newInputInfo; # cloneif (defined $input) {foreach my $alt ($input->jobsetinputalts) {#print "input ", $input->name, " (type ", $input->type, ") alt ", $alt->altnr, "\n";fetchInput($input, $alt, $inputInfo);my @newArgs = @{$extraArgs};if (defined $inputInfo->{$argName}->{storePath}) {push @newArgs, "--arg", $argName,"{path = builtins.storePath " . $inputInfo->{$argName}->{storePath} . ";" ." outPath = builtins.storePath " . $inputInfo->{$argName}->{storePath} . ";" ." rev = \"" . $inputInfo->{$argName}->{revision} . "\";}";} elsif ($inputInfo->{$argName}->{type} eq "string") {push @newArgs, "--argstr", $argName, $inputInfo->{$argName}->{value};} elsif ($inputInfo->{$argName}->{type} eq "boolean") {push @newArgs, "--arg", $argName, $inputInfo->{$argName}->{value};foreach my $input (keys %{$inputInfo}) {foreach my $alt (@{$inputInfo->{$input}}) {given ($alt->{type}) {when ("string") {push @res, "--argstr", $input, $alt->{value};}when ("boolean") {push @res, "--arg", $input, $alt->{value};}when (["svn", "path"]) {push @res, "--arg", $input, ("{ outPath = builtins.storePath " . $alt->{storePath} . "" ."; rev = \"" . $alt->{revision} . "\"" .";}");} - edit in src/script/hydra_scheduler.pl at line 278
checkJobAlternatives($project, $jobset, $inputInfo, $nixExprPath,$jobName, $jobExpr, \@newArgs, $argsNeeded, $n + 1); - edit in src/script/hydra_scheduler.pl at line 280
else {(my $prevBuild) = $db->resultset('Builds')->search({finished => 1, project => $project->name, jobset => $jobset->name, attrname => $argName, buildStatus => 0},{join => 'resultInfo', order_by => "timestamp DESC", rows => 1}); - replacement in src/script/hydra_scheduler.pl at line 281[9.2725]→[9.2725:3365](∅→∅),[9.3365]→[6.100:209](∅→∅),[6.209]→[9.3365:3366](∅→∅),[9.3365]→[9.3365:3366](∅→∅),[9.3366]→[6.210:366](∅→∅),[6.366]→[9.3785:3822](∅→∅),[9.3366]→[9.3785:3822](∅→∅),[9.3822]→[6.367:651](∅→∅),[6.651]→[9.3905:3914](∅→∅),[9.2154]→[9.3905:3914](∅→∅),[9.3905]→[9.3905:3914](∅→∅),[9.3914]→[9.3366:3453](∅→∅),[9.3366]→[9.3366:3453](∅→∅),[9.3453]→[9.3915:3980](∅→∅),[9.3980]→[9.3603:3609](∅→∅),[9.3603]→[9.3603:3609](∅→∅)
if (!defined $prevBuild) {# !!! reschedule?die "missing input `$argName'";}# The argument name matches a previously built job in this# jobset. Pick the most recent build. !!! refine the# selection criteria: e.g., most recent successful build.if (!isValidPath($prevBuild->outpath)) {die "input path " . $prevBuild->outpath . " has been garbage-collected";}$$inputInfo{$argName} ={ type => "build", storePath => $prevBuild->outpath, id => $prevBuild->id};my $pkgNameRE = "(?:(?:[A-Za-z0-9]|(?:-[^0-9]))+)";my $versionRE = "(?:[A-Za-z0-9\.\-]+)";my $relName = ($prevBuild->resultInfo->releasename or $prevBuild->nixname);my $version = $2 if $relName =~ /^($pkgNameRE)-($versionRE)$/;my @newArgs = @{$extraArgs};push @newArgs, "--arg", $argName,"{ path = builtins.storePath " . $prevBuild->outpath . "; " ." outPath = builtins.storePath " . $prevBuild->outpath . "; " .($version ? " version = \"$version\"; " : "") . # !!! escape"}";checkJobAlternatives($project, $jobset, $inputInfo, $nixExprPath,$jobName, $jobExpr, \@newArgs, $argsNeeded, $n + 1);}return @res; - edit in src/script/hydra_scheduler.pl at line 293[9.2121]→[9.3692:3832](∅→∅),[9.3692]→[9.3692:3832](∅→∅),[9.3832]→[4.118:195](∅→∅),[4.195]→[9.3867:3868](∅→∅),[9.3867]→[9.3867:3868](∅→∅),[9.3868]→[4.196:328](∅→∅)
# Fetch the input containing the Nix expression.(my $exprInput) = $jobset->jobsetinputs->search({name => $jobset->nixexprinput});die "No input named " . $jobset->nixexprinput unless defined $exprInput;die "Multiple alternatives for the Nix expression input not supported yet"if scalar($exprInput->jobsetinputalts) != 1; - replacement in src/script/hydra_scheduler.pl at line 294
fetchInput($exprInput, $exprInput->jobsetinputalts->first, $inputInfo);# Fetch all values for all inputs.fetchInputs($jobset, $inputInfo); - replacement in src/script/hydra_scheduler.pl at line 297
# Evaluate the Nix expression.my $nixExprPath = $inputInfo->{$jobset->nixexprinput}->{storePath} . "/" . $jobset->nixexprpath;# Evaluate the job expression.my $nixExprPath = $inputInfo->{$jobset->nixexprinput}->[0]->{storePath}or die "cannot find the input containing the job expression";$nixExprPath .= "/" . $jobset->nixexprpath; - edit in src/script/hydra_scheduler.pl at line 302
print "evaluating $nixExprPath\n"; - replacement in src/script/hydra_scheduler.pl at line 303
"nix-instantiate", $nixExprPath, "--eval-only", "--strict", "--xml");"eval-jobs", $nixExprPath, inputsToArgs($inputInfo)); - replacement in src/script/hydra_scheduler.pl at line 307
ForceArray => ['value', 'attr'],KeyAttr => ['name'],SuppressEmpty => '',ValueAttr => [value => 'value'])ForceArray => ['error', 'job', 'arg'],KeyAttr => [],SuppressEmpty => '') - replacement in src/script/hydra_scheduler.pl at line 312
die unless defined $jobs->{attrs};# Store the errors messages for jobs that failed to evaluate.foreach my $error (@{$jobs->{error}}) {print "error at " . $error->{location} . ": " . $error->{msg} . "\n";} - replacement in src/script/hydra_scheduler.pl at line 317[9.8110]→[9.4055:4312](∅→∅),[9.4312]→[9.8110:8170](∅→∅),[9.8110]→[9.8110:8170](∅→∅),[9.8170]→[9.4253:4297](∅→∅),[9.4297]→[9.8206:8207](∅→∅),[9.8206]→[9.8206:8207](∅→∅),[9.8207]→[9.4313:4351](∅→∅),[9.4351]→[9.8207:8265](∅→∅),[9.8207]→[9.8207:8265](∅→∅),[9.3657]→[9.8294:8295](∅→∅),[9.8294]→[9.8294:8295](∅→∅),[9.8295]→[9.4352:4437](∅→∅),[9.4437]→[9.8413:8469](∅→∅),[9.8413]→[9.8413:8469](∅→∅),[9.3671]→[9.8469:8555](∅→∅),[9.8469]→[9.8469:8555](∅→∅),[9.8555]→[9.4298:4347](∅→∅),[9.4347]→[9.4438:4508](∅→∅),[9.8609]→[9.4438:4508](∅→∅),[9.4508]→[9.8811:8821](∅→∅),[9.8811]→[9.8811:8821](∅→∅),[9.9062]→[9.9062:9063](∅→∅),[9.9063]→[9.6250:6352](∅→∅),[9.6352]→[9.4348:4406](∅→∅),[9.4406]→[9.6410:6421](∅→∅),[9.6410]→[9.6410:6421](∅→∅),[9.6421]→[9.2657:2785](∅→∅)
# Iterate over the attributes listed in the Nix expression and# perform the builds described by them. If an attribute is a# function, then fill in the function arguments with the# (alternative) values supplied in the jobsetinputs table.foreach my $jobName (keys(%{$jobs->{attrs}->{attr}})) {print "considering job $jobName\n";my @argsNeeded = ();my $jobExpr = $jobs->{attrs}->{attr}->{$jobName};# !!! fix the case where there is only 1 attr, XML::Simple fucks up as usualif (defined $jobExpr->{function}->{attrspat}) {foreach my $argName (keys(%{$jobExpr->{function}->{attrspat}->{attr}})) {#print "needs input $argName\n";push @argsNeeded, $argName;}}eval {checkJobAlternatives($project, $jobset, {}, $nixExprPath,$jobName, $jobExpr, [], \@argsNeeded, 0);};if ($@) {print "error checking job ", $jobName, ": $@";setJobsetError($jobset, $@);}# Schedule each successfully evaluated job.foreach my $job (@{$jobs->{job}}) {print "considering job " . $job->{jobName} . "\n";checkJob($project, $jobset, $inputInfo, $job);