(bug 40340) Fix cache issues with changing user groups
authorTimo Tijhof <ttijhof@wikimedia.org>
Wed, 19 Sep 2012 00:24:35 +0000 (02:24 +0200)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 28 Dec 2012 14:35:49 +0000 (14:35 +0000)
* migrateUserGroup.php: Call User::invalidateCache

* While at it, also fix the issue where User::clearInstanceCache
  did not clear cache for User::getGroups.

  Although it does clear the caches of methods used to calculate
  other group-related lists (such as User::getEffectiveGroups),
  the one for the query from user_groups was still cached in
  $this->mGroups.

  Presumably this was forgotten when this pattern was introduced
  as the instance cache precedes the user_group table.

Change-Id: I22abdba00f8ccf587a3d7696e57970ed4653afc8

includes/User.php
maintenance/migrateUserGroup.php

index 91e75b5..a6958c8 100644 (file)
@@ -1201,6 +1201,7 @@ class User {
                $this->mRights = null;
                $this->mEffectiveGroups = null;
                $this->mImplicitGroups = null;
+               $this->mGroups = null;
                $this->mOptions = null;
                $this->mOptionsLoaded = false;
                $this->mEditCount = null;
index 496af72..f3e5957 100644 (file)
@@ -55,7 +55,9 @@ class MigrateUserGroup extends Maintenance {
                $blockEnd = $start + $this->mBatchSize - 1;
                // Migrate users over in batches...
                while ( $blockEnd <= $end ) {
+                       $affected = 0;
                        $this->output( "Doing users $blockStart to $blockEnd\n" );
+
                        $dbw->begin( __METHOD__ );
                        $dbw->update( 'user_groups',
                                array( 'ug_group' => $newGroup ),
@@ -64,19 +66,42 @@ class MigrateUserGroup extends Maintenance {
                                __METHOD__,
                                array( 'IGNORE' )
                        );
-                       $count += $dbw->affectedRows();
+                       $affected += $dbw->affectedRows();
+                       // Delete rows that the UPDATE operation above had to ignore.
+                       // This happens when a user is in both the old and new group.
+                       // Updating the row for the old group membership failed since
+                       // user/group is UNIQUE.
                        $dbw->delete( 'user_groups',
                                array( 'ug_group' => $oldGroup,
                                        "ug_user BETWEEN $blockStart AND $blockEnd" ),
                                __METHOD__
                        );
-                       $count += $dbw->affectedRows();
+                       $affected += $dbw->affectedRows();
                        $dbw->commit( __METHOD__ );
+
+                       // Clear cache for the affected users (bug 40340)
+                       if ( $affected > 0 ) {
+                               // XXX: This also invalidates cache of unaffected users that
+                               // were in the new group and not in the group.
+                               $res = $dbw->select( 'user_groups', 'ug_user',
+                                       array( 'ug_group' => $newGroup,
+                                               "ug_user BETWEEN $blockStart AND $blockEnd" ),
+                                       __METHOD__
+                               );
+                               if ( $res !== false ) {
+                                       foreach ( $res as $row ) {
+                                               $user = User::newFromId( $row->ug_user );
+                                               $user->invalidateCache();
+                                       }
+                               }
+                       }
+
+                       $count += $affected;
                        $blockStart += $this->mBatchSize;
                        $blockEnd += $this->mBatchSize;
                        wfWaitForSlaves();
                }
-               $this->output( "Done! $count user(s) in group '$oldGroup' are now in '$newGroup' instead.\n" );
+               $this->output( "Done! $count users in group '$oldGroup' are now in '$newGroup' instead.\n" );
        }
 }