From 0e5cd18b74d83c50ebe7dd7ee9f09cf375aae9d7 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Wed, 14 Sep 2016 04:34:17 -0700 Subject: [PATCH] Rename LBFactory => LBFactoryMW and make LBFactory in /libs The former extends the later with MW-specific logic. Also removed a wf* method call from ChronologyProtector. Change-Id: I325f59b7467ab9c2137731d1ce69816f5a020f03 --- autoload.php | 3 +- includes/ServiceWiring.php | 2 +- includes/db/CloneDatabase.php | 5 +- includes/db/loadbalancer/LBFactoryMW.php | 149 +++++++++++ includes/db/loadbalancer/LBFactoryMulti.php | 2 +- includes/db/loadbalancer/LBFactorySimple.php | 2 +- .../ChronologyProtector.php | 12 +- .../rdbms/lbfactory}/LBFactory.php | 250 +++++++----------- .../rdbms/loadmonitor/LoadMonitorNull.php | 4 +- maintenance/Maintenance.php | 2 +- tests/phpunit/includes/db/LBFactoryTest.php | 2 +- 11 files changed, 257 insertions(+), 176 deletions(-) create mode 100644 includes/db/loadbalancer/LBFactoryMW.php rename includes/{db/loadbalancer => libs/rdbms/lbfactory}/LBFactory.php (73%) diff --git a/autoload.php b/autoload.php index d46d2cedcb..22cf9cdee6 100644 --- a/autoload.php +++ b/autoload.php @@ -653,7 +653,8 @@ $wgAutoloadLocalClasses = [ 'JsonContentHandler' => __DIR__ . '/includes/content/JsonContentHandler.php', 'KkConverter' => __DIR__ . '/languages/classes/LanguageKk.php', 'KuConverter' => __DIR__ . '/languages/classes/LanguageKu.php', - 'LBFactory' => __DIR__ . '/includes/db/loadbalancer/LBFactory.php', + 'LBFactory' => __DIR__ . '/includes/libs/rdbms/lbfactory/LBFactory.php', + 'LBFactoryMW' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMW.php', 'LBFactoryMulti' => __DIR__ . '/includes/db/loadbalancer/LBFactoryMulti.php', 'LBFactorySimple' => __DIR__ . '/includes/db/loadbalancer/LBFactorySimple.php', 'LBFactorySingle' => __DIR__ . '/includes/db/loadbalancer/LBFactorySingle.php', diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 8734bd6836..4ab412eb46 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -45,7 +45,7 @@ return [ 'DBLoadBalancerFactory' => function( MediaWikiServices $services ) { $config = $services->getMainConfig()->get( 'LBFactoryConf' ); - $class = LBFactory::getLBFactoryClass( $config ); + $class = LBFactoryMW::getLBFactoryClass( $config ); if ( !isset( $config['readOnlyReason'] ) ) { // TODO: replace the global wfConfiguredReadOnlyReason() with a service. $config['readOnlyReason'] = wfConfiguredReadOnlyReason(); diff --git a/includes/db/CloneDatabase.php b/includes/db/CloneDatabase.php index caca7e2744..ee82bdf5df 100644 --- a/includes/db/CloneDatabase.php +++ b/includes/db/CloneDatabase.php @@ -129,7 +129,10 @@ class CloneDatabase { */ public static function changePrefix( $prefix ) { global $wgDBprefix; - wfGetLBFactory()->forEachLB( function( LoadBalancer $lb ) use ( $prefix ) { + + $lbFactory = wfGetLBFactory(); + $lbFactory->setDomainPrefix( $prefix ); + $lbFactory->forEachLB( function( LoadBalancer $lb ) use ( $prefix ) { $lb->setDomainPrefix( $prefix ); $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $prefix ) { $db->tablePrefix( $prefix ); diff --git a/includes/db/loadbalancer/LBFactoryMW.php b/includes/db/loadbalancer/LBFactoryMW.php new file mode 100644 index 0000000000..87fd81bb6c --- /dev/null +++ b/includes/db/loadbalancer/LBFactoryMW.php @@ -0,0 +1,149 @@ + wfWikiID(), + 'hostname' => wfHostname(), + 'trxProfiler' => Profiler::instance()->getTransactionProfiler(), + 'replLogger' => LoggerFactory::getInstance( 'DBReplication' ), + 'queryLogger' => LoggerFactory::getInstance( 'wfLogDBError' ), + 'connLogger' => LoggerFactory::getInstance( 'wfLogDBError' ), + 'perfLogger' => LoggerFactory::getInstance( 'DBPerformance' ), + 'errorLogger' => [ MWExceptionHandler::class, 'logException' ] + ]; + // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804) + $sCache = ObjectCache::getLocalServerInstance(); + if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) { + $defaults['srvCache'] = $sCache; + } + $cCache = ObjectCache::getLocalClusterInstance(); + if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) { + $defaults['memCache'] = $cCache; + } + $wCache = ObjectCache::getMainWANInstance(); + if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) { + $defaults['wanCache'] = $wCache; + } + + parent::__construct( $conf + $defaults ); + } + + /** + * Returns the LBFactory class to use and the load balancer configuration. + * + * @todo instead of this, use a ServiceContainer for managing the different implementations. + * + * @param array $config (e.g. $wgLBFactoryConf) + * @return string Class name + */ + public static function getLBFactoryClass( array $config ) { + // For configuration backward compatibility after removing + // underscores from class names in MediaWiki 1.23. + $bcClasses = [ + 'LBFactory_Simple' => 'LBFactorySimple', + 'LBFactory_Single' => 'LBFactorySingle', + 'LBFactory_Multi' => 'LBFactoryMulti' + ]; + + $class = $config['class']; + + if ( isset( $bcClasses[$class] ) ) { + $class = $bcClasses[$class]; + wfDeprecated( + '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details', + '1.23' + ); + } + + return $class; + } + + /** + * @return bool + * @since 1.27 + * @deprecated Since 1.28; use laggedReplicaUsed() + */ + public function laggedSlaveUsed() { + return $this->laggedReplicaUsed(); + } + + protected function newChronologyProtector() { + $request = RequestContext::getMain()->getRequest(); + $chronProt = new ChronologyProtector( + ObjectCache::getMainStashInstance(), + [ + 'ip' => $request->getIP(), + 'agent' => $request->getHeader( 'User-Agent' ), + ], + $request->getFloat( 'cpPosTime', $request->getCookie( 'cpPosTime', '' ) ) + ); + if ( PHP_SAPI === 'cli' ) { + $chronProt->setEnabled( false ); + } elseif ( $request->getHeader( 'ChronologyProtection' ) === 'false' ) { + // Request opted out of using position wait logic. This is useful for requests + // done by the job queue or background ETL that do not have a meaningful session. + $chronProt->setWaitEnabled( false ); + } + + return $chronProt; + } + + /** + * Append ?cpPosTime parameter to a URL for ChronologyProtector purposes if needed + * + * Note that unlike cookies, this works accross domains + * + * @param string $url + * @param float $time UNIX timestamp just before shutdown() was called + * @return string + * @since 1.28 + */ + public function appendPreShutdownTimeAsQuery( $url, $time ) { + $usedCluster = 0; + $this->forEachLB( function ( LoadBalancer $lb ) use ( &$usedCluster ) { + $usedCluster |= ( $lb->getServerCount() > 1 ); + } ); + + if ( !$usedCluster ) { + return $url; // no master/replica clusters touched + } + + return wfAppendQuery( $url, [ 'cpPosTime' => $time ] ); + } +} diff --git a/includes/db/loadbalancer/LBFactoryMulti.php b/includes/db/loadbalancer/LBFactoryMulti.php index bbee3b8783..95bc8f418b 100644 --- a/includes/db/loadbalancer/LBFactoryMulti.php +++ b/includes/db/loadbalancer/LBFactoryMulti.php @@ -83,7 +83,7 @@ * * @ingroup Database */ -class LBFactoryMulti extends LBFactory { +class LBFactoryMulti extends LBFactoryMW { /** @var array A map of database names to section names */ private $sectionsByDB; diff --git a/includes/db/loadbalancer/LBFactorySimple.php b/includes/db/loadbalancer/LBFactorySimple.php index 908453caa5..9ccb997d6d 100644 --- a/includes/db/loadbalancer/LBFactorySimple.php +++ b/includes/db/loadbalancer/LBFactorySimple.php @@ -24,7 +24,7 @@ /** * A simple single-master LBFactory that gets its configuration from the b/c globals */ -class LBFactorySimple extends LBFactory { +class LBFactorySimple extends LBFactoryMW { /** @var LoadBalancer */ private $mainLB; /** @var LoadBalancer[] */ diff --git a/includes/libs/rdbms/chronologyprotector/ChronologyProtector.php b/includes/libs/rdbms/chronologyprotector/ChronologyProtector.php index 09b820ba2b..b102f0fc04 100644 --- a/includes/libs/rdbms/chronologyprotector/ChronologyProtector.php +++ b/includes/libs/rdbms/chronologyprotector/ChronologyProtector.php @@ -96,17 +96,17 @@ class ChronologyProtector implements LoggerAwareInterface{ } /** - * Initialise a LoadBalancer to give it appropriate chronology protection. + * Initialise a ILoadBalancer to give it appropriate chronology protection. * * If the stash has a previous master position recorded, this will try to * make sure that the next query to a replica DB of that master will see changes up * to that position by delaying execution. The delay may timeout and allow stale * data if no non-lagged replica DBs are available. * - * @param LoadBalancer $lb + * @param ILoadBalancer $lb * @return void */ - public function initLB( LoadBalancer $lb ) { + public function initLB( ILoadBalancer $lb ) { if ( !$this->enabled || $lb->getServerCount() <= 1 ) { return; // non-replicated setup or disabled } @@ -122,13 +122,13 @@ class ChronologyProtector implements LoggerAwareInterface{ } /** - * Notify the ChronologyProtector that the LoadBalancer is about to shut + * Notify the ChronologyProtector that the ILoadBalancer is about to shut * down. Saves replication positions. * - * @param LoadBalancer $lb + * @param ILoadBalancer $lb * @return void */ - public function shutdownLB( LoadBalancer $lb ) { + public function shutdownLB( ILoadBalancer $lb ) { if ( !$this->enabled ) { return; // not enabled } elseif ( !$lb->hasOrMadeRecentMasterChanges( INF ) ) { diff --git a/includes/db/loadbalancer/LBFactory.php b/includes/libs/rdbms/lbfactory/LBFactory.php similarity index 73% rename from includes/db/loadbalancer/LBFactory.php rename to includes/libs/rdbms/lbfactory/LBFactory.php index 6fd1550ff3..feae4bd05b 100644 --- a/includes/db/loadbalancer/LBFactory.php +++ b/includes/libs/rdbms/lbfactory/LBFactory.php @@ -1,6 +1,6 @@ domain = isset( $conf['domain'] ) ? $conf['domain'] : ''; if ( isset( $conf['readOnlyReason'] ) && is_string( $conf['readOnlyReason'] ) ) { $this->readOnlyReason = $conf['readOnlyReason']; } - // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804) - $sCache = ObjectCache::getLocalServerInstance(); - if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) { - $this->srvCache = $sCache; - } else { - $this->srvCache = new EmptyBagOStuff(); - } - $cCache = ObjectCache::getLocalClusterInstance(); - if ( $cCache->getQoS( $cCache::ATTR_EMULATION ) > $cCache::QOS_EMULATION_SQL ) { - $this->memCache = $cCache; - } else { - $this->memCache = new EmptyBagOStuff(); - } - $wCache = ObjectCache::getMainWANInstance(); - if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) { - $this->wanCache = $wCache; - } else { - $this->wanCache = WANObjectCache::newEmpty(); + + $this->srvCache = isset( $conf['srvCache'] ) ? $conf['srvCache'] : new EmptyBagOStuff(); + $this->memCache = isset( $conf['memCache'] ) ? $conf['memCache'] : new EmptyBagOStuff(); + $this->wanCache = isset( $conf['wanCache'] ) + ? $conf['wanCache'] + : WANObjectCache::newEmpty(); + + foreach ( self::$loggerFields as $key ) { + $this->$key = isset( $conf[$key] ) ? $conf[$key] : new \Psr\Log\NullLogger(); } - $this->trxProfiler = Profiler::instance()->getTransactionProfiler(); - $this->trxLogger = LoggerFactory::getInstance( 'DBTransaction' ); - $this->replLogger = LoggerFactory::getInstance( 'DBReplication' ); - $this->chronProt = $this->newChronologyProtector(); + $this->errorLogger = isset( $conf['errorLogger'] ) + ? $conf['errorLogger'] + : function ( Exception $e ) { + trigger_error( E_WARNING, $e->getMessage() ); + }; + $this->hostname = isset( $conf['hostname'] ) + ? $conf['hostname'] + : gethostname(); + + $this->chronProt = isset( $conf['chronProt'] ) + ? $conf['chronProt'] + : $this->newChronologyProtector(); + $this->trxProfiler = isset( $conf['trxProfiler'] ) + ? $conf['trxProfiler'] + : new TransactionProfiler(); + $this->ticket = mt_rand(); } @@ -104,80 +117,22 @@ abstract class LBFactory implements DestructibleService { $this->forEachLBCallMethod( 'disable' ); } - /** - * Disables all access to the load balancer, will cause all database access - * to throw a DBAccessError - */ - public static function disableBackend() { - MediaWikiServices::disableStorageBackend(); - } - - /** - * Get an LBFactory instance - * - * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancerFactory() instead. - * - * @return LBFactory - */ - public static function singleton() { - return MediaWikiServices::getInstance()->getDBLoadBalancerFactory(); - } - - /** - * Returns the LBFactory class to use and the load balancer configuration. - * - * @todo instead of this, use a ServiceContainer for managing the different implementations. - * - * @param array $config (e.g. $wgLBFactoryConf) - * @return string Class name - */ - public static function getLBFactoryClass( array $config ) { - // For configuration backward compatibility after removing - // underscores from class names in MediaWiki 1.23. - $bcClasses = [ - 'LBFactory_Simple' => 'LBFactorySimple', - 'LBFactory_Single' => 'LBFactorySingle', - 'LBFactory_Multi' => 'LBFactoryMulti', - ]; - - $class = $config['class']; - - if ( isset( $bcClasses[$class] ) ) { - $class = $bcClasses[$class]; - wfDeprecated( - '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details', - '1.23' - ); - } - - return $class; - } - - /** - * Shut down, close connections and destroy the cached instance. - * - * @deprecated since 1.27, use LBFactory::destroy() - */ - public static function destroyInstance() { - MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy(); - } - /** * Create a new load balancer object. The resulting object will be untracked, * not chronology-protected, and the caller is responsible for cleaning it up. * - * @param bool|string $wiki Wiki ID, or false for the current wiki - * @return LoadBalancer + * @param bool|string $domain Wiki ID, or false for the current wiki + * @return ILoadBalancer */ - abstract public function newMainLB( $wiki = false ); + abstract public function newMainLB( $domain = false ); /** * Get a cached (tracked) load balancer object. * - * @param bool|string $wiki Wiki ID, or false for the current wiki - * @return LoadBalancer + * @param bool|string $domain Wiki ID, or false for the current wiki + * @return ILoadBalancer */ - abstract public function getMainLB( $wiki = false ); + abstract public function getMainLB( $domain = false ); /** * Create a new load balancer for external storage. The resulting object will be @@ -185,19 +140,19 @@ abstract class LBFactory implements DestructibleService { * cleaning it up. * * @param string $cluster External storage cluster, or false for core - * @param bool|string $wiki Wiki ID, or false for the current wiki - * @return LoadBalancer + * @param bool|string $domain Wiki ID, or false for the current wiki + * @return ILoadBalancer */ - abstract protected function newExternalLB( $cluster, $wiki = false ); + abstract protected function newExternalLB( $cluster, $domain = false ); /** * Get a cached (tracked) load balancer for external storage * * @param string $cluster External storage cluster, or false for core - * @param bool|string $wiki Wiki ID, or false for the current wiki - * @return LoadBalancer + * @param bool|string $domain Wiki ID, or false for the current wiki + * @return ILoadBalancer */ - abstract public function getExternalLB( $cluster, $wiki = false ); + abstract public function getExternalLB( $cluster, $domain = false ); /** * Execute a function for each tracked load balancer @@ -232,9 +187,9 @@ abstract class LBFactory implements DestructibleService { * @param string $methodName * @param array $args */ - private function forEachLBCallMethod( $methodName, array $args = [] ) { + protected function forEachLBCallMethod( $methodName, array $args = [] ) { $this->forEachLB( - function ( LoadBalancer $loadBalancer, $methodName, array $args ) { + function ( ILoadBalancer $loadBalancer, $methodName, array $args ) { call_user_func_array( [ $loadBalancer, $methodName ], $args ); }, [ $methodName, $args ] @@ -316,7 +271,7 @@ abstract class LBFactory implements DestructibleService { // Run all post-commit callbacks /** @var Exception $e */ $e = null; // first callback exception - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$e ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) { $ex = $lb->runMasterPostTrxCallbacks( IDatabase::TRIGGER_COMMIT ); $e = $e ?: $ex; } ); @@ -338,7 +293,7 @@ abstract class LBFactory implements DestructibleService { $this->forEachLBCallMethod( 'suppressTransactionEndCallbacks' ); $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] ); // Run all post-rollback callbacks - $this->forEachLB( function ( LoadBalancer $lb ) { + $this->forEachLB( function ( ILoadBalancer $lb ) { $lb->runMasterPostTrxCallbacks( IDatabase::TRIGGER_ROLLBACK ); } ); } @@ -348,7 +303,7 @@ abstract class LBFactory implements DestructibleService { */ private function logIfMultiDbTransaction() { $callersByDB = []; - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$callersByDB ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$callersByDB ) { $masterName = $lb->getServerName( $lb->getWriterIndex() ); $callers = $lb->pendingMasterChangeCallers(); if ( $callers ) { @@ -362,7 +317,7 @@ abstract class LBFactory implements DestructibleService { foreach ( $callersByDB as $db => $callers ) { $msg .= "$db: " . implode( '; ', $callers ) . "\n"; } - $this->trxLogger->info( $msg ); + $this->queryLogger->info( $msg ); } } @@ -373,7 +328,7 @@ abstract class LBFactory implements DestructibleService { */ public function hasMasterChanges() { $ret = false; - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) { $ret = $ret || $lb->hasMasterChanges(); } ); @@ -387,22 +342,13 @@ abstract class LBFactory implements DestructibleService { */ public function laggedReplicaUsed() { $ret = false; - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$ret ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) { $ret = $ret || $lb->laggedReplicaUsed(); } ); return $ret; } - /** - * @return bool - * @since 1.27 - * @deprecated Since 1.28; use laggedReplicaUsed() - */ - public function laggedSlaveUsed() { - return $this->laggedReplicaUsed(); - } - /** * Determine if any master connection has pending/written changes from this request * @param float $age How many seconds ago is "recent" [defaults to LB lag wait timeout] @@ -411,7 +357,7 @@ abstract class LBFactory implements DestructibleService { */ public function hasOrMadeRecentMasterChanges( $age = null ) { $ret = false; - $this->forEachLB( function ( LoadBalancer $lb ) use ( $age, &$ret ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( $age, &$ret ) { $ret = $ret || $lb->hasOrMadeRecentMasterChanges( $age ); } ); return $ret; @@ -450,14 +396,14 @@ abstract class LBFactory implements DestructibleService { ]; // Figure out which clusters need to be checked - /** @var LoadBalancer[] $lbs */ + /** @var ILoadBalancer[] $lbs */ $lbs = []; if ( $opts['cluster'] !== false ) { $lbs[] = $this->getExternalLB( $opts['cluster'] ); } elseif ( $opts['wiki'] !== false ) { $lbs[] = $this->getMainLB( $opts['wiki'] ); } else { - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$lbs ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$lbs ) { $lbs[] = $lb; } ); if ( !$lbs ) { @@ -533,7 +479,7 @@ abstract class LBFactory implements DestructibleService { */ public function getEmptyTransactionTicket( $fname ) { if ( $this->hasMasterChanges() ) { - $this->trxLogger->error( __METHOD__ . ": $fname does not have outer scope." ); + $this->queryLogger->error( __METHOD__ . ": $fname does not have outer scope." ); return null; } @@ -553,15 +499,14 @@ abstract class LBFactory implements DestructibleService { */ public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) { if ( $ticket !== $this->ticket ) { - $logger = LoggerFactory::getInstance( 'DBPerformance' ); - $logger->error( __METHOD__ . ": cannot commit; $fname does not have outer scope." ); + $this->perfLogger->error( __METHOD__ . ": $fname does not have outer scope." ); return; } // The transaction owner and any caller with the empty transaction ticket can commit // so that getEmptyTransactionTicket() callers don't risk seeing DBTransactionError. if ( $this->trxRoundId !== false && $fname !== $this->trxRoundId ) { - $this->trxLogger->info( "$fname: committing on behalf of {$this->trxRoundId}." ); + $this->queryLogger->info( "$fname: committing on behalf of {$this->trxRoundId}." ); $fnameEffective = $this->trxRoundId; } else { $fnameEffective = $fname; @@ -600,22 +545,17 @@ abstract class LBFactory implements DestructibleService { * @return ChronologyProtector */ protected function newChronologyProtector() { - $request = RequestContext::getMain()->getRequest(); $chronProt = new ChronologyProtector( - ObjectCache::getMainStashInstance(), + $this->memCache, [ - 'ip' => $request->getIP(), - 'agent' => $request->getHeader( 'User-Agent' ), + 'ip' => isset( $_SERVER[ 'REMOTE_ADDR' ] ) ? $_SERVER[ 'REMOTE_ADDR' ] : '', + 'agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : '' ], - $request->getFloat( 'cpPosTime', $request->getCookie( 'cpPosTime', '' ) ) + isset( $_GET['cpPosTime'] ) ? $_GET['cpPosTime'] : null ); $chronProt->setLogger( $this->replLogger ); if ( PHP_SAPI === 'cli' ) { $chronProt->setEnabled( false ); - } elseif ( $request->getHeader( 'ChronologyProtection' ) === 'false' ) { - // Request opted out of using position wait logic. This is useful for requests - // done by the job queue or background ETL that do not have a meaningful session. - $chronProt->setWaitEnabled( false ); } return $chronProt; @@ -632,7 +572,7 @@ abstract class LBFactory implements DestructibleService { ChronologyProtector $cp, $workCallback, $mode ) { // Record all the master positions needed - $this->forEachLB( function ( LoadBalancer $lb ) use ( $cp ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( $cp ) { $cp->shutdownLB( $lb ); } ); // Write them to the persistent stash. Try to do something useful by running $work @@ -646,7 +586,7 @@ abstract class LBFactory implements DestructibleService { // replica DBs to catch up before responding. Even if there are several DCs, this increases // the chance that the user will see their own changes immediately afterwards. As long // as the sticky DC cookie applies (same domain), this is not even an issue. - $this->forEachLB( function ( LoadBalancer $lb ) use ( $unsavedPositions ) { + $this->forEachLB( function ( ILoadBalancer $lb ) use ( $unsavedPositions ) { $masterName = $lb->getServerName( $lb->getWriterIndex() ); if ( isset( $unsavedPositions[$masterName] ) ) { $lb->waitForAll( $unsavedPositions[$masterName] ); @@ -660,50 +600,38 @@ abstract class LBFactory implements DestructibleService { */ final protected function baseLoadBalancerParams() { return [ - 'localDomain' => wfWikiID(), + 'localDomain' => $this->domain, 'readOnlyReason' => $this->readOnlyReason, 'srvCache' => $this->srvCache, - 'memCache' => $this->memCache, 'wanCache' => $this->wanCache, 'trxProfiler' => $this->trxProfiler, - 'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ), - 'connLogger' => LoggerFactory::getInstance( 'DBConnection' ), - 'replLogger' => LoggerFactory::getInstance( 'DBReplication' ), - 'errorLogger' => [ MWExceptionHandler::class, 'logException' ], - 'hostname' => wfHostname() + 'queryLogger' => $this->queryLogger, + 'connLogger' => $this->connLogger, + 'replLogger' => $this->replLogger, + 'errorLogger' => $this->errorLogger, + 'hostname' => $this->hostname ]; } /** - * @param LoadBalancer $lb + * @param ILoadBalancer $lb */ - protected function initLoadBalancer( LoadBalancer $lb ) { + protected function initLoadBalancer( ILoadBalancer $lb ) { if ( $this->trxRoundId !== false ) { $lb->beginMasterChanges( $this->trxRoundId ); // set DBO_TRX } } /** - * Append ?cpPosTime parameter to a URL for ChronologyProtector purposes if needed + * Define a new local domain (for testing) * - * Note that unlike cookies, this works accross domains + * Caller should make sure no local connection are open to the old local domain * - * @param string $url - * @param float $time UNIX timestamp just before shutdown() was called - * @return string + * @param string $domain * @since 1.28 */ - public function appendPreShutdownTimeAsQuery( $url, $time ) { - $usedCluster = 0; - $this->forEachLB( function ( LoadBalancer $lb ) use ( &$usedCluster ) { - $usedCluster |= ( $lb->getServerCount() > 1 ); - } ); - - if ( !$usedCluster ) { - return $url; // no master/replica clusters touched - } - - return wfAppendQuery( $url, [ 'cpPosTime' => $time ] ); + public function setDomainPrefix( $domain ) { + $this->domain = $domain; } /** diff --git a/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php b/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php index a5fc85d107..1a40b8f8ea 100644 --- a/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php +++ b/includes/libs/rdbms/loadmonitor/LoadMonitorNull.php @@ -28,11 +28,11 @@ class LoadMonitorNull implements LoadMonitor { public function setLogger( LoggerInterface $logger ) { } - public function scaleLoads( &$loads, $group = false, $wiki = false ) { + public function scaleLoads( &$loads, $group = false, $domain = false ) { } - public function getLagTimes( $serverIndexes, $wiki ) { + public function getLagTimes( $serverIndexes, $domain ) { return array_fill_keys( $serverIndexes, 0 ); } diff --git a/maintenance/Maintenance.php b/maintenance/Maintenance.php index 2216de1c17..1fbca1417c 100644 --- a/maintenance/Maintenance.php +++ b/maintenance/Maintenance.php @@ -1091,7 +1091,7 @@ abstract class Maintenance { $wgLBFactoryConf['serverTemplate']['user'] = $wgDBuser; $wgLBFactoryConf['serverTemplate']['password'] = $wgDBpassword; } - LBFactory::destroyInstance(); + MediaWikiServices::getInstance()->getDBLoadBalancerFactory()->destroy(); } // Per-script profiling; useful for debugging diff --git a/tests/phpunit/includes/db/LBFactoryTest.php b/tests/phpunit/includes/db/LBFactoryTest.php index 364a6c2934..5affa9cd92 100644 --- a/tests/phpunit/includes/db/LBFactoryTest.php +++ b/tests/phpunit/includes/db/LBFactoryTest.php @@ -43,7 +43,7 @@ class LBFactoryTest extends MediaWikiTestCase { ]; $this->hideDeprecated( '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details' ); - $result = LBFactory::getLBFactoryClass( $config ); + $result = LBFactoryMW::getLBFactoryClass( $config ); $this->assertEquals( $expected, $result ); } -- 2.20.1