From 99e02eab80679cb1ac4ede7c4d8054b8a2164bad Mon Sep 17 00:00:00 2001 From: Byron Jones Date: Thu, 3 Jul 2014 15:36:08 +0800 Subject: Bug 1028795: pre-load all related bugs during show_bug initialisation r=sgreen,a=sgreen --- Bugzilla/Bug.pm | 64 +++++++++++++++++++++++++++++++++++++++++++++--- Bugzilla/Object.pm | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ Bugzilla/Template.pm | 11 +++++---- 3 files changed, 135 insertions(+), 9 deletions(-) diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index cb132f31d..b762a6500 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -504,6 +504,49 @@ sub preload { # 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. $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 +# query from the database and injecting bug objects into the object-cache. +sub _preload_referenced_bugs { + my $self = shift; + my @referenced_bug_ids; + + # inject current duplicates into the object-cache first + foreach my $bug (@{ $self->duplicates }) { + $bug->object_cache_set() + unless Bugzilla::Bug->object_cache_get($bug->id); + } + + # preload bugs from comments + require Bugzilla::Template; + foreach my $comment (@{ $self->comments }) { + 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 + my $referenced_bugs = Bugzilla::Bug->new_from_list( + [ uniq @referenced_bug_ids ]); + foreach my $bug (@$referenced_bugs) { + $bug->object_cache_set(); + } } sub possible_duplicates { @@ -3879,10 +3922,23 @@ sub EmitDependList { # Creates a lot of bug objects in the same order as the input array. sub _bugs_in_order { my ($self, $bug_ids) = @_; - my $bugs = $self->new_from_list($bug_ids); - my %bug_map = map { $_->id => $_ } @$bugs; - my @result = map { $bug_map{$_} } @$bug_ids; - return \@result; + my %bug_map; + # there's no need to load bugs from the database if they are already in the + # object-cache + my @missing_ids; + foreach my $bug_id (@$bug_ids) { + if (my $bug = Bugzilla::Bug->object_cache_get($bug_id)) { + $bug_map{$bug_id} = $bug; + } + else { + push @missing_ids, $bug_id; + } + } + my $bugs = $self->new_from_list(\@missing_ids); + foreach my $bug (@$bugs) { + $bug_map{$bug->id} = $bug; + } + return [ map { $bug_map{$_} } @$bug_ids ]; } # Get the activity of a bug, starting from $starttime (if given). diff --git a/Bugzilla/Object.pm b/Bugzilla/Object.pm index e5704b3b1..f20803632 100644 --- a/Bugzilla/Object.pm +++ b/Bugzilla/Object.pm @@ -196,6 +196,23 @@ sub initialize { } # Provides a mechanism for objects to be cached in the request_cache + +sub object_cache_get { + my ($class, $id) = @_; + return $class->_object_cache_get( + { id => $id, cache => 1}, + $class + ); +} + +sub object_cache_set { + my $self = shift; + return $self->_object_cache_set( + { id => $self->id, cache => 1 }, + $self + ); +} + sub _object_cache_get { my $class = shift; my ($param) = @_; @@ -1446,6 +1463,58 @@ Returns C<1> if the passed-in value is true, C<0> otherwise. =back +=head2 CACHE FUNCTIONS + +=over + +=item C + +=over + +=item B + +Class function which returns an object from the object-cache for the provided +C<$id>. + +=item B + +Takes an integer C<$id> of the object to retrieve. + +=item B + +Returns the object from the cache if found, otherwise returns C. + +=item B + +my $bug_from_cache = Bugzilla::Bug->object_cache_get(35); + +=back + +=item C + +=over + +=item B + +Object function which injects the object into the object-cache, using the +object's C as the key. + +=item B + +(none) + +=item B + +(nothing) + +=item B + +$bug->object_cache_set(); + +=back + +=back + =head1 CLASS FUNCTIONS =over diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index d1457a4fa..8fe50fa4f 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -147,9 +147,10 @@ sub get_format { # If you want to modify this routine, read the comments carefully sub quoteUrls { - my ($text, $bug, $comment, $user) = @_; + my ($text, $bug, $comment, $user, $bug_link_func) = @_; return $text unless $text; $user ||= Bugzilla->user; + $bug_link_func ||= \&get_bug_link; # We use /g for speed, but uris can have other things inside them # (http://foo/bug#3 for example). Filtering that out filters valid @@ -203,7 +204,7 @@ sub quoteUrls { map { qr/$_/ } grep($_, Bugzilla->params->{'urlbase'}, Bugzilla->params->{'sslbase'})) . ')'; $text =~ s~\b(${urlbase_re}\Qshow_bug.cgi?id=\E([0-9]+)(\#c([0-9]+))?)\b - ~($things[$count++] = get_bug_link($3, $1, { comment_num => $5, user => $user })) && + ~($things[$count++] = $bug_link_func->($3, $1, { comment_num => $5, user => $user })) && ("\x{FDD2}" . ($count-1) . "\x{FDD3}") ~egox; @@ -250,7 +251,7 @@ sub quoteUrls { $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 # depending on which part matched - (defined($2) ? get_bug_link($2, $1, { comment_num => $3, user => $user }) : + (defined($2) ? $bug_link_func->($2, $1, { comment_num => $3, user => $user }) : "$1") ~egx; @@ -266,7 +267,7 @@ sub quoteUrls { my $length = $+[0] - $-[0]; my $match = $1; - $match =~ s/((?:#$s*)?(\d+))/get_bug_link($2, $1);/eg; + $match =~ s/((?:#$s*)?(\d+))/$bug_link_func->($2, $1);/eg; # Replace the old string with the linkified one. substr($text, $offset, $length) = $match; } @@ -289,7 +290,7 @@ sub quoteUrls { $text =~ s~(?<=^\*\*\*\ This\ bug\ has\ been\ marked\ as\ a\ duplicate\ of\ ) (\d+) (?=\ \*\*\*\Z) - ~get_bug_link($1, $1, { user => $user }) + ~$bug_link_func->($1, $1, { user => $user }) ~egmx; # Now remove the encoding hacks in reverse order -- cgit v1.2.3-24-g4f1b