MediaWiki  1.29.1
LBFactoryMulti.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
26 use InvalidArgumentException;
27 
34 class LBFactoryMulti extends LBFactory {
36  private $sectionsByDB;
37 
42  private $sectionLoads;
43 
48  private $serverTemplate;
49 
50  // Optional settings
51 
53  private $groupLoadsBySection = [];
54 
56  private $groupLoadsByDB = [];
57 
59  private $hostsByName = [];
60 
62  private $externalLoads = [];
63 
69 
76 
79 
82 
85 
90  private $readOnlyBySection = [];
91 
93  private $conf;
94 
96  private $mainLBs = [];
97 
99  private $extLBs = [];
100 
102  private $loadMonitorClass = 'LoadMonitor';
103 
105  private $lastDomain;
106 
108  private $lastSection;
109 
166  public function __construct( array $conf ) {
167  parent::__construct( $conf );
168 
169  $this->conf = $conf;
170  $required = [ 'sectionsByDB', 'sectionLoads', 'serverTemplate' ];
171  $optional = [ 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName',
172  'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer',
173  'templateOverridesByCluster', 'templateOverridesBySection', 'masterTemplateOverrides',
174  'readOnlyBySection', 'loadMonitorClass' ];
175 
176  foreach ( $required as $key ) {
177  if ( !isset( $conf[$key] ) ) {
178  throw new InvalidArgumentException( __CLASS__ . ": $key is required." );
179  }
180  $this->$key = $conf[$key];
181  }
182 
183  foreach ( $optional as $key ) {
184  if ( isset( $conf[$key] ) ) {
185  $this->$key = $conf[$key];
186  }
187  }
188  }
189 
194  private function getSectionForDomain( $domain = false ) {
195  if ( $this->lastDomain === $domain ) {
196  return $this->lastSection;
197  }
198  list( $dbName, ) = $this->getDBNameAndPrefix( $domain );
199  if ( isset( $this->sectionsByDB[$dbName] ) ) {
200  $section = $this->sectionsByDB[$dbName];
201  } else {
202  $section = 'DEFAULT';
203  }
204  $this->lastSection = $section;
205  $this->lastDomain = $domain;
206 
207  return $section;
208  }
209 
214  public function newMainLB( $domain = false ) {
215  list( $dbName, ) = $this->getDBNameAndPrefix( $domain );
216  $section = $this->getSectionForDomain( $domain );
217  if ( isset( $this->groupLoadsByDB[$dbName] ) ) {
218  $groupLoads = $this->groupLoadsByDB[$dbName];
219  } else {
220  $groupLoads = [];
221  }
222 
223  if ( isset( $this->groupLoadsBySection[$section] ) ) {
224  $groupLoads = array_merge_recursive(
225  $groupLoads, $this->groupLoadsBySection[$section] );
226  }
227 
229  // Use the LB-specific read-only reason if everything isn't already read-only
230  if ( $readOnlyReason === false && isset( $this->readOnlyBySection[$section] ) ) {
231  $readOnlyReason = $this->readOnlyBySection[$section];
232  }
233 
235  if ( isset( $this->templateOverridesBySection[$section] ) ) {
236  $template = $this->templateOverridesBySection[$section] + $template;
237  }
238 
239  return $this->newLoadBalancer(
240  $template,
241  $this->sectionLoads[$section],
242  $groupLoads,
244  );
245  }
246 
251  public function getMainLB( $domain = false ) {
252  $section = $this->getSectionForDomain( $domain );
253  if ( !isset( $this->mainLBs[$section] ) ) {
254  $this->mainLBs[$section] = $this->newMainLB( $domain );
255  }
256 
257  return $this->mainLBs[$section];
258  }
259 
260  public function newExternalLB( $cluster ) {
261  if ( !isset( $this->externalLoads[$cluster] ) ) {
262  throw new InvalidArgumentException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
263  }
265  if ( $this->externalTemplateOverrides ) {
266  $template = $this->externalTemplateOverrides + $template;
267  }
268  if ( isset( $this->templateOverridesByCluster[$cluster] ) ) {
269  $template = $this->templateOverridesByCluster[$cluster] + $template;
270  }
271 
272  return $this->newLoadBalancer(
273  $template,
274  $this->externalLoads[$cluster],
275  [],
276  $this->readOnlyReason
277  );
278  }
279 
280  public function getExternalLB( $cluster ) {
281  if ( !isset( $this->extLBs[$cluster] ) ) {
282  $this->extLBs[$cluster] = $this->newExternalLB( $cluster );
283  }
284 
285  return $this->extLBs[$cluster];
286  }
287 
288  public function getAllMainLBs() {
289  $lbs = [];
290  foreach ( $this->sectionsByDB as $db => $section ) {
291  if ( !isset( $lbs[$section] ) ) {
292  $lbs[$section] = $this->getMainLB( $db );
293  }
294  }
295 
296  return $lbs;
297  }
298 
299  public function getAllExternalLBs() {
300  $lbs = [];
301  foreach ( $this->externalLoads as $cluster => $unused ) {
302  $lbs[$cluster] = $this->getExternalLB( $cluster );
303  }
304 
305  return $lbs;
306  }
307 
317  private function newLoadBalancer( $template, $loads, $groupLoads, $readOnlyReason ) {
318  $lb = new LoadBalancer( array_merge(
319  $this->baseLoadBalancerParams(),
320  [
321  'servers' => $this->makeServerArray( $template, $loads, $groupLoads ),
322  'loadMonitor' => [ 'class' => $this->loadMonitorClass ],
323  'readOnlyReason' => $readOnlyReason
324  ]
325  ) );
326  $this->initLoadBalancer( $lb );
327 
328  return $lb;
329  }
330 
339  private function makeServerArray( $template, $loads, $groupLoads ) {
340  $servers = [];
341  $master = true;
342  $groupLoadsByServer = $this->reindexGroupLoads( $groupLoads );
343  foreach ( $groupLoadsByServer as $server => $stuff ) {
344  if ( !isset( $loads[$server] ) ) {
345  $loads[$server] = 0;
346  }
347  }
348  foreach ( $loads as $serverName => $load ) {
349  $serverInfo = $template;
350  if ( $master ) {
351  $serverInfo['master'] = true;
352  if ( $this->masterTemplateOverrides ) {
353  $serverInfo = $this->masterTemplateOverrides + $serverInfo;
354  }
355  $master = false;
356  } else {
357  $serverInfo['replica'] = true;
358  }
359  if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
360  $serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
361  }
362  if ( isset( $groupLoadsByServer[$serverName] ) ) {
363  $serverInfo['groupLoads'] = $groupLoadsByServer[$serverName];
364  }
365  if ( isset( $this->hostsByName[$serverName] ) ) {
366  $serverInfo['host'] = $this->hostsByName[$serverName];
367  } else {
368  $serverInfo['host'] = $serverName;
369  }
370  $serverInfo['hostName'] = $serverName;
371  $serverInfo['load'] = $load;
372  $serverInfo += [ 'flags' => IDatabase::DBO_DEFAULT ];
373 
374  $servers[] = $serverInfo;
375  }
376 
377  return $servers;
378  }
379 
385  private function reindexGroupLoads( $groupLoads ) {
386  $reindexed = [];
387  foreach ( $groupLoads as $group => $loads ) {
388  foreach ( $loads as $server => $load ) {
389  $reindexed[$server][$group] = $load;
390  }
391  }
392 
393  return $reindexed;
394  }
395 
400  private function getDBNameAndPrefix( $domain = false ) {
401  $domain = ( $domain === false )
402  ? $this->localDomain
403  : DatabaseDomain::newFromId( $domain );
404 
405  return [ $domain->getDatabase(), $domain->getTablePrefix() ];
406  }
407 
415  public function forEachLB( $callback, array $params = [] ) {
416  foreach ( $this->mainLBs as $lb ) {
417  call_user_func_array( $callback, array_merge( [ $lb ], $params ) );
418  }
419  foreach ( $this->extLBs as $lb ) {
420  call_user_func_array( $callback, array_merge( [ $lb ], $params ) );
421  }
422  }
423 }
Wikimedia\Rdbms\LBFactoryMulti\$hostsByName
array $hostsByName
A map of hostname to IP address.
Definition: LBFactoryMulti.php:59
$template
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping $template
Definition: hooks.txt:783
Wikimedia\Rdbms\LBFactoryMulti\$masterTemplateOverrides
array $masterTemplateOverrides
An override array for all master servers.
Definition: LBFactoryMulti.php:84
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:189
Wikimedia\Rdbms\DatabaseDomain\newFromId
static newFromId( $domain)
Definition: DatabaseDomain.php:63
Wikimedia\Rdbms\LBFactoryMulti\$conf
array $conf
Load balancer factory configuration.
Definition: LBFactoryMulti.php:93
Wikimedia\Rdbms\LBFactoryMulti\$sectionsByDB
array $sectionsByDB
A map of database names to section names.
Definition: LBFactoryMulti.php:36
Wikimedia\Rdbms\LBFactory\initLoadBalancer
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:520
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
$params
$params
Definition: styleTest.css.php:40
Wikimedia\Rdbms\LBFactoryMulti\$sectionLoads
array $sectionLoads
A 2-d map.
Definition: LBFactoryMulti.php:42
Wikimedia\Rdbms\LBFactoryMulti\getDBNameAndPrefix
getDBNameAndPrefix( $domain=false)
Definition: LBFactoryMulti.php:400
Wikimedia\Rdbms\LBFactoryMulti\$loadMonitorClass
string $loadMonitorClass
Definition: LBFactoryMulti.php:102
Wikimedia\Rdbms\LBFactory\baseLoadBalancerParams
baseLoadBalancerParams()
Base parameters to LoadBalancer::__construct()
Definition: LBFactory.php:498
php
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
Wikimedia\Rdbms\LBFactoryMulti\$serverTemplate
array[] $serverTemplate
Server info associative array.
Definition: LBFactoryMulti.php:48
Wikimedia\Rdbms\LBFactoryMulti\$externalTemplateOverrides
array $externalTemplateOverrides
A set of server info keys overriding serverTemplate for external storage.
Definition: LBFactoryMulti.php:68
Wikimedia\Rdbms\LBFactoryMulti\__construct
__construct(array $conf)
Definition: LBFactoryMulti.php:166
Wikimedia\Rdbms\LBFactory\$readOnlyReason
string bool $readOnlyReason
Reason all LBs are read-only or false if not.
Definition: LBFactory.php:74
Wikimedia\Rdbms\LBFactoryMulti\forEachLB
forEachLB( $callback, array $params=[])
Execute a function for each tracked load balancer The callback is called with the load balancer as th...
Definition: LBFactoryMulti.php:415
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesBySection
array $templateOverridesBySection
A 2-d map overriding the server info by section.
Definition: LBFactoryMulti.php:78
Wikimedia\Rdbms\LBFactoryMulti\getMainLB
getMainLB( $domain=false)
Definition: LBFactoryMulti.php:251
Wikimedia\Rdbms\LBFactoryMulti\$mainLBs
LoadBalancer[] $mainLBs
Definition: LBFactoryMulti.php:96
Wikimedia\Rdbms\LBFactoryMulti\getAllExternalLBs
getAllExternalLBs()
Get cached (tracked) load balancers for all external database clusters.
Definition: LBFactoryMulti.php:299
Wikimedia\Rdbms\LBFactoryMulti\newLoadBalancer
newLoadBalancer( $template, $loads, $groupLoads, $readOnlyReason)
Make a new load balancer object based on template and load array.
Definition: LBFactoryMulti.php:317
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesByCluster
array $templateOverridesByCluster
A 2-d map overriding the server info by external storage cluster.
Definition: LBFactoryMulti.php:81
Wikimedia\Rdbms\LBFactoryMulti\newExternalLB
newExternalLB( $cluster)
Definition: LBFactoryMulti.php:260
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
Wikimedia\Rdbms\LBFactoryMulti\$readOnlyBySection
array bool $readOnlyBySection
A map of section name to read-only message.
Definition: LBFactoryMulti.php:90
Wikimedia\Rdbms\LoadBalancer
Database connection, tracking, load balancing, and transaction manager for a cluster.
Definition: LoadBalancer.php:41
Wikimedia\Rdbms\LBFactoryMulti\$extLBs
LoadBalancer[] $extLBs
Definition: LBFactoryMulti.php:99
Wikimedia\Rdbms\LBFactoryMulti
A multi-database, multi-master factory for Wikimedia and similar installations.
Definition: LBFactoryMulti.php:34
Wikimedia\Rdbms\LBFactoryMulti\reindexGroupLoads
reindexGroupLoads( $groupLoads)
Take a group load array indexed by group then server, and reindex it by server then group.
Definition: LBFactoryMulti.php:385
Wikimedia\Rdbms\LBFactoryMulti\$lastDomain
string $lastDomain
Definition: LBFactoryMulti.php:105
Wikimedia\Rdbms\LBFactoryMulti\$lastSection
string $lastSection
Definition: LBFactoryMulti.php:108
Wikimedia\Rdbms\LBFactoryMulti\getSectionForDomain
getSectionForDomain( $domain=false)
Definition: LBFactoryMulti.php:194
Wikimedia\Rdbms\LBFactoryMulti\makeServerArray
makeServerArray( $template, $loads, $groupLoads)
Make a server array as expected by LoadBalancer::__construct, using a template and load array.
Definition: LBFactoryMulti.php:339
Wikimedia\Rdbms\LBFactoryMulti\getAllMainLBs
getAllMainLBs()
Get cached (tracked) load balancers for all main database clusters.
Definition: LBFactoryMulti.php:288
$section
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:2929
Wikimedia\Rdbms\LBFactory
An interface for generating database load balancers.
Definition: LBFactory.php:38
as
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
Wikimedia\Rdbms\LBFactoryMulti\$externalLoads
array $externalLoads
A map of external storage cluster name to server load map.
Definition: LBFactoryMulti.php:62
Wikimedia\Rdbms\LBFactoryMulti\newMainLB
newMainLB( $domain=false)
Definition: LBFactoryMulti.php:214
Wikimedia\Rdbms\LBFactoryMulti\getExternalLB
getExternalLB( $cluster)
Definition: LBFactoryMulti.php:280
DBO_DEFAULT
const DBO_DEFAULT
Definition: defines.php:13
Wikimedia\Rdbms\LBFactoryMulti\$groupLoadsByDB
array $groupLoadsByDB
A 3-d map giving server load ratios by DB name.
Definition: LBFactoryMulti.php:56
array
the array() calling protocol came about after MediaWiki 1.4rc1.
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesByServer
array $templateOverridesByServer
A 2-d map overriding serverTemplate and externalTemplateOverrides on a server-by-server basis.
Definition: LBFactoryMulti.php:75
Wikimedia\Rdbms\LBFactoryMulti\$groupLoadsBySection
array $groupLoadsBySection
A 3-d map giving server load ratios for each section and group.
Definition: LBFactoryMulti.php:53