Revert "Use display name in category page subheadings if provided"
[lhc/web/wiklou.git] / includes / db / loadbalancer / LoadBalancer.php
index a67eac1..d08172a 100644 (file)
@@ -49,6 +49,8 @@ class LoadBalancer {
        private $mLoadMonitor;
        /** @var BagOStuff */
        private $srvCache;
+       /** @var WANObjectCache */
+       private $wanCache;
 
        /** @var bool|DatabaseBase Database connection that caused a problem */
        private $mErrorConnection;
@@ -76,6 +78,8 @@ class LoadBalancer {
        const MAX_LAG = 10;
        /** @var integer Max time to wait for a slave to catch up (e.g. ChronologyProtector) */
        const POS_WAIT_TIMEOUT = 10;
+       /** @var integer Seconds to cache master server read-only status */
+       const TTL_CACHE_READONLY = 5;
 
        /**
         * @var boolean
@@ -87,6 +91,8 @@ class LoadBalancer {
         *  - servers : Required. Array of server info structures.
         *  - loadMonitor : Name of a class used to fetch server lag and load.
         *  - readOnlyReason : Reason the master DB is read-only if so [optional]
+        *  - srvCache : BagOStuff object [optional]
+        *  - wanCache : WANObjectCache object [optional]
         * @throws MWException
         */
        public function __construct( array $params ) {
@@ -134,8 +140,16 @@ class LoadBalancer {
                        }
                }
 
-               $this->srvCache = ObjectCache::getLocalServerInstance();
-
+               if ( isset( $params['srvCache'] ) ) {
+                       $this->srvCache = $params['srvCache'];
+               } else {
+                       $this->srvCache = new EmptyBagOStuff();
+               }
+               if ( isset( $params['wanCache'] ) ) {
+                       $this->wanCache = $params['wanCache'];
+               } else {
+                       $this->wanCache = WANObjectCache::newEmpty();
+               }
                if ( isset( $params['trxProfiler'] ) ) {
                        $this->trxProfiler = $params['trxProfiler'];
                } else {
@@ -578,7 +592,7 @@ class LoadBalancer {
 
                if ( $masterOnly ) {
                        # Make master-requested DB handles inherit any read-only mode setting
-                       $conn->setLBInfo( 'readOnlyReason', $this->getReadOnlyReason( $wiki ) );
+                       $conn->setLBInfo( 'readOnlyReason', $this->getReadOnlyReason( $wiki, $conn ) );
                }
 
                return $conn;
@@ -600,7 +614,7 @@ class LoadBalancer {
                        /**
                         * This can happen in code like:
                         *   foreach ( $dbs as $db ) {
-                        *     $conn = $lb->getConnection( DB_SLAVE, array(), $db );
+                        *     $conn = $lb->getConnection( DB_SLAVE, [], $db );
                         *     ...
                         *     $lb->reuseConnection( $conn );
                         *   }
@@ -1048,7 +1062,7 @@ class LoadBalancer {
         */
        public function commitAll( $fname = __METHOD__ ) {
                $this->forEachOpenConnection( function ( DatabaseBase $conn ) use ( $fname ) {
-                       $conn->commit( $fname, 'flush' );
+                       $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
                } );
        }
 
@@ -1095,7 +1109,7 @@ class LoadBalancer {
        public function commitMasterChanges( $fname = __METHOD__ ) {
                $this->forEachOpenMasterConnection( function ( DatabaseBase $conn ) use ( $fname ) {
                        if ( $conn->writesOrCallbacksPending() ) {
-                               $conn->commit( $fname, 'flush' );
+                               $conn->commit( $fname, IDatabase::FLUSHING_ALL_PEERS );
                        }
                } );
        }
@@ -1129,7 +1143,7 @@ class LoadBalancer {
                        foreach ( $conns2[$masterIndex] as $conn ) {
                                if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) {
                                        try {
-                                               $conn->rollback( $fname, 'flush' );
+                                               $conn->rollback( $fname, IDatabase::FLUSHING_ALL_PEERS );
                                        } catch ( DBError $e ) {
                                                MWExceptionHandler::logException( $e );
                                                $failedServers[] = $conn->getServer();
@@ -1274,10 +1288,11 @@ class LoadBalancer {
        /**
         * @note This method may trigger a DB connection if not yet done
         * @param string|bool $wiki Wiki ID, or false for the current wiki
+        * @param DatabaseBase|null DB master connection; used to avoid loops [optional]
         * @return string|bool Reason the master is read-only or false if it is not
         * @since 1.27
         */
-       public function getReadOnlyReason( $wiki = false ) {
+       public function getReadOnlyReason( $wiki = false, DatabaseBase $conn = null ) {
                if ( $this->readOnlyReason !== false ) {
                        return $this->readOnlyReason;
                } elseif ( $this->getLaggedSlaveMode( $wiki ) ) {
@@ -1288,11 +1303,40 @@ class LoadBalancer {
                                return 'The database has been automatically locked ' .
                                        'while the slave database servers catch up to the master.';
                        }
+               } elseif ( $this->masterRunningReadOnly( $wiki, $conn ) ) {
+                       return 'The database master is running in read-only mode.';
                }
 
                return false;
        }
 
+       /**
+        * @param string $wiki Wiki ID, or false for the current wiki
+        * @param DatabaseBase|null DB master connectionl used to avoid loops [optional]
+        * @return bool
+        */
+       private function masterRunningReadOnly( $wiki, DatabaseBase $conn = null ) {
+               $cache = $this->wanCache;
+               $masterServer = $this->getServerName( $this->getWriterIndex() );
+
+               return (bool)$cache->getWithSetCallback(
+                       $cache->makeGlobalKey( __CLASS__, 'server-read-only', $masterServer ),
+                       self::TTL_CACHE_READONLY,
+                       function () use ( $wiki, $conn ) {
+                               $this->trxProfiler->setSilenced( true );
+                               try {
+                                       $dbw = $conn ?: $this->getConnection( DB_MASTER, [], $wiki );
+                                       $readOnly = (int)$dbw->serverIsReadOnly();
+                               } catch ( DBError $e ) {
+                                       $readOnly = 0;
+                               }
+                               $this->trxProfiler->setSilenced( false );
+                               return $readOnly;
+                       },
+                       [ 'pcTTL' => $cache::TTL_PROC_LONG, 'busyValue' => 0 ]
+               );
+       }
+
        /**
         * Disables/enables lag checks
         * @param null|bool $mode