From: Aaron Schulz Date: Wed, 10 Dec 2014 07:56:46 +0000 (-0800) Subject: Avoid blocking on ChronologyProtecter check in LoadBalancer::getConnection() X-Git-Tag: 1.31.0-rc.0~12994 X-Git-Url: http://git.cyclocoop.org/fichier?a=commitdiff_plain;h=6ade2968aedc9d961753961361b62e46ab806ecd;p=lhc%2Fweb%2Fwiklou.git Avoid blocking on ChronologyProtecter check in LoadBalancer::getConnection() Change-Id: Iccf324d87d117972cc6321b2abf1ff101d98fa65 --- diff --git a/includes/db/DatabaseMysqlBase.php b/includes/db/DatabaseMysqlBase.php index 7dfae6302b..430b20c46b 100644 --- a/includes/db/DatabaseMysqlBase.php +++ b/includes/db/DatabaseMysqlBase.php @@ -1271,13 +1271,15 @@ class MySQLField implements Field { class MySQLMasterPos implements DBMasterPos { /** @var string */ public $file; - - /** @var int Timestamp */ + /** @var int Position */ public $pos; + /** @var float UNIX timestamp */ + public $asOfTime = 0.0; function __construct( $file, $pos ) { $this->file = $file; $this->pos = $pos; + $this->asOfTime = microtime( true ); } function __toString() { @@ -1303,4 +1305,8 @@ class MySQLMasterPos implements DBMasterPos { return ( $thisPos && $thatPos && $thisPos >= $thatPos ); } + + function asOfTime() { + return $this->asOfTime; + } } diff --git a/includes/db/DatabaseUtility.php b/includes/db/DatabaseUtility.php index c1e80d3331..4e5ed08cf8 100644 --- a/includes/db/DatabaseUtility.php +++ b/includes/db/DatabaseUtility.php @@ -339,4 +339,8 @@ class LikeMatch { * The implementation details of this opaque type are up to the database subclass. */ interface DBMasterPos { + /** + * @return float UNIX timestamp + */ + public function asOfTime(); } diff --git a/includes/db/LoadBalancer.php b/includes/db/LoadBalancer.php index 07645bdd85..6930039ba0 100644 --- a/includes/db/LoadBalancer.php +++ b/includes/db/LoadBalancer.php @@ -151,17 +151,23 @@ class LoadBalancer { /** * @param array $loads * @param bool|string $wiki Wiki to get non-lagged for + * @param float $maxLag Restrict the maximum allowed lag to this many seconds * @return bool|int|string */ - private function getRandomNonLagged( array $loads, $wiki = false ) { - # Unset excessively lagged servers + private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) { $lags = $this->getLagTimes( $wiki ); + + # Unset excessively lagged servers foreach ( $lags as $i => $lag ) { if ( $i != 0 ) { + $maxServerLag = $maxLag; + if ( isset( $this->mServers[$i]['max lag'] ) ) { + $maxServerLag = min( $maxServerLag, $this->mServers[$i]['max lag'] ); + } if ( $lag === false ) { wfDebugLog( 'replication', "Server #$i is not replicating" ); unset( $loads[$i] ); - } elseif ( isset( $this->mServers[$i]['max lag'] ) && $lag > $this->mServers[$i]['max lag'] ) { + } elseif ( $lag > $maxServerLag ) { wfDebugLog( 'replication', "Server #$i is excessively lagged ($lag seconds)" ); unset( $loads[$i] ); } @@ -252,7 +258,19 @@ class LoadBalancer { if ( $wgReadOnly || $this->mAllowLagged || $laggedSlaveMode ) { $i = ArrayUtils::pickRandom( $currentLoads ); } else { - $i = $this->getRandomNonLagged( $currentLoads, $wiki ); + $i = false; + if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) { + # ChronologyProtecter causes mWaitForPos to be set via sessions. + # This triggers doWait() after connect, so it's especially good to + # avoid lagged servers so as to avoid just blocking in that method. + $ago = microtime( true ) - $this->mWaitForPos->asOfTime(); + # Aim for <= 1 second of waiting (being too picky can backfire) + $i = $this->getRandomNonLagged( $currentLoads, $wiki, $ago + 1 ); + } + if ( $i === false ) { + # Any server with less lag than it's 'max lag' param is preferable + $i = $this->getRandomNonLagged( $currentLoads, $wiki ); + } if ( $i === false && count( $currentLoads ) != 0 ) { # All slaves lagged. Switch to read-only mode wfDebugLog( 'replication', "All slaves lagged. Switch to read-only mode" );