55 private $mainLBs = [];
57 private $externalLBs = [];
60 private $hostsByServerName;
62 private $sectionsByDB;
64 private $groupLoadsBySection;
66 private $externalLoadsByCluster;
68 private $serverTemplate;
70 private $externalTemplateOverrides;
72 private $templateOverridesBySection;
74 private $templateOverridesByCluster;
76 private $masterTemplateOverrides;
78 private $templateOverridesByServer;
80 private $readOnlyBySection;
82 private $loadMonitorConfig;
84 private $nonLocalDomainCache = [];
136 parent::__construct( $conf );
138 $this->hostsByServerName = $conf[
'hostsByName'] ?? [];
139 $this->sectionsByDB = $conf[
'sectionsByDB'];
140 $this->sectionsByDB += [ self::CLUSTER_MAIN_DEFAULT => self::CLUSTER_MAIN_DEFAULT ];
141 $this->groupLoadsBySection = $conf[
'groupLoadsBySection'] ?? [];
142 foreach ( ( $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'] ?? [];
154 if ( isset( $conf[
'loadMonitor'] ) ) {
155 $this->loadMonitorConfig = $conf[
'loadMonitor'];
156 } elseif ( isset( $conf[
'loadMonitorClass'] ) ) {
157 $this->loadMonitorConfig = [
'class' => $conf[
'loadMonitorClass'] ];
159 $this->loadMonitorConfig = [
'class' => LoadMonitor::class ];
162 foreach ( $this->externalLoadsByCluster as $cluster => $_ ) {
163 if ( isset( $this->groupLoadsBySection[$cluster] ) ) {
164 throw new 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 );
177 throw new UnexpectedValueException(
"Section '$section' has no hosts defined." );
180 return $this->newLoadBalancer(
183 $this->serverTemplate,
184 $this->templateOverridesBySection[$section] ?? []
186 $this->groupLoadsBySection[$section],
188 is_string( $this->readOnlyReason )
189 ? $this->readOnlyReason
190 : ( $this->readOnlyBySection[$section] ?? false )
198 private function resolveDomainInstance( $domain ) {
199 if ( $domain instanceof DatabaseDomain ) {
201 } elseif ( $domain ===
false || $domain === $this->localDomain->getId() ) {
202 return $this->localDomain;
203 } elseif ( isset( $this->domainAliases[$domain] ) ) {
206 $this->domainAliases[$domain] =
209 return $this->domainAliases[$domain];
212 $cachedDomain = $this->nonLocalDomainCache[$domain] ??
null;
213 if ( $cachedDomain ===
null ) {
215 $this->nonLocalDomainCache = [ $domain => $cachedDomain ];
218 return $cachedDomain;
222 $domainInstance = $this->resolveDomainInstance( $domain );
223 $section = $this->getSectionFromDatabase( $domainInstance->getDatabase() );
225 if ( !isset( $this->mainLBs[$section] ) ) {
226 $this->mainLBs[$section] = $this->newMainLB( $domain );
229 return $this->mainLBs[$section];
233 if ( !isset( $this->externalLoadsByCluster[$cluster] ) ) {
234 throw new InvalidArgumentException(
"Unknown cluster '$cluster'" );
236 return $this->newLoadBalancer(
239 $this->serverTemplate,
240 $this->externalTemplateOverrides,
241 $this->templateOverridesByCluster[$cluster] ?? []
243 [ ILoadBalancer::GROUP_GENERIC => $this->externalLoadsByCluster[$cluster] ],
244 $this->readOnlyReason
249 if ( !isset( $this->externalLBs[$cluster] ) ) {
250 $this->externalLBs[$cluster] = $this->newExternalLB(
255 return $this->externalLBs[$cluster];
260 foreach ( $this->sectionsByDB as $db => $section ) {
261 if ( !isset( $lbs[$section] ) ) {
262 $lbs[$section] = $this->getMainLB( $db );
271 foreach ( $this->externalLoadsByCluster as $cluster => $unused ) {
272 $lbs[$cluster] = $this->getExternalLB( $cluster );
279 foreach ( $this->mainLBs as $lb ) {
282 foreach ( $this->externalLBs as $lb ) {
296 private function 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 );
323 private function makeServerConfigArrays( array $serverTemplate, array $groupLoads ) {
325 if ( !$groupLoads[ILoadBalancer::GROUP_GENERIC] ) {
326 throw new UnexpectedValueException(
"Empty generic load array; no primary DB defined." );
328 $groupLoadsByServerName = [];
329 foreach ( $groupLoads as $group => $loadByServerName ) {
330 foreach ( $loadByServerName as $serverName => $load ) {
331 $groupLoadsByServerName[$serverName][$group] = $load;
336 $genericLoads = $groupLoads[ILoadBalancer::GROUP_GENERIC];
338 $genericLoads += array_fill_keys( array_keys( $groupLoadsByServerName ), 0 );
340 foreach ( $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] ?? []
361 private function getSectionFromDatabase( $database ) {
362 return $this->sectionsByDB[$database]
363 ?? $this->sectionsByDB[self::CLUSTER_MAIN_DEFAULT]
364 ?? self::CLUSTER_MAIN_DEFAULT;
372 foreach ( $this->mainLBs as $lb ) {
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 );
382 foreach ( $this->externalLBs as $lb ) {
384 ILoadBalancer::GROUP_GENERIC => $conf[
'externalLoads'][$lb->getClusterName()]
387 'servers' => $this->makeServerConfigArrays( $conf[
'serverTemplate'] ?? [], $groupLoads )
389 $lb->reconfigure( $config );