From e45db871a4a4a12fb87f07e062831e4ca694cd95 Mon Sep 17 00:00:00 2001 From: uid623 <> Date: Wed, 7 Jun 2006 17:15:27 +0000 Subject: Patch for bug 305506: reduce number of SQL calls in Bugzilla::User->groups; increase speed when DB connectivity is poor and shift the burden on the webserver in order to improve scalability when multiple web frontends are used with a single backend DB; patch by Dennis Melentyev , r=wicked, r=mkanat, a=myk. --- Bugzilla/User.pm | 52 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 12 deletions(-) (limited to 'Bugzilla/User.pm') diff --git a/Bugzilla/User.pm b/Bugzilla/User.pm index 5da3db3ef..f0f8467a7 100644 --- a/Bugzilla/User.pm +++ b/Bugzilla/User.pm @@ -27,6 +27,7 @@ # Gervase Markham # Lance Larsh # Justin C. De Vries +# Dennis Melentyev ################################################################################ # Module Initialization @@ -269,24 +270,51 @@ sub groups { # The above gives us an arrayref [name, id, name, id, ...] # Convert that into a hashref my %groups = @$groups; - my $sth; my @groupidstocheck = values(%groups); my %groupidschecked = (); - $sth = $dbh->prepare("SELECT groups.name, groups.id + my $rows = $dbh->selectall_arrayref( + "SELECT DISTINCT groups.name, groups.id, member_id FROM group_group_map INNER JOIN groups ON groups.id = grantor_id - WHERE member_id = ? - AND grant_type = " . GROUP_MEMBERSHIP); - while (my $node = shift @groupidstocheck) { - $sth->execute($node); - my ($member_name, $member_id); - while (($member_name, $member_id) = $sth->fetchrow_array) { - if (!$groupidschecked{$member_id}) { - $groupidschecked{$member_id} = 1; - push @groupidstocheck, $member_id; - $groups{$member_name} = $member_id; + WHERE grant_type = " . GROUP_MEMBERSHIP); + my %group_names = (); + my %group_membership = (); + foreach my $row (@$rows) { + my ($member_name, $grantor_id, $member_id) = @$row; + # Just save the group names + $group_names{$grantor_id} = $member_name; + + # And group membership + push (@{$group_membership{$member_id}}, $grantor_id); + } + + # Let's walk the groups hierarchy tree (using FIFO) + # On the first iteration it's pre-filled with direct groups + # membership. Later on, each group can add its own members into the + # FIFO. Circular dependencies are eliminated by checking + # $groupidschecked{$member_id} hash values. + # As a result, %groups will have all the groups we are the member of. + while ($#groupidstocheck >= 0) { + # Pop the head group from FIFO + my $member_id = shift @groupidstocheck; + + # Skip the group if we have already checked it + if (!$groupidschecked{$member_id}) { + # Mark group as checked + $groupidschecked{$member_id} = 1; + + # Add all its members to the FIFO check list + # %group_membership contains arrays of group members + # for all groups. Accessible by group number. + foreach my $newgroupid (@{$group_membership{$member_id}}) { + push @groupidstocheck, $newgroupid + if (!$groupidschecked{$newgroupid}); } + # Note on if clause: we could have group in %groups from 1st + # query and do not have it in second one + $groups{$group_names{$member_id}} = $member_id + if $group_names{$member_id} && $member_id; } } $self->{groups} = \%groups; -- cgit v1.2.3-24-g4f1b