36 private $mainLBs = [];
38 private $externalLBs = [];
41 private $hostsByServerName;
43 private $sectionsByDB;
45 private $groupLoadsBySection;
47 private $externalLoadsByCluster;
49 private $serverTemplate;
51 private $externalTemplateOverrides;
53 private $templateOverridesBySection;
55 private $templateOverridesByCluster;
57 private $masterTemplateOverrides;
59 private $templateOverridesByServer;
61 private $readOnlyBySection;
63 private $loadMonitorConfig;
113 parent::__construct( $conf );
115 $this->hostsByServerName = $conf[
'hostsByName'] ?? [];
116 $this->sectionsByDB = $conf[
'sectionsByDB'];
117 $this->groupLoadsBySection = $conf[
'groupLoadsBySection'] ?? [];
118 foreach ( ( $conf[
'sectionLoads'] ?? [] ) as $section => $loadsByServerName ) {
121 $this->externalLoadsByCluster = $conf[
'externalLoads'] ?? [];
122 $this->serverTemplate = $conf[
'serverTemplate'] ?? [];
123 $this->externalTemplateOverrides = $conf[
'externalTemplateOverrides'] ?? [];
124 $this->templateOverridesBySection = $conf[
'templateOverridesBySection'] ?? [];
125 $this->templateOverridesByCluster = $conf[
'templateOverridesByCluster'] ?? [];
126 $this->masterTemplateOverrides = $conf[
'masterTemplateOverrides'] ?? [];
127 $this->templateOverridesByServer = $conf[
'templateOverridesByServer'] ?? [];
128 $this->readOnlyBySection = $conf[
'readOnlyBySection'] ?? [];
130 if ( isset( $conf[
'loadMonitor'] ) ) {
131 $this->loadMonitorConfig = $conf[
'loadMonitor'];
132 } elseif ( isset( $conf[
'loadMonitorClass'] ) ) {
133 $this->loadMonitorConfig = [
'class' => $conf[
'loadMonitorClass'] ];
135 $this->loadMonitorConfig = [
'class' => LoadMonitor::class ];
138 foreach ( array_keys( $this->externalLoadsByCluster ) as $cluster ) {
139 if ( isset( $this->groupLoadsBySection[$cluster] ) ) {
140 throw new LogicException(
141 "External cluster '$cluster' has the same name as a main section/cluster"
149 $database = $domainInstance->getDatabase();
150 $section = $this->getSectionFromDatabase( $database );
153 throw new UnexpectedValueException(
"Section '$section' has no hosts defined." );
156 return $this->newLoadBalancer(
159 $this->serverTemplate,
160 $this->templateOverridesBySection[$section] ?? []
162 $this->groupLoadsBySection[$section],
164 is_string( $this->readOnlyReason )
165 ? $this->readOnlyReason
166 : ( $this->readOnlyBySection[$section] ?? false )
171 $domainInstance = $this->resolveDomainInstance( $domain );
172 $section = $this->getSectionFromDatabase( $domainInstance->getDatabase() );
174 if ( !isset( $this->mainLBs[$section] ) ) {
175 $this->mainLBs[$section] = $this->newMainLB( $domain );
178 return $this->mainLBs[$section];
182 if ( !isset( $this->externalLoadsByCluster[$cluster] ) ) {
183 throw new InvalidArgumentException(
"Unknown cluster '$cluster'" );
185 return $this->newLoadBalancer(
188 $this->serverTemplate,
189 $this->externalTemplateOverrides,
190 $this->templateOverridesByCluster[$cluster] ?? []
192 [ ILoadBalancer::GROUP_GENERIC => $this->externalLoadsByCluster[$cluster] ],
193 $this->readOnlyReason
198 if ( !isset( $this->externalLBs[$cluster] ) ) {
199 $this->externalLBs[$cluster] = $this->newExternalLB(
204 return $this->externalLBs[$cluster];
209 foreach ( $this->sectionsByDB as $db => $section ) {
210 if ( !isset( $lbs[$section] ) ) {
211 $lbs[$section] = $this->getMainLB( $db );
220 foreach ( $this->externalLoadsByCluster as $cluster => $unused ) {
221 $lbs[$cluster] = $this->getExternalLB( $cluster );
227 public function forEachLB( $callback, array $params = [] ) {
229 foreach ( $this->mainLBs as $lb ) {
230 $callback( $lb, ...$params );
232 foreach ( $this->externalLBs as $lb ) {
233 $callback( $lb, ...$params );
238 foreach ( $this->mainLBs as $lb ) {
241 foreach ( $this->externalLBs as $lb ) {
255 private function newLoadBalancer(
257 array $serverTemplate,
262 $this->baseLoadBalancerParams(),
264 'servers' => $this->makeServerConfigArrays( $serverTemplate, $groupLoads ),
265 'loadMonitor' => $this->loadMonitorConfig,
266 'readOnlyReason' => $readOnlyReason,
267 'clusterName' => $clusterName
270 $this->initLoadBalancer( $lb );
282 private function makeServerConfigArrays( array $serverTemplate, array $groupLoads ) {
284 if ( !$groupLoads[ILoadBalancer::GROUP_GENERIC] ) {
285 throw new UnexpectedValueException(
"Empty generic load array; no primary DB defined." );
287 $groupLoadsByServerName = $this->reindexGroupLoadsByServerName( $groupLoads );
289 $genericLoads = $groupLoads[ILoadBalancer::GROUP_GENERIC];
291 $genericLoads += array_fill_keys( array_keys( $groupLoadsByServerName ), 0 );
293 foreach ( $genericLoads as $serverName => $load ) {
294 $servers[] = array_merge(
296 $servers ? [] : $this->masterTemplateOverrides,
297 $this->templateOverridesByServer[$serverName] ?? [],
299 'host' => $this->hostsByServerName[$serverName] ?? $serverName,
300 'serverName' => $serverName,
302 'groupLoads' => $groupLoadsByServerName[$serverName] ?? []
316 private function reindexGroupLoadsByServerName( array $groupLoads ) {
317 $groupLoadsByServerName = [];
318 foreach ( $groupLoads as $group => $loadByServerName ) {
319 foreach ( $loadByServerName as $serverName => $load ) {
320 $groupLoadsByServerName[$serverName][$group] = $load;
324 return $groupLoadsByServerName;
331 private function getSectionFromDatabase( $database ) {
332 return $this->sectionsByDB[$database] ?? self::CLUSTER_MAIN_DEFAULT;
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.