MediaWiki  master
LBFactoryMulti.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
26 use InvalidArgumentException;
27 use UnexpectedValueException;
28 
35 class LBFactoryMulti extends LBFactory {
37  private $mainLBs = [];
39  private $externalLBs = [];
40 
42  private $hostsByName = [];
44  private $sectionsByDB = [];
46  private $groupLoadsBySection = [];
48  private $groupLoadsByDB = [];
50  private $externalLoads = [];
52  private $serverTemplate = [];
64  private $readOnlyBySection = [];
65 
68 
70  private $lastDomain;
72  private $lastSection;
73 
138  public function __construct( array $conf ) {
139  parent::__construct( $conf );
140 
141  $this->hostsByName = $conf['hostsByName'] ?? [];
142  $this->sectionsByDB = $conf['sectionsByDB'];
143  $this->groupLoadsBySection = $conf['groupLoadsBySection'] ?? [];
144  foreach ( ( $conf['sectionLoads'] ?? [] ) as $section => $loadByHost ) {
145  $this->groupLoadsBySection[$section][ILoadBalancer::GROUP_GENERIC] = $loadByHost;
146  }
147  $this->groupLoadsByDB = $conf['groupLoadsByDB'] ?? [];
148  $this->externalLoads = $conf['externalLoads'] ?? [];
149  $this->serverTemplate = $conf['serverTemplate'] ?? [];
150  $this->externalTemplateOverrides = $conf['externalTemplateOverrides'] ?? [];
151  $this->templateOverridesBySection = $conf['templateOverridesBySection'] ?? [];
152  $this->templateOverridesByCluster = $conf['templateOverridesByCluster'] ?? [];
153  $this->masterTemplateOverrides = $conf['masterTemplateOverrides'] ?? [];
154  $this->templateOverridesByServer = $conf['templateOverridesByServer'] ?? [];
155  $this->readOnlyBySection = $conf['readOnlyBySection'] ?? [];
156 
157  $this->loadMonitorClass = $conf['loadMonitorClass'] ?? LoadMonitor::class;
158  }
159 
160  public function newMainLB( $domain = false, $owner = null ) {
161  $section = $this->getSectionForDomain( $domain );
162  if ( !isset( $this->groupLoadsBySection[$section][ILoadBalancer::GROUP_GENERIC] ) ) {
163  throw new UnexpectedValueException( "Section '$section' has no hosts defined." );
164  }
165 
166  $dbGroupLoads = $this->groupLoadsByDB[$this->getDomainDatabase( $domain )] ?? [];
167  unset( $dbGroupLoads[ILoadBalancer::GROUP_GENERIC] ); // cannot override
168 
169  return $this->newLoadBalancer(
170  array_merge(
171  $this->serverTemplate,
172  $this->templateOverridesBySection[$section] ?? []
173  ),
174  array_merge( $this->groupLoadsBySection[$section], $dbGroupLoads ),
175  // Use the LB-specific read-only reason if everything isn't already read-only
176  is_string( $this->readOnlyReason )
177  ? $this->readOnlyReason
178  : ( $this->readOnlyBySection[$section] ?? false ),
179  $owner
180  );
181  }
182 
183  public function getMainLB( $domain = false ) {
184  $section = $this->getSectionForDomain( $domain );
185 
186  if ( !isset( $this->mainLBs[$section] ) ) {
187  $this->mainLBs[$section] = $this->newMainLB( $domain, $this->getOwnershipId() );
188  }
189 
190  return $this->mainLBs[$section];
191  }
192 
193  public function newExternalLB( $cluster, $owner = null ) {
194  if ( !isset( $this->externalLoads[$cluster] ) ) {
195  throw new InvalidArgumentException( "Unknown cluster '$cluster'" );
196  }
197 
198  return $this->newLoadBalancer(
199  array_merge(
200  $this->serverTemplate,
201  $this->externalTemplateOverrides,
202  $this->templateOverridesByCluster[$cluster] ?? []
203  ),
204  [ ILoadBalancer::GROUP_GENERIC => $this->externalLoads[$cluster] ],
205  $this->readOnlyReason,
206  $owner
207  );
208  }
209 
210  public function getExternalLB( $cluster ) {
211  if ( !isset( $this->externalLBs[$cluster] ) ) {
212  $this->externalLBs[$cluster] =
213  $this->newExternalLB( $cluster, $this->getOwnershipId() );
214  }
215 
216  return $this->externalLBs[$cluster];
217  }
218 
219  public function getAllMainLBs() {
220  $lbs = [];
221  foreach ( $this->sectionsByDB as $db => $section ) {
222  if ( !isset( $lbs[$section] ) ) {
223  $lbs[$section] = $this->getMainLB( $db );
224  }
225  }
226 
227  return $lbs;
228  }
229 
230  public function getAllExternalLBs() {
231  $lbs = [];
232  foreach ( $this->externalLoads as $cluster => $unused ) {
233  $lbs[$cluster] = $this->getExternalLB( $cluster );
234  }
235 
236  return $lbs;
237  }
238 
239  public function forEachLB( $callback, array $params = [] ) {
240  foreach ( $this->mainLBs as $lb ) {
241  $callback( $lb, ...$params );
242  }
243  foreach ( $this->externalLBs as $lb ) {
244  $callback( $lb, ...$params );
245  }
246  }
247 
252  private function getSectionForDomain( $domain = false ) {
253  if ( $this->lastDomain === $domain ) {
254  return $this->lastSection;
255  }
256 
257  $database = $this->getDomainDatabase( $domain );
258  $section = $this->sectionsByDB[$database] ?? self::CLUSTER_MAIN_DEFAULT;
259  $this->lastSection = $section;
260  $this->lastDomain = $domain;
261 
262  return $section;
263  }
264 
274  private function newLoadBalancer( $serverTemplate, $groupLoads, $readOnlyReason, $owner ) {
275  $lb = new LoadBalancer( array_merge(
276  $this->baseLoadBalancerParams( $owner ),
277  [
278  'servers' => $this->makeServerArray( $serverTemplate, $groupLoads ),
279  'loadMonitor' => [ 'class' => $this->loadMonitorClass ],
280  'readOnlyReason' => $readOnlyReason
281  ]
282  ) );
283  $this->initLoadBalancer( $lb );
284 
285  return $lb;
286  }
287 
295  private function makeServerArray( array $serverTemplate, array $groupLoads ) {
296  // The master server is the first host explicitly listed in the generic load group
297  if ( !$groupLoads[ILoadBalancer::GROUP_GENERIC] ) {
298  throw new UnexpectedValueException( "Empty generic load array; no master defined." );
299  }
300 
301  $groupLoadsByHost = $this->reindexGroupLoads( $groupLoads );
302  // Get the ordered map of (host => load); the master server is first
303  $genericLoads = $groupLoads[ILoadBalancer::GROUP_GENERIC];
304  // Implictly append any hosts that only appear in custom load groups
305  $genericLoads += array_fill_keys( array_keys( $groupLoadsByHost ), 0 );
306 
307  $servers = [];
308  foreach ( $genericLoads as $host => $load ) {
309  $servers[] = array_merge(
311  $servers ? [] : $this->masterTemplateOverrides,
312  $this->templateOverridesByServer[$host] ?? [],
313  [
314  'host' => $this->hostsByName[$host] ?? $host,
315  'hostName' => $host,
316  'load' => $load,
317  'groupLoads' => $groupLoadsByHost[$host] ?? []
318  ]
319  );
320  }
321 
322  return $servers;
323  }
324 
330  private function reindexGroupLoads( array $groupLoads ) {
331  $reindexed = [];
332 
333  foreach ( $groupLoads as $group => $loadByHost ) {
334  foreach ( $loadByHost as $host => $load ) {
335  $reindexed[$host][$group] = $load;
336  }
337  }
338 
339  return $reindexed;
340  }
341 
346  private function getDomainDatabase( $domain = false ) {
347  return ( $domain === false )
348  ? $this->localDomain->getDatabase()
349  : DatabaseDomain::newFromId( $domain )->getDatabase();
350  }
351 }
Wikimedia\Rdbms\LBFactoryMulti\$masterTemplateOverrides
array $masterTemplateOverrides
Server config override map for all main and external master servers.
Definition: LBFactoryMulti.php:60
Wikimedia\Rdbms\DatabaseDomain\newFromId
static newFromId( $domain)
Definition: DatabaseDomain.php:77
Wikimedia\Rdbms\LBFactoryMulti\$groupLoadsByDB
int[][][] $groupLoadsByDB
Map of (database => group => host => load ratio)
Definition: LBFactoryMulti.php:48
Wikimedia\Rdbms\LBFactory\initLoadBalancer
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:627
Wikimedia\Rdbms\LBFactoryMulti\$hostsByName
string[] $hostsByName
Map of (hostname => IP address)
Definition: LBFactoryMulti.php:42
Wikimedia\Rdbms\LBFactory\getOwnershipId
getOwnershipId()
Definition: LBFactory.php:749
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
Wikimedia\Rdbms\LBFactoryMulti\reindexGroupLoads
reindexGroupLoads(array $groupLoads)
Take a group load array indexed by group then server, and reindex it by server then group.
Definition: LBFactoryMulti.php:330
Wikimedia\Rdbms\LBFactoryMulti\$loadMonitorClass
string $loadMonitorClass
An ILoadMonitor class.
Definition: LBFactoryMulti.php:67
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesBySection
array[] $templateOverridesBySection
Map of (section => server config map overrides)
Definition: LBFactoryMulti.php:56
Wikimedia\Rdbms\LBFactoryMulti\$externalTemplateOverrides
array $externalTemplateOverrides
Server config map overriding "serverTemplate" for external storage.
Definition: LBFactoryMulti.php:54
Wikimedia\Rdbms\LBFactoryMulti\__construct
__construct(array $conf)
Template override precedence (highest => lowest):
Definition: LBFactoryMulti.php:138
Wikimedia\Rdbms\LBFactoryMulti\makeServerArray
makeServerArray(array $serverTemplate, array $groupLoads)
Make a server array as expected by LoadBalancer::__construct()
Definition: LBFactoryMulti.php:295
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesByCluster
array[] $templateOverridesByCluster
Map of (cluster => server config map overrides) for external storage.
Definition: LBFactoryMulti.php:58
Wikimedia\Rdbms\LBFactory\$readOnlyReason
string bool $readOnlyReason
Reason all LBs are read-only or false if not.
Definition: LBFactory.php:100
Wikimedia\Rdbms\LBFactoryMulti\forEachLB
forEachLB( $callback, array $params=[])
Execute a function for each currently tracked (instantiated) load balancer.
Definition: LBFactoryMulti.php:239
Wikimedia\Rdbms\LBFactoryMulti\getDomainDatabase
getDomainDatabase( $domain=false)
Definition: LBFactoryMulti.php:346
Wikimedia\Rdbms\LBFactoryMulti\getMainLB
getMainLB( $domain=false)
Get a cached (tracked) load balancer object.
Definition: LBFactoryMulti.php:183
Wikimedia\Rdbms\LBFactoryMulti\$mainLBs
LoadBalancer[] $mainLBs
Definition: LBFactoryMulti.php:37
Wikimedia\Rdbms\LBFactoryMulti\$sectionsByDB
string[] $sectionsByDB
Map of (database name => section name)
Definition: LBFactoryMulti.php:44
Wikimedia\Rdbms\LBFactory\baseLoadBalancerParams
baseLoadBalancerParams( $owner)
Get parameters to ILoadBalancer::__construct()
Definition: LBFactory.php:588
Wikimedia\Rdbms\LBFactoryMulti\getAllExternalLBs
getAllExternalLBs()
Get cached (tracked) load balancers for all external database clusters.
Definition: LBFactoryMulti.php:230
Wikimedia\Rdbms\LoadBalancer
Database connection, tracking, load balancing, and transaction manager for a cluster.
Definition: LoadBalancer.php:42
Wikimedia\Rdbms\LBFactoryMulti\$externalLBs
LoadBalancer[] $externalLBs
Definition: LBFactoryMulti.php:39
Wikimedia\Rdbms\LBFactoryMulti\$serverTemplate
array $serverTemplate
Server config map ("host", "hostName", "load", and "groupLoads" are ignored)
Definition: LBFactoryMulti.php:52
Wikimedia\Rdbms\LBFactoryMulti
A multi-database, multi-master factory for Wikimedia and similar installations.
Definition: LBFactoryMulti.php:35
Wikimedia\Rdbms\LBFactoryMulti\$lastDomain
string $lastDomain
Definition: LBFactoryMulti.php:70
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesByServer
array[] $templateOverridesByServer
Map of (host => server config map overrides) for main and external servers.
Definition: LBFactoryMulti.php:62
Wikimedia\Rdbms\LBFactoryMulti\$lastSection
string $lastSection
Definition: LBFactoryMulti.php:72
Wikimedia\Rdbms\LBFactoryMulti\getSectionForDomain
getSectionForDomain( $domain=false)
Definition: LBFactoryMulti.php:252
Wikimedia\Rdbms\LBFactoryMulti\getAllMainLBs
getAllMainLBs()
Get cached (tracked) load balancers for all main database clusters.
Definition: LBFactoryMulti.php:219
Wikimedia\Rdbms\LBFactoryMulti\newLoadBalancer
newLoadBalancer( $serverTemplate, $groupLoads, $readOnlyReason, $owner)
Make a new load balancer object based on template and load array.
Definition: LBFactoryMulti.php:274
Wikimedia\Rdbms\LBFactoryMulti\newMainLB
newMainLB( $domain=false, $owner=null)
Create a new load balancer object.
Definition: LBFactoryMulti.php:160
Wikimedia\Rdbms\LBFactory
An interface for generating database load balancers.
Definition: LBFactory.php:40
Wikimedia\Rdbms\LBFactoryMulti\$readOnlyBySection
string[] bool[] $readOnlyBySection
A map of section name to read-only message.
Definition: LBFactoryMulti.php:64
Wikimedia\Rdbms\LBFactoryMulti\$externalLoads
int[][] $externalLoads
Map of (cluster => host => load ratio)
Definition: LBFactoryMulti.php:50
Wikimedia\Rdbms\LBFactoryMulti\$groupLoadsBySection
int[][][] $groupLoadsBySection
Map of (section => group => host => load ratio)
Definition: LBFactoryMulti.php:46
Wikimedia\Rdbms\LBFactoryMulti\getExternalLB
getExternalLB( $cluster)
Get a cached (tracked) load balancer for external storage.
Definition: LBFactoryMulti.php:210
Wikimedia\Rdbms\LBFactoryMulti\newExternalLB
newExternalLB( $cluster, $owner=null)
Create a new load balancer for external storage.
Definition: LBFactoryMulti.php:193