Merge the BuildSchedulingInfo table into the Builds table

This simplifies the code and improves performance since it reduces
the number of joins.
This commit is contained in:
Eelco Dolstra 2012-02-29 02:22:49 +01:00
parent 19fe4b9b4a
commit 25334715f8
21 changed files with 194 additions and 301 deletions

View file

@ -136,12 +136,10 @@ sub queue : Chained('api') PathPart('queue') Args(0) {
my $nr = $c->request->params->{nr} ;
error($c, "Parameter not defined!") if !defined $nr;
my @builds = $c->model('DB::Builds')->search({finished => 0}, {rows => $nr, join => ['schedulingInfo'] , order_by => ["busy DESC", "priority DESC", "timestamp"], '+select' => ['schedulingInfo.priority', 'schedulingInfo.busy'], '+as' => ['priority', 'busy'] });
my @builds = $c->model('DB::Builds')->search({finished => 0}, {rows => $nr, order_by => ["busy DESC", "priority DESC", "timestamp"]});
my @list;
foreach my $b (@builds) {
push @list, buildToHash($b) ;
}
push @list, buildToHash($_) foreach @builds;
$c->stash->{'plain'} = {
data => scalar (JSON::Any->objToJson(\@list))
@ -151,7 +149,7 @@ sub queue : Chained('api') PathPart('queue') Args(0) {
sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) {
my ($self, $c) = @_;
my $nrQueuedBuilds = $c->model('DB::BuildSchedulingInfo')->count();
my $nrQueuedBuilds = $c->model('DB::Builds')->search({finished => 0})->count();
$c->stash->{'plain'} = {
data => "$nrQueuedBuilds"
};
@ -160,7 +158,7 @@ sub nrqueue : Chained('api') PathPart('nrqueue') Args(0) {
sub nrrunning : Chained('api') PathPart('nrrunning') Args(0) {
my ($self, $c) = @_;
my $nrRunningBuilds = $c->model('DB::BuildSchedulingInfo')->search({ busy => 1 }, {})->count();
my $nrRunningBuilds = $c->model('DB::Builds')->search({finished => 0, busy => 1 })->count();
$c->stash->{'plain'} = {
data => "$nrRunningBuilds"
};

View file

@ -57,9 +57,9 @@ sub index : Chained('admin') PathPart('') Args(0) {
, '+as' => ['idle']
})];
$c->stash->{steps} = [ $c->model('DB::BuildSteps')->search(
{ 'me.busy' => 1, 'schedulingInfo.busy' => 1 },
{ join => [ 'schedulingInfo', 'build' ]
, order_by => [ 'machine' ]
{ finished => 0, 'me.busy' => 1, 'build.busy' => 1, },
{ join => [ 'build' ]
, order_by => [ 'machine', 'stepnr' ]
} ) ];
$c->stash->{template} = 'admin.tt';
}
@ -296,13 +296,15 @@ sub machine_disable : Chained('machine') PathPart('disable') Args(0) {
sub clear_queue_non_current : Chained('admin') Path('clear-queue-non-current') Args(0) {
my ($self, $c) = @_;
$c->model('DB::Builds')->search({iscurrent => 0, busy => 0}, { join => 'schedulingInfo' })->delete_all;
# !!! Mark the builds as cancelled instead.
$c->model('DB::Builds')->search({finished => 0, iscurrent => 0, busy => 0})->delete_all;
$c->res->redirect("/admin");
}
sub clear_queue : Chained('admin') Path('clear-queue') Args(0) {
my ($self, $c) = @_;
$c->model('DB::Builds')->search({busy => 0}, { join => 'schedulingInfo' })->delete_all;
# !!! Mark the builds as cancelled instead.
$c->model('DB::Builds')->search({finished => 0, busy => 0})->delete_all;
$c->res->redirect("/admin");
}

View file

@ -41,11 +41,10 @@ sub view_build : Chained('build') PathPart('') Args(0) {
$c->stash->{drvAvailable} = isValidPath $build->drvpath;
$c->stash->{flashMsg} = $c->flash->{buildMsg};
my $pathHash = $c->stash->{available} ? queryPathHash($build->outpath) : "Not available";
$c->stash->{pathHash} = $pathHash;
$c->stash->{pathHash} = $c->stash->{available} ? queryPathHash($build->outpath) : undef;
if (!$build->finished && $build->schedulingInfo->busy) {
my $logfile = $build->schedulingInfo->logfile;
if (!$build->finished && $build->busy) {
my $logfile = $build->logfile;
$c->stash->{logtext} = `cat $logfile` if defined $logfile && -e $logfile;
}
@ -81,13 +80,13 @@ sub view_build : Chained('build') PathPart('') Args(0) {
];
}
my $r = joinWithResultInfo( $c, $c->model('DB::Builds'))->search(
{ eval => { -in => $build->jobsetevalmembers->get_column('eval')->as_query } }
, { join => 'jobsetevalmembers', order_by => [ 'project', 'jobset', 'job'], distinct => 1 }
);
if ($r->count <= 100) {
$c->stash->{relatedbuilds} = [$r->all];
}
#my $r = joinWithResultInfo( $c, $c->model('DB::Builds'))->search(
# { eval => { -in => $build->jobsetevalmembers->all->get_column('eval')->as_query } }
# , { join => 'jobsetevalmembers', order_by => [ 'project', 'jobset', 'job'], distinct => 1 }
# );
#if ($r->count <= 100) {
# $c->stash->{relatedbuilds} = [$r->all];
#}
}
@ -141,7 +140,7 @@ sub showLog {
my $url = $c->request->uri->as_string;
$url =~ s/tail-reload/tail/g;
$c->stash->{url} = $url;
$c->stash->{reload} = defined $c->stash->{build}->schedulingInfo && $c->stash->{build}->schedulingInfo->busy;
$c->stash->{reload} = !$c->stash->{build}->finished && $c->stash->{build}->busy;
$c->stash->{title} = "";
$c->stash->{contents} = (scalar `$pipestart | tail -n 50`) || " ";
$c->stash->{template} = 'plain-reload.tt';
@ -406,21 +405,19 @@ sub cancel : Chained('build') PathPart Args(0) {
txn_do($c->model('DB')->schema, sub {
error($c, "This build cannot be cancelled.")
if $build->finished || $build->schedulingInfo->busy;
if $build->finished || $build->busy;
# !!! Actually, it would be nice to be able to cancel busy
# builds as well, but we would have to send a signal or
# something to the build process.
$build->update({finished => 1, timestamp => time});
$build->update({finished => 1, busy => 0, timestamp => time});
$c->model('DB::BuildResultInfo')->create(
{ id => $build->id
, iscachedbuild => 0
, buildstatus => 4 # = cancelled
});
$build->schedulingInfo->delete;
});
$c->flash->{buildMsg} = "Build has been cancelled.";

View file

@ -36,9 +36,15 @@ sub overview : Chained('job') PathPart('') Args(0) {
, order_by => 'timestamp DESC', rows => 10
}) ];
$c->stash->{runningBuilds} = [$c->stash->{job}->builds->search({busy => 1}, { join => ['schedulingInfo', 'project'] , order_by => ["priority DESC", "timestamp"]
, '+select' => ['project.enabled', 'schedulingInfo.priority', 'schedulingInfo.disabled', 'schedulingInfo.busy']
, '+as' => ['enabled', 'priority', 'disabled', 'busy'] })];
$c->stash->{runningBuilds} = [
$c->stash->{job}->builds->search(
{ busy => 1 },
{ join => ['project']
, order_by => ["priority DESC", "timestamp"]
, '+select' => ['project.enabled']
, '+as' => ['enabled']
}
) ];
$c->stash->{systems} = [$c->stash->{job}->builds->search({iscurrent => 1}, {select => ["system"], distinct => 1})];
}

View file

@ -65,10 +65,10 @@ sub jobsetIndex {
my @as = ();
push(@select, "job"); push(@as, "job");
foreach my $system (@systems) {
push(@select, "(SELECT buildstatus FROM BuildResultInfo bri NATURAL JOIN Builds b WHERE b.id = (SELECT MAX(id) FROM Builds t WHERE t.project = me.project AND t.jobset = me.jobset AND t.job = me.job AND t.system = '$system' AND t.iscurrent = 1 ))");
push(@select, "(select buildstatus from BuildResultInfo bri join Builds b using (id) where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))");
push(@as, $system);
push(@select, "(SELECT b.id FROM BuildResultInfo bri NATURAL JOIN Builds b WHERE b.id = (SELECT MAX(id) FROM Builds t WHERE t.project = me.project AND t.jobset = me.jobset AND t.job = me.job AND t.system = '$system' AND t.iscurrent = 1 ))");
push(@as, $system."-build");
push(@select, "(select b.id from BuildResultInfo bri join Builds b using (id) where b.id = (select max(id) from Builds t where t.project = me.project and t.jobset = me.jobset and t.job = me.job and t.system = '$system' and t.iscurrent = 1 ))");
push(@as, "$system-build");
}
$c->stash->{activeJobsStatus} =
[ $c->model('DB')->resultset('ActiveJobsForJobset')->search(

View file

@ -22,8 +22,8 @@ sub begin :Private {
$c->stash->{tracker} = $ENV{"HYDRA_TRACKER"} ;
if (scalar(@args) == 0 || $args[0] ne "static") {
$c->stash->{nrRunningBuilds} = $c->model('DB::BuildSchedulingInfo')->search({ busy => 1 }, {})->count();
$c->stash->{nrQueuedBuilds} = $c->model('DB::BuildSchedulingInfo')->count();
$c->stash->{nrRunningBuilds} = $c->model('DB::Builds')->search({ finished => 0, busy => 1 }, {})->count();
$c->stash->{nrQueuedBuilds} = $c->model('DB::Builds')->search({ finished => 0 })->count();
}
}
@ -74,7 +74,7 @@ sub queue :Local {
my ($self, $c) = @_;
$c->stash->{template} = 'queue.tt';
$c->stash->{queue} = [$c->model('DB::Builds')->search(
{finished => 0}, {join => ['schedulingInfo', 'project'] , order_by => ["priority DESC", "timestamp"], '+select' => ['project.enabled', 'schedulingInfo.priority', 'schedulingInfo.disabled', 'schedulingInfo.busy'], '+as' => ['enabled', 'priority', 'disabled', 'busy'] })];
{finished => 0}, {join => ['project'] , order_by => ["priority DESC", "timestamp"], '+select' => ['project.enabled'], '+as' => ['enabled'] })];
$c->stash->{flashMsg} = $c->flash->{buildMsg};
}
@ -99,8 +99,8 @@ sub timeline :Local {
sub status :Local {
my ($self, $c) = @_;
$c->stash->{steps} = [ $c->model('DB::BuildSteps')->search(
{ 'me.busy' => 1, 'schedulingInfo.busy' => 1 },
{ join => [ 'schedulingInfo', 'build' ]
{ 'me.busy' => 1, 'build.busy' => 1 },
{ join => [ 'build' ]
, order_by => [ 'machine' ]
} ) ];
}

View file

@ -851,7 +851,6 @@ sub checkBuild {
, nixexprpath => $jobset->nixexprpath
});
$currentBuilds->{$build->id} = 1;
if (isValidPath($outPath)) {
@ -869,7 +868,7 @@ sub checkBuild {
addBuildProducts($db, $build);
} else {
print STDERR "added to queue as build ", $build->id, "\n";
$build->create_related('buildschedulinginfo',
$build->update(
{ priority => $priority
, busy => 0
, locker => ""
@ -915,15 +914,14 @@ sub restartBuild {
}
my $r = `nix-store --clear-failed-paths $paths $outpath`;
$build->update({finished => 0, timestamp => time});
$build->resultInfo->delete;
$db->resultset('BuildSchedulingInfo')->create(
{ id => $build->id
, priority => 0 # don't know the original priority anymore...
$build->update(
{ finished => 0
, timestamp => time
, busy => 0
, locker => ""
});
$build->resultInfo->delete;
});
}

View file

@ -82,9 +82,7 @@ sub getBuildStats {
$c->stash->{scheduledBuilds} = $builds->search({finished => 0}) || 0;
$c->stash->{busyBuilds} = $builds->search(
{finished => 0, busy => 1},
{join => 'schedulingInfo'}) || 0;
$c->stash->{busyBuilds} = $builds->search({finished => 0, busy => 1}) || 0;
my $res;
$res = $builds->search({},

View file

@ -195,10 +195,10 @@ sub jobsetOverview {
return $project->jobsets->search( isProjectOwner($c, $project) ? {} : { hidden => 0 },
{ order_by => "name"
, "+select" =>
[ "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildSchedulingInfo WHERE me.project = a.project AND me.name = a.jobset AND a.isCurrent = 1)"
, "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE me.project = a.project AND me.name = a.jobset AND buildstatus <> 0 AND a.isCurrent = 1)"
, "(SELECT COUNT(*) FROM Builds AS a NATURAL JOIN BuildResultInfo WHERE me.project = a.project AND me.name = a.jobset AND buildstatus = 0 AND a.isCurrent = 1)"
, "(SELECT COUNT(*) FROM Builds AS a WHERE me.project = a.project AND me.name = a.jobset AND a.isCurrent = 1)"
[ "(select count(*) from Builds as a where a.finished = 0 and me.project = a.project and me.name = a.jobset and a.isCurrent = 1)"
, "(select count(*) from Builds as a join BuildResultInfo r using (id) where me.project = a.project and me.name = a.jobset and buildstatus <> 0 and a.isCurrent = 1)"
, "(select count(*) from Builds as a join BuildResultInfo r using (id) where me.project = a.project and me.name = a.jobset and buildstatus = 0 and a.isCurrent = 1)"
, "(select count(*) from Builds as a where me.project = a.project and me.name = a.jobset and a.isCurrent = 1)"
]
, "+as" => ["nrscheduled", "nrfailed", "nrsucceeded", "nrtotal"]
});

View file

@ -46,7 +46,7 @@ __PACKAGE__->table("BuildProducts");
=head2 filesize
data_type: 'integer'
data_type: 'bigint'
is_nullable: 1
=head2 sha1hash
@ -91,7 +91,7 @@ __PACKAGE__->add_columns(
"subtype",
{ data_type => "text", is_nullable => 0 },
"filesize",
{ data_type => "integer", is_nullable => 1 },
{ data_type => "bigint", is_nullable => 1 },
"sha1hash",
{ data_type => "text", is_nullable => 1 },
"sha256hash",
@ -133,8 +133,8 @@ Related object: L<Hydra::Schema::Builds>
__PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" }, {});
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:suSgQkBLXzu0yD4YicRS1A
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2012-02-29 00:47:18
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dzTKwZ7bby7kplnSgta3Gw
# You can replace this text with custom content, and it will be preserved on regeneration
1;

View file

@ -1,120 +0,0 @@
use utf8;
package Hydra::Schema::BuildSchedulingInfo;
# Created by DBIx::Class::Schema::Loader
# DO NOT MODIFY THE FIRST PART OF THIS FILE
=head1 NAME
Hydra::Schema::BuildSchedulingInfo
=cut
use strict;
use warnings;
use base 'DBIx::Class::Core';
=head1 TABLE: C<BuildSchedulingInfo>
=cut
__PACKAGE__->table("BuildSchedulingInfo");
=head1 ACCESSORS
=head2 id
data_type: 'integer'
is_auto_increment: 1
is_foreign_key: 1
is_nullable: 0
=head2 priority
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 busy
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 locker
data_type: 'text'
default_value: (empty string)
is_nullable: 0
=head2 logfile
data_type: 'text'
is_nullable: 1
=head2 disabled
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 starttime
data_type: 'integer'
is_nullable: 1
=cut
__PACKAGE__->add_columns(
"id",
{
data_type => "integer",
is_auto_increment => 1,
is_foreign_key => 1,
is_nullable => 0,
},
"priority",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"busy",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"locker",
{ data_type => "text", default_value => "", is_nullable => 0 },
"logfile",
{ data_type => "text", is_nullable => 1 },
"disabled",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"starttime",
{ data_type => "integer", is_nullable => 1 },
);
=head1 PRIMARY KEY
=over 4
=item * L</id>
=back
=cut
__PACKAGE__->set_primary_key("id");
=head1 RELATIONS
=head2 id
Type: belongs_to
Related object: L<Hydra::Schema::Builds>
=cut
__PACKAGE__->belongs_to("id", "Hydra::Schema::Builds", { id => "id" }, {});
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Uz7y9Ly+ADRrtrPfEk9lGA
# You can replace this text with custom content, and it will be preserved on regeneration
1;

View file

@ -151,10 +151,4 @@ __PACKAGE__->belongs_to("build", "Hydra::Schema::Builds", { id => "build" }, {})
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:5H+OkGT0zQEWkAjU+OlBdg
__PACKAGE__->belongs_to(
"schedulingInfo",
"Hydra::Schema::BuildSchedulingInfo",
{ id => "build" },
);
1;

View file

@ -130,6 +130,39 @@ __PACKAGE__->table("Builds");
data_type: 'text'
is_nullable: 1
=head2 priority
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 busy
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 locker
data_type: 'text'
is_nullable: 1
=head2 logfile
data_type: 'text'
is_nullable: 1
=head2 disabled
data_type: 'integer'
default_value: 0
is_nullable: 0
=head2 starttime
data_type: 'integer'
is_nullable: 1
=cut
__PACKAGE__->add_columns(
@ -173,6 +206,18 @@ __PACKAGE__->add_columns(
{ data_type => "text", is_nullable => 1 },
"nixexprpath",
{ data_type => "text", is_nullable => 1 },
"priority",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"busy",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"locker",
{ data_type => "text", is_nullable => 1 },
"logfile",
{ data_type => "text", is_nullable => 1 },
"disabled",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"starttime",
{ data_type => "integer", is_nullable => 1 },
);
=head1 PRIMARY KEY
@ -249,21 +294,6 @@ __PACKAGE__->might_have(
{},
);
=head2 buildschedulinginfo
Type: might_have
Related object: L<Hydra::Schema::BuildSchedulingInfo>
=cut
__PACKAGE__->might_have(
"buildschedulinginfo",
"Hydra::Schema::BuildSchedulingInfo",
{ "foreign.id" => "self.id" },
{},
);
=head2 buildsteps
Type: has_many
@ -350,8 +380,8 @@ __PACKAGE__->has_many(
);
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:RRtBPTdD946kA5133+c4kw
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2012-02-29 00:47:54
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:VnnyFTwnLncGb2Dj2/giiA
use Hydra::Helper::Nix;
@ -369,12 +399,6 @@ __PACKAGE__->has_many(
{ "foreign.build" => "self.id" },
);
__PACKAGE__->belongs_to(
"schedulingInfo",
"Hydra::Schema::BuildSchedulingInfo",
{ id => "id" },
);
__PACKAGE__->belongs_to(
"resultInfo",
"Hydra::Schema::BuildResultInfo",
@ -410,11 +434,11 @@ sub makeQueries {
my $joinWithStatusChange =
<<QUERY;
natural join BuildResultInfo r
join BuildResultInfo r using (id)
left join Builds b on
b.id =
(select max(id)
from builds c natural join buildresultinfo r2
(select max(c.id)
from builds c join buildresultinfo r2 on c.id = r2.id
where
x.project = c.project and x.jobset = c.jobset and x.job = c.job and x.system = c.system and
x.id > c.id and
@ -432,11 +456,12 @@ QUERY
x.id, x.finished, x.timestamp, x.project, x.jobset, x.job, x.nixname,
x.description, x.drvpath, x.outpath, x.system, x.longdescription,
x.license, x.homepage, x.maintainers, x.isCurrent, x.nixExprInput,
x.nixExprPath, x.maxsilent, x.timeout,
x.nixExprPath, x.maxsilent, x.timeout, x.priority, x.busy, x.locker,
x.logfile, x.disabled, x.startTime,
b.id as statusChangeId, b.timestamp as statusChangeTime
from
(select
(select max(id) from builds b
(select max(b.id) from builds b
where
project = activeJobs.project and jobset = activeJobs.jobset
and job = activeJobs.job and system = activeJobs.system
@ -457,7 +482,7 @@ QUERY
select *
from
(select
(select max(id) from builds b
(select max(b.id) from builds b
where
project = activeJobs.project and jobset = activeJobs.jobset
and job = activeJobs.job and system = activeJobs.system

View file

@ -26,31 +26,15 @@ __PACKAGE__->table("SchemaVersion");
=head2 version
data_type: 'integer'
is_auto_increment: 1
is_nullable: 0
=cut
__PACKAGE__->add_columns(
"version",
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
);
=head1 PRIMARY KEY
=over 4
=item * L</version>
=back
=cut
__PACKAGE__->set_primary_key("version");
__PACKAGE__->add_columns("version", { data_type => "integer", is_nullable => 0 });
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2011-12-05 14:15:43
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:F/jsSRq8pxR4mWq/N4qYGw
# Created by DBIx::Class::Schema::Loader v0.07014 @ 2012-02-29 00:47:18
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:LFD28W0GvvrOOylCM98SEQ
# You can replace this text with custom code or comments, and it will be preserved on regeneration

View file

@ -70,7 +70,7 @@
<h1>
Job <tt>[% project.name %]:[% jobset.name %]:[% job.name %]</tt> build [% id %]
[% IF !build.finished %]
[% IF build.schedulingInfo.busy %]
[% IF build.busy %]
(currently building)
[% ELSE %]
(scheduled)
@ -127,7 +127,7 @@
<th>System:</th>
<td><tt>[% build.system %]</tt></td>
</tr>
[% IF !build.schedulingInfo %]
[% IF !build.finished %]
<tr>
<th>Duration:</th>
<td>
@ -316,12 +316,14 @@
[% END %]
</td>
</tr>
[% IF pathHash %]
<tr>
<th>Output store path hash:</th>
<td>
<tt>[% pathHash %]</tt>
</td>
</tr>
[% END %]
<tr>
<th>Time added:</th>
<td>[% INCLUDE renderDateTime timestamp = build.timestamp %]</td>
@ -366,7 +368,7 @@
[% IF !build.finished %]
<tr>
<th>Priority:</th>
<td>[% build.schedulingInfo.priority %]</td>
<td>[% build.priority %]</td>
</tr>
[% END %]
[% IF build.finished && build.buildproducts %]

View file

@ -93,7 +93,7 @@
[%- FOREACH build IN builds -%]
<tr class="clickable
[%- IF showSchedulingInfo -%]
[%- IF build.get_column('busy') %]runningBuild[% ELSIF build.get_column('disabled') == 1 || build.get_column('enabled') == 0 %]disabledBuild[% END -%]
[%- IF build.busy %]runningBuild[% ELSIF build.disabled == 1 || build.get_column('enabled') == 0 %]disabledBuild[% END -%]
[%- ELSE -%]
[%- IF odd %] odd [% END; odd = !odd -%]
[%- END %]"
@ -105,8 +105,8 @@
[%- END -%]
<td><a href="[% c.uri_for('/build' build.id) %]">[% build.id %]</a></td>
[%- IF showSchedulingInfo -%]
<td>[% IF build.get_column('busy') %]<img src="/static/images/running.gif" alt="Running" />[% ELSIF build.get_column('disabled') == 1 || build.get_column('enabled') == 0 %]Disabled[% END %]</td>
<td>[% build.get_column('priority') %]</td>
<td>[% IF build.busy %]<img src="/static/images/running.gif" alt="Running" />[% ELSIF build.disabled == 1 || build.get_column('enabled') == 0 %]Disabled[% END %]</td>
<td>[% build.priority %]</td>
[%- END -%]
<td>[%- INCLUDE renderFullJobNameOfBuild -%]</td>
<td>[% !showSchedulingInfo and build.get_column('releasename') ? build.get_column('releasename') : build.nixname %]</td>
@ -203,7 +203,7 @@
[%- BLOCK renderBuildStatusIcon -%]
[%- finished = build != undef ? build.finished : 1 -%]
[%- busy = busy != undef ? busy : build.schedulingInfo.busy -%]
[%- busy = busy != undef ? busy : build.busy -%]
[%- buildstatus = buildstatus != undef ? buildstatus : build.resultInfo.buildstatus -%]
[%- IF finished -%]
[%- IF buildstatus == 0 -%]
@ -255,9 +255,9 @@
<button id="restart" type="submit">Restart</button>
</form>
[% END %]
[% ELSIF build.schedulingInfo.busy %]
[% ELSIF build.busy %]
<strong>Build in progress</strong>
since [% INCLUDE renderDateTime timestamp = build.schedulingInfo.starttime %]
since [% INCLUDE renderDateTime timestamp = build.starttime %]
[% ELSE %]
<strong>Scheduled to be built</strong>
[% IF c.user_exists %]

View file

@ -398,7 +398,7 @@ sub doBuild {
}
txn_do($db, sub {
$build->update({finished => 1, timestamp => time});
$build->update({finished => 1, busy => 0, locker => '', logfile => '', timestamp => time});
my $releaseName = getReleaseName($outPath);
@ -423,8 +423,6 @@ sub doBuild {
if ($buildStatus == 0 || $buildStatus == 6) {
addBuildProducts($db, $build);
}
$build->schedulingInfo->delete;
});
sendEmailNotification $build;
@ -453,10 +451,10 @@ txn_do($db, sub {
$build = $db->resultset('Builds')->find($buildId);
die "build $buildId doesn't exist" unless defined $build;
die "build $buildId already done" if defined $build->resultInfo;
if ($build->schedulingInfo->busy != 0 && $build->schedulingInfo->locker != getppid) {
if ($build->busy != 0 && $build->locker != getppid) {
die "build $buildId is already being built";
}
$build->schedulingInfo->update({busy => 1, locker => $$});
$build->update({busy => 1, locker => $$});
$build->buildsteps->search({busy => 1})->delete_all;
$build->buildproducts->delete_all;
});
@ -472,6 +470,6 @@ eval {
if ($@) {
warn $@;
txn_do($db, sub {
$build->schedulingInfo->update({busy => 0, locker => $$});
$build->update({busy => 0, locker => $$});
});
}

View file

@ -20,10 +20,9 @@ STDOUT->autoflush();
sub unlockDeadBuilds {
# Unlock builds whose building process has died.
txn_do($db, sub {
my @builds = $db->resultset('Builds')->search(
{finished => 0, busy => 1}, {join => 'schedulingInfo'});
my @builds = $db->resultset('Builds')->search({finished => 0, busy => 1});
foreach my $build (@builds) {
my $pid = $build->schedulingInfo->locker;
my $pid = $build->locker;
my $unlock = 0;
if ($pid == $$) {
# Work around sqlite locking timeouts: if the child
@ -32,7 +31,7 @@ sub unlockDeadBuilds {
# So if after a minute it hasn't been updated,
# unlock the build. !!! need a better fix for those
# locking timeouts.
if ($build->schedulingInfo->starttime + 60 < time) {
if ($build->starttime + 60 < time) {
$unlock = 1;
}
} elsif (kill(0, $pid) != 1) { # see if we can signal the process
@ -40,9 +39,9 @@ sub unlockDeadBuilds {
}
if ($unlock) {
print "build ", $build->id, " pid $pid died, unlocking\n";
$build->schedulingInfo->busy(0);
$build->schedulingInfo->locker("");
$build->schedulingInfo->update;
$build->busy(0);
$build->locker("");
$build->update;
}
}
});
@ -64,7 +63,7 @@ sub findBuildDependencyInQueue {
($depBuild) = $db->resultset('Builds')->search(
{ drvpath => [ @drvs ], finished => 0, busy => 0, enabled => 1, disabled => 0 },
{ join => ['schedulingInfo', 'project'], rows => 1 } ) ;
{ join => ['project'], rows => 1 } ) ;
return $depBuild;
}
@ -79,7 +78,7 @@ sub checkBuilds {
# Get the system types for the runnable builds.
my @systemTypes = $db->resultset('Builds')->search(
{ finished => 0, busy => 0, enabled => 1, disabled => 0 },
{ join => ['schedulingInfo', 'project'], select => ['system'], as => ['system'], distinct => 1 });
{ join => ['project'], select => ['system'], as => ['system'], distinct => 1 });
# For each system type, select up to the maximum number of
# concurrent build for that system type. Choose the highest
@ -88,8 +87,7 @@ sub checkBuilds {
# How many builds are already currently executing for this
# system type?
my $nrActive = $db->resultset('Builds')->search(
{finished => 0, busy => 1, system => $system->system},
{join => 'schedulingInfo'})->count;
{finished => 0, busy => 1, system => $system->system})->count;
# How many extra builds can we start?
(my $systemTypeInfo) = $db->resultset('SystemTypes')->search({system => $system->system});
@ -100,7 +98,7 @@ sub checkBuilds {
# Select the highest-priority builds to start.
my @builds = $extraAllowed == 0 ? () : $db->resultset('Builds')->search(
{ finished => 0, busy => 0, system => $system->system, enabled => 1, disabled => 0 },
{ join => ['schedulingInfo', 'project'], order_by => ["priority DESC", "timestamp"],
{ join => ['project'], order_by => ["priority DESC", "timestamp"],
rows => $extraAllowed });
print "system type `", $system->system,
@ -114,11 +112,11 @@ sub checkBuilds {
my $logfile = getcwd . "/logs/" . $build->id;
mkdir(dirname $logfile);
unlink($logfile);
$build->schedulingInfo->busy(1);
$build->schedulingInfo->locker($$);
$build->schedulingInfo->logfile($logfile);
$build->schedulingInfo->starttime(time);
$build->schedulingInfo->update;
$build->busy(1);
$build->locker($$);
$build->logfile($logfile);
$build->starttime(time);
$build->update;
push @buildsStarted, $build;
}
}
@ -130,7 +128,7 @@ sub checkBuilds {
my $id = $build->id;
print "starting build $id (", $build->project->name, ":", $build->jobset->name, ':', $build->job->name, ") on ", $build->system, "\n";
eval {
my $logfile = $build->schedulingInfo->logfile;
my $logfile = $build->logfile;
my $child = fork();
die unless defined $child;
if ($child == 0) {
@ -147,9 +145,9 @@ sub checkBuilds {
if ($@) {
warn $@;
txn_do($db, sub {
$build->schedulingInfo->busy(0);
$build->schedulingInfo->locker($$);
$build->schedulingInfo->update;
$build->busy(0);
$build->locker($$);
$build->update;
});
}
}

View file

@ -112,7 +112,7 @@ keepBuild $_ foreach @buildsToKeep;
# For scheduled builds, we register the derivation as a GC root.
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})) {
if (isValidPath($build->drvpath)) {
print STDERR "keeping scheduled build ", $build->id, " (",
strftime("%Y-%m-%d %H:%M:%S", localtime($build->timestamp)), ")\n";

View file

@ -114,11 +114,6 @@ create table Jobs (
);
-- This table contains all wbuilds, either scheduled or finished. For
-- scheduled builds, additional info (such as the priority) can be
-- found in the BuildSchedulingInfo table. For finished builds,
-- additional info (such as the logs, build products, etc.) can be
-- found in several tables, such as BuildResultInfo and BuildProducts.
create table Builds (
#ifdef POSTGRESQL
id serial primary key not null,
@ -157,28 +152,21 @@ create table Builds (
nixExprInput text,
nixExprPath text,
foreign key (project) references Projects(name) on update cascade,
foreign key (project, jobset) references Jobsets(project, name) on update cascade,
foreign key (project, jobset, job) references Jobs(project, jobset, name) on update cascade
);
-- Info for a scheduled build.
create table BuildSchedulingInfo (
id integer primary key not null,
-- Information about scheduled builds.
priority integer not null default 0,
busy integer not null default 0, -- true means someone is building this job now
locker text not null default '', -- !!! hostname/pid of the process building this job?
locker text, -- !!! hostname/pid of the process building this job?
logfile text, -- if busy, the path of the logfile
disabled integer not null default 0,
disabled integer not null default 0, -- !!! boolean
startTime integer, -- if busy, time we started
foreign key (id) references Builds(id) on delete cascade
foreign key (project) references Projects(name) on update cascade,
foreign key (project, jobset) references Jobsets(project, name) on update cascade,
foreign key (project, jobset, job) references Jobs(project, jobset, name) on update cascade
);
@ -523,7 +511,6 @@ create index IndexBuildInputsOnBuild on BuildInputs(build);
create index IndexBuildInputsOnDependency on BuildInputs(dependency);
create index IndexBuildProducstOnBuildAndType on BuildProducts(build, type);
create index IndexBuildProductsOnBuild on BuildProducts(build);
create index IndexBuildSchedulingInfoOnBuild on BuildSchedulingInfo(id); -- idem
create index IndexBuildStepsOnBuild on BuildSteps(build);
create index IndexBuildStepsOnDrvpathTypeBusyStatus on BuildSteps(drvpath, type, busy, status);
create index IndexBuildStepsOnOutpath on BuildSteps(outpath);

26
src/sql/upgrade-2.sql Normal file
View file

@ -0,0 +1,26 @@
alter table Builds
add column priority integer not null default 0,
add column busy integer not null default 0,
add column locker text,
add column logfile text,
add column disabled integer not null default 0,
add column startTime integer;
--alter table Builds
-- add column isCachedBuild integer,
-- add column buildStatus integer,
-- add column errorMsg text;
update Builds b set
priority = (select priority from BuildSchedulingInfo s where s.id = b.id),
busy = (select busy from BuildSchedulingInfo s where s.id = b.id),
disabled = (select disabled from BuildSchedulingInfo s where s.id = b.id),
locker = (select locker from BuildSchedulingInfo s where s.id = b.id),
logfile = (select logfile from BuildSchedulingInfo s where s.id = b.id)
where exists (select 1 from BuildSchedulingInfo s where s.id = b.id);
update Builds b set
startTime = ((select startTime from BuildSchedulingInfo s where s.id = b.id) union (select startTime from BuildResultInfo r where r.id = b.id));
-- isCachedBuild = (select isCachedBuild from BuildResultInfo r where r.id = b.id),
-- buildStatus = (select buildStatus from BuildResultInfo r where r.id = b.id),
-- errorMsg = (select errorMsg from BuildResultInfo r where r.id = b.id);