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;
48  private $groupLoadsByDB;
50  private $externalLoads;
52  private $serverTemplate;
67 
113  public function __construct( array $conf ) {
114  parent::__construct( $conf );
115 
116  $this->hostsByName = $conf['hostsByName'] ?? [];
117  $this->sectionsByDB = $conf['sectionsByDB'];
118  $this->groupLoadsBySection = $conf['groupLoadsBySection'] ?? [];
119  foreach ( ( $conf['sectionLoads'] ?? [] ) as $section => $loadByHost ) {
120  $this->groupLoadsBySection[$section][ILoadBalancer::GROUP_GENERIC] = $loadByHost;
121  }
122  $this->groupLoadsByDB = $conf['groupLoadsByDB'] ?? [];
123  $this->externalLoads = $conf['externalLoads'] ?? [];
124  $this->serverTemplate = $conf['serverTemplate'] ?? [];
125  $this->externalTemplateOverrides = $conf['externalTemplateOverrides'] ?? [];
126  $this->templateOverridesBySection = $conf['templateOverridesBySection'] ?? [];
127  $this->templateOverridesByCluster = $conf['templateOverridesByCluster'] ?? [];
128  $this->masterTemplateOverrides = $conf['masterTemplateOverrides'] ?? [];
129  $this->templateOverridesByServer = $conf['templateOverridesByServer'] ?? [];
130  $this->readOnlyBySection = $conf['readOnlyBySection'] ?? [];
131 
132  if ( isset( $conf['loadMonitor'] ) ) {
133  $this->loadMonitorConfig = $conf['loadMonitor'];
134  } elseif ( isset( $conf['loadMonitorClass'] ) ) { // b/c
135  $this->loadMonitorConfig = [ 'class' => $conf['loadMonitorClass'] ];
136  } else {
137  $this->loadMonitorConfig = [ 'class' => LoadMonitor::class ];
138  }
139  }
140 
141  public function newMainLB( $domain = false, $owner = null ) {
142  $domainInstance = $this->resolveDomainInstance( $domain );
143  $database = $domainInstance->getDatabase();
144  $section = $this->getSectionFromDatabase( $database );
145  if ( !isset( $this->groupLoadsBySection[$section][ILoadBalancer::GROUP_GENERIC] ) ) {
146  throw new UnexpectedValueException( "Section '$section' has no hosts defined." );
147  }
148  $dbGroupLoads = $this->groupLoadsByDB[$database] ?? [];
149  unset( $dbGroupLoads[ILoadBalancer::GROUP_GENERIC] ); // cannot override
150  return $this->newLoadBalancer(
151  array_merge(
152  $this->serverTemplate,
153  $this->templateOverridesBySection[$section] ?? []
154  ),
155  array_merge( $this->groupLoadsBySection[$section], $dbGroupLoads ),
156  // Use the LB-specific read-only reason if everything isn't already read-only
157  is_string( $this->readOnlyReason )
158  ? $this->readOnlyReason
159  : ( $this->readOnlyBySection[$section] ?? false ),
160  $owner
161  );
162  }
163 
164  public function getMainLB( $domain = false ) {
165  $domainInstance = $this->resolveDomainInstance( $domain );
166  $section = $this->getSectionFromDatabase( $domainInstance->getDatabase() );
167 
168  if ( !isset( $this->mainLBs[$section] ) ) {
169  $this->mainLBs[$section] = $this->newMainLB( $domain, $this->getOwnershipId() );
170  }
171 
172  return $this->mainLBs[$section];
173  }
174 
175  public function newExternalLB( $cluster, $owner = null ) {
176  if ( !isset( $this->externalLoads[$cluster] ) ) {
177  throw new InvalidArgumentException( "Unknown cluster '$cluster'" );
178  }
179  return $this->newLoadBalancer(
180  array_merge(
181  $this->serverTemplate,
182  $this->externalTemplateOverrides,
183  $this->templateOverridesByCluster[$cluster] ?? []
184  ),
185  [ ILoadBalancer::GROUP_GENERIC => $this->externalLoads[$cluster] ],
186  $this->readOnlyReason,
187  $owner
188  );
189  }
190 
191  public function getExternalLB( $cluster ) {
192  if ( !isset( $this->externalLBs[$cluster] ) ) {
193  $this->externalLBs[$cluster] =
194  $this->newExternalLB( $cluster, $this->getOwnershipId() );
195  }
196 
197  return $this->externalLBs[$cluster];
198  }
199 
200  public function getAllMainLBs() {
201  $lbs = [];
202  foreach ( $this->sectionsByDB as $db => $section ) {
203  if ( !isset( $lbs[$section] ) ) {
204  $lbs[$section] = $this->getMainLB( $db );
205  }
206  }
207 
208  return $lbs;
209  }
210 
211  public function getAllExternalLBs() {
212  $lbs = [];
213  foreach ( $this->externalLoads as $cluster => $unused ) {
214  $lbs[$cluster] = $this->getExternalLB( $cluster );
215  }
216 
217  return $lbs;
218  }
219 
220  public function forEachLB( $callback, array $params = [] ) {
221  foreach ( $this->mainLBs as $lb ) {
222  $callback( $lb, ...$params );
223  }
224  foreach ( $this->externalLBs as $lb ) {
225  $callback( $lb, ...$params );
226  }
227  }
228 
238  private function newLoadBalancer( $serverTemplate, $groupLoads, $readOnlyReason, $owner ) {
239  $lb = new LoadBalancer( array_merge(
240  $this->baseLoadBalancerParams( $owner ),
241  [
242  'servers' => $this->makeServerConfigArrays( $serverTemplate, $groupLoads ),
243  'loadMonitor' => $this->loadMonitorConfig,
244  'readOnlyReason' => $readOnlyReason
245  ]
246  ) );
247  $this->initLoadBalancer( $lb );
248 
249  return $lb;
250  }
251 
259  private function makeServerConfigArrays( array $serverTemplate, array $groupLoads ) {
260  // The master server is the first host explicitly listed in the generic load group
261  if ( !$groupLoads[ILoadBalancer::GROUP_GENERIC] ) {
262  throw new UnexpectedValueException( "Empty generic load array; no master defined." );
263  }
264  $groupLoadsByHost = $this->reindexGroupLoadsByHost( $groupLoads );
265  // Get the ordered map of (host => load); the master server is first
266  $genericLoads = $groupLoads[ILoadBalancer::GROUP_GENERIC];
267  // Implictly append any hosts that only appear in custom load groups
268  $genericLoads += array_fill_keys( array_keys( $groupLoadsByHost ), 0 );
269  $servers = [];
270  foreach ( $genericLoads as $host => $load ) {
271  $servers[] = array_merge(
273  $servers ? [] : $this->masterTemplateOverrides,
274  $this->templateOverridesByServer[$host] ?? [],
275  [
276  'host' => $this->hostsByName[$host] ?? $host,
277  'hostName' => $host,
278  'load' => $load,
279  'groupLoads' => $groupLoadsByHost[$host] ?? []
280  ]
281  );
282  }
283 
284  return $servers;
285  }
286 
292  private function reindexGroupLoadsByHost( $groupLoads ) {
293  $groupLoadsByHost = [];
294  foreach ( $groupLoads as $group => $loadByHost ) {
295  foreach ( $loadByHost as $host => $load ) {
296  $groupLoadsByHost[$host][$group] = $load;
297  }
298  }
299 
300  return $groupLoadsByHost;
301  }
302 
307  private function getSectionFromDatabase( $database ) {
308  return $this->sectionsByDB[$database] ?? 'DEFAULT';
309  }
310 }
Wikimedia\Rdbms\LBFactoryMulti\$masterTemplateOverrides
array $masterTemplateOverrides
Server config override map for all main and external master servers.
Definition: LBFactoryMulti.php:60
Wikimedia\Rdbms\LBFactoryMulti\$groupLoadsByDB
int[][][] $groupLoadsByDB
Map of (database => group => host => load ratio)
Definition: LBFactoryMulti.php:48
Wikimedia\Rdbms\LBFactoryMulti\$loadMonitorConfig
array $loadMonitorConfig
Configuration for the LoadMonitor to use within LoadBalancer instances.
Definition: LBFactoryMulti.php:66
Wikimedia\Rdbms\LBFactory\initLoadBalancer
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:663
Wikimedia\Rdbms\LBFactoryMulti\$hostsByName
string[] $hostsByName
Map of (hostname => IP address)
Definition: LBFactoryMulti.php:42
Wikimedia\Rdbms\LBFactoryMulti\reindexGroupLoadsByHost
reindexGroupLoadsByHost( $groupLoads)
Take a group load array indexed by group then server, and reindex it by server then group.
Definition: LBFactoryMulti.php:292
Wikimedia\Rdbms\LBFactory\getOwnershipId
getOwnershipId()
Definition: LBFactory.php:794
Wikimedia\Rdbms
Definition: ChronologyProtector.php:24
Wikimedia\Rdbms\LBFactory\resolveDomainInstance
resolveDomainInstance( $domain)
Definition: LBFactory.php:191
Wikimedia\Rdbms\LBFactoryMulti\$templateOverridesBySection
array[] $templateOverridesBySection
Map of (section => server config map overrides)
Definition: LBFactoryMulti.php:56
Wikimedia\Rdbms\LBFactoryMulti\makeServerConfigArrays
makeServerConfigArrays(array $serverTemplate, array $groupLoads)
Make a server array as expected by LoadBalancer::__construct()
Definition: LBFactoryMulti.php:259
Wikimedia\Rdbms\LBFactoryMulti\$externalTemplateOverrides
array $externalTemplateOverrides
Server config map overriding "serverTemplate" for external storage.
Definition: LBFactoryMulti.php:54
Wikimedia\Rdbms\LBFactoryMulti\getSectionFromDatabase
getSectionFromDatabase( $database)
Definition: LBFactoryMulti.php:307
Wikimedia\Rdbms\LBFactoryMulti\__construct
__construct(array $conf)
Template override precedence (highest => lowest):
Definition: LBFactoryMulti.php:113
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:103
Wikimedia\Rdbms\LBFactoryMulti\forEachLB
forEachLB( $callback, array $params=[])
Execute a function for each currently tracked (instantiated) load balancer.
Definition: LBFactoryMulti.php:220
Wikimedia\Rdbms\LBFactoryMulti\getMainLB
getMainLB( $domain=false)
Get a cached (tracked) load balancer object.
Definition: LBFactoryMulti.php:164
Wikimedia\Rdbms\LBFactoryMulti\$mainLBs
LoadBalancer[] $mainLBs
Tracked main load balancer instances.
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:624
Wikimedia\Rdbms\LBFactoryMulti\getAllExternalLBs
getAllExternalLBs()
Get cached (tracked) load balancers for all external database clusters.
Definition: LBFactoryMulti.php:211
Wikimedia\Rdbms\LoadBalancer
Database connection, tracking, load balancing, and transaction manager for a cluster.
Definition: LoadBalancer.php:42
Wikimedia\Rdbms\LBFactoryMulti\$externalLBs
LoadBalancer[] $externalLBs
Tracked external load balancer instances.
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\$templateOverridesByServer
array[] $templateOverridesByServer
Map of (host => server config map overrides) for main and external servers.
Definition: LBFactoryMulti.php:62
Wikimedia\Rdbms\LBFactoryMulti\getAllMainLBs
getAllMainLBs()
Get cached (tracked) load balancers for all main database clusters.
Definition: LBFactoryMulti.php:200
Wikimedia\Rdbms\LBFactoryMulti\newLoadBalancer
newLoadBalancer( $serverTemplate, $groupLoads, $readOnlyReason, $owner)
Make a new load balancer object based on template and load array.
Definition: LBFactoryMulti.php:238
Wikimedia\Rdbms\LBFactoryMulti\newMainLB
newMainLB( $domain=false, $owner=null)
Create a new load balancer object.
Definition: LBFactoryMulti.php:141
Wikimedia\Rdbms\LBFactory
An interface for generating database load balancers.
Definition: LBFactory.php:41
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:191
Wikimedia\Rdbms\LBFactoryMulti\newExternalLB
newExternalLB( $cluster, $owner=null)
Create a new load balancer for external storage.
Definition: LBFactoryMulti.php:175