Merge "Add @deprecated annotations to NS_IMAGE and NS_IMAGE_TALK"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 28 Sep 2016 03:49:57 +0000 (03:49 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 28 Sep 2016 03:49:57 +0000 (03:49 +0000)
includes/WatchedItemStore.php
includes/libs/rdbms/chronologyprotector/ChronologyProtector.php
includes/libs/rdbms/lbfactory/ILBFactory.php
includes/libs/rdbms/lbfactory/LBFactory.php
includes/libs/rdbms/loadbalancer/LoadBalancer.php
tests/phpunit/includes/WatchedItemStoreUnitTest.php

index 478cc5f..90d45ce 100644 (file)
@@ -192,20 +192,11 @@ class WatchedItemStore implements StatsdAwareInterface {
        /**
         * @param int $dbIndex DB_MASTER or DB_REPLICA
         *
-        * @return DatabaseBase
+        * @return IDatabase
         * @throws MWException
         */
-       private function getConnection( $dbIndex ) {
-               return $this->loadBalancer->getConnection( $dbIndex, [ 'watchlist' ] );
-       }
-
-       /**
-        * @param Database $connection
-        *
-        * @throws MWException
-        */
-       private function reuseConnection( $connection ) {
-               $this->loadBalancer->reuseConnection( $connection );
+       private function getConnectionRef( $dbIndex ) {
+               return $this->loadBalancer->getConnectionRef( $dbIndex, [ 'watchlist' ] );
        }
 
        /**
@@ -217,7 +208,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @return int
         */
        public function countWatchedItems( User $user ) {
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
                $return = (int)$dbr->selectField(
                        'watchlist',
                        'COUNT(*)',
@@ -226,7 +217,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ],
                        __METHOD__
                );
-               $this->reuseConnection( $dbr );
 
                return $return;
        }
@@ -237,7 +227,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @return int
         */
        public function countWatchers( LinkTarget $target ) {
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
                $return = (int)$dbr->selectField(
                        'watchlist',
                        'COUNT(*)',
@@ -247,7 +237,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ],
                        __METHOD__
                );
-               $this->reuseConnection( $dbr );
 
                return $return;
        }
@@ -263,7 +252,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @throws MWException
         */
        public function countVisitingWatchers( LinkTarget $target, $threshold ) {
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
                $visitingWatchers = (int)$dbr->selectField(
                        'watchlist',
                        'COUNT(*)',
@@ -276,7 +265,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ],
                        __METHOD__
                );
-               $this->reuseConnection( $dbr );
 
                return $visitingWatchers;
        }
@@ -293,7 +281,7 @@ class WatchedItemStore implements StatsdAwareInterface {
        public function countWatchersMultiple( array $targets, array $options = [] ) {
                $dbOptions = [ 'GROUP BY' => [ 'wl_namespace', 'wl_title' ] ];
 
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
 
                if ( array_key_exists( 'minimumWatchers', $options ) ) {
                        $dbOptions['HAVING'] = 'COUNT(*) >= ' . (int)$options['minimumWatchers'];
@@ -308,8 +296,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        $dbOptions
                );
 
-               $this->reuseConnection( $dbr );
-
                $watchCounts = [];
                foreach ( $targets as $linkTarget ) {
                        $watchCounts[$linkTarget->getNamespace()][$linkTarget->getDBkey()] = 0;
@@ -341,7 +327,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                array $targetsWithVisitThresholds,
                $minimumWatchers = null
        ) {
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
 
                $conds = $this->getVisitingWatchersCondition( $dbr, $targetsWithVisitThresholds );
 
@@ -357,8 +343,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        $dbOptions
                );
 
-               $this->reuseConnection( $dbr );
-
                $watcherCounts = [];
                foreach ( $targetsWithVisitThresholds as list( $target ) ) {
                        /* @var LinkTarget $target */
@@ -452,14 +436,13 @@ class WatchedItemStore implements StatsdAwareInterface {
                        return false;
                }
 
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
                $row = $dbr->selectRow(
                        'watchlist',
                        'wl_notificationtimestamp',
                        $this->dbCond( $user, $target ),
                        __METHOD__
                );
-               $this->reuseConnection( $dbr );
 
                if ( !$row ) {
                        return false;
@@ -499,7 +482,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                                "wl_title {$options['sort']}"
                        ];
                }
-               $db = $this->getConnection( $options['forWrite'] ? DB_MASTER : DB_REPLICA );
+               $db = $this->getConnectionRef( $options['forWrite'] ? DB_MASTER : DB_REPLICA );
 
                $res = $db->select(
                        'watchlist',
@@ -508,7 +491,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        __METHOD__,
                        $dbOptions
                );
-               $this->reuseConnection( $db );
 
                $watchedItems = [];
                foreach ( $res as $row ) {
@@ -569,7 +551,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                        return $timestamps;
                }
 
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
 
                $lb = new LinkBatch( $targetsToLoad );
                $res = $dbr->select(
@@ -581,7 +563,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ],
                        __METHOD__
                );
-               $this->reuseConnection( $dbr );
 
                foreach ( $res as $row ) {
                        $timestamps[$row->wl_namespace][$row->wl_title] = $row->wl_notificationtimestamp;
@@ -630,13 +611,12 @@ class WatchedItemStore implements StatsdAwareInterface {
                        $this->uncache( $user, $target );
                }
 
-               $dbw = $this->getConnection( DB_MASTER );
+               $dbw = $this->getConnectionRef( DB_MASTER );
                foreach ( array_chunk( $rows, 100 ) as $toInsert ) {
                        // Use INSERT IGNORE to avoid overwriting the notification timestamp
                        // if there's already an entry for this page
                        $dbw->insert( 'watchlist', $toInsert, __METHOD__, 'IGNORE' );
                }
-               $this->reuseConnection( $dbw );
 
                return true;
        }
@@ -660,7 +640,7 @@ class WatchedItemStore implements StatsdAwareInterface {
 
                $this->uncache( $user, $target );
 
-               $dbw = $this->getConnection( DB_MASTER );
+               $dbw = $this->getConnectionRef( DB_MASTER );
                $dbw->delete( 'watchlist',
                        [
                                'wl_user' => $user->getId(),
@@ -669,7 +649,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ], __METHOD__
                );
                $success = (bool)$dbw->affectedRows();
-               $this->reuseConnection( $dbw );
 
                return $success;
        }
@@ -687,7 +666,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                        return false;
                }
 
-               $dbw = $this->getConnection( DB_MASTER );
+               $dbw = $this->getConnectionRef( DB_MASTER );
 
                $conds = [ 'wl_user' => $user->getId() ];
                if ( $targets ) {
@@ -702,8 +681,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        __METHOD__
                );
 
-               $this->reuseConnection( $dbw );
-
                $this->uncacheUser( $user );
 
                return $success;
@@ -718,7 +695,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @return int[] Array of user IDs the timestamp has been updated for
         */
        public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
-               $dbw = $this->getConnection( DB_MASTER );
+               $dbw = $this->getConnectionRef( DB_MASTER );
                $uids = $dbw->selectFieldValues(
                        'watchlist',
                        'wl_user',
@@ -730,7 +707,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        ],
                        __METHOD__
                );
-               $this->reuseConnection( $dbw );
 
                $watchers = array_map( 'intval', $uids );
                if ( $watchers ) {
@@ -740,7 +716,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                                function () use ( $timestamp, $watchers, $target, $fname ) {
                                        global $wgUpdateRowsPerQuery;
 
-                                       $dbw = $this->getConnection( DB_MASTER );
+                                       $dbw = $this->getConnectionRef( DB_MASTER );
                                        $factory = wfGetLBFactory();
                                        $ticket = $factory->getEmptyTransactionTicket( __METHOD__ );
 
@@ -762,8 +738,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                                                }
                                        }
                                        $this->uncacheLinkTarget( $target );
-
-                                       $this->reuseConnection( $dbw );
                                },
                                DeferredUpdates::POSTSEND,
                                $dbw
@@ -885,7 +859,7 @@ class WatchedItemStore implements StatsdAwareInterface {
                        $queryOptions['LIMIT'] = $unreadLimit;
                }
 
-               $dbr = $this->getConnection( DB_REPLICA );
+               $dbr = $this->getConnectionRef( DB_REPLICA );
                $rowCount = $dbr->selectRowCount(
                        'watchlist',
                        '1',
@@ -896,7 +870,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                        __METHOD__,
                        $queryOptions
                );
-               $this->reuseConnection( $dbr );
 
                if ( !isset( $unreadLimit ) ) {
                        return $rowCount;
@@ -937,7 +910,7 @@ class WatchedItemStore implements StatsdAwareInterface {
         * @param LinkTarget $newTarget
         */
        public function duplicateEntry( LinkTarget $oldTarget, LinkTarget $newTarget ) {
-               $dbw = $this->getConnection( DB_MASTER );
+               $dbw = $this->getConnectionRef( DB_MASTER );
 
                $result = $dbw->select(
                        'watchlist',
@@ -975,8 +948,6 @@ class WatchedItemStore implements StatsdAwareInterface {
                                __METHOD__
                        );
                }
-
-               $this->reuseConnection( $dbw );
        }
 
 }
index 94a3b6c..1f9aff1 100644 (file)
@@ -27,7 +27,7 @@ use Psr\Log\LoggerInterface;
  * Class for ensuring a consistent ordering of events as seen by the user, despite replication.
  * Kind of like Hawking's [[Chronology Protection Agency]].
  */
-class ChronologyProtector implements LoggerAwareInterface{
+class ChronologyProtector implements LoggerAwareInterface {
        /** @var BagOStuff */
        protected $store;
        /** @var LoggerInterface */
index d7ca7cd..9c9f18d 100644 (file)
@@ -136,9 +136,9 @@ interface ILBFactory {
        public function flushReplicaSnapshots( $fname = __METHOD__ );
 
        /**
-        * Commit on all connections. Done for two reasons:
-        * 1. To commit changes to the masters.
-        * 2. To release the snapshot on all connections, master and replica DB.
+        * Commit open transactions on all connections. This is useful for two main cases:
+        *   - a) To commit changes to the masters.
+        *   - b) To release the snapshot on all connections, master and replica DBs.
         * @param string $fname Caller name
         * @param array $options Options map:
         *   - maxWriteDuration: abort if more than this much time was spent in write queries
index 85194bc..0635d04 100644 (file)
@@ -178,6 +178,8 @@ abstract class LBFactory implements ILBFactory {
                                "$fname: transaction round '{$this->trxRoundId}' still running."
                        );
                }
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedPHPBehaviorForCommit(); // try to ignore client aborts
                // Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
                $this->forEachLBCallMethod( 'finalizeMasterChanges' );
                $this->trxRoundId = false;
@@ -516,6 +518,23 @@ abstract class LBFactory implements ILBFactory {
                $this->requestInfo = $info + $this->requestInfo;
        }
 
+       /**
+        * Make PHP ignore user aborts/disconnects until the returned
+        * value leaves scope. This returns null and does nothing in CLI mode.
+        *
+        * @return ScopedCallback|null
+        */
+       final protected function getScopedPHPBehaviorForCommit() {
+               if ( PHP_SAPI != 'cli' ) { // http://bugs.php.net/bug.php?id=47540
+                       $old = ignore_user_abort( true ); // avoid half-finished operations
+                       return new ScopedCallback( function () use ( $old ) {
+                               ignore_user_abort( $old );
+                       } );
+               }
+
+               return null;
+       }
+
        function __destruct() {
                $this->destroy();
        }
index a60e741..37c028b 100644 (file)
@@ -1101,6 +1101,9 @@ class LoadBalancer implements ILoadBalancer {
        public function commitMasterChanges( $fname = __METHOD__ ) {
                $failures = [];
 
+               /** @noinspection PhpUnusedLocalVariableInspection */
+               $scope = $this->getScopedPHPBehaviorForCommit(); // try to ignore client aborts
+
                $restore = ( $this->trxRoundId !== false );
                $this->trxRoundId = false;
                $this->forEachOpenMasterConnection(
@@ -1516,6 +1519,23 @@ class LoadBalancer implements ILoadBalancer {
                } );
        }
 
+       /**
+        * Make PHP ignore user aborts/disconnects until the returned
+        * value leaves scope. This returns null and does nothing in CLI mode.
+        *
+        * @return ScopedCallback|null
+        */
+       final protected function getScopedPHPBehaviorForCommit() {
+               if ( PHP_SAPI != 'cli' ) { // http://bugs.php.net/bug.php?id=47540
+                       $old = ignore_user_abort( true ); // avoid half-finished operations
+                       return new ScopedCallback( function () use ( $old ) {
+                               ignore_user_abort( $old );
+                       } );
+               }
+
+               return null;
+       }
+
        function __destruct() {
                // Avoid connection leaks for sanity
                $this->closeAll();
index 030d9d5..c51d496 100644 (file)
@@ -28,12 +28,12 @@ class WatchedItemStoreUnitTest extends MediaWikiTestCase {
                        ->getMock();
                if ( $expectedConnectionType !== null ) {
                        $mock->expects( $this->any() )
-                               ->method( 'getConnection' )
+                               ->method( 'getConnectionRef' )
                                ->with( $expectedConnectionType )
                                ->will( $this->returnValue( $mockDb ) );
                } else {
                        $mock->expects( $this->any() )
-                               ->method( 'getConnection' )
+                               ->method( 'getConnectionRef' )
                                ->will( $this->returnValue( $mockDb ) );
                }
                $mock->expects( $this->any() )