MediaWiki  master
MWLBFactory.php
Go to the documentation of this file.
1 <?php
27 
32 abstract class MWLBFactory {
33 
35  private static $loggedDeprecations = [];
36 
46  public static function applyDefaultConfig(
47  array $lbConf,
48  Config $mainConfig,
49  ConfiguredReadOnlyMode $readOnlyMode,
50  BagOStuff $srvCace,
51  BagOStuff $mainStash,
52  WANObjectCache $wanCache
53  ) {
54  global $wgCommandLineMode;
55 
56  $typesWithSchema = self::getDbTypesWithSchemas();
57 
58  $lbConf += [
59  'localDomain' => new DatabaseDomain(
60  $mainConfig->get( 'DBname' ),
61  $mainConfig->get( 'DBmwschema' ),
62  $mainConfig->get( 'DBprefix' )
63  ),
64  'profiler' => function ( $section ) {
65  return Profiler::instance()->scopedProfileIn( $section );
66  },
67  'trxProfiler' => Profiler::instance()->getTransactionProfiler(),
68  'replLogger' => LoggerFactory::getInstance( 'DBReplication' ),
69  'queryLogger' => LoggerFactory::getInstance( 'DBQuery' ),
70  'connLogger' => LoggerFactory::getInstance( 'DBConnection' ),
71  'perfLogger' => LoggerFactory::getInstance( 'DBPerformance' ),
72  'errorLogger' => [ MWExceptionHandler::class, 'logException' ],
73  'deprecationLogger' => [ static::class, 'logDeprecation' ],
74  'cliMode' => $wgCommandLineMode,
75  'hostname' => wfHostname(),
76  'readOnlyReason' => $readOnlyMode->getReason(),
77  'defaultGroup' => $mainConfig->get( 'DBDefaultGroup' ),
78  ];
79 
80  $serversCheck = [];
81  // When making changes here, remember to also specify MediaWiki-specific options
82  // for Database classes in the relevant Installer subclass.
83  // Such as MysqlInstaller::openConnection and PostgresInstaller::openConnectionWithParams.
84  if ( $lbConf['class'] === Wikimedia\Rdbms\LBFactorySimple::class ) {
85  if ( isset( $lbConf['servers'] ) ) {
86  // Server array is already explicitly configured
87  } elseif ( is_array( $mainConfig->get( 'DBservers' ) ) ) {
88  $lbConf['servers'] = [];
89  foreach ( $mainConfig->get( 'DBservers' ) as $i => $server ) {
90  $lbConf['servers'][$i] = self::initServerInfo( $server, $mainConfig );
91  }
92  } else {
93  $server = self::initServerInfo(
94  [
95  'host' => $mainConfig->get( 'DBserver' ),
96  'user' => $mainConfig->get( 'DBuser' ),
97  'password' => $mainConfig->get( 'DBpassword' ),
98  'dbname' => $mainConfig->get( 'DBname' ),
99  'type' => $mainConfig->get( 'DBtype' ),
100  'load' => 1
101  ],
102  $mainConfig
103  );
104 
105  $server['flags'] |= $mainConfig->get( 'DBssl' ) ? DBO_SSL : 0;
106  $server['flags'] |= $mainConfig->get( 'DBcompress' ) ? DBO_COMPRESS : 0;
107 
108  $lbConf['servers'] = [ $server ];
109  }
110  if ( !isset( $lbConf['externalClusters'] ) ) {
111  $lbConf['externalClusters'] = $mainConfig->get( 'ExternalServers' );
112  }
113 
114  $serversCheck = $lbConf['servers'];
115  } elseif ( $lbConf['class'] === Wikimedia\Rdbms\LBFactoryMulti::class ) {
116  if ( isset( $lbConf['serverTemplate'] ) ) {
117  if ( in_array( $lbConf['serverTemplate']['type'], $typesWithSchema, true ) ) {
118  $lbConf['serverTemplate']['schema'] = $mainConfig->get( 'DBmwschema' );
119  }
120  $lbConf['serverTemplate']['sqlMode'] = $mainConfig->get( 'SQLMode' );
121  }
122  $serversCheck = [ $lbConf['serverTemplate'] ] ?? [];
123  }
124 
125  self::assertValidServerConfigs( $serversCheck, $mainConfig );
126 
127  $lbConf = self::injectObjectCaches( $lbConf, $srvCace, $mainStash, $wanCache );
128 
129  return $lbConf;
130  }
131 
135  private static function getDbTypesWithSchemas() {
136  return [ 'postgres', 'msssql' ];
137  }
138 
144  private static function initServerInfo( array $server, Config $mainConfig ) {
145  if ( $server['type'] === 'sqlite' ) {
146  $httpMethod = $_SERVER['REQUEST_METHOD'] ?? null;
147  // T93097: hint for how file-based databases (e.g. sqlite) should go about locking.
148  // See https://www.sqlite.org/lang_transaction.html
149  // See https://www.sqlite.org/lockingv3.html#shared_lock
150  $isHttpRead = in_array( $httpMethod, [ 'GET', 'HEAD', 'OPTIONS', 'TRACE' ] );
151  $server += [
152  'dbDirectory' => $mainConfig->get( 'SQLiteDataDir' ),
153  'trxMode' => $isHttpRead ? 'DEFERRED' : 'IMMEDIATE'
154  ];
155  } elseif ( $server['type'] === 'postgres' ) {
156  $server += [
157  'port' => $mainConfig->get( 'DBport' ),
158  // Work around the reserved word usage in MediaWiki schema
159  'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
160  ];
161  } elseif ( $server['type'] === 'oracle' ) {
162  $server += [
163  // Work around the reserved word usage in MediaWiki schema
164  'keywordTableMap' => [ 'user' => 'mwuser', 'text' => 'pagecontent' ]
165  ];
166  } elseif ( $server['type'] === 'mssql' ) {
167  $server += [
168  'port' => $mainConfig->get( 'DBport' ),
169  'useWindowsAuth' => $mainConfig->get( 'DBWindowsAuthentication' )
170  ];
171  }
172 
173  if ( in_array( $server['type'], self::getDbTypesWithSchemas(), true ) ) {
174  $server += [ 'schema' => $mainConfig->get( 'DBmwschema' ) ];
175  }
176 
177  $flags = DBO_DEFAULT;
178  $flags |= $mainConfig->get( 'DebugDumpSql' ) ? DBO_DEBUG : 0;
179  if ( $server['type'] === 'oracle' ) {
180  $flags |= $mainConfig->get( 'DBOracleDRCP' ) ? DBO_PERSISTENT : 0;
181  }
182 
183  $server += [
184  'tablePrefix' => $mainConfig->get( 'DBprefix' ),
185  'flags' => $flags,
186  'sqlMode' => $mainConfig->get( 'SQLMode' ),
187  ];
188 
189  return $server;
190  }
191 
199  private static function injectObjectCaches(
200  array $lbConf, BagOStuff $sCache, BagOStuff $mStash, WANObjectCache $wCache
201  ) {
202  // Use APC/memcached style caching, but avoids loops with CACHE_DB (T141804)
203  if ( $sCache->getQoS( $sCache::ATTR_EMULATION ) > $sCache::QOS_EMULATION_SQL ) {
204  $lbConf['srvCache'] = $sCache;
205  }
206  if ( $mStash->getQoS( $mStash::ATTR_EMULATION ) > $mStash::QOS_EMULATION_SQL ) {
207  $lbConf['memStash'] = $mStash;
208  }
209  if ( $wCache->getQoS( $wCache::ATTR_EMULATION ) > $wCache::QOS_EMULATION_SQL ) {
210  $lbConf['wanCache'] = $wCache;
211  }
212 
213  return $lbConf;
214  }
215 
220  private static function assertValidServerConfigs( array $servers, Config $mainConfig ) {
221  $ldDB = $mainConfig->get( 'DBname' ); // local domain DB
222  $ldTP = $mainConfig->get( 'DBprefix' ); // local domain prefix
223 
224  foreach ( $servers as $server ) {
225  $type = $server['type'] ?? null;
226  $srvDB = $server['dbname'] ?? null; // server DB
227  $srvTP = $server['tablePrefix'] ?? ''; // server table prefix
228 
229  if ( $type === 'mysql' ) {
230  // A DB name is not needed to connect to mysql; 'dbname' is useless.
231  // This field only defines the DB to use for unspecified DB domains.
232  if ( $srvDB !== null && $srvDB !== $ldDB ) {
233  self::reportMismatchedDBs( $srvDB, $ldDB );
234  }
235  } elseif ( $type === 'postgres' ) {
236  if ( $srvTP !== '' ) {
237  self::reportIfPrefixSet( $srvTP, $type );
238  }
239  }
240 
241  if ( $srvTP !== '' && $srvTP !== $ldTP ) {
242  self::reportMismatchedPrefixes( $srvTP, $ldTP );
243  }
244  }
245  }
246 
251  private static function reportIfPrefixSet( $prefix, $dbType ) {
253  "\$wgDBprefix is set to '$prefix' but the database type is '$dbType'. " .
254  "MediaWiki does not support using a table prefix with this RDBMS type."
255  );
257  exit;
258  }
259 
264  private static function reportMismatchedDBs( $srvDB, $ldDB ) {
266  "\$wgDBservers has dbname='$srvDB' but \$wgDBname='$ldDB'. " .
267  "Set \$wgDBname to the database used by this wiki project. " .
268  "There is rarely a need to set 'dbname' in \$wgDBservers. " .
269  "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
270  "use of Database::getDomainId(), and other features are not reliable when " .
271  "\$wgDBservers does not match the local wiki database/prefix."
272  );
274  exit;
275  }
276 
281  private static function reportMismatchedPrefixes( $srvTP, $ldTP ) {
283  "\$wgDBservers has tablePrefix='$srvTP' but \$wgDBprefix='$ldTP'. " .
284  "Set \$wgDBprefix to the table prefix used by this wiki project. " .
285  "There is rarely a need to set 'tablePrefix' in \$wgDBservers. " .
286  "Cross-wiki database access, use of WikiMap::getCurrentWikiDbDomain(), " .
287  "use of Database::getDomainId(), and other features are not reliable when " .
288  "\$wgDBservers does not match the local wiki database/prefix."
289  );
291  exit;
292  }
293 
302  public static function getLBFactoryClass( array $config ) {
303  // For configuration backward compatibility after removing
304  // underscores from class names in MediaWiki 1.23.
305  $bcClasses = [
306  'LBFactory_Simple' => 'LBFactorySimple',
307  'LBFactory_Single' => 'LBFactorySingle',
308  'LBFactory_Multi' => 'LBFactoryMulti'
309  ];
310 
311  $class = $config['class'];
312 
313  if ( isset( $bcClasses[$class] ) ) {
314  $class = $bcClasses[$class];
315  wfDeprecated(
316  '$wgLBFactoryConf must be updated. See RELEASE-NOTES for details',
317  '1.23'
318  );
319  }
320 
321  // For configuration backward compatibility after moving classes to namespaces (1.29)
322  $compat = [
323  'LBFactorySingle' => Wikimedia\Rdbms\LBFactorySingle::class,
324  'LBFactorySimple' => Wikimedia\Rdbms\LBFactorySimple::class,
325  'LBFactoryMulti' => Wikimedia\Rdbms\LBFactoryMulti::class
326  ];
327 
328  if ( isset( $compat[$class] ) ) {
329  $class = $compat[$class];
330  }
331 
332  return $class;
333  }
334 
335  public static function setSchemaAliases( LBFactory $lbFactory, Config $config ) {
336  if ( $config->get( 'DBtype' ) === 'mysql' ) {
351  $lbFactory->setIndexAliases( [
352  'ar_usertext_timestamp' => 'usertext_timestamp',
353  'un_user_id' => 'user_id',
354  'un_user_ip' => 'user_ip',
355  ] );
356  }
357  }
358 
363  public static function logDeprecation( $msg ) {
364  global $wgDevelopmentWarnings;
365 
366  if ( isset( self::$loggedDeprecations[$msg] ) ) {
367  return;
368  }
369  self::$loggedDeprecations[$msg] = true;
370 
371  if ( $wgDevelopmentWarnings ) {
372  trigger_error( $msg, E_USER_DEPRECATED );
373  }
374  wfDebugLog( 'deprecated', $msg, 'private' );
375  }
376 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
An interface for generating database load balancers.
Definition: LBFactory.php:39
static assertValidServerConfigs(array $servers, Config $mainConfig)
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2159
static instance()
Singleton.
Definition: Profiler.php:62
wfHostname()
Fetch server name for use in error reporting etc.
static getDbTypesWithSchemas()
A read-only mode service which does not depend on LoadBalancer.
get( $name)
Get a configuration variable such as "Sitename" or "UploadMaintenance.".
const DBO_PERSISTENT
Definition: defines.php:14
This program is free software; you can redistribute it and/or modify it under the terms of the GNU Ge...
Interface for configuration instances.
Definition: Config.php:28
const DBO_DEBUG
Definition: defines.php:9
static logDeprecation( $msg)
Log a database deprecation warning.
static reportMismatchedPrefixes( $srvTP, $ldTP)
static array $loggedDeprecations
Cache of already-logged deprecation messages.
Definition: MWLBFactory.php:35
static injectObjectCaches(array $lbConf, BagOStuff $sCache, BagOStuff $mStash, WANObjectCache $wCache)
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
usually copyright or history_copyright This message must be in HTML not wikitext if the section is included from a template $section
Definition: hooks.txt:3050
getQoS( $flag)
Definition: BagOStuff.php:783
static output( $e, $mode, $eNew=null)
setIndexAliases(array $aliases)
Convert certain index names to alternative names before querying the DB.
Definition: LBFactory.php:622
getReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
const DBO_DEFAULT
Definition: defines.php:13
Class to handle database/prefix specification for IDatabase domains.
static reportIfPrefixSet( $prefix, $dbType)
you have access to all of the normal MediaWiki so you can get a DB use the etc For full docs on the Maintenance class
Definition: maintenance.txt:52
static getLBFactoryClass(array $config)
Returns the LBFactory class to use and the load balancer configuration.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
global $wgCommandLineMode
MediaWiki Logger LoggerFactory implements a PSR [0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method. MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances. The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An SPI is an API intended to be implemented or extended by a third party. This software design pattern is intended to enable framework extension and replaceable components. It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki. The service provider interface allows the backend logging library to be implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime. This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance. Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
static setSchemaAliases(LBFactory $lbFactory, Config $config)
static initServerInfo(array $server, Config $mainConfig)
MediaWiki-specific class for generating database load balancers.
Definition: MWLBFactory.php:32
static applyDefaultConfig(array $lbConf, Config $mainConfig, ConfiguredReadOnlyMode $readOnlyMode, BagOStuff $srvCace, BagOStuff $mainStash, WANObjectCache $wanCache)
Definition: MWLBFactory.php:46
const DBO_SSL
Definition: defines.php:17
static reportMismatchedDBs( $srvDB, $ldDB)
$wgDevelopmentWarnings
If set to true MediaWiki will throw notices for some possible error conditions and for deprecated fun...
const DBO_COMPRESS
Definition: defines.php:18