
jesse at bestpractical
Jan 13, 2005, 8:38 PM
Post #1 of 1
(301 views)
Permalink
|
|
RT 3.4 / Postgres / Search UI performance
|
|
I've spent the evening doing some stress testing / performance work on RT 3.4's search page under postgres. I have a proposed patch, but I really need folks to beat on it to see if it improves things significantly and whether it seems to actually do the right thing. It's attached to this message. If folks see a speed boost without errors, it'll make it into 3.4.0. But this means taht I need sites running postgres (and other databases) to test it out. It's likey that the issue in question only manifests with a large number of queues. === html/Elements/SelectOwner ================================================================== --- html/Elements/SelectOwner (revision 2678) +++ html/Elements/SelectOwner (local) @@ -67,25 +67,19 @@ @objects = keys %{$cfqueues}; } else { - my $Queues = RT::Queues->new($session{CurrentUser}); - $Queues->UnLimit(); - while (my $Queue = $Queues->Next()) { - push( @objects, $Queue ); - } + # Let's check rights on an empty queue object. that will do a search for any queue. + my $queue = RT::Queue->new($session{'CurrentUser'}); + push( @objects, $queue ); } my %user_uniq_hash; foreach my $object (@objects) { my $Users = RT::Users->new($session{CurrentUser}); - $Users->WhoHaveRight(Right => 'OwnTicket', - Object => $object, - IncludeSystemRights => 1, - IncludeSuperusers => 0); - while (my $User = $Users->Next()) { + $Users->WhoHaveRight(Right => 'OwnTicket', Object => $object, IncludeSystemRights => 1, IncludeSuperusers => 0); while (my $User = $Users->Next()) { $user_uniq_hash{$User->Id()} = $User; } } - [at] user = sort { uc($a->Name) cmp uc($b->Name) } values %user_uniq_hash; +@users = sort { uc($a->Name) cmp uc($b->Name) } values %user_uniq_hash; </%INIT> <%ARGS> === lib/RT/Users_Overlay.pm ================================================================== --- lib/RT/Users_Overlay.pm (revision 2678) +++ lib/RT/Users_Overlay.pm (local) @@ -239,6 +239,7 @@ or as members of groups +If passed a queue object, with no id, it will find users who have that right for _any_ queue @@ -246,38 +247,121 @@ sub WhoHaveRight { my $self = shift; - my %args = ( Right => undef, - Object => undef, - IncludeSystemRights => undef, - IncludeSuperusers => undef, - IncludeSubgroupMembers => 1, - @_ ); + my %args = ( + Right => undef, + Object => undef, + IncludeSystemRights => undef, + IncludeSuperusers => undef, + IncludeSubgroupMembers => 1, + @_ + ); - if (defined $args{'ObjectType'} || defined $args{'ObjectId'}) { - $RT::Logger->crit("$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API"); - return(undef); + if ( defined $args{'ObjectType'} || defined $args{'ObjectId'} ) { + $RT::Logger->crit( "$self WhoHaveRight called with the Obsolete ObjectId/ObjectType API"); + return (undef); } - my @privgroups; - my $Groups = RT::Groups->new($RT::SystemUser); - $Groups->WithRight(Right=> $args{'Right'}, - Object => $args{'Object'}, - IncludeSystemRights => $args{'IncludeSystemRights'}, - IncludeSuperusers => $args{'IncludeSuperusers'}); - while (my $Group = $Groups->Next()) { - push @privgroups, $Group->Id(); - } + + # Find only members of groups that have the right. - if (@privgroups) { - $self->WhoBelongToGroups(Groups => \@privgroups, - IncludeSubgroupMembers => $args{'IncludeSubgroupMembers'}); + my $acl = $self->NewAlias('ACL'); + my $groups = $self->NewAlias('Groups'); + my $userprinc = $self->{'princalias'}; + +# The cachedgroupmembers table is used for unrolling group memberships to allow fast lookups +# if we bind to CachedGroupMembers, we'll find all members of groups recursively. +# if we don't we'll find only 'direct' members of the group in question + my $cgm; + + if ( $args{'IncludeSubgroupMembers'} ) { + $cgm = $self->NewAlias('CachedGroupMembers'); } else { - # We don't have any group that matches -- make it impossible. - $self->Limit( FIELD => 'Id', VALUE => 'IS', OPERATOR => 'NULL' ); + $cgm = $self->NewAlias('GroupMembers'); } + +#Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) + $self->Join( + ALIAS1 => $cgm, + FIELD1 => 'MemberId', + ALIAS2 => $userprinc, + FIELD2 => 'id' + ); + + $self->Join( + ALIAS1 => $groups, + FIELD1 => 'id', + ALIAS2 => $cgm, + FIELD2 => 'GroupId' + ); + +# {{{ Find only rows where the right granted is the one we're looking up or _possibly_ superuser + $self->Limit( + ALIAS => $acl, + FIELD => 'RightName', + OPERATOR => ( $args{Right} ? '=' : 'IS NOT' ), + VALUE => $args{Right} || 'NULL', + ENTRYAGGREGATOR => 'OR' + ); + + if ( $args{'IncludeSuperusers'} and $args{'Right'} ) { + $self->Limit( + ALIAS => $acl, + FIELD => 'RightName', + OPERATOR => '=', + VALUE => 'SuperUser', + ENTRYAGGREGATOR => 'OR' + ); + } + + # }}} + + my ( $or_check_ticket_roles, $or_check_roles ); + my $which_object = "$acl.ObjectType = 'RT::System'"; + + if ( defined $args{'Object'} ) { + if ( ref( $args{'Object'} ) eq 'RT::Ticket' ) { + $or_check_ticket_roles = " OR ( $groups.Domain = 'RT::Ticket-Role' AND $groups.Instance = " . $args{'Object'}->Id . ") "; + +# If we're looking at ticket rights, we also want to look at the associated queue rights. +# this is a little bit hacky, but basically, now that we've done the ticket roles magic, +# we load the queue object and ask all the rest of our questions about the queue. + $args{'Object'} = $args{'Object'}->QueueObj; + } + + # TODO XXX This really wants some refactoring + if ( ref( $args{'Object'} ) eq 'RT::Queue' ) { + $or_check_roles = " OR ( ( ($groups.Domain = 'RT::Queue-Role' "; + $or_check_roles .= "AND $groups.Instance = " . $args{'Object'}->id if ( $args{'Object'}->id ); + $or_check_roles .= ") $or_check_ticket_roles ) " . " AND $groups.Type = $acl.PrincipalType) "; + } + if ( $args{'IncludeSystemRights'} ) { + $which_object .= ' OR '; + } + else { + $which_object = ''; + } + $which_object .= " ($acl.ObjectType = '" . ref( $args{'Object'} ) . "'"; + if ( $args{'Object'}->id ) { + $which_object .= " AND $acl.ObjectId = " . $args{'Object'}->id; + } + + $which_object .= ") "; + } + $self->_AddSubClause( "WhichObject", "($which_object)" ); + $self->_AddSubClause( + "WhichGroup", + qq{ ( ( $acl.PrincipalId = $groups.id AND $acl.PrincipalType = 'Group' + AND ( $groups.Domain = 'SystemInternal' OR $groups.Domain = 'UserDefined' OR $groups.Domain = 'ACLEquivalence')) + $or_check_roles) } + ); + # only include regular RT users + $self->LimitToEnabled; + + # no system user + $self->Limit( ALIAS => $userprinc, FIELD => 'id', OPERATOR => '!=', VALUE => $RT::SystemUser->id); + } - # }}} # {{{ WhoBelongToGroups @@ -310,20 +394,14 @@ $cgm = $self->NewAlias('GroupMembers'); } - # {{{ Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) + #Tie the users we're returning ($userprinc) to the groups that have rights granted to them ($groupprinc) $self->Join( ALIAS1 => $cgm, FIELD1 => 'MemberId', ALIAS2 => $userprinc, FIELD2 => 'id' ); - # }}} - # my $and_check_groups = "($cgm.GroupId = NULL"; foreach my $groupid (@{$args{'Groups'}}) { $self->Limit(ALIAS => $cgm, FIELD => 'GroupId', VALUE => $groupid, QUOTEVALUE => 0, ENTRYAGGREGATOR=> 'OR') - #$and_check_groups .= " OR $cgm.GroupId = $groupid"; } - #$and_check_groups .= ")"; - - #$self->_AddSubClause("WhichGroup", $and_check_groups); } # }}} -- _______________________________________________ http://lists.bestpractical.com/cgi-bin/mailman/listinfo/rt-users Be sure to check out the RT wiki at http://wiki.bestpractical.com
|