Merge "RightsLogFormatter: Use DB key to generate foreign user link"
[lhc/web/wiklou.git] / includes / db / loadbalancer / LBFactory.php
index 606f4f4..549a8b5 100644 (file)
@@ -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,50 +60,52 @@ 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
         */
        public static function getLBFactoryClass( array $config ) {
                // For configuration backward compatibility after removing
                // underscores from class names in MediaWiki 1.23.
-               $bcClasses = array(
+               $bcClasses = [
                        'LBFactory_Simple' => 'LBFactorySimple',
                        'LBFactory_Single' => 'LBFactorySingle',
                        'LBFactory_Multi' => 'LBFactoryMulti',
                        'LBFactory_Fake' => 'LBFactoryFake',
-               );
+               ];
 
                $class = $config['class'];
 
@@ -118,27 +120,6 @@ abstract class LBFactory {
                return $class;
        }
 
-       /**
-        * 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
-        */
-       public static function setInstance( $instance ) {
-               self::destroyInstance();
-               self::$instance = $instance;
-       }
-
        /**
         * Create a new load balancer object. The resulting object will be untracked,
         * not chronology-protected, and the caller is responsible for cleaning it up.
@@ -184,7 +165,7 @@ abstract class LBFactory {
         * @param callable $callback
         * @param array $params
         */
-       abstract public function forEachLB( $callback, array $params = array() );
+       abstract public function forEachLB( $callback, array $params = [] );
 
        /**
         * Prepare all tracked load balancers for shutdown
@@ -200,12 +181,12 @@ abstract class LBFactory {
         * @param string $methodName
         * @param array $args
         */
-       private function forEachLBCallMethod( $methodName, array $args = array() ) {
+       private function forEachLBCallMethod( $methodName, array $args = [] ) {
                $this->forEachLB(
                        function ( LoadBalancer $loadBalancer, $methodName, array $args ) {
-                               call_user_func_array( array( $loadBalancer, $methodName ), $args );
+                               call_user_func_array( [ $loadBalancer, $methodName ], $args );
                        },
-                       array( $methodName, $args )
+                       [ $methodName, $args ]
                );
        }
 
@@ -219,7 +200,7 @@ abstract class LBFactory {
                $this->logMultiDbTransaction();
 
                $start = microtime( true );
-               $this->forEachLBCallMethod( 'commitAll', array( $fname ) );
+               $this->forEachLBCallMethod( 'commitAll', [ $fname ] );
                $timeMs = 1000 * ( microtime( true ) - $start );
 
                RequestContext::getMain()->getStats()->timing( "db.commit-all", $timeMs );
@@ -231,7 +212,7 @@ abstract class LBFactory {
         * @param array $options Options map:
         *   - maxWriteDuration: abort if more than this much time was spent in write queries
         */
-       public function commitMasterChanges( $fname = __METHOD__, array $options = array() ) {
+       public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
                $limit = isset( $options['maxWriteDuration'] ) ? $options['maxWriteDuration'] : 0;
 
                $this->logMultiDbTransaction();
@@ -248,7 +229,7 @@ abstract class LBFactory {
                } );
 
                $start = microtime( true );
-               $this->forEachLBCallMethod( 'commitMasterChanges', array( $fname ) );
+               $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
                $timeMs = 1000 * ( microtime( true ) - $start );
 
                RequestContext::getMain()->getStats()->timing( "db.commit-masters", $timeMs );
@@ -260,14 +241,14 @@ abstract class LBFactory {
         * @since 1.23
         */
        public function rollbackMasterChanges( $fname = __METHOD__ ) {
-               $this->forEachLBCallMethod( 'rollbackMasterChanges', array( $fname ) );
+               $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] );
        }
 
        /**
         * Log query info if multi DB transactions are going to be committed now
         */
        private function logMultiDbTransaction() {
-               $callersByDB = array();
+               $callersByDB = [];
                $this->forEachLB( function ( LoadBalancer $lb ) use ( &$callersByDB ) {
                        $masterName = $lb->getServerName( $lb->getWriterIndex() );
                        $callers = $lb->pendingMasterChangeCallers();
@@ -351,17 +332,17 @@ abstract class LBFactory {
         * @throws DBReplicationWaitError If a timeout or error occured waiting on a DB cluster
         * @since 1.27
         */
-       public function waitForReplication( array $opts = array() ) {
-               $opts += array(
+       public function waitForReplication( array $opts = [] ) {
+               $opts += [
                        'wiki' => false,
                        'cluster' => false,
                        'timeout' => 60,
                        'ifWritesSince' => null
-               );
+               ];
 
                // Figure out which clusters need to be checked
                /** @var LoadBalancer[] $lbs */
-               $lbs = array();
+               $lbs = [];
                if ( $opts['cluster'] !== false ) {
                        $lbs[] = $this->getExternalLB( $opts['cluster'] );
                } elseif ( $opts['wiki'] !== false ) {
@@ -392,7 +373,7 @@ abstract class LBFactory {
                        $masterPositions[$i] = $lb->getMasterPos();
                }
 
-               $failed = array();
+               $failed = [];
                foreach ( $lbs as $i => $lb ) {
                        if ( $masterPositions[$i] ) {
                                // The DBMS may not support getMasterPos() or the whole
@@ -429,10 +410,10 @@ abstract class LBFactory {
                $request = RequestContext::getMain()->getRequest();
                $chronProt = new ChronologyProtector(
                        ObjectCache::getMainStashInstance(),
-                       array(
+                       [
                                'ip' => $request->getIP(),
                                'agent' => $request->getHeader( 'User-Agent' )
-                       )
+                       ]
                );
                if ( PHP_SAPI === 'cli' ) {
                        $chronProt->setEnabled( false );
@@ -473,8 +454,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." );
+               parent::__construct( 'The storage backend is disabled!' );
        }
 }