Merge "Http::getProxy() method to get proxy configuration"
[lhc/web/wiklou.git] / includes / db / loadbalancer / LoadBalancer.php
index 85a6bf0..997efa6 100644 (file)
@@ -93,11 +93,11 @@ class LoadBalancer {
 
                $this->mReadIndex = -1;
                $this->mWriteIndex = -1;
-               $this->mConns = array(
-                       'local' => array(),
-                       'foreignUsed' => array(),
-                       'foreignFree' => array() );
-               $this->mLoads = array();
+               $this->mConns = [
+                       'local' => [],
+                       'foreignUsed' => [],
+                       'foreignFree' => [] ];
+               $this->mLoads = [];
                $this->mWaitForPos = false;
                $this->mErrorConnection = false;
                $this->mAllowLagged = false;
@@ -122,7 +122,7 @@ class LoadBalancer {
                        if ( isset( $server['groupLoads'] ) ) {
                                foreach ( $server['groupLoads'] as $group => $ratio ) {
                                        if ( !isset( $this->mGroupLoads[$group] ) ) {
-                                               $this->mGroupLoads[$group] = array();
+                                               $this->mGroupLoads[$group] = [];
                                        }
                                        $this->mGroupLoads[$group][$i] = $ratio;
                                }
@@ -190,11 +190,13 @@ class LoadBalancer {
                                if ( isset( $this->mServers[$i]['max lag'] ) ) {
                                        $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] );
                                }
+
+                               $host = $this->getServerName( $i );
                                if ( $lag === false ) {
-                                       wfDebugLog( 'replication', "Server #$i is not replicating" );
+                                       wfDebugLog( 'replication', "Server $host (#$i) is not replicating?" );
                                        unset( $loads[$i] );
                                } elseif ( $lag > $maxServerLag ) {
-                                       wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" );
+                                       wfDebugLog( 'replication', "Server $host (#$i) has >= $lag seconds of lag" );
                                        unset( $loads[$i] );
                                }
                        }
@@ -523,7 +525,7 @@ class LoadBalancer {
         * @throws MWException
         * @return DatabaseBase
         */
-       public function getConnection( $i, $groups = array(), $wiki = false ) {
+       public function getConnection( $i, $groups = [], $wiki = false ) {
                if ( $i === null || $i === false ) {
                        throw new MWException( 'Attempt to call ' . __METHOD__ .
                                ' with invalid server index' );
@@ -533,8 +535,8 @@ class LoadBalancer {
                        $wiki = false;
                }
 
-               $groups = ( $groups === false || $groups === array() )
-                       ? array( false ) // check one "group": the generic pool
+               $groups = ( $groups === false || $groups === [] )
+                       ? [ false ] // check one "group": the generic pool
                        : (array)$groups;
 
                $masterOnly = ( $i == DB_MASTER || $i == $this->getWriterIndex() );
@@ -649,7 +651,7 @@ class LoadBalancer {
         * @param string|bool $wiki Wiki ID, or false for the current wiki
         * @return DBConnRef
         */
-       public function getConnectionRef( $db, $groups = array(), $wiki = false ) {
+       public function getConnectionRef( $db, $groups = [], $wiki = false ) {
                return new DBConnRef( $this, $this->getConnection( $db, $groups, $wiki ) );
        }
 
@@ -665,8 +667,8 @@ class LoadBalancer {
         * @param string|bool $wiki Wiki ID, or false for the current wiki
         * @return DBConnRef
         */
-       public function getLazyConnectionRef( $db, $groups = array(), $wiki = false ) {
-               return new DBConnRef( $this, array( $db, $groups, $wiki ) );
+       public function getLazyConnectionRef( $db, $groups = [], $wiki = false ) {
+               return new DBConnRef( $this, [ $db, $groups, $wiki ] );
        }
 
        /**
@@ -679,9 +681,7 @@ class LoadBalancer {
         *
         * @param int $i Server index
         * @param string|bool $wiki Wiki ID, or false for the current wiki
-        * @return DatabaseBase
-        *
-        * @access private
+        * @return DatabaseBase|bool Returns false on errors
         */
        public function openConnection( $i, $wiki = false ) {
                if ( $wiki !== false ) {
@@ -847,7 +847,7 @@ class LoadBalancer {
 
                $db->setLBInfo( $server );
                $db->setLazyMasterHandle(
-                       $this->getLazyConnectionRef( DB_MASTER, array(), $db->getWikiID() )
+                       $this->getLazyConnectionRef( DB_MASTER, [], $db->getWikiID() )
                );
                $db->setTransactionProfiler( $this->trxProfiler );
 
@@ -860,10 +860,10 @@ class LoadBalancer {
         */
        private function reportConnectionError() {
                $conn = $this->mErrorConnection; // The connection which caused the error
-               $context = array(
+               $context = [
                        'method' => __METHOD__,
                        'last_error' => $this->mLastError,
-               );
+               ];
 
                if ( !is_object( $conn ) ) {
                        // No last connection, probably due to all servers being too busy
@@ -1001,11 +1001,11 @@ class LoadBalancer {
                                }
                        }
                }
-               $this->mConns = array(
-                       'local' => array(),
-                       'foreignFree' => array(),
-                       'foreignUsed' => array(),
-               );
+               $this->mConns = [
+                       'local' => [],
+                       'foreignFree' => [],
+                       'foreignUsed' => [],
+               ];
                $this->connsOpened = 0;
        }
 
@@ -1078,7 +1078,7 @@ class LoadBalancer {
         * @since 1.23
         */
        public function rollbackMasterChanges( $fname = __METHOD__ ) {
-               $failedServers = array();
+               $failedServers = [];
 
                $masterIndex = $this->getWriterIndex();
                foreach ( $this->mConns as $conns2 ) {
@@ -1168,6 +1168,29 @@ class LoadBalancer {
                        || $this->lastMasterChangeTimestamp() > microtime( true ) - $age );
        }
 
+       /**
+        * Get the list of callers that have pending master changes
+        *
+        * @return array
+        * @since 1.27
+        */
+       public function pendingMasterChangeCallers() {
+               $fnames = [];
+
+               $masterIndex = $this->getWriterIndex();
+               foreach ( $this->mConns as $conns2 ) {
+                       if ( empty( $conns2[$masterIndex] ) ) {
+                               continue;
+                       }
+                       /** @var DatabaseBase $conn */
+                       foreach ( $conns2[$masterIndex] as $conn ) {
+                               $fnames = array_merge( $fnames, $conn->pendingWriteCallers() );
+                       }
+               }
+
+               return $fnames;
+       }
+
        /**
         * @param mixed $value
         * @return mixed
@@ -1268,11 +1291,11 @@ class LoadBalancer {
         * @param callable $callback
         * @param array $params
         */
-       public function forEachOpenConnection( $callback, array $params = array() ) {
+       public function forEachOpenConnection( $callback, array $params = [] ) {
                foreach ( $this->mConns as $conns2 ) {
                        foreach ( $conns2 as $conns3 ) {
                                foreach ( $conns3 as $conn ) {
-                                       $mergedParams = array_merge( array( $conn ), $params );
+                                       $mergedParams = array_merge( [ $conn ], $params );
                                        call_user_func_array( $callback, $mergedParams );
                                }
                        }
@@ -1295,7 +1318,7 @@ class LoadBalancer {
                $maxIndex = 0;
 
                if ( $this->getServerCount() <= 1 ) {
-                       return array( $host, $maxLag, $maxIndex ); // no replication = no lag
+                       return [ $host, $maxLag, $maxIndex ]; // no replication = no lag
                }
 
                $lagTimes = $this->getLagTimes( $wiki );
@@ -1307,7 +1330,7 @@ class LoadBalancer {
                        }
                }
 
-               return array( $host, $maxLag, $maxIndex );
+               return [ $host, $maxLag, $maxIndex ];
        }
 
        /**
@@ -1322,7 +1345,7 @@ class LoadBalancer {
         */
        public function getLagTimes( $wiki = false ) {
                if ( $this->getServerCount() <= 1 ) {
-                       return array( 0 => 0 ); // no replication = no lag
+                       return [ 0 => 0 ]; // no replication = no lag
                }
 
                # Send the request to the load monitor
@@ -1340,10 +1363,10 @@ class LoadBalancer {
         * function instead of Database::getLag() avoids a fatal error in this
         * case on many installations.
         *
-        * @param DatabaseBase $conn
-        * @return int
+        * @param IDatabase $conn
+        * @return int|bool Returns false on error
         */
-       public function safeGetLag( $conn ) {
+       public function safeGetLag( IDatabase $conn ) {
                if ( $this->getServerCount() == 1 ) {
                        return 0;
                } else {
@@ -1351,6 +1374,41 @@ class LoadBalancer {
                }
        }
 
+       /**
+        * Wait for a slave DB to reach a specified master position
+        *
+        * This will connect to the master to get an accurate position if $pos is not given
+        *
+        * @param IDatabase $conn Slave DB
+        * @param DBMasterPos|bool $pos Master position; default: current position
+        * @param integer $timeout Timeout in seconds
+        * @return bool Success
+        * @since 1.27
+        */
+       public function safeWaitForMasterPos( IDatabase $conn, $pos = false, $timeout = 10 ) {
+               if ( $this->getServerCount() == 1 || !$conn->getLBInfo( 'slave' ) ) {
+                       return true; // server is not a slave DB
+               }
+
+               $pos = $pos ?: $this->getConnection( DB_MASTER )->getMasterPos();
+               if ( !$pos ) {
+                       return false; // something is misconfigured
+               }
+
+               $result = $conn->masterPosWait( $pos, $timeout );
+               if ( $result == -1 || is_null( $result ) ) {
+                       $msg = __METHOD__ . ": Timed out waiting on {$conn->getServer()} pos {$pos}";
+                       wfDebugLog( 'replication', "$msg\n" );
+                       wfDebugLog( 'DBPerformance', "$msg:\n" . wfBacktrace( true ) );
+                       $ok = false;
+               } else {
+                       wfDebugLog( 'replication', __METHOD__ . ": Done\n" );
+                       $ok = true;
+               }
+
+               return $ok;
+       }
+
        /**
         * Clear the cache for slag lag delay times
         *