MediaWiki  REL1_31
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 
111  private $maxLag = self::MAX_LAG_DEFAULT;
112 
114  const MAX_LAG_DEFAULT = 10;
115 
173  public function __construct( array $conf ) {
174  parent::__construct( $conf );
175 
176  $this->conf = $conf;
177  $required = [ 'sectionsByDB', 'sectionLoads', 'serverTemplate' ];
178  $optional = [ 'groupLoadsBySection', 'groupLoadsByDB', 'hostsByName',
179  'externalLoads', 'externalTemplateOverrides', 'templateOverridesByServer',
180  'templateOverridesByCluster', 'templateOverridesBySection', 'masterTemplateOverrides',
181  'readOnlyBySection', 'maxLag', 'loadMonitorClass' ];
182 
183  foreach ( $required as $key ) {
184  if ( !isset( $conf[$key] ) ) {
185  throw new InvalidArgumentException( __CLASS__ . ": $key is required." );
186  }
187  $this->$key = $conf[$key];
188  }
189 
190  foreach ( $optional as $key ) {
191  if ( isset( $conf[$key] ) ) {
192  $this->$key = $conf[$key];
193  }
194  }
195  }
196 
201  private function getSectionForDomain( $domain = false ) {
202  if ( $this->lastDomain === $domain ) {
203  return $this->lastSection;
204  }
205  list( $dbName, ) = $this->getDBNameAndPrefix( $domain );
206  if ( isset( $this->sectionsByDB[$dbName] ) ) {
207  $section = $this->sectionsByDB[$dbName];
208  } else {
209  $section = 'DEFAULT';
210  }
211  $this->lastSection = $section;
212  $this->lastDomain = $domain;
213 
214  return $section;
215  }
216 
221  public function newMainLB( $domain = false ) {
222  list( $dbName, ) = $this->getDBNameAndPrefix( $domain );
223  $section = $this->getSectionForDomain( $domain );
224  if ( isset( $this->groupLoadsByDB[$dbName] ) ) {
225  $groupLoads = $this->groupLoadsByDB[$dbName];
226  } else {
227  $groupLoads = [];
228  }
229 
230  if ( isset( $this->groupLoadsBySection[$section] ) ) {
231  $groupLoads = array_merge_recursive(
232  $groupLoads, $this->groupLoadsBySection[$section] );
233  }
234 
236  // Use the LB-specific read-only reason if everything isn't already read-only
237  if ( $readOnlyReason === false && isset( $this->readOnlyBySection[$section] ) ) {
238  $readOnlyReason = $this->readOnlyBySection[$section];
239  }
240 
242  if ( isset( $this->templateOverridesBySection[$section] ) ) {
243  $template = $this->templateOverridesBySection[$section] + $template;
244  }
245 
246  return $this->newLoadBalancer(
247  $template,
248  $this->sectionLoads[$section],
249  $groupLoads,
251  );
252  }
253 
258  public function getMainLB( $domain = false ) {
259  $section = $this->getSectionForDomain( $domain );
260  if ( !isset( $this->mainLBs[$section] ) ) {
261  $this->mainLBs[$section] = $this->newMainLB( $domain );
262  }
263 
264  return $this->mainLBs[$section];
265  }
266 
267  public function newExternalLB( $cluster ) {
268  if ( !isset( $this->externalLoads[$cluster] ) ) {
269  throw new InvalidArgumentException( __METHOD__ . ": Unknown cluster \"$cluster\"" );
270  }
272  if ( $this->externalTemplateOverrides ) {
273  $template = $this->externalTemplateOverrides + $template;
274  }
275  if ( isset( $this->templateOverridesByCluster[$cluster] ) ) {
276  $template = $this->templateOverridesByCluster[$cluster] + $template;
277  }
278 
279  return $this->newLoadBalancer(
280  $template,
281  $this->externalLoads[$cluster],
282  [],
283  $this->readOnlyReason
284  );
285  }
286 
287  public function getExternalLB( $cluster ) {
288  if ( !isset( $this->extLBs[$cluster] ) ) {
289  $this->extLBs[$cluster] = $this->newExternalLB( $cluster );
290  }
291 
292  return $this->extLBs[$cluster];
293  }
294 
295  public function getAllMainLBs() {
296  $lbs = [];
297  foreach ( $this->sectionsByDB as $db => $section ) {
298  if ( !isset( $lbs[$section] ) ) {
299  $lbs[$section] = $this->getMainLB( $db );
300  }
301  }
302 
303  return $lbs;
304  }
305 
306  public function getAllExternalLBs() {
307  $lbs = [];
308  foreach ( $this->externalLoads as $cluster => $unused ) {
309  $lbs[$cluster] = $this->getExternalLB( $cluster );
310  }
311 
312  return $lbs;
313  }
314 
324  private function newLoadBalancer( $template, $loads, $groupLoads, $readOnlyReason ) {
325  $lb = new LoadBalancer( array_merge(
326  $this->baseLoadBalancerParams(),
327  [
328  'servers' => $this->makeServerArray( $template, $loads, $groupLoads ),
329  'maxLag' => $this->maxLag,
330  'loadMonitor' => [ 'class' => $this->loadMonitorClass ],
331  'readOnlyReason' => $readOnlyReason
332  ]
333  ) );
334  $this->initLoadBalancer( $lb );
335 
336  return $lb;
337  }
338 
347  private function makeServerArray( $template, $loads, $groupLoads ) {
348  $servers = [];
349  $master = true;
350  $groupLoadsByServer = $this->reindexGroupLoads( $groupLoads );
351  foreach ( $groupLoadsByServer as $server => $stuff ) {
352  if ( !isset( $loads[$server] ) ) {
353  $loads[$server] = 0;
354  }
355  }
356  foreach ( $loads as $serverName => $load ) {
357  $serverInfo = $template;
358  if ( $master ) {
359  $serverInfo['master'] = true;
360  if ( $this->masterTemplateOverrides ) {
361  $serverInfo = $this->masterTemplateOverrides + $serverInfo;
362  }
363  $master = false;
364  } else {
365  $serverInfo['replica'] = true;
366  }
367  if ( isset( $this->templateOverridesByServer[$serverName] ) ) {
368  $serverInfo = $this->templateOverridesByServer[$serverName] + $serverInfo;
369  }
370  if ( isset( $groupLoadsByServer[$serverName] ) ) {
371  $serverInfo['groupLoads'] = $groupLoadsByServer[$serverName];
372  }
373  if ( isset( $this->hostsByName[$serverName] ) ) {
374  $serverInfo['host'] = $this->hostsByName[$serverName];
375  } else {
376  $serverInfo['host'] = $serverName;
377  }
378  $serverInfo['hostName'] = $serverName;
379  $serverInfo['load'] = $load;
380  $serverInfo += [ 'flags' => IDatabase::DBO_DEFAULT ];
381 
382  $servers[] = $serverInfo;
383  }
384 
385  return $servers;
386  }
387 
393  private function reindexGroupLoads( $groupLoads ) {
394  $reindexed = [];
395  foreach ( $groupLoads as $group => $loads ) {
396  foreach ( $loads as $server => $load ) {
397  $reindexed[$server][$group] = $load;
398  }
399  }
400 
401  return $reindexed;
402  }
403 
408  private function getDBNameAndPrefix( $domain = false ) {
409  $domain = ( $domain === false )
410  ? $this->localDomain
411  : DatabaseDomain::newFromId( $domain );
412 
413  return [ $domain->getDatabase(), $domain->getTablePrefix() ];
414  }
415 
423  public function forEachLB( $callback, array $params = [] ) {
424  foreach ( $this->mainLBs as $lb ) {
425  call_user_func_array( $callback, array_merge( [ $lb ], $params ) );
426  }
427  foreach ( $this->extLBs as $lb ) {
428  call_user_func_array( $callback, array_merge( [ $lb ], $params ) );
429  }
430  }
431 }
Wikimedia\Rdbms\LBFactoryMulti\$hostsByName
array $hostsByName
A map of hostname to IP address.
Definition: LBFactoryMulti.php:59
Wikimedia\Rdbms\LBFactoryMulti\$masterTemplateOverrides
array $masterTemplateOverrides
An override array for all master servers.
Definition: LBFactoryMulti.php:84
use
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Definition: APACHE-LICENSE-2.0.txt:10
Wikimedia\Rdbms\DatabaseDomain\newFromId
static newFromId( $domain)
Definition: DatabaseDomain.php:63
array
the array() calling protocol came about after MediaWiki 1.4rc1.
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
$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:831
Wikimedia\Rdbms\LBFactory\initLoadBalancer
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:546
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:408
Wikimedia\Rdbms\LBFactoryMulti\$loadMonitorClass
string $loadMonitorClass
Definition: LBFactoryMulti.php:102
Wikimedia\Rdbms\LBFactory\baseLoadBalancerParams
baseLoadBalancerParams()
Base parameters to LoadBalancer::__construct()
Definition: LBFactory.php:519
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:37
Wikimedia\Rdbms\LBFactoryMulti\$maxLag
int $maxLag
Definition: LBFactoryMulti.php:111
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:173
Wikimedia\Rdbms\LBFactory\$readOnlyReason
string bool $readOnlyReason
Reason all LBs are read-only or false if not.
Definition: LBFactory.php:77
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:423
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:258
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:306
Wikimedia\Rdbms\LBFactoryMulti\newLoadBalancer
newLoadBalancer( $template, $loads, $groupLoads, $readOnlyReason)
Make a new load balancer object based on template and load array.
Definition: LBFactoryMulti.php:324
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:267
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:393
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:201
$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:3022
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:347
Wikimedia\Rdbms\LBFactoryMulti\getAllMainLBs
getAllMainLBs()
Get cached (tracked) load balancers for all main database clusters.
Definition: LBFactoryMulti.php:295
Wikimedia\Rdbms\LBFactory
An interface for generating database load balancers.
Definition: LBFactory.php:39
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:22
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:221
Wikimedia\Rdbms\LBFactoryMulti\getExternalLB
getExternalLB( $cluster)
Definition: LBFactoryMulti.php:287
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
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
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