MediaWiki  master
LBFactory.php
Go to the documentation of this file.
1 <?php
24 namespace Wikimedia\Rdbms;
25 
34 
39 abstract class LBFactory implements ILBFactory {
41  private $chronProt;
43  private $profiler;
45  private $trxProfiler;
47  private $replLogger;
49  private $connLogger;
51  private $queryLogger;
53  private $perfLogger;
55  private $errorLogger;
58 
60  protected $srvCache;
62  protected $memStash;
64  protected $wanCache;
65 
67  protected $localDomain;
68 
70  private $hostname;
72  private $requestInfo;
74  private $cliMode;
76  private $agent;
77 
79  private $tableAliases = [];
81  private $indexAliases = [];
84 
86  private $ticket;
88  private $trxRoundId = false;
90  private $trxRoundStage = self::ROUND_CURSORY;
91 
93  protected $readOnlyReason = false;
94 
96  private $defaultGroup = null;
97 
99  protected $maxLag;
100 
101  const ROUND_CURSORY = 'cursory';
102  const ROUND_BEGINNING = 'within-begin';
103  const ROUND_COMMITTING = 'within-commit';
104  const ROUND_ROLLING_BACK = 'within-rollback';
105  const ROUND_COMMIT_CALLBACKS = 'within-commit-callbacks';
106  const ROUND_ROLLBACK_CALLBACKS = 'within-rollback-callbacks';
107 
108  private static $loggerFields =
109  [ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ];
110 
111  public function __construct( array $conf ) {
112  $this->localDomain = isset( $conf['localDomain'] )
113  ? DatabaseDomain::newFromId( $conf['localDomain'] )
115 
116  $this->maxLag = $conf['maxLag'] ?? null;
117  if ( isset( $conf['readOnlyReason'] ) && is_string( $conf['readOnlyReason'] ) ) {
118  $this->readOnlyReason = $conf['readOnlyReason'];
119  }
120 
121  $this->srvCache = $conf['srvCache'] ?? new EmptyBagOStuff();
122  $this->memStash = $conf['memStash'] ?? new EmptyBagOStuff();
123  $this->wanCache = $conf['wanCache'] ?? WANObjectCache::newEmpty();
124 
125  foreach ( self::$loggerFields as $key ) {
126  $this->$key = $conf[$key] ?? new \Psr\Log\NullLogger();
127  }
128  $this->errorLogger = $conf['errorLogger'] ?? function ( Exception $e ) {
129  trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
130  };
131  $this->deprecationLogger = $conf['deprecationLogger'] ?? function ( $msg ) {
132  trigger_error( $msg, E_USER_DEPRECATED );
133  };
134 
135  $this->profiler = $conf['profiler'] ?? null;
136  $this->trxProfiler = $conf['trxProfiler'] ?? new TransactionProfiler();
137 
138  $this->requestInfo = [
139  'IPAddress' => $_SERVER[ 'REMOTE_ADDR' ] ?? '',
140  'UserAgent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
141  // Headers application can inject via LBFactory::setRequestInfo()
142  'ChronologyProtection' => null,
143  'ChronologyClientId' => null, // prior $cpClientId value from LBFactory::shutdown()
144  'ChronologyPositionIndex' => null // prior $cpIndex value from LBFactory::shutdown()
145  ];
146 
147  $this->cliMode = $conf['cliMode'] ?? ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
148  $this->hostname = $conf['hostname'] ?? gethostname();
149  $this->agent = $conf['agent'] ?? '';
150  $this->defaultGroup = $conf['defaultGroup'] ?? null;
151 
152  $this->ticket = mt_rand();
153  }
154 
155  public function destroy() {
156  $this->shutdown( self::SHUTDOWN_NO_CHRONPROT );
157  $this->forEachLBCallMethod( 'disable' );
158  }
159 
160  public function getLocalDomainID() {
161  return $this->localDomain->getId();
162  }
163 
164  public function resolveDomainID( $domain ) {
165  return ( $domain !== false ) ? (string)$domain : $this->getLocalDomainID();
166  }
167 
168  public function shutdown(
169  $mode = self::SHUTDOWN_CHRONPROT_SYNC,
170  callable $workCallback = null,
171  &$cpIndex = null,
172  &$cpClientId = null
173  ) {
175  if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) {
176  $this->shutdownChronologyProtector( $chronProt, $workCallback, 'sync', $cpIndex );
177  } elseif ( $mode === self::SHUTDOWN_CHRONPROT_ASYNC ) {
178  $this->shutdownChronologyProtector( $chronProt, null, 'async', $cpIndex );
179  }
180 
181  $cpClientId = $chronProt->getClientId();
182 
183  $this->commitMasterChanges( __METHOD__ ); // sanity
184  }
185 
191  abstract public function newMainLB( $domain = false );
192 
198  abstract public function getMainLB( $domain = false );
199 
205  abstract public function newExternalLB( $cluster );
206 
212  abstract public function getExternalLB( $cluster );
213 
220  protected function forEachLBCallMethod( $methodName, array $args = [] ) {
221  $this->forEachLB(
222  function ( ILoadBalancer $loadBalancer, $methodName, array $args ) {
223  $loadBalancer->$methodName( ...$args );
224  },
225  [ $methodName, $args ]
226  );
227  }
228 
229  public function flushReplicaSnapshots( $fname = __METHOD__ ) {
230  $this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] );
231  }
232 
233  final public function commitAll( $fname = __METHOD__, array $options = [] ) {
235  $this->forEachLBCallMethod( 'flushMasterSnapshots', [ $fname ] );
236  $this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] );
237  }
238 
239  final public function beginMasterChanges( $fname = __METHOD__ ) {
240  $this->assertTransactionRoundStage( self::ROUND_CURSORY );
241  $this->trxRoundStage = self::ROUND_BEGINNING;
242  if ( $this->trxRoundId !== false ) {
243  throw new DBTransactionError(
244  null,
245  "$fname: transaction round '{$this->trxRoundId}' already started."
246  );
247  }
248  $this->trxRoundId = $fname;
249  // Set DBO_TRX flags on all appropriate DBs
250  $this->forEachLBCallMethod( 'beginMasterChanges', [ $fname ] );
251  $this->trxRoundStage = self::ROUND_CURSORY;
252  }
253 
254  final public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
255  $this->assertTransactionRoundStage( self::ROUND_CURSORY );
256  $this->trxRoundStage = self::ROUND_COMMITTING;
257  if ( $this->trxRoundId !== false && $this->trxRoundId !== $fname ) {
258  throw new DBTransactionError(
259  null,
260  "$fname: transaction round '{$this->trxRoundId}' still running."
261  );
262  }
264  $scope = ScopedCallback::newScopedIgnoreUserAbort(); // try to ignore client aborts
265  // Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
266  do {
267  $count = 0; // number of callbacks executed this iteration
268  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$count ) {
269  $count += $lb->finalizeMasterChanges();
270  } );
271  } while ( $count > 0 );
272  $this->trxRoundId = false;
273  // Perform pre-commit checks, aborting on failure
274  $this->forEachLBCallMethod( 'approveMasterChanges', [ $options ] );
275  // Log the DBs and methods involved in multi-DB transactions
276  $this->logIfMultiDbTransaction();
277  // Actually perform the commit on all master DB connections and revert DBO_TRX
278  $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
279  // Run all post-commit callbacks in a separate step
280  $this->trxRoundStage = self::ROUND_COMMIT_CALLBACKS;
282  $this->trxRoundStage = self::ROUND_CURSORY;
283  // Throw any last post-commit callback error
284  if ( $e instanceof Exception ) {
285  throw $e;
286  }
287  }
288 
289  final public function rollbackMasterChanges( $fname = __METHOD__ ) {
290  $this->trxRoundStage = self::ROUND_ROLLING_BACK;
291  $this->trxRoundId = false;
292  // Actually perform the rollback on all master DB connections and revert DBO_TRX
293  $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] );
294  // Run all post-commit callbacks in a separate step
295  $this->trxRoundStage = self::ROUND_ROLLBACK_CALLBACKS;
297  $this->trxRoundStage = self::ROUND_CURSORY;
298  }
299 
303  private function executePostTransactionCallbacks() {
304  // Run all post-commit callbacks until new ones stop getting added
305  $e = null; // first callback exception
306  do {
307  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
309  $e = $e ?: $ex;
310  } );
311  } while ( $this->hasMasterChanges() );
312  // Run all listener callbacks once
313  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
315  $e = $e ?: $ex;
316  } );
317 
318  return $e;
319  }
320 
321  public function hasTransactionRound() {
322  return ( $this->trxRoundId !== false );
323  }
324 
325  public function isReadyForRoundOperations() {
326  return ( $this->trxRoundStage === self::ROUND_CURSORY );
327  }
328 
332  private function logIfMultiDbTransaction() {
333  $callersByDB = [];
334  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$callersByDB ) {
335  $masterName = $lb->getServerName( $lb->getWriterIndex() );
336  $callers = $lb->pendingMasterChangeCallers();
337  if ( $callers ) {
338  $callersByDB[$masterName] = $callers;
339  }
340  } );
341 
342  if ( count( $callersByDB ) >= 2 ) {
343  $dbs = implode( ', ', array_keys( $callersByDB ) );
344  $msg = "Multi-DB transaction [{$dbs}]:\n";
345  foreach ( $callersByDB as $db => $callers ) {
346  $msg .= "$db: " . implode( '; ', $callers ) . "\n";
347  }
348  $this->queryLogger->info( $msg );
349  }
350  }
351 
352  public function hasMasterChanges() {
353  $ret = false;
354  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) {
355  $ret = $ret || $lb->hasMasterChanges();
356  } );
357 
358  return $ret;
359  }
360 
361  public function laggedReplicaUsed() {
362  $ret = false;
363  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) {
364  $ret = $ret || $lb->laggedReplicaUsed();
365  } );
366 
367  return $ret;
368  }
369 
370  public function hasOrMadeRecentMasterChanges( $age = null ) {
371  $ret = false;
372  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $age, &$ret ) {
373  $ret = $ret || $lb->hasOrMadeRecentMasterChanges( $age );
374  } );
375  return $ret;
376  }
377 
378  public function waitForReplication( array $opts = [] ) {
379  $opts += [
380  'domain' => false,
381  'cluster' => false,
382  'timeout' => $this->cliMode ? 60 : 1,
383  'ifWritesSince' => null
384  ];
385 
386  if ( $opts['domain'] === false && isset( $opts['wiki'] ) ) {
387  $opts['domain'] = $opts['wiki']; // b/c
388  }
389 
390  // Figure out which clusters need to be checked
392  $lbs = [];
393  if ( $opts['cluster'] !== false ) {
394  $lbs[] = $this->getExternalLB( $opts['cluster'] );
395  } elseif ( $opts['domain'] !== false ) {
396  $lbs[] = $this->getMainLB( $opts['domain'] );
397  } else {
398  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$lbs ) {
399  $lbs[] = $lb;
400  } );
401  if ( !$lbs ) {
402  return true; // nothing actually used
403  }
404  }
405 
406  // Get all the master positions of applicable DBs right now.
407  // This can be faster since waiting on one cluster reduces the
408  // time needed to wait on the next clusters.
409  $masterPositions = array_fill( 0, count( $lbs ), false );
410  foreach ( $lbs as $i => $lb ) {
411  if ( $lb->getServerCount() <= 1 ) {
412  // T29975 - Don't try to wait for replica DBs if there are none
413  // Prevents permission error when getting master position
414  continue;
415  } elseif ( $opts['ifWritesSince']
416  && $lb->lastMasterChangeTimestamp() < $opts['ifWritesSince']
417  ) {
418  continue; // no writes since the last wait
419  }
420  $masterPositions[$i] = $lb->getMasterPos();
421  }
422 
423  // Run any listener callbacks *after* getting the DB positions. The more
424  // time spent in the callbacks, the less time is spent in waitForAll().
425  foreach ( $this->replicationWaitCallbacks as $callback ) {
426  $callback();
427  }
428 
429  $failed = [];
430  foreach ( $lbs as $i => $lb ) {
431  if ( $masterPositions[$i] ) {
432  // The RDBMS may not support getMasterPos()
433  if ( !$lb->waitForAll( $masterPositions[$i], $opts['timeout'] ) ) {
434  $failed[] = $lb->getServerName( $lb->getWriterIndex() );
435  }
436  }
437  }
438 
439  return !$failed;
440  }
441 
442  public function setWaitForReplicationListener( $name, callable $callback = null ) {
443  if ( $callback ) {
444  $this->replicationWaitCallbacks[$name] = $callback;
445  } else {
446  unset( $this->replicationWaitCallbacks[$name] );
447  }
448  }
449 
450  public function getEmptyTransactionTicket( $fname ) {
451  if ( $this->hasMasterChanges() ) {
452  $this->queryLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
453  ( new RuntimeException() )->getTraceAsString() );
454 
455  return null;
456  }
457 
458  return $this->ticket;
459  }
460 
461  final public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) {
462  if ( $ticket !== $this->ticket ) {
463  $this->perfLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
464  ( new RuntimeException() )->getTraceAsString() );
465 
466  return;
467  }
468 
469  // The transaction owner and any caller with the empty transaction ticket can commit
470  // so that getEmptyTransactionTicket() callers don't risk seeing DBTransactionError.
471  if ( $this->trxRoundId !== false && $fname !== $this->trxRoundId ) {
472  $this->queryLogger->info( "$fname: committing on behalf of {$this->trxRoundId}." );
473  $fnameEffective = $this->trxRoundId;
474  } else {
475  $fnameEffective = $fname;
476  }
477 
478  $this->commitMasterChanges( $fnameEffective );
479  $waitSucceeded = $this->waitForReplication( $opts );
480  // If a nested caller committed on behalf of $fname, start another empty $fname
481  // transaction, leaving the caller with the same empty transaction state as before.
482  if ( $fnameEffective !== $fname ) {
483  $this->beginMasterChanges( $fnameEffective );
484  }
485  return $waitSucceeded;
486  }
487 
488  public function getChronologyProtectorTouched( $dbName ) {
489  return $this->getChronologyProtector()->getTouched( $dbName );
490  }
491 
492  public function disableChronologyProtection() {
493  $this->getChronologyProtector()->setEnabled( false );
494  }
495 
499  protected function getChronologyProtector() {
500  if ( $this->chronProt ) {
501  return $this->chronProt;
502  }
503 
504  $this->chronProt = new ChronologyProtector(
505  $this->memStash,
506  [
507  'ip' => $this->requestInfo['IPAddress'],
508  'agent' => $this->requestInfo['UserAgent'],
509  'clientId' => $this->requestInfo['ChronologyClientId']
510  ],
511  $this->requestInfo['ChronologyPositionIndex']
512  );
513  $this->chronProt->setLogger( $this->replLogger );
514 
515  if ( $this->cliMode ) {
516  $this->chronProt->setEnabled( false );
517  } elseif ( $this->requestInfo['ChronologyProtection'] === 'false' ) {
518  // Request opted out of using position wait logic. This is useful for requests
519  // done by the job queue or background ETL that do not have a meaningful session.
520  $this->chronProt->setWaitEnabled( false );
521  } elseif ( $this->memStash instanceof EmptyBagOStuff ) {
522  // No where to store any DB positions and wait for them to appear
523  $this->chronProt->setEnabled( false );
524  $this->replLogger->info( 'Cannot use ChronologyProtector with EmptyBagOStuff.' );
525  }
526 
527  $this->replLogger->debug( __METHOD__ . ': using request info ' .
528  json_encode( $this->requestInfo, JSON_PRETTY_PRINT ) );
529 
530  return $this->chronProt;
531  }
532 
541  protected function shutdownChronologyProtector(
542  ChronologyProtector $cp, $workCallback, $mode, &$cpIndex = null
543  ) {
544  // Record all the master positions needed
545  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $cp ) {
546  $cp->shutdownLB( $lb );
547  } );
548  // Write them to the persistent stash. Try to do something useful by running $work
549  // while ChronologyProtector waits for the stash write to replicate to all DCs.
550  $unsavedPositions = $cp->shutdown( $workCallback, $mode, $cpIndex );
551  if ( $unsavedPositions && $workCallback ) {
552  // Invoke callback in case it did not cache the result yet
553  $workCallback(); // work now to block for less time in waitForAll()
554  }
555  // If the positions failed to write to the stash, at least wait on local datacenter
556  // replica DBs to catch up before responding. Even if there are several DCs, this increases
557  // the chance that the user will see their own changes immediately afterwards. As long
558  // as the sticky DC cookie applies (same domain), this is not even an issue.
559  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $unsavedPositions ) {
560  $masterName = $lb->getServerName( $lb->getWriterIndex() );
561  if ( isset( $unsavedPositions[$masterName] ) ) {
562  $lb->waitForAll( $unsavedPositions[$masterName] );
563  }
564  } );
565  }
566 
571  final protected function baseLoadBalancerParams() {
572  if ( $this->trxRoundStage === self::ROUND_COMMIT_CALLBACKS ) {
573  $initStage = ILoadBalancer::STAGE_POSTCOMMIT_CALLBACKS;
574  } elseif ( $this->trxRoundStage === self::ROUND_ROLLBACK_CALLBACKS ) {
575  $initStage = ILoadBalancer::STAGE_POSTROLLBACK_CALLBACKS;
576  } else {
577  $initStage = null;
578  }
579 
580  return [
581  'localDomain' => $this->localDomain,
582  'readOnlyReason' => $this->readOnlyReason,
583  'srvCache' => $this->srvCache,
584  'wanCache' => $this->wanCache,
585  'profiler' => $this->profiler,
586  'trxProfiler' => $this->trxProfiler,
587  'queryLogger' => $this->queryLogger,
588  'connLogger' => $this->connLogger,
589  'replLogger' => $this->replLogger,
590  'errorLogger' => $this->errorLogger,
591  'deprecationLogger' => $this->deprecationLogger,
592  'hostname' => $this->hostname,
593  'cliMode' => $this->cliMode,
594  'agent' => $this->agent,
595  'maxLag' => $this->maxLag,
596  'defaultGroup' => $this->defaultGroup,
597  'chronologyCallback' => function ( ILoadBalancer $lb ) {
598  // Defer ChronologyProtector construction in case setRequestInfo() ends up
599  // being called later (but before the first connection attempt) (T192611)
600  $this->getChronologyProtector()->initLB( $lb );
601  },
602  'roundStage' => $initStage
603  ];
604  }
605 
609  protected function initLoadBalancer( ILoadBalancer $lb ) {
610  if ( $this->trxRoundId !== false ) {
611  $lb->beginMasterChanges( $this->trxRoundId ); // set DBO_TRX
612  }
613 
614  $lb->setTableAliases( $this->tableAliases );
615  $lb->setIndexAliases( $this->indexAliases );
616  }
617 
618  public function setTableAliases( array $aliases ) {
619  $this->tableAliases = $aliases;
620  }
621 
622  public function setIndexAliases( array $aliases ) {
623  $this->indexAliases = $aliases;
624  }
625 
630  public function setDomainPrefix( $prefix ) {
631  $this->setLocalDomainPrefix( $prefix );
632  }
633 
634  public function setLocalDomainPrefix( $prefix ) {
635  $this->localDomain = new DatabaseDomain(
636  $this->localDomain->getDatabase(),
637  $this->localDomain->getSchema(),
638  $prefix
639  );
640 
641  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $prefix ) {
642  $lb->setLocalDomainPrefix( $prefix );
643  } );
644  }
645 
646  public function redefineLocalDomain( $domain ) {
647  $this->closeAll();
648 
649  $this->localDomain = DatabaseDomain::newFromId( $domain );
650 
651  $this->forEachLB( function ( ILoadBalancer $lb ) {
652  $lb->redefineLocalDomain( $this->localDomain );
653  } );
654  }
655 
656  public function closeAll() {
657  $this->forEachLBCallMethod( 'closeAll' );
658  }
659 
660  public function setAgentName( $agent ) {
661  $this->agent = $agent;
662  }
663 
664  public function appendShutdownCPIndexAsQuery( $url, $index ) {
665  $usedCluster = 0;
666  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$usedCluster ) {
667  $usedCluster |= ( $lb->getServerCount() > 1 );
668  } );
669 
670  if ( !$usedCluster ) {
671  return $url; // no master/replica clusters touched
672  }
673 
674  return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index";
675  }
676 
677  public function getChronologyProtectorClientId() {
678  return $this->getChronologyProtector()->getClientId();
679  }
680 
688  public static function makeCookieValueFromCPIndex( $index, $time, $clientId ) {
689  return "$index@$time#$clientId";
690  }
691 
698  public static function getCPInfoFromCookieValue( $value, $minTimestamp ) {
699  static $placeholder = [ 'index' => null, 'clientId' => null ];
700 
701  if ( !preg_match( '/^(\d+)@(\d+)#([0-9a-f]{32})$/', $value, $m ) ) {
702  return $placeholder; // invalid
703  }
704 
705  $index = (int)$m[1];
706  if ( $index <= 0 ) {
707  return $placeholder; // invalid
708  } elseif ( isset( $m[2] ) && $m[2] !== '' && (int)$m[2] < $minTimestamp ) {
709  return $placeholder; // expired
710  }
711 
712  $clientId = ( isset( $m[3] ) && $m[3] !== '' ) ? $m[3] : null;
713 
714  return [ 'index' => $index, 'clientId' => $clientId ];
715  }
716 
717  public function setRequestInfo( array $info ) {
718  if ( $this->chronProt ) {
719  throw new LogicException( 'ChronologyProtector already initialized.' );
720  }
721 
722  $this->requestInfo = $info + $this->requestInfo;
723  }
724 
728  private function assertTransactionRoundStage( $stage ) {
729  if ( $this->trxRoundStage !== $stage ) {
730  throw new DBTransactionError(
731  null,
732  "Transaction round stage must be '$stage' (not '{$this->trxRoundStage}')"
733  );
734  }
735  }
736 
737  function __destruct() {
738  $this->destroy();
739  }
740 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
Helper class that detects high-contention DB queries via profiling calls.
disableChronologyProtection()
Disable the ChronologyProtector for all load balancers.
Definition: LBFactory.php:492
ChronologyProtector $chronProt
Definition: LBFactory.php:41
string null $defaultGroup
Definition: LBFactory.php:96
array $requestInfo
Web request information about the client.
Definition: LBFactory.php:72
flushReplicaSnapshots( $fname=__METHOD__)
Commit all replica DB transactions so as to flush any REPEATABLE-READ or SSI snapshot.
Definition: LBFactory.php:229
commitAll( $fname=__METHOD__, array $options=[])
Commit open transactions on all connections.
Definition: LBFactory.php:233
beginMasterChanges( $fname=__METHOD__)
Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
string bool $readOnlyReason
Reason all LBs are read-only or false if not.
Definition: LBFactory.php:93
shutdown(callable $workCallback=null, $mode='sync', &$cpIndex=null)
Notify the ChronologyProtector that the LBFactory is done calling shutdownLB() for now...
runMasterTransactionListenerCallbacks()
Run all recurring post-COMMIT/ROLLBACK listener callbacks.
An interface for generating database load balancers.
Definition: LBFactory.php:39
LoggerInterface $replLogger
Definition: LBFactory.php:47
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1982
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
setRequestInfo(array $info)
Definition: LBFactory.php:717
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2159
hasTransactionRound()
Check if an explicit transaction round is active.
Definition: LBFactory.php:321
getChronologyProtectorClientId()
Get the client ID of the ChronologyProtector instance.
Definition: LBFactory.php:677
TransactionProfiler $trxProfiler
Definition: LBFactory.php:45
string $hostname
Local hostname of the app server.
Definition: LBFactory.php:70
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:175
$value
finalizeMasterChanges()
Run pre-commit callbacks and defer execution of post-commit callbacks.
getLocalDomainID()
Get the local (and default) database domain ID of connection handles.
Definition: LBFactory.php:160
commitAndWaitForReplication( $fname, $ticket, array $opts=[])
Convenience method for safely running commitMasterChanges()/waitForReplication()
Definition: LBFactory.php:461
laggedReplicaUsed()
Detemine if any lagged replica DB connection was used.
Definition: LBFactory.php:361
DatabaseDomain $localDomain
Local domain.
Definition: LBFactory.php:67
redefineLocalDomain( $domain)
Close all connection and redefine the local domain for testing or schema creation.
__construct(array $conf)
Construct a manager of ILoadBalancer objects.
Definition: LBFactory.php:111
setLocalDomainPrefix( $prefix)
Set a new table prefix for the existing local domain ID for testing.
forEachLBCallMethod( $methodName, array $args=[])
Call a method of each tracked load balancer.
Definition: LBFactory.php:220
LoggerInterface $connLogger
Definition: LBFactory.php:49
isReadyForRoundOperations()
Check if transaction rounds can be started, committed, or rolled back right now.
Definition: LBFactory.php:325
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1799
commitMasterChanges( $fname=__METHOD__, array $options=[])
Commit changes and clear view snapshots on all master connections.
Definition: LBFactory.php:254
LoggerInterface $perfLogger
Definition: LBFactory.php:53
waitForAll( $pos, $timeout=null)
Set the master wait position and wait for ALL replica DBs to catch up to it.
getServerCount()
Get the number of defined servers (not the number of open connections)
forEachLB( $callback, array $params=[])
Execute a function for each tracked load balancer The callback is called with the load balancer as th...
if( $line===false) $args
Definition: cdb.php:64
hasMasterChanges()
Whether there are pending changes or callbacks in a transaction by this thread.
getServerName( $i)
Get the host name or IP address of the server with the specified index.
static newEmpty()
Get an instance that wraps EmptyBagOStuff.
setIndexAliases(array $aliases)
Convert certain index names to alternative names before querying the DB.
string [] $indexAliases
Map of (index alias => index)
Definition: LBFactory.php:81
Class for ensuring a consistent ordering of events as seen by the user, despite replication.
hasMasterChanges()
Determine if any master connection has pending changes.
Definition: LBFactory.php:352
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:609
runMasterTransactionIdleCallbacks()
Consume and run all pending post-COMMIT/ROLLBACK callbacks and commit dangling transactions.
setTableAliases(array $aliases)
Make certain table names use their own database, schema, and table prefix when passed into SQL querie...
Definition: LBFactory.php:618
LoggerInterface $queryLogger
Definition: LBFactory.php:51
callable [] $replicationWaitCallbacks
Definition: LBFactory.php:83
string bool $trxRoundId
String if a requested DBO_TRX transaction round is active.
Definition: LBFactory.php:88
static makeCookieValueFromCPIndex( $index, $time, $clientId)
Definition: LBFactory.php:688
getEmptyTransactionTicket( $fname)
Get a token asserting that no transaction writes are active.
Definition: LBFactory.php:450
hasOrMadeRecentMasterChanges( $age=null)
Determine if any master connection has pending/written changes from this request. ...
Definition: LBFactory.php:370
laggedReplicaUsed()
Checks whether the database for generic connections this request was both:
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1982
getChronologyProtectorTouched( $dbName)
Definition: LBFactory.php:488
shutdownChronologyProtector(ChronologyProtector $cp, $workCallback, $mode, &$cpIndex=null)
Get and record all of the staged DB positions into persistent memory storage.
Definition: LBFactory.php:541
bool $cliMode
Whether this PHP instance is for a CLI script.
Definition: LBFactory.php:74
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that When $user is not null
Definition: hooks.txt:780
WANObjectCache $wanCache
Definition: LBFactory.php:64
appendShutdownCPIndexAsQuery( $url, $index)
Append ?cpPosIndex parameter to a URL for ChronologyProtector purposes if needed. ...
Definition: LBFactory.php:664
setWaitForReplicationListener( $name, callable $callback=null)
Add a callback to be run in every call to waitForReplication() before waiting.
Definition: LBFactory.php:442
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
destroy()
Disables all load balancers.
Definition: LBFactory.php:155
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings, LocalSettings).
Definition: Setup.php:123
string $agent
Agent name for query profiling.
Definition: LBFactory.php:76
setIndexAliases(array $aliases)
Convert certain index names to alternative names before querying the DB.
Definition: LBFactory.php:622
waitForReplication(array $opts=[])
Waits for the replica DBs to catch up to the current master position.
Definition: LBFactory.php:378
hasOrMadeRecentMasterChanges( $age=null)
Check if this load balancer object had any recent or still pending writes issued against it by this P...
shutdown( $mode=self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback=null, &$cpIndex=null, &$cpClientId=null)
Prepare all tracked load balancers for shutdown.
Definition: LBFactory.php:168
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
Database cluster connection, tracking, load balancing, and transaction manager interface.
callable $deprecationLogger
Deprecation logger.
Definition: LBFactory.php:57
shutdownLB(ILoadBalancer $lb)
Notify the ChronologyProtector that the ILoadBalancer is about to shut down.
An interface for generating database load balancers.
Definition: ILBFactory.php:33
object string $profiler
Class name or object With profileIn/profileOut methods.
Definition: LBFactory.php:43
Class to handle database/prefix specification for IDatabase domains.
static getCPInfoFromCookieValue( $value, $minTimestamp)
Definition: LBFactory.php:698
rollbackMasterChanges( $fname=__METHOD__)
Rollback changes on all master connections.
Definition: LBFactory.php:289
baseLoadBalancerParams()
Base parameters to ILoadBalancer::__construct()
Definition: LBFactory.php:571
setTableAliases(array $aliases)
Make certain table names use their own database, schema, and table prefix when passed into SQL querie...
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:271
beginMasterChanges( $fname=__METHOD__)
Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
Definition: LBFactory.php:239
getMainLB( $domain=false)
newMainLB( $domain=false)
logIfMultiDbTransaction()
Log query info if multi DB transactions are going to be committed now.
Definition: LBFactory.php:332
callable $errorLogger
Error logger.
Definition: LBFactory.php:55
string $trxRoundStage
One of the ROUND_* class constants.
Definition: LBFactory.php:90
closeAll()
Close all open database connections on all open load balancers.
Definition: LBFactory.php:656
pendingMasterChangeCallers()
Get the list of callers that have pending master changes.
assertTransactionRoundStage( $stage)
Definition: LBFactory.php:728
redefineLocalDomain( $domain)
Close all connection and redefine the local domain for testing or schema creation.
Definition: LBFactory.php:646
setLocalDomainPrefix( $prefix)
Set a new table prefix for the existing local domain ID for testing.
Definition: LBFactory.php:634