Make various MWCallableUpdate usages rollback-safe
authorAaron Schulz <aschulz@wikimedia.org>
Sat, 13 Aug 2016 19:28:53 +0000 (12:28 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Mon, 15 Aug 2016 07:47:42 +0000 (00:47 -0700)
Support for this added to MWCallableUpdate and its helper method
in DeferredUpdates.

Bug: T141988
Change-Id: Ief150ea655036e2708557dd8ae847379edf21933

includes/WatchedItemStore.php
includes/changes/RecentChange.php
includes/deferred/AtomicSectionUpdate.php
includes/deferred/AutoCommitUpdate.php
includes/deferred/DeferredUpdates.php
includes/deferred/MWCallableUpdate.php
includes/page/WikiPage.php
includes/revisiondelete/RevDelList.php

index 89ca50c..b8a47fa 100644 (file)
@@ -761,7 +761,9 @@ class WatchedItemStore implements StatsdAwareInterface {
                                        $this->uncacheLinkTarget( $target );
 
                                        $this->reuseConnection( $dbw );
-                               }
+                               },
+                               DeferredUpdates::POSTSEND,
+                               $dbw
                        );
                }
 
index 159cfd9..daf76df 100644 (file)
@@ -589,16 +589,20 @@ class RecentChange {
                        'pageStatus' => 'changed'
                ];
 
-               DeferredUpdates::addCallableUpdate( function() use ( $rc, $tags ) {
-                       $rc->save();
-                       if ( $rc->mAttribs['rc_patrolled'] ) {
-                               PatrolLog::record( $rc, true, $rc->getPerformer() );
-                       }
-                       if ( count( $tags ) ) {
-                               ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
-                                       $rc->mAttribs['rc_this_oldid'], null, null );
-                       }
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $rc, $tags ) {
+                               $rc->save();
+                               if ( $rc->mAttribs['rc_patrolled'] ) {
+                                       PatrolLog::record( $rc, true, $rc->getPerformer() );
+                               }
+                               if ( count( $tags ) ) {
+                                       ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
+                                               $rc->mAttribs['rc_this_oldid'], null, null );
+                               }
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $rc;
        }
@@ -661,16 +665,20 @@ class RecentChange {
                        'pageStatus' => 'created'
                ];
 
-               DeferredUpdates::addCallableUpdate( function() use ( $rc, $tags ) {
-                       $rc->save();
-                       if ( $rc->mAttribs['rc_patrolled'] ) {
-                               PatrolLog::record( $rc, true, $rc->getPerformer() );
-                       }
-                       if ( count( $tags ) ) {
-                               ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
-                                       $rc->mAttribs['rc_this_oldid'], null, null );
-                       }
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $rc, $tags ) {
+                               $rc->save();
+                               if ( $rc->mAttribs['rc_patrolled'] ) {
+                                       PatrolLog::record( $rc, true, $rc->getPerformer() );
+                               }
+                               if ( count( $tags ) ) {
+                                       ChangeTags::addTags( $tags, $rc->mAttribs['rc_id'],
+                                               $rc->mAttribs['rc_this_oldid'], null, null );
+                               }
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $rc;
        }
index 0da5d7d..a348719 100644 (file)
@@ -9,7 +9,7 @@ class AtomicSectionUpdate implements DeferrableUpdate, DeferrableCallback {
        private $dbw;
        /** @var string */
        private $fname;
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
 
        /**
index ef5903b..d26cf9d 100644 (file)
@@ -9,7 +9,7 @@ class AutoCommitUpdate implements DeferrableUpdate, DeferrableCallback {
        private $dbw;
        /** @var string */
        private $fname;
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
 
        /**
index 9768838..ee14e1a 100644 (file)
@@ -68,9 +68,12 @@ class DeferredUpdates {
         *
         * @param callable $callable
         * @param integer $type DeferredUpdates constant (PRESEND or POSTSEND) (since 1.27)
+        * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28)
         */
-       public static function addCallableUpdate( $callable, $type = self::POSTSEND ) {
-               self::addUpdate( new MWCallableUpdate( $callable, wfGetCaller() ), $type );
+       public static function addCallableUpdate(
+               $callable, $type = self::POSTSEND, IDatabase $dbw = null
+       ) {
+               self::addUpdate( new MWCallableUpdate( $callable, wfGetCaller(), $dbw ), $type );
        }
 
        /**
index d63c292..47b162c 100644 (file)
@@ -4,7 +4,7 @@
  * Deferrable Update for closure/callback
  */
 class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
-       /** @var callable */
+       /** @var callable|null */
        private $callback;
        /** @var string */
        private $fname;
@@ -12,14 +12,27 @@ class MWCallableUpdate implements DeferrableUpdate, DeferrableCallback {
        /**
         * @param callable $callback
         * @param string $fname Calling method
+        * @param IDatabase|null $dbw Abort if this DB is rolled back [optional] (since 1.28)
         */
-       public function __construct( callable $callback, $fname = 'unknown' ) {
+       public function __construct( callable $callback, $fname = 'unknown', IDatabase $dbw = null ) {
                $this->callback = $callback;
                $this->fname = $fname;
+
+               if ( $dbw && $dbw->trxLevel() ) {
+                       $dbw->onTransactionResolution( [ $this, 'cancelOnRollback' ] );
+               }
        }
 
        public function doUpdate() {
-               call_user_func( $this->callback );
+               if ( $this->callback ) {
+                       call_user_func( $this->callback );
+               }
+       }
+
+       public function cancelOnRollback( $trigger ) {
+               if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
+                       $this->callback = null;
+               }
        }
 
        public function getOrigin() {
index 8eba1cc..8545c36 100644 (file)
@@ -887,9 +887,13 @@ class WikiPage implements Page, IDBAccessObject {
                // Update the DB post-send if the page has not cached since now
                $that = $this;
                $latest = $this->getLatest();
-               DeferredUpdates::addCallableUpdate( function() use ( $that, $retval, $latest ) {
-                       $that->insertRedirectEntry( $retval, $latest );
-               } );
+               DeferredUpdates::addCallableUpdate(
+                       function () use ( $that, $retval, $latest ) {
+                               $that->insertRedirectEntry( $retval, $latest );
+                       },
+                       DeferredUpdates::POSTSEND,
+                       wfGetDB( DB_MASTER )
+               );
 
                return $retval;
        }
index d365bf6..48604e1 100644 (file)
@@ -275,7 +275,8 @@ abstract class RevDelList extends RevisionListBase {
                        function () use ( $visibilityChangeMap ) {
                                $this->doPostCommitUpdates( $visibilityChangeMap );
                        },
-                       DeferredUpdates::PRESEND
+                       DeferredUpdates::PRESEND,
+                       $dbw
                );
 
                $dbw->endAtomic( __METHOD__ );