From 08aa4418c30cfc18ccc69a0f0f9cb9e17be6c196 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Mon, 12 Aug 2013 09:28:15 +0200 Subject: Update to MediaWiki 1.21.1 --- includes/db/LoadBalancer.php | 150 +++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 85 deletions(-) (limited to 'includes/db/LoadBalancer.php') diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php index 0e455e0c..1e859278 100644 --- a/includes/db/LoadBalancer.php +++ b/includes/db/LoadBalancer.php @@ -37,14 +37,15 @@ class LoadBalancer { private $mLoadMonitorClass, $mLoadMonitor; /** - * @param $params Array with keys: + * @param array $params with keys: * servers Required. Array of server info structures. * masterWaitTimeout Replication lag wait timeout * loadMonitor Name of a class used to fetch server lag and load. + * @throws MWException */ function __construct( $params ) { if ( !isset( $params['servers'] ) ) { - throw new MWException( __CLASS__.': missing servers parameter' ); + throw new MWException( __CLASS__ . ': missing servers parameter' ); } $this->mServers = $params['servers']; @@ -116,34 +117,14 @@ class LoadBalancer { * Given an array of non-normalised probabilities, this function will select * an element and return the appropriate key * + * @deprecated 1.21, use ArrayUtils::pickRandom() + * * @param $weights array * - * @return int + * @return bool|int|string */ function pickRandom( $weights ) { - if ( !is_array( $weights ) || count( $weights ) == 0 ) { - return false; - } - - $sum = array_sum( $weights ); - if ( $sum == 0 ) { - # No loads on any of them - # In previous versions, this triggered an unweighted random selection, - # but this feature has been removed as of April 2006 to allow for strict - # separation of query groups. - return false; - } - $max = mt_getrandmax(); - $rand = mt_rand( 0, $max ) / $max * $sum; - - $sum = 0; - foreach ( $weights as $i => $w ) { - $sum += $w; - if ( $sum >= $rand ) { - break; - } - } - return $i; + return ArrayUtils::pickRandom( $weights ); } /** @@ -197,17 +178,18 @@ class LoadBalancer { * Side effect: opens connections to databases * @param $group bool * @param $wiki bool + * @throws MWException * @return bool|int|string */ function getReaderIndex( $group = false, $wiki = false ) { global $wgReadOnly, $wgDBClusterTimeout, $wgDBAvgStatusPoll, $wgDBtype; # @todo FIXME: For now, only go through all this for mysql databases - if ($wgDBtype != 'mysql') { + if ( $wgDBtype != 'mysql' ) { return $this->getWriterIndex(); } - if ( count( $this->mServers ) == 1 ) { + if ( count( $this->mServers ) == 1 ) { # Skip the load balancing if there's only one server return 0; } elseif ( $group === false and $this->mReadIndex >= 0 ) { @@ -228,7 +210,7 @@ class LoadBalancer { $nonErrorLoads = $this->mGroupLoads[$group]; } else { # No loads for this group, return false and the caller can use some other group - wfDebug( __METHOD__.": no loads for group $group\n" ); + wfDebug( __METHOD__ . ": no loads for group $group\n" ); wfProfileOut( __METHOD__ ); return false; } @@ -256,7 +238,7 @@ class LoadBalancer { $i = $this->pickRandom( $currentLoads ); } else { $i = $this->getRandomNonLagged( $currentLoads, $wiki ); - if ( $i === false && count( $currentLoads ) != 0 ) { + if ( $i === false && count( $currentLoads ) != 0 ) { # All slaves lagged. Switch to read-only mode wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode\n" ); $wgReadOnly = 'The database has been automatically locked ' . @@ -270,16 +252,16 @@ class LoadBalancer { # pickRandom() returned false # This is permanent and means the configuration or the load monitor # wants us to return false. - wfDebugLog( 'connect', __METHOD__.": pickRandom() returned false\n" ); + wfDebugLog( 'connect', __METHOD__ . ": pickRandom() returned false\n" ); wfProfileOut( __METHOD__ ); return false; } - wfDebugLog( 'connect', __METHOD__.": Using reader #$i: {$this->mServers[$i]['host']}...\n" ); + wfDebugLog( 'connect', __METHOD__ . ": Using reader #$i: {$this->mServers[$i]['host']}...\n" ); $conn = $this->openConnection( $i, $wiki ); if ( !$conn ) { - wfDebugLog( 'connect', __METHOD__.": Failed connecting to $i/$wiki\n" ); + wfDebugLog( 'connect', __METHOD__ . ": Failed connecting to $i/$wiki\n" ); unset( $nonErrorLoads[$i] ); unset( $currentLoads[$i] ); continue; @@ -318,7 +300,7 @@ class LoadBalancer { # Some servers must have been overloaded if ( $overloadedServers == 0 ) { - throw new MWException( __METHOD__.": unexpectedly found no overloaded servers" ); + throw new MWException( __METHOD__ . ": unexpectedly found no overloaded servers" ); } # Back off for a while # Scale the sleep time by the number of connected threads, to produce a @@ -341,7 +323,7 @@ class LoadBalancer { $this->mServers[$i]['slave pos'] = $conn->getSlavePos(); } } - if ( $this->mReadIndex <=0 && $this->mLoads[$i]>0 && $i !== false ) { + if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $i !== false ) { $this->mReadIndex = $i; } } @@ -356,7 +338,7 @@ class LoadBalancer { */ function sleep( $t ) { wfProfileIn( __METHOD__ ); - wfDebug( __METHOD__.": waiting $t us\n" ); + wfDebug( __METHOD__ . ": waiting $t us\n" ); usleep( $t ); wfProfileOut( __METHOD__ ); return $t; @@ -390,7 +372,7 @@ class LoadBalancer { wfProfileIn( __METHOD__ ); $this->mWaitForPos = $pos; for ( $i = 1; $i < count( $this->mServers ); $i++ ) { - $this->doWait( $i , true ); + $this->doWait( $i, true ); } wfProfileOut( __METHOD__ ); } @@ -433,15 +415,15 @@ class LoadBalancer { } } - wfDebug( __METHOD__.": Waiting for slave #$index to catch up...\n" ); + wfDebug( __METHOD__ . ": Waiting for slave #$index to catch up...\n" ); $result = $conn->masterPosWait( $this->mWaitForPos, $this->mWaitTimeout ); 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" ); + wfDebug( __METHOD__ . ": Timed out waiting for slave #$index pos {$this->mWaitForPos}\n" ); return false; } else { - wfDebug( __METHOD__.": Done\n" ); + wfDebug( __METHOD__ . ": Done\n" ); return true; } } @@ -451,9 +433,10 @@ class LoadBalancer { * This is the main entry point for this class. * * @param $i Integer: server index - * @param $groups Array: query groups - * @param $wiki String: wiki ID + * @param array $groups query groups + * @param bool|string $wiki Wiki ID * + * @throws MWException * @return DatabaseBase */ public function &getConnection( $i, $groups = array(), $wiki = false ) { @@ -476,7 +459,7 @@ class LoadBalancer { $groupIndex = $this->getReaderIndex( $groups, $wiki ); if ( $groupIndex !== false ) { $serverName = $this->getServerName( $groupIndex ); - wfDebug( __METHOD__.": using server $serverName for group $groups\n" ); + wfDebug( __METHOD__ . ": using server $serverName for group $groups\n" ); $i = $groupIndex; } } else { @@ -484,7 +467,7 @@ class LoadBalancer { $groupIndex = $this->getReaderIndex( $group, $wiki ); if ( $groupIndex !== false ) { $serverName = $this->getServerName( $groupIndex ); - wfDebug( __METHOD__.": using server $serverName for group $group\n" ); + wfDebug( __METHOD__ . ": using server $serverName for group $group\n" ); $i = $groupIndex; break; } @@ -497,16 +480,16 @@ class LoadBalancer { # Couldn't find a working server in getReaderIndex()? if ( $i === false ) { $this->mLastError = 'No working slave server: ' . $this->mLastError; - $this->reportConnectionError( $this->mErrorConnection ); wfProfileOut( __METHOD__ ); - return false; + return $this->reportConnectionError(); } } # Now we have an explicit index into the servers array $conn = $this->openConnection( $i, $wiki ); if ( !$conn ) { - $this->reportConnectionError( $this->mErrorConnection ); + wfProfileOut( __METHOD__ ); + return $this->reportConnectionError(); } wfProfileOut( __METHOD__ ); @@ -519,10 +502,11 @@ class LoadBalancer { * the same number of times as getConnection() to work. * * @param DatabaseBase $conn + * @throws MWException */ public function reuseConnection( $conn ) { - $serverIndex = $conn->getLBInfo('serverIndex'); - $refCount = $conn->getLBInfo('foreignPoolRefCount'); + $serverIndex = $conn->getLBInfo( 'serverIndex' ); + $refCount = $conn->getLBInfo( 'foreignPoolRefCount' ); $dbName = $conn->getDBname(); $prefix = $conn->tablePrefix(); if ( strval( $prefix ) !== '' ) { @@ -531,7 +515,7 @@ class LoadBalancer { $wiki = $dbName; } if ( $serverIndex === null || $refCount === null ) { - wfDebug( __METHOD__.": this connection was not opened as a foreign connection\n" ); + wfDebug( __METHOD__ . ": this connection was not opened as a foreign connection\n" ); /** * This can happen in code like: * foreach ( $dbs as $db ) { @@ -545,15 +529,15 @@ class LoadBalancer { 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 ) { $this->mConns['foreignFree'][$serverIndex][$wiki] = $conn; unset( $this->mConns['foreignUsed'][$serverIndex][$wiki] ); - wfDebug( __METHOD__.": freed connection $serverIndex/$wiki\n" ); + wfDebug( __METHOD__ . ": freed connection $serverIndex/$wiki\n" ); } else { - wfDebug( __METHOD__.": reference count for $serverIndex/$wiki reduced to $refCount\n" ); + wfDebug( __METHOD__ . ": reference count for $serverIndex/$wiki reduced to $refCount\n" ); } } @@ -566,7 +550,7 @@ class LoadBalancer { * error will be available via $this->mErrorConnection. * * @param $i Integer server index - * @param $wiki String wiki ID to open + * @param string $wiki wiki ID to open * @return DatabaseBase * * @access private @@ -575,7 +559,7 @@ class LoadBalancer { wfProfileIn( __METHOD__ ); if ( $wiki !== false ) { $conn = $this->openForeignConnection( $i, $wiki ); - wfProfileOut( __METHOD__); + wfProfileOut( __METHOD__ ); return $conn; } if ( isset( $this->mConns['local'][$i][0] ) ) { @@ -585,6 +569,7 @@ class LoadBalancer { $server['serverIndex'] = $i; $conn = $this->reallyOpenConnection( $server, false ); if ( $conn->isOpen() ) { + wfDebug( "Connected to database $i at {$this->mServers[$i]['host']}\n" ); $this->mConns['local'][$i][0] = $conn; } else { wfDebug( "Failed to connect to database $i at {$this->mServers[$i]['host']}\n" ); @@ -611,22 +596,22 @@ class LoadBalancer { * error will be available via $this->mErrorConnection. * * @param $i Integer: server index - * @param $wiki String: wiki ID to open + * @param string $wiki wiki ID to open * @return DatabaseBase */ function openForeignConnection( $i, $wiki ) { - wfProfileIn(__METHOD__); + wfProfileIn( __METHOD__ ); list( $dbName, $prefix ) = wfSplitWikiID( $wiki ); if ( isset( $this->mConns['foreignUsed'][$i][$wiki] ) ) { // Reuse an already-used connection $conn = $this->mConns['foreignUsed'][$i][$wiki]; - wfDebug( __METHOD__.": reusing connection $i/$wiki\n" ); + wfDebug( __METHOD__ . ": reusing connection $i/$wiki\n" ); } elseif ( isset( $this->mConns['foreignFree'][$i][$wiki] ) ) { // Reuse a free connection for the same wiki $conn = $this->mConns['foreignFree'][$i][$wiki]; unset( $this->mConns['foreignFree'][$i][$wiki] ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; - wfDebug( __METHOD__.": reusing free connection $i/$wiki\n" ); + wfDebug( __METHOD__ . ": reusing free connection $i/$wiki\n" ); } elseif ( !empty( $this->mConns['foreignFree'][$i] ) ) { // Reuse a connection from another wiki $conn = reset( $this->mConns['foreignFree'][$i] ); @@ -641,7 +626,7 @@ class LoadBalancer { $conn->tablePrefix( $prefix ); unset( $this->mConns['foreignFree'][$i][$oldWiki] ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; - wfDebug( __METHOD__.": reusing free connection from $oldWiki for $wiki\n" ); + wfDebug( __METHOD__ . ": reusing free connection from $oldWiki for $wiki\n" ); } } else { // Open a new connection @@ -650,13 +635,13 @@ class LoadBalancer { $server['foreignPoolRefCount'] = 0; $conn = $this->reallyOpenConnection( $server, $dbName ); if ( !$conn->isOpen() ) { - wfDebug( __METHOD__.": error opening connection for $i/$wiki\n" ); + wfDebug( __METHOD__ . ": error opening connection for $i/$wiki\n" ); $this->mErrorConnection = $conn; $conn = false; } else { $conn->tablePrefix( $prefix ); $this->mConns['foreignUsed'][$i][$wiki] = $conn; - wfDebug( __METHOD__.": opened new connection for $i/$wiki\n" ); + wfDebug( __METHOD__ . ": opened new connection for $i/$wiki\n" ); } } @@ -665,7 +650,7 @@ class LoadBalancer { $refCount = $conn->getLBInfo( 'foreignPoolRefCount' ); $conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 ); } - wfProfileOut(__METHOD__); + wfProfileOut( __METHOD__ ); return $conn; } @@ -690,6 +675,7 @@ class LoadBalancer { * * @param $server * @param $dbNameOverride bool + * @throws MWException * @return DatabaseBase */ function reallyOpenConnection( $server, $dbNameOverride = false ) { @@ -698,15 +684,11 @@ class LoadBalancer { 'See DefaultSettings.php entry for $wgDBservers.' ); } - $host = $server['host']; - $dbname = $server['dbname']; - if ( $dbNameOverride !== false ) { - $server['dbname'] = $dbname = $dbNameOverride; + $server['dbname'] = $dbNameOverride; } # Create object - wfDebug( "Connecting to $host $dbname...\n" ); try { $db = DatabaseBase::factory( $server['type'], $server ); } catch ( DBConnectionError $e ) { @@ -715,11 +697,6 @@ class LoadBalancer { $db = $e->db; } - if ( $db->isOpen() ) { - wfDebug( "Connected to $host $dbname.\n" ); - } else { - wfDebug( "Connection failed to $host $dbname.\n" ); - } $db->setLBInfo( $server ); if ( isset( $server['fakeSlaveLag'] ) ) { $db->setFakeSlaveLag( $server['fakeSlaveLag'] ); @@ -731,24 +708,24 @@ class LoadBalancer { } /** - * @param $conn * @throws DBConnectionError + * @return bool */ - function reportConnectionError( &$conn ) { - wfProfileIn( __METHOD__ ); + private function reportConnectionError() { + $conn = $this->mErrorConnection; // The connection which caused the error if ( !is_object( $conn ) ) { // No last connection, probably due to all servers being too busy wfLogDBError( "LB failure with no last connection. Connection error: {$this->mLastError}\n" ); - $conn = new Database; + // If all servers were busy, mLastError will contain something sensible - throw new DBConnectionError( $conn, $this->mLastError ); + throw new DBConnectionError( null, $this->mLastError ); } else { $server = $conn->getProperty( 'mServer' ); wfLogDBError( "Connection error: {$this->mLastError} ({$server})\n" ); - $conn->reportConnectionError( "{$this->mLastError} ({$server})" ); + $conn->reportConnectionError( "{$this->mLastError} ({$server})" ); // throws DBConnectionError } - wfProfileOut( __METHOD__ ); + return false; /* not reached */ } /** @@ -909,7 +886,9 @@ class LoadBalancer { foreach ( $this->mConns as $conns2 ) { foreach ( $conns2 as $conns3 ) { foreach ( $conns3 as $conn ) { - $conn->commit( __METHOD__ ); + if ( $conn->trxLevel() ) { + $conn->commit( __METHOD__, 'flush' ); + } } } } @@ -926,8 +905,8 @@ class LoadBalancer { continue; } foreach ( $conns2[$masterIndex] as $conn ) { - if ( $conn->writesOrCallbacksPending() ) { - $conn->commit( __METHOD__ ); + if ( $conn->trxLevel() && $conn->writesOrCallbacksPending() ) { + $conn->commit( __METHOD__, 'flush' ); } } } @@ -954,10 +933,11 @@ class LoadBalancer { * @return bool */ function allowLagged( $mode = null ) { - if ( $mode === null) { + if ( $mode === null ) { return $this->mAllowLagged; } $this->mAllowLagged = $mode; + return $this->mAllowLagged; } /** @@ -999,7 +979,7 @@ class LoadBalancer { * May attempt to open connections to slaves on the default DB. If there is * no lag, the maximum lag will be reported as -1. * - * @param $wiki string Wiki ID, or false for the default database + * @param string $wiki Wiki ID, or false for the default database * * @return array ( host, max lag, index of max lagged host ) */ -- cgit v1.2.2