X-Git-Url: http://git.cyclocoop.org/%28?a=blobdiff_plain;f=includes%2Fdb%2Floadbalancer%2FLoadBalancer.php;h=a7c486c69c14096dbfdf6f9c5aa8d9dab6090c05;hb=b54d9cb68067a4a274b518a510b59cedabab937f;hp=a67eac1e79e5df1215e4f4e89d55865c570145b2;hpb=4fa2e1833ddef6ee8a241418cece9292561da6ad;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/db/loadbalancer/LoadBalancer.php b/includes/db/loadbalancer/LoadBalancer.php index a67eac1e79..a7c486c69c 100644 --- a/includes/db/loadbalancer/LoadBalancer.php +++ b/includes/db/loadbalancer/LoadBalancer.php @@ -49,6 +49,8 @@ class LoadBalancer { private $mLoadMonitor; /** @var BagOStuff */ private $srvCache; + /** @var WANObjectCache */ + private $wanCache; /** @var bool|DatabaseBase Database connection that caused a problem */ private $mErrorConnection; @@ -76,6 +78,8 @@ class LoadBalancer { const MAX_LAG = 10; /** @var integer Max time to wait for a slave to catch up (e.g. ChronologyProtector) */ const POS_WAIT_TIMEOUT = 10; + /** @var integer Seconds to cache master server read-only status */ + const TTL_CACHE_READONLY = 5; /** * @var boolean @@ -87,6 +91,8 @@ class LoadBalancer { * - servers : Required. Array of server info structures. * - loadMonitor : Name of a class used to fetch server lag and load. * - readOnlyReason : Reason the master DB is read-only if so [optional] + * - srvCache : BagOStuff object [optional] + * - wanCache : WANObjectCache object [optional] * @throws MWException */ public function __construct( array $params ) { @@ -134,8 +140,16 @@ class LoadBalancer { } } - $this->srvCache = ObjectCache::getLocalServerInstance(); - + if ( isset( $params['srvCache'] ) ) { + $this->srvCache = $params['srvCache']; + } else { + $this->srvCache = new EmptyBagOStuff(); + } + if ( isset( $params['wanCache'] ) ) { + $this->wanCache = $params['wanCache']; + } else { + $this->wanCache = WANObjectCache::newEmpty(); + } if ( isset( $params['trxProfiler'] ) ) { $this->trxProfiler = $params['trxProfiler']; } else { @@ -578,7 +592,7 @@ class LoadBalancer { if ( $masterOnly ) { # Make master-requested DB handles inherit any read-only mode setting - $conn->setLBInfo( 'readOnlyReason', $this->getReadOnlyReason( $wiki ) ); + $conn->setLBInfo( 'readOnlyReason', $this->getReadOnlyReason( $wiki, $conn ) ); } return $conn; @@ -600,7 +614,7 @@ class LoadBalancer { /** * This can happen in code like: * foreach ( $dbs as $db ) { - * $conn = $lb->getConnection( DB_SLAVE, array(), $db ); + * $conn = $lb->getConnection( DB_SLAVE, [], $db ); * ... * $lb->reuseConnection( $conn ); * } @@ -1274,10 +1288,11 @@ class LoadBalancer { /** * @note This method may trigger a DB connection if not yet done * @param string|bool $wiki Wiki ID, or false for the current wiki + * @param DatabaseBase|null DB master connection; used to avoid loops [optional] * @return string|bool Reason the master is read-only or false if it is not * @since 1.27 */ - public function getReadOnlyReason( $wiki = false ) { + public function getReadOnlyReason( $wiki = false, DatabaseBase $conn = null ) { if ( $this->readOnlyReason !== false ) { return $this->readOnlyReason; } elseif ( $this->getLaggedSlaveMode( $wiki ) ) { @@ -1288,11 +1303,40 @@ class LoadBalancer { return 'The database has been automatically locked ' . 'while the slave database servers catch up to the master.'; } + } elseif ( $this->masterRunningReadOnly( $wiki, $conn ) ) { + return 'The database master is running in read-only mode.'; } return false; } + /** + * @param string $wiki Wiki ID, or false for the current wiki + * @param DatabaseBase|null DB master connectionl used to avoid loops [optional] + * @return bool + */ + private function masterRunningReadOnly( $wiki, DatabaseBase $conn = null ) { + $cache = $this->wanCache; + $masterServer = $this->getServerName( $this->getWriterIndex() ); + + return (bool)$cache->getWithSetCallback( + $cache->makeGlobalKey( __CLASS__, 'server-read-only', $masterServer ), + self::TTL_CACHE_READONLY, + function () use ( $wiki, $conn ) { + $this->trxProfiler->setSilenced( true ); + try { + $dbw = $conn ?: $this->getConnection( DB_MASTER, [], $wiki ); + $readOnly = (int)$dbw->serverIsReadOnly(); + } catch ( DBError $e ) { + $readOnly = 0; + } + $this->trxProfiler->setSilenced( false ); + return $readOnly; + }, + [ 'pcTTL' => $cache::TTL_PROC_LONG, 'busyValue' => 0 ] + ); + } + /** * Disables/enables lag checks * @param null|bool $mode