Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
46.00% covered (danger)
46.00%
23 / 50
60.00% covered (warning)
60.00%
3 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
MWLBFactory
46.94% covered (danger)
46.94%
23 / 49
60.00% covered (warning)
60.00%
3 / 5
17.56
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 applyServices
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
6
 getLBFactoryClass
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 setDomainAliases
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 logDeprecation
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Generator of database load balancing objects.
4 *
5 * @license GPL-2.0-or-later
6 * @file
7 * @ingroup Database
8 */
9
10namespace MediaWiki\DB;
11
12use MediaWiki\Config\ServiceOptions;
13use MediaWiki\Debug\MWDebug;
14use MediaWiki\Exception\MWExceptionHandler;
15use MediaWiki\Logger\LoggerFactory;
16use MediaWiki\Profiler\Profiler;
17use MediaWiki\Profiler\ProfilerStub;
18use Wikimedia\ObjectCache\BagOStuff;
19use Wikimedia\ObjectCache\WANObjectCache;
20use Wikimedia\Rdbms\ChronologyProtector;
21use Wikimedia\Rdbms\ConfiguredReadOnlyMode;
22use Wikimedia\Rdbms\DatabaseDomain;
23use Wikimedia\Rdbms\ILBFactory;
24use Wikimedia\Rdbms\LBFactory;
25use Wikimedia\Rdbms\LBFactoryMulti;
26use Wikimedia\Rdbms\LBFactorySimple;
27use Wikimedia\Rdbms\LBFactorySingle;
28use Wikimedia\RequestTimeout\CriticalSectionProvider;
29use Wikimedia\Stats\StatsFactory;
30use Wikimedia\Telemetry\TracerInterface;
31
32/**
33 * MediaWiki-specific class for generating database load balancers
34 *
35 * @internal For use by core ServiceWiring only.
36 * @ingroup Database
37 */
38class MWLBFactory {
39
40    /** Cache of already-logged deprecation messages */
41    private static array $loggedDeprecations = [];
42
43    private ServiceOptions $options;
44    private ConfiguredReadOnlyMode $readOnlyMode;
45    private ChronologyProtector $chronologyProtector;
46    private BagOStuff $srvCache;
47    private WANObjectCache $wanCache;
48    private CriticalSectionProvider $csProvider;
49    private StatsFactory $statsFactory;
50    private TracerInterface $tracer;
51    private ?string $uniqueIdentifier;
52
53    /**
54     * @param ConfiguredReadOnlyMode $readOnlyMode
55     * @param ChronologyProtector $chronologyProtector
56     * @param BagOStuff $srvCache
57     * @param WANObjectCache $wanCache
58     * @param CriticalSectionProvider $csProvider
59     * @param StatsFactory $statsFactory
60     * @param TracerInterface $tracer
61     * @param ?string $uniqueIdentifier
62     */
63    public function __construct(
64        ConfiguredReadOnlyMode $readOnlyMode,
65        ChronologyProtector $chronologyProtector,
66        BagOStuff $srvCache,
67        WANObjectCache $wanCache,
68        CriticalSectionProvider $csProvider,
69        StatsFactory $statsFactory,
70        TracerInterface $tracer,
71        ?string $uniqueIdentifier = null
72    ) {
73        $this->readOnlyMode = $readOnlyMode;
74        $this->chronologyProtector = $chronologyProtector;
75        $this->srvCache = $srvCache;
76        $this->wanCache = $wanCache;
77        $this->csProvider = $csProvider;
78        $this->statsFactory = $statsFactory;
79        $this->tracer = $tracer;
80        $this->uniqueIdentifier = $uniqueIdentifier;
81    }
82
83    /**
84     * @param array $lbConf Config for LBFactory::__construct()
85     * @return array
86     * @internal For use with service wiring
87     */
88    public function applyServices( array $lbConf ): array {
89        if ( Profiler::instance() instanceof ProfilerStub ) {
90            $profilerCallback = null;
91        } else {
92            $profilerCallback = static function ( $section ) {
93                return Profiler::instance()->scopedProfileIn( $section );
94            };
95        }
96
97        $lbConf += [
98            'profiler' => $profilerCallback,
99            'trxProfiler' => Profiler::instance()->getTransactionProfiler(),
100            'logger' => LoggerFactory::getInstance( 'rdbms' ),
101            'errorLogger' => MWExceptionHandler::logException( ... ),
102            'deprecationLogger' => static::logDeprecation( ... ),
103            'statsFactory' => $this->statsFactory,
104            'cliMode' => MW_ENTRY_POINT === 'cli',
105            'readOnlyReason' => $this->readOnlyMode->getReason(),
106            'criticalSectionProvider' => $this->csProvider,
107            'uniqueIdentifier' => $this->uniqueIdentifier,
108        ];
109        $lbConf['chronologyProtector'] = $this->chronologyProtector;
110        $lbConf['srvCache'] = $this->srvCache;
111        $lbConf['wanCache'] = $this->wanCache;
112        $lbConf['tracer'] = $this->tracer;
113
114        return $lbConf;
115    }
116
117    /**
118     * Decide which LBFactory class to use.
119     *
120     * @internal For use by ServiceWiring
121     * @param array $config (e.g. $wgLBFactoryConf)
122     * @return class-string<LBFactory>
123     */
124    public function getLBFactoryClass( array $config ): string {
125        $compat = [
126            // For LocalSettings.php compat after removing underscores (since 1.23).
127            'LBFactory_Single' => LBFactorySingle::class,
128            'LBFactory_Simple' => LBFactorySimple::class,
129            'LBFactory_Multi' => LBFactoryMulti::class,
130            // For LocalSettings.php compat after moving classes to namespaces (since 1.29).
131            'LBFactorySingle' => LBFactorySingle::class,
132            'LBFactorySimple' => LBFactorySimple::class,
133            'LBFactoryMulti' => LBFactoryMulti::class
134        ];
135
136        $class = $config['class'];
137        return $compat[$class] ?? $class;
138    }
139
140    public function setDomainAliases( ILBFactory $lbFactory ): void {
141        $domain = DatabaseDomain::newFromId( $lbFactory->getLocalDomainID() );
142        // For compatibility with hyphenated $wgDBname values on older wikis, handle callers
143        // that assume corresponding database domain IDs and wiki IDs have identical values
144        $rawLocalDomain = strlen( $domain->getTablePrefix() )
145            ? "{$domain->getDatabase()}-{$domain->getTablePrefix()}"
146            : (string)$domain->getDatabase();
147
148        $lbFactory->setDomainAliases( [ $rawLocalDomain => $domain ] );
149    }
150
151    /**
152     * Log a database deprecation warning
153     *
154     * @param string $msg Deprecation message
155     */
156    public static function logDeprecation( string $msg ): void {
157        if ( isset( self::$loggedDeprecations[$msg] ) ) {
158            return;
159        }
160        self::$loggedDeprecations[$msg] = true;
161        MWDebug::sendRawDeprecated( $msg, true, wfGetCaller() );
162    }
163}
164
165/** @deprecated class alias since 1.46 */
166class_alias( MWLBFactory::class, 'MWLBFactory' );