41 private $mainLBs = [];
43 private $externalLBs = [];
46 private $hostsByServerName;
48 private $sectionsByDB;
50 private $loadsBySection;
52 private $externalLoadsByCluster;
54 private $serverTemplate;
56 private $externalTemplateOverrides;
58 private $templateOverridesBySection;
60 private $templateOverridesByCluster;
62 private $masterTemplateOverrides;
64 private $templateOverridesByServer;
66 private $readOnlyBySection;
68 private $loadMonitorConfig;
70 private $nonLocalDomainCache = [];
119 parent::__construct( $conf );
121 $this->hostsByServerName = $conf[
'hostsByName'] ?? [];
122 $this->sectionsByDB = $conf[
'sectionsByDB'];
124 $this->loadsBySection = $conf[
'sectionLoads'] ?? [];
125 $this->externalLoadsByCluster = $conf[
'externalLoads'] ?? [];
126 $this->serverTemplate = $conf[
'serverTemplate'] ?? [];
127 $this->externalTemplateOverrides = $conf[
'externalTemplateOverrides'] ?? [];
128 $this->templateOverridesBySection = $conf[
'templateOverridesBySection'] ?? [];
129 $this->templateOverridesByCluster = $conf[
'templateOverridesByCluster'] ?? [];
130 $this->masterTemplateOverrides = $conf[
'masterTemplateOverrides'] ?? [];
131 $this->templateOverridesByServer = $conf[
'templateOverridesByServer'] ?? [];
132 $this->readOnlyBySection = $conf[
'readOnlyBySection'] ?? [];
134 if ( isset( $conf[
'loadMonitor'] ) ) {
135 $this->loadMonitorConfig = $conf[
'loadMonitor'];
136 } elseif ( isset( $conf[
'loadMonitorClass'] ) ) {
137 $this->loadMonitorConfig = [
'class' => $conf[
'loadMonitorClass'] ];
139 $this->loadMonitorConfig = [
'class' => LoadMonitor::class ];
142 foreach ( $this->externalLoadsByCluster as $cluster => $_ ) {
143 if ( isset( $this->loadsBySection[$cluster] ) ) {
144 throw new LogicException(
145 "External cluster '$cluster' has the same name as a main section/cluster"
153 $domainInstance = $this->resolveDomainInstance( $domain );
154 $database = $domainInstance->getDatabase();
155 $section = $this->getSectionFromDatabase( $database );
157 if ( !isset( $this->loadsBySection[$section] ) ) {
158 throw new UnexpectedValueException(
"Section '$section' has no hosts defined." );
161 return $this->newLoadBalancer(
164 $this->serverTemplate,
165 $this->templateOverridesBySection[$section] ?? []
167 $this->loadsBySection[$section],
169 is_string( $this->readOnlyReason )
170 ? $this->readOnlyReason
171 : ( $this->readOnlyBySection[$section] ?? false )
179 private function resolveDomainInstance( $domain ) {
180 if ( $domain instanceof DatabaseDomain ) {
182 } elseif ( $domain ===
false || $domain === $this->localDomain->getId() ) {
183 return $this->localDomain;
184 } elseif ( isset( $this->domainAliases[$domain] ) ) {
187 $this->domainAliases[$domain] =
190 return $this->domainAliases[$domain];
193 $cachedDomain = $this->nonLocalDomainCache[$domain] ??
null;
194 if ( $cachedDomain ===
null ) {
196 $this->nonLocalDomainCache = [ $domain => $cachedDomain ];
199 return $cachedDomain;
204 $domainInstance = $this->resolveDomainInstance( $domain );
205 $section = $this->getSectionFromDatabase( $domainInstance->getDatabase() );
207 if ( !isset( $this->mainLBs[$section] ) ) {
208 $this->mainLBs[$section] = $this->newMainLB( $domain );
211 return $this->mainLBs[$section];
216 if ( !isset( $this->externalLoadsByCluster[$cluster] ) ) {
217 throw new InvalidArgumentException(
"Unknown cluster '$cluster'" );
219 return $this->newLoadBalancer(
222 $this->serverTemplate,
223 $this->externalTemplateOverrides,
224 $this->templateOverridesByCluster[$cluster] ?? []
226 $this->externalLoadsByCluster[$cluster],
227 $this->readOnlyReason
233 if ( !isset( $this->externalLBs[$cluster] ) ) {
234 $this->externalLBs[$cluster] = $this->newExternalLB(
239 return $this->externalLBs[$cluster];
244 foreach ( $this->sectionsByDB as $db => $section ) {
245 if ( !isset( $lbs[$section] ) ) {
246 $lbs[$section] = $this->getMainLB( $db );
255 foreach ( $this->externalLoadsByCluster as $cluster => $unused ) {
256 $lbs[$cluster] = $this->getExternalLB( $cluster );
264 foreach ( $this->mainLBs as $lb ) {
267 foreach ( $this->externalLBs as $lb ) {
281 private function newLoadBalancer(
283 array $serverTemplate,
288 $this->baseLoadBalancerParams(),
290 'servers' => $this->makeServerConfigArrays( $serverTemplate, $loads ),
291 'loadMonitor' => $this->loadMonitorConfig,
292 'readOnlyReason' => $readOnlyReason,
293 'clusterName' => $clusterName
296 $this->initLoadBalancer( $lb );
308 private function makeServerConfigArrays( array $serverTemplate, array $loads ) {
311 foreach ( $loads as $serverName => $load ) {
312 $servers[] = array_merge(
314 $servers ? [] : $this->masterTemplateOverrides,
315 $this->templateOverridesByServer[$serverName] ?? [],
317 'host' => $this->hostsByServerName[$serverName] ?? $serverName,
318 'serverName' => $serverName,
331 private function getSectionFromDatabase( $database ) {
332 if ( $database !==
null && isset( $this->sectionsByDB[$database] ) ) {
333 return $this->sectionsByDB[$database];
335 return $this->sectionsByDB[self::CLUSTER_MAIN_DEFAULT]
336 ?? self::CLUSTER_MAIN_DEFAULT;
344 foreach ( $this->mainLBs as $lb ) {
347 'servers' => $this->makeServerConfigArrays(
348 $conf[
'serverTemplate'] ?? [],
349 $conf[
'sectionLoads'][$lb->getClusterName()]
352 $lb->reconfigure( $config );
355 foreach ( $this->externalLBs as $lb ) {
357 'servers' => $this->makeServerConfigArrays(
358 $conf[
'serverTemplate'] ?? [],
359 $conf[
'externalLoads'][$lb->getClusterName()]
362 $lb->reconfigure( $config );