Merge "Avoid repeat of class name when appending in Linker"
[lhc/web/wiklou.git] / includes / db / LoadBalancer.php
index 60c2833..9967cc0 100644 (file)
@@ -101,6 +101,7 @@ class LoadBalancer {
                        $class = $this->mLoadMonitorClass;
                        $this->mLoadMonitor = new $class( $this );
                }
+
                return $this->mLoadMonitor;
        }
 
@@ -167,7 +168,7 @@ class LoadBalancer {
                #wfDebugLog( 'connect', var_export( $loads, true ) );
 
                # Return a random representative of the remainder
-               return $this->pickRandom( $loads );
+               return ArrayUtils::pickRandom( $loads );
        }
 
        /**
@@ -212,6 +213,7 @@ class LoadBalancer {
                                # No loads for this group, return false and the caller can use some other group
                                wfDebug( __METHOD__ . ": no loads for group $group\n" );
                                wfProfileOut( __METHOD__ );
+
                                return false;
                        }
                } else {
@@ -236,7 +238,7 @@ class LoadBalancer {
                        $currentLoads = $nonErrorLoads;
                        while ( count( $currentLoads ) ) {
                                if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) {
-                                       $i = $this->pickRandom( $currentLoads );
+                                       $i = ArrayUtils::pickRandom( $currentLoads );
                                } else {
                                        $i = $this->getRandomNonLagged( $currentLoads, $wiki );
                                        if ( $i === false && count( $currentLoads ) != 0 ) {
@@ -244,7 +246,7 @@ class LoadBalancer {
                                                wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode\n" );
                                                $wgReadOnly = 'The database has been automatically locked ' .
                                                        'while the slave database servers catch up to the master';
-                                               $i = $this->pickRandom( $currentLoads );
+                                               $i = ArrayUtils::pickRandom( $currentLoads );
                                                $laggedSlaveMode = true;
                                        }
                                }
@@ -255,6 +257,7 @@ class LoadBalancer {
                                        # wants us to return false.
                                        wfDebugLog( 'connect', __METHOD__ . ": pickRandom() returned false\n" );
                                        wfProfileOut( __METHOD__ );
+
                                        return false;
                                }
 
@@ -329,6 +332,7 @@ class LoadBalancer {
                        }
                }
                wfProfileOut( __METHOD__ );
+
                return $i;
        }
 
@@ -342,6 +346,7 @@ class LoadBalancer {
                wfDebug( __METHOD__ . ": waiting $t us\n" );
                usleep( $t );
                wfProfileOut( __METHOD__ );
+
                return $t;
        }
 
@@ -372,8 +377,11 @@ class LoadBalancer {
        public function waitForAll( $pos ) {
                wfProfileIn( __METHOD__ );
                $this->mWaitForPos = $pos;
-               for ( $i = 1; $i < count( $this->mServers ); $i++ ) {
-                       $this->doWait( $i, true );
+               $serverCount = count( $this->mServers );
+               for ( $i = 1; $i < $serverCount; $i++ ) {
+                       if ( $this->mLoads[$i] > 0 ) {
+                               $this->doWait( $i, true );
+                       }
                }
                wfProfileOut( __METHOD__ );
        }
@@ -391,6 +399,7 @@ class LoadBalancer {
                                return reset( $conns[$i] );
                        }
                }
+
                return false;
        }
 
@@ -406,11 +415,13 @@ class LoadBalancer {
                if ( !$conn ) {
                        if ( !$open ) {
                                wfDebug( __METHOD__ . ": no connection open\n" );
+
                                return false;
                        } else {
                                $conn = $this->openConnection( $index, '' );
                                if ( !$conn ) {
                                        wfDebug( __METHOD__ . ": failed to open connection\n" );
+
                                        return false;
                                }
                        }
@@ -422,9 +433,11 @@ class LoadBalancer {
                if ( $result == -1 || is_null( $result ) ) {
                        # Timed out waiting for slave, use master instead
                        wfDebug( __METHOD__ . ": Timed out waiting for slave #$index pos {$this->mWaitForPos}\n" );
+
                        return false;
                } else {
                        wfDebug( __METHOD__ . ": Done\n" );
+
                        return true;
                }
        }
@@ -445,10 +458,12 @@ class LoadBalancer {
 
                if ( $i == DB_LAST ) {
                        wfProfileOut( __METHOD__ );
-                       throw new MWException( 'Attempt to call ' . __METHOD__ . ' with deprecated server index DB_LAST' );
+                       throw new MWException( 'Attempt to call ' . __METHOD__ .
+                               ' with deprecated server index DB_LAST' );
                } elseif ( $i === null || $i === false ) {
                        wfProfileOut( __METHOD__ );
-                       throw new MWException( 'Attempt to call ' . __METHOD__ . ' with invalid server index' );
+                       throw new MWException( 'Attempt to call ' . __METHOD__ .
+                               ' with invalid server index' );
                }
 
                if ( $wiki === wfWikiID() ) {
@@ -485,6 +500,7 @@ class LoadBalancer {
                        if ( $i === false ) {
                                $this->mLastError = 'No working slave server: ' . $this->mLastError;
                                wfProfileOut( __METHOD__ );
+
                                return $this->reportConnectionError();
                        }
                }
@@ -493,10 +509,12 @@ class LoadBalancer {
                $conn = $this->openConnection( $i, $wiki );
                if ( !$conn ) {
                        wfProfileOut( __METHOD__ );
+
                        return $this->reportConnectionError();
                }
 
                wfProfileOut( __METHOD__ );
+
                return $conn;
        }
 
@@ -520,6 +538,7 @@ class LoadBalancer {
                }
                if ( $serverIndex === null || $refCount === null ) {
                        wfDebug( __METHOD__ . ": this connection was not opened as a foreign connection\n" );
+
                        /**
                         * This can happen in code like:
                         *   foreach ( $dbs as $db ) {
@@ -530,10 +549,12 @@ class LoadBalancer {
                         * When a connection to the local DB is opened in this way, reuseConnection()
                         * should be ignored
                         */
+
                        return;
                }
                if ( $this->mConns['foreignUsed'][$serverIndex][$wiki] !== $conn ) {
-                       throw new MWException( __METHOD__ . ": connection not found, has the connection been freed already?" );
+                       throw new MWException( __METHOD__ . ": connection not found, has " .
+                               "the connection been freed already?" );
                }
                $conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
                if ( $refCount <= 0 ) {
@@ -561,6 +582,22 @@ class LoadBalancer {
                return new DBConnRef( $this, $this->getConnection( $db, $groups, $wiki ) );
        }
 
+       /**
+        * Get a database connection handle reference without connecting yet
+        *
+        * The handle's methods wrap simply wrap those of a DatabaseBase handle
+        *
+        * @see LoadBalancer::getConnection() for parameter information
+        *
+        * @param integer $db
+        * @param mixed $groups
+        * @param string $wiki
+        * @return DBConnRef
+        */
+       public function getLazyConnectionRef( $db, $groups = array(), $wiki = false ) {
+               return new DBConnRef( $this, array( $db, $groups, $wiki ) );
+       }
+
        /**
         * Open a connection to the server given by the specified index
         * Index must be an actual index into the array.
@@ -580,6 +617,7 @@ class LoadBalancer {
                if ( $wiki !== false ) {
                        $conn = $this->openForeignConnection( $i, $wiki );
                        wfProfileOut( __METHOD__ );
+
                        return $conn;
                }
                if ( isset( $this->mConns['local'][$i][0] ) ) {
@@ -598,6 +636,7 @@ class LoadBalancer {
                        }
                }
                wfProfileOut( __METHOD__ );
+
                return $conn;
        }
 
@@ -672,6 +711,7 @@ class LoadBalancer {
                        $conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
                }
                wfProfileOut( __METHOD__ );
+
                return $conn;
        }
 
@@ -686,6 +726,7 @@ class LoadBalancer {
                if ( !is_integer( $index ) ) {
                        return false;
                }
+
                return (bool)$this->getAnyOpenConnection( $index );
        }
 
@@ -725,6 +766,7 @@ class LoadBalancer {
                if ( isset( $server['fakeMaster'] ) ) {
                        $db->setFakeMaster( true );
                }
+
                return $db;
        }
 
@@ -746,6 +788,7 @@ class LoadBalancer {
                        wfLogDBError( "Connection error: {$this->mLastError} ({$server})\n" );
                        $conn->reportConnectionError( "{$this->mLastError} ({$server})" ); // throws DBConnectionError
                }
+
                return false; /* not reached */
        }
 
@@ -815,7 +858,8 @@ class LoadBalancer {
        }
 
        /**
-        * Sets the server info structure for the given index. Entry at index $i is created if it doesn't exist
+        * Sets the server info structure for the given index. Entry at index $i
+        * is created if it doesn't exist
         * @param $i
         * @param $serverInfo
         */
@@ -832,17 +876,21 @@ class LoadBalancer {
                # master (however unlikely that may be), then we can fetch the position from the slave.
                $masterConn = $this->getAnyOpenConnection( 0 );
                if ( !$masterConn ) {
-                       for ( $i = 1; $i < count( $this->mServers ); $i++ ) {
+                       $serverCount = count( $this->mServers );
+                       for ( $i = 1; $i < $serverCount; $i++ ) {
                                $conn = $this->getAnyOpenConnection( $i );
                                if ( $conn ) {
                                        wfDebug( "Master pos fetched from slave\n" );
+
                                        return $conn->getSlavePos();
                                }
                        }
                } else {
                        wfDebug( "Master pos fetched from master\n" );
+
                        return $masterConn->getMasterPos();
                }
+
                return false;
        }
 
@@ -958,6 +1006,7 @@ class LoadBalancer {
                        return $this->mAllowLagged;
                }
                $this->mAllowLagged = $mode;
+
                return $this->mAllowLagged;
        }
 
@@ -975,6 +1024,7 @@ class LoadBalancer {
                                }
                        }
                }
+
                return $success;
        }
 
@@ -1028,6 +1078,7 @@ class LoadBalancer {
                                }
                        }
                }
+
                return array( $host, $maxLag, $maxIndex );
        }
 
@@ -1052,6 +1103,7 @@ class LoadBalancer {
                        $this->mLagTimes = $this->getLoadMonitor()->getLagTimes(
                                array_keys( $this->mServers ), $wiki );
                }
+
                return $this->mLagTimes;
        }
 
@@ -1088,6 +1140,7 @@ class LoadBalancer {
 
 /**
  * Helper class to handle automatically marking connectons as reusable (via RAII pattern)
+ * as well handling deferring the actual network connection until the handle is used
  *
  * @ingroup Database
  * @since 1.22
@@ -1095,23 +1148,36 @@ class LoadBalancer {
 class DBConnRef implements IDatabase {
        /** @var LoadBalancer */
        protected $lb;
-       /** @var DatabaseBase */
+       /** @var DatabaseBase|null */
        protected $conn;
+       /** @var Array|null */
+       protected $params;
 
        /**
         * @param $lb LoadBalancer
-        * @param $conn DatabaseBase
+        * @param $conn DatabaseBase|array Connection or (server index, group, wiki ID) array
         */
-       public function __construct( LoadBalancer $lb, DatabaseBase $conn ) {
+       public function __construct( LoadBalancer $lb, $conn ) {
                $this->lb = $lb;
-               $this->conn = $conn;
+               if ( $conn instanceof DatabaseBase ) {
+                       $this->conn = $conn;
+               } else {
+                       $this->params = $conn;
+               }
        }
 
        public function __call( $name, $arguments ) {
+               if ( $this->conn === null ) {
+                       list( $db, $groups, $wiki ) = $this->params;
+                       $this->conn = $this->lb->getConnection( $db, $groups, $wiki );
+               }
+
                return call_user_func_array( array( $this->conn, $name ), $arguments );
        }
 
        function __destruct() {
-               $this->lb->reuseConnection( $this->conn );
+               if ( $this->conn !== null ) {
+                       $this->lb->reuseConnection( $this->conn );
+               }
        }
 }