Commit 9c9eac99 authored by Frédéric Buclin's avatar Frédéric Buclin

Bug 1143871: Correctly preload bug data when viewing a bug

r=dkl a=sgreen
parent fcd44591
...@@ -505,59 +505,68 @@ sub preload { ...@@ -505,59 +505,68 @@ sub preload {
# to the more complex method. # to the more complex method.
my @all_dep_ids; my @all_dep_ids;
foreach my $bug (@$bugs) { foreach my $bug (@$bugs) {
push(@all_dep_ids, @{ $bug->blocked }, @{ $bug->dependson }); push @all_dep_ids, @{ $bug->blocked }, @{ $bug->dependson };
push(@all_dep_ids, @{ $bug->duplicate_ids }); push @all_dep_ids, @{ $bug->duplicate_ids };
push @all_dep_ids, @{ $bug->_preload_referenced_bugs };
} }
@all_dep_ids = uniq @all_dep_ids; @all_dep_ids = uniq @all_dep_ids;
# If we don't do this, can_see_bug will do one call per bug in # If we don't do this, can_see_bug will do one call per bug in
# the dependency and duplicate lists, in Bugzilla::Template::get_bug_link. # the dependency and duplicate lists, in Bugzilla::Template::get_bug_link.
$user->visible_bugs(\@all_dep_ids); $user->visible_bugs(\@all_dep_ids);
foreach my $bug (@$bugs) {
$bug->_preload_referenced_bugs();
}
} }
# Helps load up bugs referenced in comments by retrieving them with a single # Helps load up bugs referenced in comments by retrieving them with a single
# query from the database and injecting bug objects into the object-cache. # query from the database and injecting bug objects into the object-cache.
sub _preload_referenced_bugs { sub _preload_referenced_bugs {
my $self = shift; my $self = shift;
my @referenced_bug_ids;
# inject current duplicates into the object-cache first # inject current duplicates into the object-cache first
foreach my $bug (@{ $self->duplicates }) { foreach my $bug (@{ $self->duplicates }) {
$bug->object_cache_set() $bug->object_cache_set() unless Bugzilla::Bug->object_cache_get($bug->id);
unless Bugzilla::Bug->object_cache_get($bug->id);
} }
# preload bugs from comments # preload bugs from comments
require Bugzilla::Template; my $referenced_bug_ids = _extract_bug_ids($self->comments);
foreach my $comment (@{ $self->comments }) { my @ref_bug_ids = grep { !Bugzilla::Bug->object_cache_get($_) } @$referenced_bug_ids;
if ($comment->type == CMT_HAS_DUPE || $comment->type == CMT_DUPE_OF) {
# duplicate bugs that aren't currently in $self->duplicates
push @referenced_bug_ids, $comment->extra_data
unless Bugzilla::Bug->object_cache_get($comment->extra_data);
}
else {
# bugs referenced in comments
Bugzilla::Template::quoteUrls($comment->body, undef, undef, undef,
sub {
my $bug_id = $_[0];
push @referenced_bug_ids, $bug_id
unless Bugzilla::Bug->object_cache_get($bug_id);
});
}
}
# inject into object-cache # inject into object-cache
my $referenced_bugs = Bugzilla::Bug->new_from_list( my $referenced_bugs = Bugzilla::Bug->new_from_list(\@ref_bug_ids);
[ uniq @referenced_bug_ids ]); $_->object_cache_set() foreach @$referenced_bugs;
foreach my $bug (@$referenced_bugs) {
$bug->object_cache_set();
}
# preload bug visibility return $referenced_bug_ids
Bugzilla->user->visible_bugs(\@referenced_bug_ids); }
# Extract bug IDs mentioned in comments. This is much faster than calling quoteUrls().
sub _extract_bug_ids {
my $comments = shift;
my @bug_ids;
my $params = Bugzilla->params;
my @urlbases = ($params->{'urlbase'});
push(@urlbases, $params->{'sslbase'}) if $params->{'sslbase'};
my $urlbase_re = '(?:' . join('|', map { qr/$_/ } @urlbases) . ')';
my $bug_word = template_var('terms')->{bug};
my $bugs_word = template_var('terms')->{bugs};
foreach my $comment (@$comments) {
if ($comment->type == CMT_HAS_DUPE || $comment->type == CMT_DUPE_OF) {
push @bug_ids, $comment->extra_data;
next;
}
my $s = $comment->already_wrapped ? qr/\s/ : qr/\h/;
my $text = $comment->body;
# Full bug links
push @bug_ids, $text =~ /\b$urlbase_re\Qshow_bug.cgi?id=\E(\d+)(?:\#c\d+)?/g;
# bug X
my $bug_re = qr/\Q$bug_word\E$s*\#?$s*(\d+)/i;
push @bug_ids, $text =~ /\b$bug_re/g;
# bugs X, Y, Z
my $bugs_re = qr/\Q$bugs_word\E$s*\#?$s*(\d+)(?:$s*,$s*\#?$s*(\d+))+/i;
push @bug_ids, $text =~ /\b$bugs_re/g;
# Old duplicate markers
push @bug_ids, $text =~ /(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ )(\d+)(?=\ \*\*\*\Z)/;
}
return [uniq @bug_ids];
} }
sub possible_duplicates { sub possible_duplicates {
...@@ -3374,13 +3383,8 @@ sub alias { ...@@ -3374,13 +3383,8 @@ sub alias {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
$self->{'alias'} = $dbh->selectcol_arrayref( $self->{'alias'} = $dbh->selectcol_arrayref(
q{SELECT alias q{SELECT alias FROM bugs_aliases WHERE bug_id = ? ORDER BY alias},
FROM bugs_aliases undef, $self->bug_id);
WHERE bug_id = ?
ORDER BY alias},
undef, $self->bug_id);
$self->{'alias'} = [] if !scalar(@{$self->{'alias'}});
return $self->{'alias'}; return $self->{'alias'};
} }
...@@ -3408,6 +3412,7 @@ sub attachments { ...@@ -3408,6 +3412,7 @@ sub attachments {
$self->{'attachments'} = $self->{'attachments'} =
Bugzilla::Attachment->get_attachments_by_bug($self, {preload => 1}); Bugzilla::Attachment->get_attachments_by_bug($self, {preload => 1});
$_->object_cache_set() foreach @{ $self->{'attachments'} };
return $self->{'attachments'}; return $self->{'attachments'};
} }
...@@ -4039,7 +4044,11 @@ sub EmitDependList { ...@@ -4039,7 +4044,11 @@ sub EmitDependList {
# Creates a lot of bug objects in the same order as the input array. # Creates a lot of bug objects in the same order as the input array.
sub _bugs_in_order { sub _bugs_in_order {
my ($self, $bug_ids) = @_; my ($self, $bug_ids) = @_;
return [] unless @$bug_ids;
my %bug_map; my %bug_map;
my $dbh = Bugzilla->dbh;
# there's no need to load bugs from the database if they are already in the # there's no need to load bugs from the database if they are already in the
# object-cache # object-cache
my @missing_ids; my @missing_ids;
...@@ -4051,10 +4060,25 @@ sub _bugs_in_order { ...@@ -4051,10 +4060,25 @@ sub _bugs_in_order {
push @missing_ids, $bug_id; push @missing_ids, $bug_id;
} }
} }
my $bugs = $self->new_from_list(\@missing_ids); if (@missing_ids) {
foreach my $bug (@$bugs) { my $bugs = Bugzilla::Bug->new_from_list(\@missing_ids);
$bug_map{$bug->id} = $bug; $bug_map{$_->id} = $_ foreach @$bugs;
}
# Dependencies are often displayed using their aliases instead of their
# bug ID. Load them all at once.
my $rows = $dbh->selectall_arrayref(
'SELECT bug_id, alias FROM bugs_aliases WHERE ' .
$dbh->sql_in('bug_id', $bug_ids) . ' ORDER BY alias');
foreach my $row (@$rows) {
my ($bug_id, $alias) = @$row;
$bug_map{$bug_id}->{alias} ||= [];
push @{ $bug_map{$bug_id}->{alias} }, $alias;
} }
# Make sure all bugs have their alias attribute set.
$bug_map{$_}->{alias} ||= [] foreach @$bug_ids;
return [ map { $bug_map{$_} } @$bug_ids ]; return [ map { $bug_map{$_} } @$bug_ids ];
} }
...@@ -4497,6 +4521,10 @@ sub ValidateDependencies { ...@@ -4497,6 +4521,10 @@ sub ValidateDependencies {
my $dbh = Bugzilla->dbh; my $dbh = Bugzilla->dbh;
my %deps; my %deps;
my %deptree; my %deptree;
my %sth;
$sth{dependson} = $dbh->prepare('SELECT dependson FROM dependencies WHERE blocked = ?');
$sth{blocked} = $dbh->prepare('SELECT blocked FROM dependencies WHERE dependson = ?');
foreach my $pair (["blocked", "dependson"], ["dependson", "blocked"]) { foreach my $pair (["blocked", "dependson"], ["dependson", "blocked"]) {
my ($me, $target) = @{$pair}; my ($me, $target) = @{$pair};
$deptree{$target} = []; $deptree{$target} = [];
...@@ -4521,10 +4549,7 @@ sub ValidateDependencies { ...@@ -4521,10 +4549,7 @@ sub ValidateDependencies {
my @stack = @{$deps{$target}}; my @stack = @{$deps{$target}};
while (@stack) { while (@stack) {
my $i = shift @stack; my $i = shift @stack;
my $dep_list = my $dep_list = $dbh->selectcol_arrayref($sth{$target}, undef, $i);
$dbh->selectcol_arrayref("SELECT $target
FROM dependencies
WHERE $me = ?", undef, $i);
foreach my $t (@$dep_list) { foreach my $t (@$dep_list) {
# ignore any _current_ dependencies involving this bug, # ignore any _current_ dependencies involving this bug,
# as they will be overwritten with data from the form. # as they will be overwritten with data from the form.
......
...@@ -148,10 +148,9 @@ sub get_format { ...@@ -148,10 +148,9 @@ sub get_format {
# If you want to modify this routine, read the comments carefully # If you want to modify this routine, read the comments carefully
sub quoteUrls { sub quoteUrls {
my ($text, $bug, $comment, $user, $bug_link_func) = @_; my ($text, $bug, $comment, $user) = @_;
return $text unless $text; return $text unless $text;
$user ||= Bugzilla->user; $user ||= Bugzilla->user;
$bug_link_func ||= \&get_bug_link;
# We use /g for speed, but uris can have other things inside them # We use /g for speed, but uris can have other things inside them
# (http://foo/bug#3 for example). Filtering that out filters valid # (http://foo/bug#3 for example). Filtering that out filters valid
...@@ -205,7 +204,7 @@ sub quoteUrls { ...@@ -205,7 +204,7 @@ sub quoteUrls {
map { qr/$_/ } grep($_, Bugzilla->params->{'urlbase'}, map { qr/$_/ } grep($_, Bugzilla->params->{'urlbase'},
Bugzilla->params->{'sslbase'})) . ')'; Bugzilla->params->{'sslbase'})) . ')';
$text =~ s~\b(${urlbase_re}\Qshow_bug.cgi?id=\E([0-9]+)(\#c([0-9]+))?)\b $text =~ s~\b(${urlbase_re}\Qshow_bug.cgi?id=\E([0-9]+)(\#c([0-9]+))?)\b
~($things[$count++] = $bug_link_func->($3, $1, { comment_num => $5, user => $user })) && ~($things[$count++] = get_bug_link($3, $1, { comment_num => $5, user => $user })) &&
("\x{FDD2}" . ($count-1) . "\x{FDD3}") ("\x{FDD2}" . ($count-1) . "\x{FDD3}")
~egox; ~egox;
...@@ -252,7 +251,7 @@ sub quoteUrls { ...@@ -252,7 +251,7 @@ sub quoteUrls {
$text =~ s~\b($bug_re(?:$s*,?$s*$comment_re)?|$comment_re) $text =~ s~\b($bug_re(?:$s*,?$s*$comment_re)?|$comment_re)
~ # We have several choices. $1 here is the link, and $2-4 are set ~ # We have several choices. $1 here is the link, and $2-4 are set
# depending on which part matched # depending on which part matched
(defined($2) ? $bug_link_func->($2, $1, { comment_num => $3, user => $user }) : (defined($2) ? get_bug_link($2, $1, { comment_num => $3, user => $user }) :
"<a href=\"$current_bugurl#c$4\">$1</a>") "<a href=\"$current_bugurl#c$4\">$1</a>")
~egx; ~egx;
...@@ -266,7 +265,7 @@ sub quoteUrls { ...@@ -266,7 +265,7 @@ sub quoteUrls {
$text =~ s{($bugs_re)}{ $text =~ s{($bugs_re)}{
my $match = $1; my $match = $1;
$match =~ s/((?:#$s*)?(\d+))/$bug_link_func->($2, $1);/eg; $match =~ s/((?:#$s*)?(\d+))/get_bug_link($2, $1);/eg;
$match; $match;
}eg; }eg;
...@@ -286,7 +285,7 @@ sub quoteUrls { ...@@ -286,7 +285,7 @@ sub quoteUrls {
$text =~ s~(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ ) $text =~ s~(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ )
(\d+) (\d+)
(?=\ \*\*\*\Z) (?=\ \*\*\*\Z)
~$bug_link_func->($1, $1, { user => $user }) ~get_bug_link($1, $1, { user => $user })
~egmx; ~egmx;
# Now remove the encoding hacks in reverse order # Now remove the encoding hacks in reverse order
...@@ -300,7 +299,6 @@ sub quoteUrls { ...@@ -300,7 +299,6 @@ sub quoteUrls {
# Creates a link to an attachment, including its title. # Creates a link to an attachment, including its title.
sub get_attachment_link { sub get_attachment_link {
my ($attachid, $link_text, $user) = @_; my ($attachid, $link_text, $user) = @_;
my $dbh = Bugzilla->dbh;
$user ||= Bugzilla->user; $user ||= Bugzilla->user;
my $attachment = new Bugzilla::Attachment({ id => $attachid, cache => 1 }); my $attachment = new Bugzilla::Attachment({ id => $attachid, cache => 1 });
...@@ -351,7 +349,6 @@ sub get_bug_link { ...@@ -351,7 +349,6 @@ sub get_bug_link {
my ($bug, $link_text, $options) = @_; my ($bug, $link_text, $options) = @_;
$options ||= {}; $options ||= {};
$options->{user} ||= Bugzilla->user; $options->{user} ||= Bugzilla->user;
my $dbh = Bugzilla->dbh;
if (defined $bug && $bug ne '') { if (defined $bug && $bug ne '') {
if (!blessed($bug)) { if (!blessed($bug)) {
......
...@@ -406,6 +406,10 @@ elsif ($action eq 'next_bug' or $action eq 'same_bug') { ...@@ -406,6 +406,10 @@ elsif ($action eq 'next_bug' or $action eq 'same_bug') {
if ($action eq 'next_bug') { if ($action eq 'next_bug') {
$vars->{'nextbug'} = $bug->id; $vars->{'nextbug'} = $bug->id;
} }
# For performance reasons, preload visibility of dependencies
# and duplicates related to this bug.
Bugzilla::Bug->preload([$bug]);
$template->process("bug/show.html.tmpl", $vars) $template->process("bug/show.html.tmpl", $vars)
|| ThrowTemplateError($template->error()); || ThrowTemplateError($template->error());
exit; exit;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment