[Rt-commit] rt branch, 4.2/optimize-cgm-table, updated. rt-4.0.0rc7-269-gc44ea57

Ruslan Zakirov ruz at bestpractical.com
Wed Mar 21 12:12:24 EDT 2012


The branch, 4.2/optimize-cgm-table has been updated
       via  c44ea579cb333032708663e0eb3712d47917e4e4 (commit)
       via  aa2388585f55474fd0ae288396c503a040c97255 (commit)
      from  df50bf2b38e2cb90537fd43daa73769c17800426 (commit)

Summary of changes:
 lib/RT/CachedGroupMember.pm |   74 +++++++++++++++---------
 t/api/group_members.t       |  133 +++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 176 insertions(+), 31 deletions(-)

- Log -----------------------------------------------------------------
commit aa2388585f55474fd0ae288396c503a040c97255
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Mar 21 20:10:47 2012 +0400

    test Disabled column in CGM table

diff --git a/t/api/group_members.t b/t/api/group_members.t
index 268b864..b85e0dc 100644
--- a/t/api/group_members.t
+++ b/t/api/group_members.t
@@ -1,7 +1,7 @@
 use strict;
 use warnings;
 
-use RT::Test nodata => 1, tests => 38;
+use RT::Test nodata => 1, tests => 376;
 
 my %GROUP;
 foreach my $name (qw(A B C D)) {
@@ -17,6 +17,8 @@ foreach my $name (qw(a b c d)) {
     ok $status, "created an user '$name'" or diag "error: $msg";
 }
 
+my %DISABLED;
+
 {
     add_members_ok( A => qw(a b c) );
     check_membership( A => [qw(a b c)] );
@@ -62,16 +64,73 @@ foreach my $name (qw(a b c d)) {
     random_delete( A => [qw(B C)], B => [qw(d)], C => [qw(d)] );
 }
 
-for (1..5) {
+for (1..3) {
     random_delete( random_build() );
 }
 
+{
+# variations of ruby:
+#   A
+# / | \
+# B | C
+# \ | /
+#   D
+    add_members_ok( A => qw(B C) );
+    add_members_ok( B => qw(D) );
+    add_members_ok( C => qw(D) );
+
+    # disable B with A -> C -> D active alternative for A->D
+    disable_group_ok( 'B' );
+    check_cgm_activity( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    # disable C, no more active alternative for A->D
+    disable_group_ok( 'C' );
+    check_cgm_activity( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    # add direct active (A->D) link
+    add_members_ok( A => qw(D) );
+    check_cgm_activity( A => [qw(B C D)], B => [qw(D)], C => [qw(D)] );
+
+    # delete active (A->D) when all alternative are disabled
+    del_members_ok( A => 'D' );
+    check_cgm_activity( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    # enable C that enables A->D
+    enable_group_ok( 'C' );
+    check_cgm_activity( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    # delete (A->B) and add back, B is disabled
+    del_members_ok( A => 'B' );
+    add_members_ok( A => qw(B) );
+    check_cgm_activity( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    random_delete( A => [qw(B C)], B => [qw(D)], C => [qw(D)] );
+
+    enable_group_ok( 'B' );
+}
+
+{
+# variations of triangle
+#   A
+# /   \
+# B -> C
+    add_members_ok( A => qw(B C) );
+    disable_group_ok( 'B' );
+
+    # add member to disabled group
+    add_members_ok( B => qw(C) );
+    check_cgm_activity( A => [qw(B C)], B => [qw(C)] );
+
+    random_delete( A => [qw(B C)], B => [qw(C)] );
+    enable_group_ok( 'B' );
+}
+
 sub random_build {
     my (%GM, %RCGM);
 
     my @groups = keys %GROUP;
 
-    my $i = 12;
+    my $i = 9;
     while ( $i-- ) {
         REPICK:
         my $g = $groups[int rand @groups];
@@ -97,7 +156,6 @@ sub random_build {
         push @{ $GM{ $g }||=[] }, $m;
         unless ( check_membership( %GM ) ) {
             Test::More::diag("were adding $error") unless $ENV{'TEST_VERBOSE'};
-            exit 1;
         }
 
         %RCGM = reverse_gm( gm_to_cgm(%GM) );
@@ -140,6 +198,7 @@ sub check_membership {
     my $res = _check_membership( HasMember => %GM );
     my %CGM = gm_to_cgm(%GM);
     $res &&= _check_membership( HasMemberRecursively => %CGM );
+    $res &&= check_cgm_activity( %GM );
     return $res;
 }
 
@@ -157,6 +216,22 @@ sub gm_to_cgm {
     return %CGM;
 }
 
+sub gm_to_activity {
+    my %GM = @_;
+
+    my $flat;
+    $flat = sub {
+        return if $DISABLED{ $_[0] };
+        my @self_ref = $GROUP{$_[0]} && !$DISABLED{$_[0]}? ($_[0]) : ();
+        return @self_ref unless $GM{ $_[0] };
+        return @self_ref, map { $_, $flat->($_) } @{ $GM{ $_[0] } };
+    };
+
+    my %CGM;
+    $CGM{ $_ } = [ $flat->( $_ ) ] foreach keys %GROUP;
+    return %CGM;
+}
+
 sub reverse_gm {
     my %GM = @_;
     my %res = @_;
@@ -167,6 +242,43 @@ sub reverse_gm {
     return %res;
 }
 
+sub check_cgm_activity {
+    local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+    my %GM = @_;
+
+    my $id_to_name = sub {
+        my $p = RT::Principal->new( RT->SystemUser );
+        $p->Load($_[0]);
+        $p->Object->Name;
+    };
+
+    my $data = $RT::Handle->dbh->selectall_arrayref(
+        "SELECT GroupId, MemberId FROM CachedGroupMembers WHERE Disabled = 0"
+        .' AND GroupId IN ('. join( ', ', map $_->id, values %GROUP, values %USER ) .')'
+        .' AND MemberId IN ('. join( ', ', map $_->id, values %GROUP, values %USER ) .')'
+    );
+
+    my %got;
+    foreach (@$data) {
+        my ($g, $m) = (map $id_to_name->($_), @$_);
+        push @{ $got{$g} ||= []}, $m;
+    }
+
+    my %expected = gm_to_activity( %GM );
+
+    foreach my $hash (\%got, \%expected) {
+        foreach ( values %$hash ) {
+            my %seen;
+            @$_ = sort grep !$seen{$_}++, @$_;
+        }
+        delete $hash->{$_} foreach grep !@{$hash->{$_}}, keys %$hash;
+    }
+    use Data::Dumper;
+    is_deeply(\%got, \%expected, 'activity of the records is correct')
+        or diag Dumper( \%got, \%expected );
+}
+
 sub _check_membership {
     local $Test::Builder::Level = $Test::Builder::Level + 1;
 
@@ -258,6 +370,19 @@ sub dump_gm {
     $anc_des_pairs->($G, $M);
 }
 
+sub disable_group_ok {
+    my $g = shift;
+    my ($status, $msg) = $GROUP{ $g }->SetDisabled(1);
+    ok $status, "disabled group '$g'" or diag "error: $msg";
+    $DISABLED{$g} = $GROUP{ $g }->Disabled;
+}
+sub enable_group_ok {
+    my $g = shift;
+    my ($status, $msg) = $GROUP{ $g }->SetDisabled(0);
+    ok $status, "enabled group '$g'" or diag "error: $msg";
+    $DISABLED{$g} = $GROUP{ $g }->Disabled;
+}
+
 sub substract_list {
     my $list = shift;
     foreach my $e ( @_ ) {

commit c44ea579cb333032708663e0eb3712d47917e4e4
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Mar 21 20:11:36 2012 +0400

    fix Disabled column handling

diff --git a/lib/RT/CachedGroupMember.pm b/lib/RT/CachedGroupMember.pm
index b27cddb..7cefb92 100644
--- a/lib/RT/CachedGroupMember.pm
+++ b/lib/RT/CachedGroupMember.pm
@@ -292,7 +292,7 @@ sub Delete {
     );
     return $res unless $res;
 
-    if ( $res > 1 && $member_is_group ) {
+    if ( $res > 0 && $member_is_group ) {
         $query =
             "SELECT main.id
             FROM $table main
@@ -311,16 +311,34 @@ sub Delete {
                 AND main.MemberId = CGMD.MemberId
                 AND main.Disabled = 1
         ";
-        $RT::Handle->SimpleUpdateFromSelect(
-            $table, { Disabled => 0 }, $query,
-            $self->GroupId,
-            $self->MemberId,
-        );
-        return $res unless $res;
     }
-    elsif ( $res > 1 ) {
-        
+    elsif ( $res > 0 ) {
+        $query =
+            "SELECT main.id
+            FROM $table main
+            JOIN $table CGMA ON CGMA.MemberId = ?
+
+            JOIN $table CGM3 ON CGM3.GroupId != CGM3.MemberId
+                AND CGM3.GroupId = main.GroupId
+                AND CGM3.Disabled = 0
+            JOIN $table CGM4 ON CGM4.GroupId != CGM4.MemberId
+                AND CGM4.MemberId = main.MemberId
+                AND CGM4.Disabled = 0
+                AND CGM3.MemberId = CGM4.GroupId
+            WHERE
+                main.GroupId = CGMA.GroupId
+                AND main.MemberId = ?
+                AND main.Disabled = 1
+        ";
     }
+
+    $res = $RT::Handle->SimpleUpdateFromSelect(
+        $table, { Disabled => 0 }, $query,
+        $self->GroupId,
+        $self->MemberId,
+    ) if $res > 0;
+    return $res unless $res;
+
     if ( my $m = $self->can('_FlushKeyCache') ) { $m->($self) };
 
     return 1;
@@ -349,35 +367,36 @@ sub SetDisabled {
         }
 
         my $query = "SELECT main.id FROM CachedGroupMembers main
-            JOIN CachedGroupMembers CGM1 ON main.GroupId = CGM1.GroupId
-                AND CGM1.MemberId = ?
-                AND CGM1.Disabled = 0
-            JOIN CachedGroupMembers CGM2 ON main.MemberId = CGM2.MemberId
-                AND CGM2.GroupId = ?
-            WHERE main.Disabled = 0";
+            WHERE main.Disabled = 0 AND main.GroupId = ?";
 
         $RT::Handle->SimpleUpdateFromSelect(
             $self->Table, { Disabled => 1 }, $query,
-            ($self->GroupId)x2,
+            $self->GroupId,
         ) or return undef;
 
         $query = "SELECT main.id FROM CachedGroupMembers main
             JOIN CachedGroupMembers CGM1 ON main.GroupId = CGM1.GroupId
                 AND CGM1.MemberId = ?
-                AND CGM1.Disabled = 0
             JOIN CachedGroupMembers CGM2 ON main.MemberId = CGM2.MemberId
-                AND CGM2.GroupId = ?
+                AND CGM2.GroupId = ? AND CGM2.GroupId != CGM2.MemberId
+
+            WHERE main.Disabled = 0
+                AND NOT EXISTS (
+                    SELECT CGM3.id
+                    FROM CachedGroupMembers CGM3, CachedGroupMembers CGM4
+                    WHERE CGM3.Disabled = 0 AND CGM4.Disabled = 0
+                        AND CGM3.GroupId = main.GroupId
+                        AND CGM3.MemberId = CGM4.GroupId
+                        AND CGM4.MemberId = main.MemberId
+                        AND CGM3.id != main.id
+                        AND CGM4.id != main.id
+                )
+        ";
 
-            JOIN CachedGroupMembers CGM3 ON CGM3.Disabled = 0
-                AND main.GroupId = CGM3.GroupID
-            JOIN CachedGroupMembers CGM4 ON CGM4.Disabled = 0
-                AND main.MemberId = CGM4.MemberId
-                AND CGM4.GroupId = CGM3.MemberId
 
-            WHERE main.Disabled = 1";
 
         $RT::Handle->SimpleUpdateFromSelect(
-            $self->Table, { Disabled => 0 }, $query,
+            $self->Table, { Disabled => 1 }, $query,
             ($self->GroupId)x2,
         ) or return undef;
     }
@@ -389,18 +408,19 @@ sub SetDisabled {
             );
             return $status;
         }
+        REDO:
         my $query = "SELECT main.id FROM CachedGroupMembers main
             JOIN CachedGroupMembers CGM1 ON main.GroupId = CGM1.GroupId
                 AND CGM1.MemberId = ?
-                AND CGM1.Disabled = 0
             JOIN CachedGroupMembers CGM2 ON main.MemberId = CGM2.MemberId
                 AND CGM2.GroupId = ?
             WHERE main.Disabled = 1";
 
-        $RT::Handle->SimpleUpdateFromSelect(
+        my $res = $RT::Handle->SimpleUpdateFromSelect(
             $self->Table, { Disabled => 0 }, $query,
             $self->GroupId, $self->MemberId
         ) or return undef;
+        goto REDO if $res > 0;
     }
     if ( my $m = $self->can('_FlushKeyCache') ) { $m->($self) };
     return (1);

-----------------------------------------------------------------------


More information about the Rt-commit mailing list