Fixed sanity cache clear in User::saveSettings()
authorAaron Schulz <aschulz@wikimedia.org>
Mon, 28 Sep 2015 21:07:01 +0000 (14:07 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Mon, 28 Sep 2015 21:07:01 +0000 (14:07 -0700)
* This works by adding a refresh mode to clearSharedCache()
  when we want to purge the cache in case it might stale to
  avoid further CAS errors. Because an exception will be
  thrown, the usual DB callback will not get fired, so avoid
  using commit hooks when doing these cache purges.
* Also lowered the tombstone TTL for such purges, since no
  data actually changed.

Bug: T114023
Change-Id: Iaad87b4ed24733dac40bc9607d3c97c940710087

includes/User.php

index faf1bdc..168c4ac 100644 (file)
@@ -1484,11 +1484,12 @@ class User implements IDBAccessObject {
 
                if ( $success ) {
                        $this->mTouched = $newTouched;
+                       $this->clearSharedCache();
+               } else {
+                       // Clears on failure too since that is desired if the cache is stale
+                       $this->clearSharedCache( 'refresh' );
                }
 
-               // Clears on failure too since that is desired if the cache is stale
-               $this->clearSharedCache();
-
                return $success;
        }
 
@@ -2282,22 +2283,29 @@ class User implements IDBAccessObject {
        }
 
        /**
-        * Clear user data from memcached.
-        * Use after applying fun updates to the database; caller's
+        * Clear user data from memcached
+        *
+        * Use after applying updates to the database; caller's
         * responsibility to update user_touched if appropriate.
         *
         * Called implicitly from invalidateCache() and saveSettings().
+        *
+        * @param string $mode Use 'refresh' to clear now; otherwise before DB commit
         */
-       public function clearSharedCache() {
+       public function clearSharedCache( $mode = 'changed' ) {
                $id = $this->getId();
                if ( !$id ) {
                        return;
                }
 
                $key = wfMemcKey( 'user', 'id', $id );
-               wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $key ) {
-                       ObjectCache::getMainWANInstance()->delete( $key );
-               } );
+               if ( $mode === 'refresh' ) {
+                       ObjectCache::getMainWANInstance()->delete( $key, 1 );
+               } else {
+                       wfGetDB( DB_MASTER )->onTransactionPreCommitOrIdle( function() use ( $key ) {
+                               ObjectCache::getMainWANInstance()->delete( $key );
+                       } );
+               }
        }
 
        /**
@@ -3702,7 +3710,7 @@ class User implements IDBAccessObject {
 
                if ( !$dbw->affectedRows() ) {
                        // Maybe the problem was a missed cache update; clear it to be safe
-                       $this->clearSharedCache();
+                       $this->clearSharedCache( 'refresh' );
                        // User was changed in the meantime or loaded with stale data
                        $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'master' : 'slave';
                        throw new MWException(