X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FLoadBalancer.php;h=abbf936e5b986eea06ea852a7d8af4739df2e97c;hb=4b390e9c9b77ea8c5d2244747a6e233b13a595fd;hp=9813c2af42feb3d290088b8fef618e0ae5bbb56d;hpb=ba2afcd9fa9b1f3f6a865da054068466164fd2fa;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/LoadBalancer.php b/includes/LoadBalancer.php index 9813c2af42..abbf936e5b 100644 --- a/includes/LoadBalancer.php +++ b/includes/LoadBalancer.php @@ -19,19 +19,6 @@ define( 'DB_LAST', -3 ); # Whatever database was used last define( 'DB_READ', -1 ); define( 'DB_WRITE', -2 ); -# Task-based indexes -# ***NOT USED YET, EXPERIMENTAL*** -# These may be defined in $wgDBservers. If they aren't, the default reader or writer will be used -# Even numbers are always readers, odd numbers are writers -define( 'DB_TASK_FIRST', 1000 ); # First in list -define( 'DB_SEARCH_R', 1000 ); # Search read -define( 'DB_SEARCH_W', 1001 ); # Search write -define( 'DB_ASKSQL_R', 1002 ); # Special:Asksql read -define( 'DB_WATCHLIST_R', 1004 ); # Watchlist read -define( 'DB_TASK_LAST', 1004) ; # Last in list - -define( 'MASTER_WAIT_TIMEOUT', 15 ); # Time to wait for a slave to synchronise - /** * Database load balancing object * @@ -39,10 +26,11 @@ define( 'MASTER_WAIT_TIMEOUT', 15 ); # Time to wait for a slave to synchronise * @package MediaWiki */ class LoadBalancer { - /* private */ var $mServers, $mConnections, $mLoads; + /* private */ var $mServers, $mConnections, $mLoads, $mGroupLoads; /* private */ var $mFailFunction; /* private */ var $mForce, $mReadIndex, $mLastIndex; - /* private */ var $mWaitForFile, $mWaitForPos; + /* private */ var $mWaitForFile, $mWaitForPos, $mWaitTimeout; + /* private */ var $mLaggedSlaveMode; function LoadBalancer() { @@ -54,14 +42,14 @@ class LoadBalancer { $this->mLastIndex = -1; } - function newFromParams( $servers, $failFunction = false ) + function newFromParams( $servers, $failFunction = false, $waitTimeout = 10 ) { $lb = new LoadBalancer; - $lb->initialise( $servers, $failFunction = false ); + $lb->initialise( $servers, $failFunction, $waitTimeout ); return $lb; } - function initialise( $servers, $failFunction = false ) + function initialise( $servers, $failFunction = false, $waitTimeout = 10 ) { $this->mServers = $servers; $this->mFailFunction = $failFunction; @@ -73,10 +61,20 @@ class LoadBalancer { $this->mLoads = array(); $this->mWaitForFile = false; $this->mWaitForPos = false; + $this->mWaitTimeout = $waitTimeout; + $this->mLaggedSlaveMode = false; foreach( $servers as $i => $server ) { $this->mLoads[$i] = $server['load']; - } + if ( isset( $server['groupLoads'] ) ) { + foreach ( $server['groupLoads'] as $group => $ratio ) { + if ( !isset( $this->mGroupLoads[$group] ) ) { + $this->mGroupLoads[$group] = array(); + } + $this->mGroupLoads[$group][$i] = $ratio; + } + } + } } /** @@ -124,12 +122,17 @@ class LoadBalancer { do { $i = $this->pickRandom( $loads ); if ( $i !== false ) { - wfDebug( "Using reader #$i: {$this->mServers[$i]['host']}\n" ); - + wfDebug( "Using reader #$i: {$this->mServers[$i]['host']}...\n" ); $this->openConnection( $i ); - + if ( !$this->isOpen( $i ) ) { + wfDebug( "Failed\n" ); unset( $loads[$i] ); + } elseif ( isset( $this->mServers[$i]['slave pos'] ) ) { + wfDebug( "Lagged slave\n" ); + $this->mLaggedSlaveMode = true; + } else { + wfDebug( "OK\n" ); } } } while ( $i !== false && !$this->isOpen( $i ) ); @@ -144,7 +147,20 @@ class LoadBalancer { wfProfileOut( $fname ); return $i; } - + + /** + * Get a random server to use in a query group + */ + function getGroupIndex( $group ) { + if ( isset( $this->mGroupLoads[$group] ) ) { + $i = $this->pickRandom( $this->mGroupLoads[$group] ); + } else { + $i = false; + } + wfDebug( "Query group $group => $i\n" ); + return $i; + } + /** * Set the master wait position * If a DB_SLAVE connection has been opened already, waits @@ -161,11 +177,12 @@ class LoadBalancer { if ( count( $this->mServers ) > 1 ) { $this->mWaitForFile = $file; $this->mWaitForPos = $pos; + $i = $this->mReadIndex; - if ( $this->mReadIndex > 0 ) { - if ( !$this->doWait( $this->mReadIndex ) ) { - # Use master instead - $this->mReadIndex = 0; + if ( $i > 0 ) { + if ( !$this->doWait( $i ) ) { + $this->mServers[$i]['slave pos'] = $this->mConnections[$i]->getSlavePos(); + $this->mLaggedSlaveMode = true; } } } @@ -180,6 +197,13 @@ class LoadBalancer { $retVal = false; + # Debugging hacks + if ( isset( $this->mServers[$index]['lagged slave'] ) ) { + return false; + } elseif ( isset( $this->mServers[$index]['fake slave'] ) ) { + return true; + } + $key = 'masterpos:' . $index; $memcPos = $wgMemc->get( $key ); if ( $memcPos ) { @@ -191,9 +215,9 @@ class LoadBalancer { } if ( !$retVal && $this->isOpen( $index ) ) { - $conn =& $this->mConnections( $index ); + $conn =& $this->mConnections[$index]; wfDebug( "Waiting for slave #$index to catch up...\n" ); - $result = $conn->masterPosWait( $this->mWaitForFile, $this->mWaitForPos, MASTER_WAIT_TIMEOUT ); + $result = $conn->masterPosWait( $this->mWaitForFile, $this->mWaitForPos, $this->mWaitTimeout ); if ( $result == -1 || is_null( $result ) ) { # Timed out waiting for slave, use master instead @@ -210,22 +234,21 @@ class LoadBalancer { /** * Get a connection by index */ - function &getConnection( $i, $fail = true ) + function &getConnection( $i, $fail = true, $groups = array() ) { $fname = 'LoadBalancer::getConnection'; wfProfileIn( $fname ); - /* - # Task-based index - if ( $i >= DB_TASK_FIRST && $i < DB_TASK_LAST ) { - if ( $i % 2 ) { - # Odd index use writer - $i = DB_MASTER; - } else { - # Even index use reader - $i = DB_SLAVE; + + # Query groups + $groupIndex = false; + foreach ( $groups as $group ) { + $groupIndex = $this->getGroupIndex( $group ); + if ( $groupIndex !== false ) { + $i = $groupIndex; + break; } - }*/ - + } + # Operation-based index if ( $i == DB_SLAVE ) { $i = $this->getReaderIndex(); @@ -242,6 +265,7 @@ class LoadBalancer { } # Now we have an explicit index into the servers array $this->openConnection( $i, $fail ); + wfProfileOut( $fname ); return $this->mConnections[$i]; } @@ -249,24 +273,21 @@ class LoadBalancer { /** * Open a connection to the server given by the specified index * Index must be an actual index into the array + * Returns success * @private */ function openConnection( $i, $fail = false ) { $fname = 'LoadBalancer::openConnection'; wfProfileIn( $fname ); + $success = true; if ( !$this->isOpen( $i ) ) { $this->mConnections[$i] = $this->reallyOpenConnection( $this->mServers[$i] ); - - if ( $i != 0 && $this->mWaitForFile ) { + + if ( $this->isOpen( $i ) && $i != 0 && $this->mWaitForFile ) { if ( !$this->doWait( $i ) ) { - # Error waiting for this slave, use master instead - $this->mReadIndex = 0; - $i = 0; - if ( !$this->isOpen( 0 ) ) { - $this->mConnections[0] = $this->reallyOpenConnection( $this->mServers[0] ); - } - wfDebug( "Failed over to {$this->mConnections[0]->mServer}\n" ); + $this->mServers[$i]['slave pos'] = $this->mConnections[$i]->getSlavePos(); + $success = false; } } } @@ -276,9 +297,11 @@ class LoadBalancer { $this->reportConnectionError( $this->mConnections[$i] ); } $this->mConnections[$i] = false; + $success = false; } $this->mLastIndex = $i; wfProfileOut( $fname ); + return $success; } /** @@ -303,15 +326,19 @@ class LoadBalancer { * @private */ function reallyOpenConnection( &$server ) { - extract( $server ); - # Get class for this database type - $class = 'Database' . ucfirst( $type ); - if ( !class_exists( $class ) ) { - require_once( "$class.php" ); - } + if( !is_array( $server ) ) { + wfDebugDieBacktrace( 'You must update your load-balancing configuration. See DefaultSettings.php entry for $wgDBservers.' ); + } + + extract( $server ); + # Get class for this database type + $class = 'Database' . ucfirst( $type ); + if ( !class_exists( $class ) ) { + require_once( "$class.php" ); + } - # Create object - return new $class( $host, $user, $password, $dbname, 1, $flags ); + # Create object + return new $class( $host, $user, $password, $dbname, 1, $flags ); } function reportConnectionError( &$conn ) @@ -398,7 +425,8 @@ class LoadBalancer { function closeAll() { foreach( $this->mConnections as $i => $conn ) { if ( $this->isOpen( $i ) ) { - $conn->close(); + // Need to use this syntax because $conn is a copy not a reference + $this->mConnections[$i]->close(); } } } @@ -406,8 +434,31 @@ class LoadBalancer { function commitAll() { foreach( $this->mConnections as $i => $conn ) { if ( $this->isOpen( $i ) ) { - $conn->immediateCommit(); + // Need to use this syntax because $conn is a copy not a reference + $this->mConnections[$i]->immediateCommit(); } } } + + function waitTimeout( $value = NULL ) { + return wfSetVar( $this->mWaitTimeout, $value ); + } + + function getLaggedSlaveMode() { + return $this->mLaggedSlaveMode; + } + + function pingAll() { + $success = true; + foreach ( $this->mConnections as $i => $conn ) { + if ( $this->isOpen( $i ) ) { + if ( !$this->mConnections[$i]->ping() ) { + $success = false; + } + } + } + return $success; + } } + +?>