X-Git-Url: https://git.cyclocoop.org/admin/?a=blobdiff_plain;f=includes%2Fdb%2Floadbalancer%2FLBFactory.php;h=053f9f816db9a93644521138011fb457180dfecb;hb=d484555db6b734ef56edf2d521dbcfb54170c7a6;hp=f39596b75e5784e752107888b61f37c9b9c8bce3;hpb=29906d505b9b3d5f0fd1e6534f077b7fe2c623dc;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/db/loadbalancer/LBFactory.php b/includes/db/loadbalancer/LBFactory.php index f39596b75e..053f9f816d 100644 --- a/includes/db/loadbalancer/LBFactory.php +++ b/includes/db/loadbalancer/LBFactory.php @@ -21,6 +21,8 @@ * @ingroup Database */ +use MediaWiki\MediaWikiServices; +use MediaWiki\Services\DestructibleService; use Psr\Log\LoggerInterface; use MediaWiki\Logger\LoggerFactory; @@ -28,7 +30,8 @@ use MediaWiki\Logger\LoggerFactory; * An interface for generating database load balancers * @ingroup Database */ -abstract class LBFactory { +abstract class LBFactory implements DestructibleService { + /** @var ChronologyProtector */ protected $chronProt; @@ -38,9 +41,6 @@ abstract class LBFactory { /** @var LoggerInterface */ protected $logger; - /** @var LBFactory */ - private static $instance; - /** @var string|bool Reason all LBs are read-only or false if not */ protected $readOnlyReason = false; @@ -60,38 +60,40 @@ abstract class LBFactory { $this->logger = LoggerFactory::getInstance( 'DBTransaction' ); } + /** + * Disables all load balancers. All connections are closed, and any attempt to + * open a new connection will result in a DBAccessError. + * @see LoadBalancer::disable() + */ + public function destroy() { + $this->shutdown(); + $this->forEachLBCallMethod( 'disable' ); + } + /** * Disables all access to the load balancer, will cause all database access * to throw a DBAccessError */ public static function disableBackend() { - global $wgLBFactoryConf; - self::$instance = new LBFactoryFake( $wgLBFactoryConf ); + MediaWikiServices::disableStorageBackend(); } /** * Get an LBFactory instance * + * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancerFactory() instead. + * * @return LBFactory */ public static function singleton() { - global $wgLBFactoryConf; - - if ( is_null( self::$instance ) ) { - $class = self::getLBFactoryClass( $wgLBFactoryConf ); - $config = $wgLBFactoryConf; - if ( !isset( $config['readOnlyReason'] ) ) { - $config['readOnlyReason'] = wfConfiguredReadOnlyReason(); - } - self::$instance = new $class( $config ); - } - - return self::$instance; + 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 */ @@ -120,23 +122,11 @@ abstract class LBFactory { /** * Shut down, close connections and destroy the cached instance. - */ - public static function destroyInstance() { - if ( self::$instance ) { - self::$instance->shutdown(); - self::$instance->forEachLBCallMethod( 'closeAll' ); - self::$instance = null; - } - } - - /** - * Set the instance to be the given object * - * @param LBFactory $instance + * @deprecated since 1.27, use LBFactory::destroy() */ - public static function setInstance( $instance ) { - self::destroyInstance(); - self::$instance = $instance; + public static function destroyInstance() { + self::singleton()->destroy(); } /** @@ -214,15 +204,12 @@ abstract class LBFactory { * 1. To commit changes to the masters. * 2. To release the snapshot on all connections, master and slave. * @param string $fname Caller name + * @param array $options Options map: + * - maxWriteDuration: abort if more than this much time was spent in write queries */ - public function commitAll( $fname = __METHOD__ ) { - $this->logMultiDbTransaction(); - - $start = microtime( true ); + public function commitAll( $fname = __METHOD__, array $options = [] ) { + $this->commitMasterChanges( $fname, $options ); $this->forEachLBCallMethod( 'commitAll', [ $fname ] ); - $timeMs = 1000 * ( microtime( true ) - $start ); - - RequestContext::getMain()->getStats()->timing( "db.commit-all", $timeMs ); } /** @@ -232,21 +219,17 @@ abstract class LBFactory { * - maxWriteDuration: abort if more than this much time was spent in write queries */ public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) { - $limit = isset( $options['maxWriteDuration'] ) ? $options['maxWriteDuration'] : 0; - - $this->logMultiDbTransaction(); - $this->forEachLB( function ( LoadBalancer $lb ) use ( $limit ) { - $lb->forEachOpenConnection( function ( IDatabase $db ) use ( $limit ) { - $time = $db->pendingWriteQueryDuration(); - if ( $limit > 0 && $time > $limit ) { - throw new DBTransactionError( - $db, - wfMessage( 'transaction-duration-limit-exceeded', $time, $limit )->text() - ); - } - } ); - } ); - + // Perform all pre-commit callbacks, aborting on failure + $this->forEachLBCallMethod( 'runMasterPreCommitCallbacks' ); + // Perform all pre-commit checks, aborting on failure + $this->forEachLBCallMethod( 'approveMasterChanges', [ $options ] ); + // Log the DBs and methods involved in multi-DB transactions + $this->logIfMultiDbTransaction(); + // Actually perform the commit on all master DB connections + $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] ); + // Run all post-commit callbacks + $this->forEachLBCallMethod( 'runMasterPostCommitCallbacks' ); + // Commit any dangling DBO_TRX transactions from callbacks on one DB to another DB $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] ); } @@ -262,7 +245,7 @@ abstract class LBFactory { /** * Log query info if multi DB transactions are going to be committed now */ - private function logMultiDbTransaction() { + private function logIfMultiDbTransaction() { $callersByDB = []; $this->forEachLB( function ( LoadBalancer $lb ) use ( &$callersByDB ) { $masterName = $lb->getServerName( $lb->getWriterIndex() ); @@ -462,6 +445,15 @@ abstract class LBFactory { } } ); } + + /** + * Close all open database connections on all open load balancers. + * @since 1.28 + */ + public function closeAll() { + $this->forEachLBCallMethod( 'closeAll', [] ); + } + } /** @@ -470,7 +462,7 @@ abstract class LBFactory { class DBAccessError extends MWException { public function __construct() { parent::__construct( "Mediawiki tried to access the database via wfGetDB(). " . - "This is not allowed." ); + "This is not allowed, because database access has been disabled." ); } }