57private $externalLBs = [];
60private $hostsByServerName;
64private $groupLoadsBySection;
66private $externalLoadsByCluster;
68private $serverTemplate;
70private $externalTemplateOverrides;
72private $templateOverridesBySection;
74private $templateOverridesByCluster;
76private $masterTemplateOverrides;
78private $templateOverridesByServer;
80private $readOnlyBySection;
82private $loadMonitorConfig;
84private $nonLocalDomainCache = [];
136 parent::__construct( $conf );
138 $this->hostsByServerName = $conf[
'hostsByName'] ?? [];
139 $this->sectionsByDB = $conf[
'sectionsByDB'];
141 $this->groupLoadsBySection = $conf[
'groupLoadsBySection'] ?? [];
142foreach ( ( $conf[
'sectionLoads'] ?? [] ) as $section => $loadsByServerName ) {
145 $this->externalLoadsByCluster = $conf[
'externalLoads'] ?? [];
146 $this->serverTemplate = $conf[
'serverTemplate'] ?? [];
147 $this->externalTemplateOverrides = $conf[
'externalTemplateOverrides'] ?? [];
148 $this->templateOverridesBySection = $conf[
'templateOverridesBySection'] ?? [];
149 $this->templateOverridesByCluster = $conf[
'templateOverridesByCluster'] ?? [];
150 $this->masterTemplateOverrides = $conf[
'masterTemplateOverrides'] ?? [];
151 $this->templateOverridesByServer = $conf[
'templateOverridesByServer'] ?? [];
152 $this->readOnlyBySection = $conf[
'readOnlyBySection'] ?? [];
154if ( isset( $conf[
'loadMonitor'] ) ) {
155 $this->loadMonitorConfig = $conf[
'loadMonitor'];
156 } elseif ( isset( $conf[
'loadMonitorClass'] ) ) {
// b/c 157 $this->loadMonitorConfig = [
'class' => $conf[
'loadMonitorClass'] ];
159 $this->loadMonitorConfig = [
'class' => LoadMonitor::class ];
162foreach ( $this->externalLoadsByCluster as $cluster => $_ ) {
163if ( isset( $this->groupLoadsBySection[$cluster] ) ) {
164thrownew LogicException(
165"External cluster '$cluster' has the same name as a main section/cluster" 172 $domainInstance = $this->resolveDomainInstance( $domain );
173 $database = $domainInstance->getDatabase();
174 $section = $this->getSectionFromDatabase( $database );
177thrownew UnexpectedValueException(
"Section '$section' has no hosts defined." );
180return $this->newLoadBalancer(
183 $this->serverTemplate,
184 $this->templateOverridesBySection[$section] ?? []
186 $this->groupLoadsBySection[$section],
187// Use the LB-specific read-only reason if everything isn't already read-only 188 is_string( $this->readOnlyReason )
189 ? $this->readOnlyReason
190 : ( $this->readOnlyBySection[$section] ?? false )
198privatefunction resolveDomainInstance( $domain ) {
199if ( $domain instanceof DatabaseDomain ) {
200return $domain;
// already a domain instance 201 } elseif ( $domain ===
false || $domain === $this->localDomain->getId() ) {
202return $this->localDomain;
203 } elseif ( isset( $this->domainAliases[$domain] ) ) {
204// This array acts as both the original map and as instance cache. 205// Instances pass-through DatabaseDomain::newFromId as-is. 206 $this->domainAliases[$domain] =
209return $this->domainAliases[$domain];
212 $cachedDomain = $this->nonLocalDomainCache[$domain] ??
null;
213if ( $cachedDomain ===
null ) {
215 $this->nonLocalDomainCache = [ $domain => $cachedDomain ];
222 $domainInstance = $this->resolveDomainInstance( $domain );
223 $section = $this->getSectionFromDatabase( $domainInstance->getDatabase() );
225if ( !isset( $this->mainLBs[$section] ) ) {
226 $this->mainLBs[$section] = $this->newMainLB( $domain );
229return $this->mainLBs[$section];
233if ( !isset( $this->externalLoadsByCluster[$cluster] ) ) {
234thrownew InvalidArgumentException(
"Unknown cluster '$cluster'" );
236return $this->newLoadBalancer(
239 $this->serverTemplate,
240 $this->externalTemplateOverrides,
241 $this->templateOverridesByCluster[$cluster] ?? []
243 [ ILoadBalancer::GROUP_GENERIC => $this->externalLoadsByCluster[$cluster] ],
244 $this->readOnlyReason
249if ( !isset( $this->externalLBs[$cluster] ) ) {
250 $this->externalLBs[$cluster] = $this->newExternalLB(
255return $this->externalLBs[$cluster];
260foreach ( $this->sectionsByDB as $db => $section ) {
261if ( !isset( $lbs[$section] ) ) {
262 $lbs[$section] = $this->getMainLB( $db );
271foreach ( $this->externalLoadsByCluster as $cluster => $unused ) {
272 $lbs[$cluster] = $this->getExternalLB( $cluster );
279foreach ( $this->mainLBs as $lb ) {
282foreach ( $this->externalLBs as $lb ) {
296privatefunction newLoadBalancer(
298 array $serverTemplate,
303 $this->baseLoadBalancerParams(),
305'servers' => $this->makeServerConfigArrays( $serverTemplate, $groupLoads ),
306'loadMonitor' => $this->loadMonitorConfig,
307'readOnlyReason' => $readOnlyReason,
308'clusterName' => $clusterName
311 $this->initLoadBalancer( $lb );
323privatefunction makeServerConfigArrays( array $serverTemplate, array $groupLoads ) {
324// The primary DB server is the first host explicitly listed in the generic load group 325if ( !$groupLoads[ILoadBalancer::GROUP_GENERIC] ) {
326thrownew UnexpectedValueException(
"Empty generic load array; no primary DB defined." );
328 $groupLoadsByServerName = [];
329foreach ( $groupLoads as $group => $loadByServerName ) {
330foreach ( $loadByServerName as $serverName => $load ) {
331 $groupLoadsByServerName[$serverName][$group] = $load;
335// Get the ordered map of (server name => load); the primary DB server is first 336 $genericLoads = $groupLoads[ILoadBalancer::GROUP_GENERIC];
337// Implicitly append any hosts that only appear in custom load groups 338 $genericLoads += array_fill_keys( array_keys( $groupLoadsByServerName ), 0 );
340foreach ( $genericLoads as $serverName => $load ) {
341 $servers[] = array_merge(
343 $servers ? [] : $this->masterTemplateOverrides,
344 $this->templateOverridesByServer[$serverName] ?? [],
346'host' => $this->hostsByServerName[$serverName] ?? $serverName,
347'serverName' => $serverName,
349'groupLoads' => $groupLoadsByServerName[$serverName] ?? []
361privatefunction getSectionFromDatabase( $database ) {
362return $this->sectionsByDB[$database]
363 ?? $this->sectionsByDB[self::CLUSTER_MAIN_DEFAULT]
364 ?? self::CLUSTER_MAIN_DEFAULT;
372foreach ( $this->mainLBs as $lb ) {
373// Approximate what LBFactoryMulti::__construct does (T346365) 374 $groupLoads = $conf[
'groupLoadsBySection'][$lb->getClusterName()] ?? [];
375 $groupLoads[ILoadBalancer::GROUP_GENERIC] = $conf[
'sectionLoads'][$lb->getClusterName()];
377'servers' => $this->makeServerConfigArrays( $conf[
'serverTemplate'] ?? [], $groupLoads )
379 $lb->reconfigure( $config );
382foreach ( $this->externalLBs as $lb ) {
384 ILoadBalancer::GROUP_GENERIC => $conf[
'externalLoads'][$lb->getClusterName()]
387'servers' => $this->makeServerConfigArrays( $conf[
'serverTemplate'] ?? [], $groupLoads )
389 $lb->reconfigure( $config );