Reduce I/O in build listings by only fetching required columns

Columns such as "longDescription" can be large, so fetching them
when they're not needed is wasteful.
This commit is contained in:
Eelco Dolstra 2012-03-07 22:20:15 +01:00
parent 6526d4a65f
commit 07b3dffd20
6 changed files with 24 additions and 14 deletions

View file

@ -65,6 +65,7 @@ sub all : Chained('get_builds') PathPart {
$c->stash->{builds} = [ $c->stash->{allBuilds}->search( $c->stash->{builds} = [ $c->stash->{allBuilds}->search(
{ finished => 1 }, { finished => 1 },
{ order_by => "timestamp DESC" { order_by => "timestamp DESC"
, columns => [@buildListColumns]
, rows => $resultsPerPage , rows => $resultsPerPage
, page => $page }) ]; , page => $page }) ];
} }

View file

@ -51,16 +51,15 @@ sub nixexprs : Chained('nix') PathPart('nixexprs.tar.bz2') Args(0) {
sub name { sub name {
my ($build) = @_; my ($build) = @_;
return $build->get_column('releasename') || $build->nixname; return $build->releasename || $build->nixname;
} }
sub sortPkgs { sub sortPkgs {
# Sort by name, then timestamp. # Sort by name, then id.
return sort return sort
{ lc(name($a->{build})) cmp lc(name($b->{build})) { lc(name($a->{build})) cmp lc(name($b->{build}))
or $a->{build}->timestamp <=> $b->{build}->timestamp or $a->{build}->id <=> $b->{build}->id } @_;
} @_;
} }

View file

@ -29,7 +29,7 @@ sub overview : Chained('job') PathPart('') Args(0) {
$c->stash->{lastBuilds} = $c->stash->{lastBuilds} =
[ $c->stash->{job}->builds->search({ finished => 1 }, [ $c->stash->{job}->builds->search({ finished => 1 },
{ order_by => 'timestamp DESC', rows => 10 }) ]; { order_by => 'timestamp DESC', rows => 10, columns => [@buildListColumns] }) ];
$c->stash->{runningBuilds} = [ $c->stash->{runningBuilds} = [
$c->stash->{job}->builds->search( $c->stash->{job}->builds->search(

View file

@ -83,7 +83,7 @@ sub jobsetIndex {
# Last builds for jobset. # Last builds for jobset.
$c->stash->{lastBuilds} = $c->stash->{lastBuilds} =
[ $c->stash->{jobset}->builds->search({ finished => 1 }, [ $c->stash->{jobset}->builds->search({ finished => 1 },
{ order_by => "timestamp DESC", rows => 5 }) ]; { order_by => "timestamp DESC", rows => 5, columns => [@buildListColumns] }) ];
} }

View file

@ -74,7 +74,7 @@ sub queue :Local {
my ($self, $c) = @_; my ($self, $c) = @_;
$c->stash->{template} = 'queue.tt'; $c->stash->{template} = 'queue.tt';
$c->stash->{queue} = [$c->model('DB::Builds')->search( $c->stash->{queue} = [$c->model('DB::Builds')->search(
{finished => 0}, {join => ['project'] , order_by => ["priority DESC", "timestamp"], '+select' => ['project.enabled'], '+as' => ['enabled'] })]; {finished => 0}, { join => ['project'], order_by => ["priority DESC", "timestamp"], columns => [@buildListColumns], '+select' => ['project.enabled'], '+as' => ['enabled'] })];
$c->stash->{flashMsg} = $c->flash->{buildMsg}; $c->stash->{flashMsg} = $c->flash->{buildMsg};
} }

View file

@ -13,9 +13,14 @@ our @EXPORT = qw(
requireLogin requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner requireLogin requireProjectOwner requireAdmin requirePost isAdmin isProjectOwner
trim trim
$pathCompRE $relPathRE $relNameRE $jobNameRE $systemRE $pathCompRE $relPathRE $relNameRE $jobNameRE $systemRE
@buildListColumns
); );
# Columns from the Builds table needed to render build lists.
Readonly our @buildListColumns => ('id', 'finished', 'timestamp', 'project', 'jobset', 'job', 'nixname', 'system', 'priority', 'busy', 'buildstatus', 'releasename');
sub getBuild { sub getBuild {
my ($c, $id) = @_; my ($c, $id) = @_;
my $build = $c->model('DB::Builds')->find($id); my $build = $c->model('DB::Builds')->find($id);
@ -97,7 +102,9 @@ sub getBuildStats {
sub getChannelData { sub getChannelData {
my ($c, $builds) = @_; my ($c, $builds) = @_;
my @builds2 = $builds->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')"); my @builds2 = $builds
->search_literal("exists (select 1 from buildproducts where build = me.id and type = 'nix-build')")
->search({}, { columns => [@buildListColumns, 'drvpath', 'outpath', 'description', 'homepage'] });
my @storePaths = (); my @storePaths = ();
foreach my $build (@builds2) { foreach my $build (@builds2) {
@ -144,12 +151,14 @@ sub requireLogin {
$c->detach; # doesn't return $c->detach; # doesn't return
} }
sub isProjectOwner { sub isProjectOwner {
my ($c, $project) = @_; my ($c, $project) = @_;
return $c->user_exists && ($c->check_user_roles('admin') || $c->user->username eq $project->owner->username || defined $c->model('DB::ProjectMembers')->find({ project => $project, userName => $c->user->username })); return $c->user_exists && ($c->check_user_roles('admin') || $c->user->username eq $project->owner->username || defined $c->model('DB::ProjectMembers')->find({ project => $project, userName => $c->user->username }));
} }
sub requireProjectOwner { sub requireProjectOwner {
my ($c, $project) = @_; my ($c, $project) = @_;
@ -166,6 +175,7 @@ sub isAdmin {
return $c->user_exists && $c->check_user_roles('admin'); return $c->user_exists && $c->check_user_roles('admin');
} }
sub requireAdmin { sub requireAdmin {
my ($c) = @_; my ($c) = @_;
@ -190,12 +200,12 @@ sub trim {
# Security checking of filenames. # Security checking of filenames.
Readonly::Scalar our $pathCompRE => "(?:[A-Za-z0-9-\+\._][A-Za-z0-9-\+\._]*)"; Readonly our $pathCompRE => "(?:[A-Za-z0-9-\+\._][A-Za-z0-9-\+\._]*)";
Readonly::Scalar our $relPathRE => "(?:$pathCompRE(?:/$pathCompRE)*)"; Readonly our $relPathRE => "(?:$pathCompRE(?:/$pathCompRE)*)";
Readonly::Scalar our $relNameRE => "(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)"; Readonly our $relNameRE => "(?:[A-Za-z0-9-][A-Za-z0-9-\.]*)";
Readonly::Scalar our $attrNameRE => "(?:[A-Za-z_][A-Za-z0-9_]*)"; Readonly our $attrNameRE => "(?:[A-Za-z_][A-Za-z0-9_]*)";
Readonly::Scalar our $jobNameRE => "(?:$attrNameRE(?:\\.$attrNameRE)*)"; Readonly our $jobNameRE => "(?:$attrNameRE(?:\\.$attrNameRE)*)";
Readonly::Scalar our $systemRE => "(?:[a-z0-9_]+-[a-z0-9_]+)"; Readonly our $systemRE => "(?:[a-z0-9_]+-[a-z0-9_]+)";
1; 1;