[Rt-commit] rt branch 5.0/cgm-cascade-delete created. rt-5.0.5-76-g7b87e46322

BPS Git Server git at git.bestpractical.com
Wed Apr 3 14:07:59 UTC 2024


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".

The branch, 5.0/cgm-cascade-delete has been created
        at  7b87e463224e650348e7685103278ca18864842c (commit)

- Log -----------------------------------------------------------------
commit 7b87e463224e650348e7685103278ca18864842c
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu Dec 7 15:48:17 2023 -0500

    Test cascaded deletion of cached group members

diff --git a/t/api/group.t b/t/api/group.t
index 13389567ee..0f5a997748 100644
--- a/t/api/group.t
+++ b/t/api/group.t
@@ -201,4 +201,33 @@ diag "Ticket role group members";
     ok( !$CGM->id, 'No CGM record for admincc <-> bob still' );
 }
 
+
+diag "Cascade delete cached group members";
+{
+    my $test1 = RT::Test->load_or_create_group('cascade test 1');
+    my $test2 = RT::Test->load_or_create_group('cascade test 2');
+    my $test3 = RT::Test->load_or_create_group('cascade test 3');
+    my $user  = RT::Test->load_or_create_user( Name => 'User 1' );
+
+    ok( $test3->AddMember( $user->PrincipalId ),  'Add User 1 to test 3' );
+    ok( $test2->AddMember( $test3->PrincipalId ), 'Add test 3 to test 2' );
+    ok( $test1->AddMember( $test2->PrincipalId ),  'Add test 2 to test 1' );
+
+    ok( $test1->HasMemberRecursively( $test2->PrincipalId ), "Group test 1 has test 2 recursively" );
+    ok( $test1->HasMemberRecursively( $test3->PrincipalId ), "Group test 1 has test 3 recursively" );
+    ok( $test1->HasMemberRecursively( $user->PrincipalId ),  "Group test 1 has User 1 recursively" );
+
+    my $cgms = RT::CachedGroupMembers->new( RT->SystemUser );
+    $cgms->Limit( FIELD => 'GroupId', VALUE => $test1->Id );
+    is( $cgms->Count, 4, 'Group test has 4 CachedGroupMembers rows' );
+
+    ok( $test1->DeleteMember( $test2->PrincipalId ), 'Delete test 2 from test' );
+    $cgms->RedoSearch;
+    is( $cgms->Count, 1, 'Group test has 1 CachedGroupMembers row' );
+
+    ok( !$test1->HasMemberRecursively( $test2->PrincipalId ), "Group test 1 does not have test 2 recursively" );
+    ok( !$test1->HasMemberRecursively( $test3->PrincipalId ), "Group test 1 does not have test 3 recursively" );
+    ok( !$test1->HasMemberRecursively( $user->PrincipalId ),  "Group test 1 does not have User 1 recursively" );
+}
+
 done_testing;

commit f22f1b1622c32b9909c7509fcd192294854ab2bc
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu Dec 7 15:38:57 2023 -0500

    Implement cascaded deletion of cached group members on DB level
    
    The performance is obviously better to clean up stuff on DB level. As
    Via is a foreign key, it can't be 0 any more.

diff --git a/etc/schema.Oracle b/etc/schema.Oracle
index d0893a74c9..28c59f6357 100644
--- a/etc/schema.Oracle
+++ b/etc/schema.Oracle
@@ -199,7 +199,8 @@ CREATE TABLE CachedGroupMembers (
         MemberId        NUMBER(11,0),
         Via             NUMBER(11,0),
         ImmediateParentId       NUMBER(11,0),
-        Disabled        NUMBER(11,0) DEFAULT 0 NOT NULL
+        Disabled        NUMBER(11,0) DEFAULT 0 NOT NULL,
+        FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE
 );
 CREATE INDEX DisGrouMem ON CachedGroupMembers (GroupId, MemberId, Disabled);
 CREATE INDEX CachedGroupMembers2 ON CachedGroupMembers (MemberId, GroupId, Disabled);
diff --git a/etc/schema.Pg b/etc/schema.Pg
index 2e7a983062..2440171ee1 100644
--- a/etc/schema.Pg
+++ b/etc/schema.Pg
@@ -325,6 +325,7 @@ CREATE TABLE CachedGroupMembers (
         Via int, 
         ImmediateParentId int, 
         Disabled integer NOT NULL DEFAULT 0 , 
+        FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE,
         PRIMARY KEY (id)
 
 );
diff --git a/etc/schema.SQLite b/etc/schema.SQLite
index be08cfd925..3df66dd98f 100644
--- a/etc/schema.SQLite
+++ b/etc/schema.SQLite
@@ -221,11 +221,12 @@ create table CachedGroupMembers (
         MemberId int, 
         Via int, 
         ImmediateParentId int,
-        Disabled int2 NOT NULL DEFAULT 0  # if this cached group member is a member of this group by way of a disabled
+        Disabled int2 NOT NULL DEFAULT 0,  # if this cached group member is a member of this group by way of a disabled
                                            # group or this group is disabled, this will be set to 1
                                            # this allows us to not find members of disabled subgroups when listing off
                                            # group members recursively.
                                            # Also, this allows us to have the ACL system elide members of disabled groups
+        FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE
 
         
 ) ;
diff --git a/etc/schema.mysql b/etc/schema.mysql
index 0c21d2b8b4..aa18b45a77 100644
--- a/etc/schema.mysql
+++ b/etc/schema.mysql
@@ -207,6 +207,7 @@ create table CachedGroupMembers (
                                            # this allows us to not find members of disabled subgroups when listing off
                                            # group members recursively.
                                            # Also, this allows us to have the ACL system elide members of disabled groups
+        FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE,
         PRIMARY KEY (id)
 ) ENGINE=InnoDB CHARACTER SET utf8mb4;
 
diff --git a/etc/upgrade/5.0.6/schema.Oracle b/etc/upgrade/5.0.6/schema.Oracle
new file mode 100644
index 0000000000..1f33351140
--- /dev/null
+++ b/etc/upgrade/5.0.6/schema.Oracle
@@ -0,0 +1 @@
+ALTER TABLE CachedGroupMembers ADD FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE;
diff --git a/etc/upgrade/5.0.6/schema.Pg b/etc/upgrade/5.0.6/schema.Pg
new file mode 100644
index 0000000000..1f33351140
--- /dev/null
+++ b/etc/upgrade/5.0.6/schema.Pg
@@ -0,0 +1 @@
+ALTER TABLE CachedGroupMembers ADD FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE;
diff --git a/etc/upgrade/5.0.6/schema.mysql b/etc/upgrade/5.0.6/schema.mysql
new file mode 100644
index 0000000000..1f33351140
--- /dev/null
+++ b/etc/upgrade/5.0.6/schema.mysql
@@ -0,0 +1 @@
+ALTER TABLE CachedGroupMembers ADD FOREIGN KEY (Via) REFERENCES CachedGroupMembers(id) ON DELETE CASCADE;
diff --git a/lib/RT/CachedGroupMember.pm b/lib/RT/CachedGroupMember.pm
index dc2feeed18..9debea6d56 100644
--- a/lib/RT/CachedGroupMember.pm
+++ b/lib/RT/CachedGroupMember.pm
@@ -99,7 +99,7 @@ sub Create {
     my %args = ( Group           => '',
                  Member          => '',
                  ImmediateParent => '',
-                 Via             => '0',
+                 Via             => undef,
                  Disabled        => '0',
                  @_ );
 
@@ -141,7 +141,12 @@ sub Create {
                            . $args{'Via'} );
         return (undef);  #this will percolate up and bail out of the transaction
     }
-    if ( $self->__Value('Via') == 0 ) {
+
+    # Check $args{Via} instead of __Value('Via') to avoid cache issues on
+    # SQLite that may reuse ids: t/validator/group_members.t fails with
+    # __Value('Via')
+
+    if ( !$args{Via} ) {
         my ( $vid, $vmsg ) = $self->__Set( Field => 'Via', Value => $id );
         unless ($vid) {
             $RT::Logger->warning( "Due to a via error, couldn't create "
@@ -181,44 +186,6 @@ sub Create {
 
 
 
-=head2 Delete
-
-Deletes the current CachedGroupMember from the group it's in and
-cascades the delete to all submembers.
-
-=cut
-
-sub Delete {
-    my $self = shift;
-
-
-    my $member = $self->MemberObj();
-    if ( $member->IsGroup ) {
-        my $deletable = RT::CachedGroupMembers->new( $self->CurrentUser );
-
-        $deletable->Limit( FIELD    => 'id',
-                           OPERATOR => '!=',
-                           VALUE    => $self->id );
-        $deletable->Limit( FIELD    => 'Via',
-                           OPERATOR => '=',
-                           VALUE    => $self->id );
-
-        while ( my $kid = $deletable->Next ) {
-            my ($ok, $msg) = $kid->Delete();
-            unless ($ok) {
-                $RT::Logger->error(
-                    "Couldn't delete CachedGroupMember " . $kid->Id );
-                return ($ok, $msg);
-            }
-        }
-    }
-    my ($ok, $msg) = $self->SUPER::Delete();
-    $RT::Logger->error( "Couldn't delete CachedGroupMember " . $self->Id ) unless $ok;
-    return ($ok, $msg);
-}
-
-
-
 =head2 SetDisabled
 
 SetDisableds the current CachedGroupMember from the group it's in and cascades 
diff --git a/lib/RT/GroupMember.pm b/lib/RT/GroupMember.pm
index 41b083561b..44286aa7a2 100644
--- a/lib/RT/GroupMember.pm
+++ b/lib/RT/GroupMember.pm
@@ -103,7 +103,7 @@ sub _InsertCGM {
         Member          => $self->MemberObj,
         Group           => $self->GroupObj,
         ImmediateParent => $self->GroupObj,
-        Via             => '0'
+        Via             => undef,
     );
 
 
@@ -289,7 +289,7 @@ sub _StashUser {
         Member          => $args{'Member'},
         Group           => $args{'Group'},
         ImmediateParent => $args{'Group'},
-        Via             => '0'
+        Via             => undef,
     );
 
     unless ($cached_id) {
diff --git a/lib/RT/Handle.pm b/lib/RT/Handle.pm
index 02e4667d7f..a7af75533e 100644
--- a/lib/RT/Handle.pm
+++ b/lib/RT/Handle.pm
@@ -154,6 +154,7 @@ sub Connect {
     }
     elsif ( $db_type eq 'SQLite' ) {
         $self->dbh->{sqlite_see_if_its_a_number} = 1;
+        $self->dbh->do('PRAGMA foreign_keys = ON'); # ON DELETE CASCADE for CachedGroupMembers needs it
     }
 
     $self->dbh->{'LongReadLen'} = RT->Config->Get('MaxAttachmentSize');
diff --git a/lib/RT/Migrate/Importer.pm b/lib/RT/Migrate/Importer.pm
index f73240e522..6da135c5d0 100644
--- a/lib/RT/Migrate/Importer.pm
+++ b/lib/RT/Migrate/Importer.pm
@@ -632,7 +632,7 @@ sub CloseStream {
     # Groups
     $self->RunSQL(<<'EOF');
 INSERT INTO CachedGroupMembers (GroupId, MemberId, Via, ImmediateParentId, Disabled)
-    SELECT Groups.id, Groups.id, 0, Groups.id, Principals.Disabled FROM Groups
+    SELECT Groups.id, Groups.id, NULL, Groups.id, Principals.Disabled FROM Groups
     LEFT JOIN Principals ON ( Groups.id = Principals.id )
     LEFT JOIN CachedGroupMembers ON (
         Groups.id = CachedGroupMembers.GroupId
@@ -645,7 +645,7 @@ EOF
     # GroupMembers
     $self->RunSQL(<<'EOF');
 INSERT INTO CachedGroupMembers (GroupId, MemberId, Via, ImmediateParentId, Disabled)
-    SELECT GroupMembers.GroupId, GroupMembers.MemberId, 0, GroupMembers.GroupId, Principals.Disabled FROM GroupMembers
+    SELECT GroupMembers.GroupId, GroupMembers.MemberId, NULL, GroupMembers.GroupId, Principals.Disabled FROM GroupMembers
     LEFT JOIN Principals ON ( GroupMembers.GroupId = Principals.id )
     LEFT JOIN CachedGroupMembers ON (
         GroupMembers.GroupId = CachedGroupMembers.GroupId
@@ -657,7 +657,7 @@ EOF
 
     # Fixup Via
     $self->RunSQL(<<'EOF');
-UPDATE CachedGroupMembers SET Via=id WHERE Via=0
+UPDATE CachedGroupMembers SET Via=id WHERE Via IS NULL
 EOF
 
     # Cascaded GroupMembers, use the same SQL in rt-validator

commit ffdaf3ef61bbc2029d0ddb9114431ed15e94ee4c
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Thu Dec 7 15:37:40 2023 -0500

    Index Via column of CachedGroupMembers
    
    When we delete CachedGroupMember rows, we need to find and delete all
    derived rows, by means of the Via column. Without the index, the search
    could be quite slow.

diff --git a/etc/schema.Oracle b/etc/schema.Oracle
index 53210b145b..d0893a74c9 100644
--- a/etc/schema.Oracle
+++ b/etc/schema.Oracle
@@ -204,6 +204,7 @@ CREATE TABLE CachedGroupMembers (
 CREATE INDEX DisGrouMem ON CachedGroupMembers (GroupId, MemberId, Disabled);
 CREATE INDEX CachedGroupMembers2 ON CachedGroupMembers (MemberId, GroupId, Disabled);
 CREATE INDEX CachedGroupMembers3 on CachedGroupMembers (MemberId, ImmediateParentId);
+CREATE INDEX CachedGroupMembers4 ON CachedGroupMembers (Via);
 
 
 CREATE SEQUENCE USERS_seq;
diff --git a/etc/schema.Pg b/etc/schema.Pg
index b614793b07..2e7a983062 100644
--- a/etc/schema.Pg
+++ b/etc/schema.Pg
@@ -332,6 +332,7 @@ CREATE TABLE CachedGroupMembers (
 CREATE INDEX CachedGroupMembers2 on CachedGroupMembers (MemberId, GroupId, Disabled);
 CREATE INDEX DisGrouMem  on CachedGroupMembers (GroupId,MemberId,Disabled);
 CREATE INDEX CachedGroupMembers3  on CachedGroupMembers (MemberId,ImmediateParentId);
+CREATE INDEX CachedGroupMembers4 ON CachedGroupMembers (Via);
 
 
 
diff --git a/etc/schema.SQLite b/etc/schema.SQLite
index 4b64f3349f..be08cfd925 100644
--- a/etc/schema.SQLite
+++ b/etc/schema.SQLite
@@ -233,6 +233,7 @@ create table CachedGroupMembers (
 CREATE INDEX CachedGroupMembers1 ON CachedGroupMembers (GroupId, MemberId, Disabled);
 CREATE INDEX CachedGroupMembers2 ON CachedGroupMembers (MemberId, GroupId, Disabled);
 CREATE INDEX CachedGroupMembers3 ON CachedGroupMembers (MemberId, ImmediateParentId);
+CREATE INDEX CachedGroupMembers4 ON CachedGroupMembers (Via);
 
 --- }}}
 
diff --git a/etc/schema.mysql b/etc/schema.mysql
index 382a10fc43..0c21d2b8b4 100644
--- a/etc/schema.mysql
+++ b/etc/schema.mysql
@@ -213,6 +213,7 @@ create table CachedGroupMembers (
 CREATE INDEX DisGrouMem  on CachedGroupMembers (GroupId,MemberId,Disabled);
 CREATE INDEX CachedGroupMembers2 on CachedGroupMembers (MemberId, GroupId, Disabled);
 CREATE INDEX CachedGroupMembers3 on CachedGroupMembers (MemberId, ImmediateParentId);
+CREATE INDEX CachedGroupMembers4 ON CachedGroupMembers (Via);
 
 
 
diff --git a/etc/upgrade/5.0.6/indexes b/etc/upgrade/5.0.6/indexes
new file mode 100644
index 0000000000..ae14e76e5a
--- /dev/null
+++ b/etc/upgrade/5.0.6/indexes
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+
+$RT::Handle->MakeSureIndexExists(
+    Table => 'CachedGroupMembers',
+    Columns => ['Via'],
+);
+
+1;

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


hooks/post-receive
-- 
rt


More information about the rt-commit mailing list