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 
98  const ROUND_CURSORY = 'cursory';
99  const ROUND_BEGINNING = 'within-begin';
100  const ROUND_COMMITTING = 'within-commit';
101  const ROUND_ROLLING_BACK = 'within-rollback';
102  const ROUND_COMMIT_CALLBACKS = 'within-commit-callbacks';
103  const ROUND_ROLLBACK_CALLBACKS = 'within-rollback-callbacks';
104 
105  private static $loggerFields =
106  [ 'replLogger', 'connLogger', 'queryLogger', 'perfLogger' ];
107 
108  public function __construct( array $conf ) {
109  $this->localDomain = isset( $conf['localDomain'] )
110  ? DatabaseDomain::newFromId( $conf['localDomain'] )
112 
113  if ( isset( $conf['readOnlyReason'] ) && is_string( $conf['readOnlyReason'] ) ) {
114  $this->readOnlyReason = $conf['readOnlyReason'];
115  }
116 
117  $this->srvCache = $conf['srvCache'] ?? new EmptyBagOStuff();
118  $this->memStash = $conf['memStash'] ?? new EmptyBagOStuff();
119  $this->wanCache = $conf['wanCache'] ?? WANObjectCache::newEmpty();
120 
121  foreach ( self::$loggerFields as $key ) {
122  $this->$key = $conf[$key] ?? new \Psr\Log\NullLogger();
123  }
124  $this->errorLogger = $conf['errorLogger'] ?? function ( Exception $e ) {
125  trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
126  };
127  $this->deprecationLogger = $conf['deprecationLogger'] ?? function ( $msg ) {
128  trigger_error( $msg, E_USER_DEPRECATED );
129  };
130 
131  $this->profiler = $conf['profiler'] ?? null;
132  $this->trxProfiler = $conf['trxProfiler'] ?? new TransactionProfiler();
133 
134  $this->requestInfo = [
135  'IPAddress' => $_SERVER[ 'REMOTE_ADDR' ] ?? '',
136  'UserAgent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
137  // Headers application can inject via LBFactory::setRequestInfo()
138  'ChronologyProtection' => null,
139  'ChronologyClientId' => null, // prior $cpClientId value from LBFactory::shutdown()
140  'ChronologyPositionIndex' => null // prior $cpIndex value from LBFactory::shutdown()
141  ];
142 
143  $this->cliMode = $conf['cliMode'] ?? ( PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg' );
144  $this->hostname = $conf['hostname'] ?? gethostname();
145  $this->agent = $conf['agent'] ?? '';
146  $this->defaultGroup = $conf['defaultGroup'] ?? null;
147 
148  $this->ticket = mt_rand();
149  }
150 
151  public function destroy() {
152  $this->shutdown( self::SHUTDOWN_NO_CHRONPROT );
153  $this->forEachLBCallMethod( 'disable' );
154  }
155 
156  public function getLocalDomainID() {
157  return $this->localDomain->getId();
158  }
159 
160  public function resolveDomainID( $domain ) {
161  return ( $domain !== false ) ? (string)$domain : $this->getLocalDomainID();
162  }
163 
164  public function shutdown(
165  $mode = self::SHUTDOWN_CHRONPROT_SYNC,
166  callable $workCallback = null,
167  &$cpIndex = null,
168  &$cpClientId = null
169  ) {
171  if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) {
172  $this->shutdownChronologyProtector( $chronProt, $workCallback, 'sync', $cpIndex );
173  } elseif ( $mode === self::SHUTDOWN_CHRONPROT_ASYNC ) {
174  $this->shutdownChronologyProtector( $chronProt, null, 'async', $cpIndex );
175  }
176 
177  $cpClientId = $chronProt->getClientId();
178 
179  $this->commitMasterChanges( __METHOD__ ); // sanity
180  }
181 
187  abstract public function newMainLB( $domain = false );
188 
194  abstract public function getMainLB( $domain = false );
195 
201  abstract public function newExternalLB( $cluster );
202 
208  abstract public function getExternalLB( $cluster );
209 
216  protected function forEachLBCallMethod( $methodName, array $args = [] ) {
217  $this->forEachLB(
218  function ( ILoadBalancer $loadBalancer, $methodName, array $args ) {
219  $loadBalancer->$methodName( ...$args );
220  },
221  [ $methodName, $args ]
222  );
223  }
224 
225  public function flushReplicaSnapshots( $fname = __METHOD__ ) {
226  $this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] );
227  }
228 
229  final public function commitAll( $fname = __METHOD__, array $options = [] ) {
231  $this->forEachLBCallMethod( 'flushMasterSnapshots', [ $fname ] );
232  $this->forEachLBCallMethod( 'flushReplicaSnapshots', [ $fname ] );
233  }
234 
235  final public function beginMasterChanges( $fname = __METHOD__ ) {
236  $this->assertTransactionRoundStage( self::ROUND_CURSORY );
237  $this->trxRoundStage = self::ROUND_BEGINNING;
238  if ( $this->trxRoundId !== false ) {
239  throw new DBTransactionError(
240  null,
241  "$fname: transaction round '{$this->trxRoundId}' already started."
242  );
243  }
244  $this->trxRoundId = $fname;
245  // Set DBO_TRX flags on all appropriate DBs
246  $this->forEachLBCallMethod( 'beginMasterChanges', [ $fname ] );
247  $this->trxRoundStage = self::ROUND_CURSORY;
248  }
249 
250  final public function commitMasterChanges( $fname = __METHOD__, array $options = [] ) {
251  $this->assertTransactionRoundStage( self::ROUND_CURSORY );
252  $this->trxRoundStage = self::ROUND_COMMITTING;
253  if ( $this->trxRoundId !== false && $this->trxRoundId !== $fname ) {
254  throw new DBTransactionError(
255  null,
256  "$fname: transaction round '{$this->trxRoundId}' still running."
257  );
258  }
260  $scope = ScopedCallback::newScopedIgnoreUserAbort(); // try to ignore client aborts
261  // Run pre-commit callbacks and suppress post-commit callbacks, aborting on failure
262  do {
263  $count = 0; // number of callbacks executed this iteration
264  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$count ) {
265  $count += $lb->finalizeMasterChanges();
266  } );
267  } while ( $count > 0 );
268  $this->trxRoundId = false;
269  // Perform pre-commit checks, aborting on failure
270  $this->forEachLBCallMethod( 'approveMasterChanges', [ $options ] );
271  // Log the DBs and methods involved in multi-DB transactions
272  $this->logIfMultiDbTransaction();
273  // Actually perform the commit on all master DB connections and revert DBO_TRX
274  $this->forEachLBCallMethod( 'commitMasterChanges', [ $fname ] );
275  // Run all post-commit callbacks in a separate step
276  $this->trxRoundStage = self::ROUND_COMMIT_CALLBACKS;
278  $this->trxRoundStage = self::ROUND_CURSORY;
279  // Throw any last post-commit callback error
280  if ( $e instanceof Exception ) {
281  throw $e;
282  }
283  }
284 
285  final public function rollbackMasterChanges( $fname = __METHOD__ ) {
286  $this->trxRoundStage = self::ROUND_ROLLING_BACK;
287  $this->trxRoundId = false;
288  // Actually perform the rollback on all master DB connections and revert DBO_TRX
289  $this->forEachLBCallMethod( 'rollbackMasterChanges', [ $fname ] );
290  // Run all post-commit callbacks in a separate step
291  $this->trxRoundStage = self::ROUND_ROLLBACK_CALLBACKS;
293  $this->trxRoundStage = self::ROUND_CURSORY;
294  }
295 
299  private function executePostTransactionCallbacks() {
300  // Run all post-commit callbacks until new ones stop getting added
301  $e = null; // first callback exception
302  do {
303  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
305  $e = $e ?: $ex;
306  } );
307  } while ( $this->hasMasterChanges() );
308  // Run all listener callbacks once
309  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$e ) {
311  $e = $e ?: $ex;
312  } );
313 
314  return $e;
315  }
316 
317  public function hasTransactionRound() {
318  return ( $this->trxRoundId !== false );
319  }
320 
321  public function isReadyForRoundOperations() {
322  return ( $this->trxRoundStage === self::ROUND_CURSORY );
323  }
324 
328  private function logIfMultiDbTransaction() {
329  $callersByDB = [];
330  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$callersByDB ) {
331  $masterName = $lb->getServerName( $lb->getWriterIndex() );
332  $callers = $lb->pendingMasterChangeCallers();
333  if ( $callers ) {
334  $callersByDB[$masterName] = $callers;
335  }
336  } );
337 
338  if ( count( $callersByDB ) >= 2 ) {
339  $dbs = implode( ', ', array_keys( $callersByDB ) );
340  $msg = "Multi-DB transaction [{$dbs}]:\n";
341  foreach ( $callersByDB as $db => $callers ) {
342  $msg .= "$db: " . implode( '; ', $callers ) . "\n";
343  }
344  $this->queryLogger->info( $msg );
345  }
346  }
347 
348  public function hasMasterChanges() {
349  $ret = false;
350  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) {
351  $ret = $ret || $lb->hasMasterChanges();
352  } );
353 
354  return $ret;
355  }
356 
357  public function laggedReplicaUsed() {
358  $ret = false;
359  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$ret ) {
360  $ret = $ret || $lb->laggedReplicaUsed();
361  } );
362 
363  return $ret;
364  }
365 
366  public function hasOrMadeRecentMasterChanges( $age = null ) {
367  $ret = false;
368  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $age, &$ret ) {
369  $ret = $ret || $lb->hasOrMadeRecentMasterChanges( $age );
370  } );
371  return $ret;
372  }
373 
374  public function waitForReplication( array $opts = [] ) {
375  $opts += [
376  'domain' => false,
377  'cluster' => false,
378  'timeout' => $this->cliMode ? 60 : 1,
379  'ifWritesSince' => null
380  ];
381 
382  if ( $opts['domain'] === false && isset( $opts['wiki'] ) ) {
383  $opts['domain'] = $opts['wiki']; // b/c
384  }
385 
386  // Figure out which clusters need to be checked
388  $lbs = [];
389  if ( $opts['cluster'] !== false ) {
390  $lbs[] = $this->getExternalLB( $opts['cluster'] );
391  } elseif ( $opts['domain'] !== false ) {
392  $lbs[] = $this->getMainLB( $opts['domain'] );
393  } else {
394  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$lbs ) {
395  $lbs[] = $lb;
396  } );
397  if ( !$lbs ) {
398  return; // nothing actually used
399  }
400  }
401 
402  // Get all the master positions of applicable DBs right now.
403  // This can be faster since waiting on one cluster reduces the
404  // time needed to wait on the next clusters.
405  $masterPositions = array_fill( 0, count( $lbs ), false );
406  foreach ( $lbs as $i => $lb ) {
407  if ( $lb->getServerCount() <= 1 ) {
408  // T29975 - Don't try to wait for replica DBs if there are none
409  // Prevents permission error when getting master position
410  continue;
411  } elseif ( $opts['ifWritesSince']
412  && $lb->lastMasterChangeTimestamp() < $opts['ifWritesSince']
413  ) {
414  continue; // no writes since the last wait
415  }
416  $masterPositions[$i] = $lb->getMasterPos();
417  }
418 
419  // Run any listener callbacks *after* getting the DB positions. The more
420  // time spent in the callbacks, the less time is spent in waitForAll().
421  foreach ( $this->replicationWaitCallbacks as $callback ) {
422  $callback();
423  }
424 
425  $failed = [];
426  foreach ( $lbs as $i => $lb ) {
427  if ( $masterPositions[$i] ) {
428  // The RDBMS may not support getMasterPos()
429  if ( !$lb->waitForAll( $masterPositions[$i], $opts['timeout'] ) ) {
430  $failed[] = $lb->getServerName( $lb->getWriterIndex() );
431  }
432  }
433  }
434 
435  return !$failed;
436  }
437 
438  public function setWaitForReplicationListener( $name, callable $callback = null ) {
439  if ( $callback ) {
440  $this->replicationWaitCallbacks[$name] = $callback;
441  } else {
442  unset( $this->replicationWaitCallbacks[$name] );
443  }
444  }
445 
446  public function getEmptyTransactionTicket( $fname ) {
447  if ( $this->hasMasterChanges() ) {
448  $this->queryLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
449  ( new RuntimeException() )->getTraceAsString() );
450 
451  return null;
452  }
453 
454  return $this->ticket;
455  }
456 
457  final public function commitAndWaitForReplication( $fname, $ticket, array $opts = [] ) {
458  if ( $ticket !== $this->ticket ) {
459  $this->perfLogger->error( __METHOD__ . ": $fname does not have outer scope.\n" .
460  ( new RuntimeException() )->getTraceAsString() );
461 
462  return;
463  }
464 
465  // The transaction owner and any caller with the empty transaction ticket can commit
466  // so that getEmptyTransactionTicket() callers don't risk seeing DBTransactionError.
467  if ( $this->trxRoundId !== false && $fname !== $this->trxRoundId ) {
468  $this->queryLogger->info( "$fname: committing on behalf of {$this->trxRoundId}." );
469  $fnameEffective = $this->trxRoundId;
470  } else {
471  $fnameEffective = $fname;
472  }
473 
474  $this->commitMasterChanges( $fnameEffective );
475  $waitSucceeded = $this->waitForReplication( $opts );
476  // If a nested caller committed on behalf of $fname, start another empty $fname
477  // transaction, leaving the caller with the same empty transaction state as before.
478  if ( $fnameEffective !== $fname ) {
479  $this->beginMasterChanges( $fnameEffective );
480  }
481  return $waitSucceeded;
482  }
483 
484  public function getChronologyProtectorTouched( $dbName ) {
485  return $this->getChronologyProtector()->getTouched( $dbName );
486  }
487 
488  public function disableChronologyProtection() {
489  $this->getChronologyProtector()->setEnabled( false );
490  }
491 
495  protected function getChronologyProtector() {
496  if ( $this->chronProt ) {
497  return $this->chronProt;
498  }
499 
500  $this->chronProt = new ChronologyProtector(
501  $this->memStash,
502  [
503  'ip' => $this->requestInfo['IPAddress'],
504  'agent' => $this->requestInfo['UserAgent'],
505  'clientId' => $this->requestInfo['ChronologyClientId']
506  ],
507  $this->requestInfo['ChronologyPositionIndex']
508  );
509  $this->chronProt->setLogger( $this->replLogger );
510 
511  if ( $this->cliMode ) {
512  $this->chronProt->setEnabled( false );
513  } elseif ( $this->requestInfo['ChronologyProtection'] === 'false' ) {
514  // Request opted out of using position wait logic. This is useful for requests
515  // done by the job queue or background ETL that do not have a meaningful session.
516  $this->chronProt->setWaitEnabled( false );
517  } elseif ( $this->memStash instanceof EmptyBagOStuff ) {
518  // No where to store any DB positions and wait for them to appear
519  $this->chronProt->setEnabled( false );
520  $this->replLogger->info( 'Cannot use ChronologyProtector with EmptyBagOStuff.' );
521  }
522 
523  $this->replLogger->debug( __METHOD__ . ': using request info ' .
524  json_encode( $this->requestInfo, JSON_PRETTY_PRINT ) );
525 
526  return $this->chronProt;
527  }
528 
537  protected function shutdownChronologyProtector(
538  ChronologyProtector $cp, $workCallback, $mode, &$cpIndex = null
539  ) {
540  // Record all the master positions needed
541  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $cp ) {
542  $cp->shutdownLB( $lb );
543  } );
544  // Write them to the persistent stash. Try to do something useful by running $work
545  // while ChronologyProtector waits for the stash write to replicate to all DCs.
546  $unsavedPositions = $cp->shutdown( $workCallback, $mode, $cpIndex );
547  if ( $unsavedPositions && $workCallback ) {
548  // Invoke callback in case it did not cache the result yet
549  $workCallback(); // work now to block for less time in waitForAll()
550  }
551  // If the positions failed to write to the stash, at least wait on local datacenter
552  // replica DBs to catch up before responding. Even if there are several DCs, this increases
553  // the chance that the user will see their own changes immediately afterwards. As long
554  // as the sticky DC cookie applies (same domain), this is not even an issue.
555  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $unsavedPositions ) {
556  $masterName = $lb->getServerName( $lb->getWriterIndex() );
557  if ( isset( $unsavedPositions[$masterName] ) ) {
558  $lb->waitForAll( $unsavedPositions[$masterName] );
559  }
560  } );
561  }
562 
567  final protected function baseLoadBalancerParams() {
568  if ( $this->trxRoundStage === self::ROUND_COMMIT_CALLBACKS ) {
569  $initStage = ILoadBalancer::STAGE_POSTCOMMIT_CALLBACKS;
570  } elseif ( $this->trxRoundStage === self::ROUND_ROLLBACK_CALLBACKS ) {
571  $initStage = ILoadBalancer::STAGE_POSTROLLBACK_CALLBACKS;
572  } else {
573  $initStage = null;
574  }
575 
576  return [
577  'localDomain' => $this->localDomain,
578  'readOnlyReason' => $this->readOnlyReason,
579  'srvCache' => $this->srvCache,
580  'wanCache' => $this->wanCache,
581  'profiler' => $this->profiler,
582  'trxProfiler' => $this->trxProfiler,
583  'queryLogger' => $this->queryLogger,
584  'connLogger' => $this->connLogger,
585  'replLogger' => $this->replLogger,
586  'errorLogger' => $this->errorLogger,
587  'deprecationLogger' => $this->deprecationLogger,
588  'hostname' => $this->hostname,
589  'cliMode' => $this->cliMode,
590  'agent' => $this->agent,
591  'defaultGroup' => $this->defaultGroup,
592  'chronologyCallback' => function ( ILoadBalancer $lb ) {
593  // Defer ChronologyProtector construction in case setRequestInfo() ends up
594  // being called later (but before the first connection attempt) (T192611)
595  $this->getChronologyProtector()->initLB( $lb );
596  },
597  'roundStage' => $initStage
598  ];
599  }
600 
604  protected function initLoadBalancer( ILoadBalancer $lb ) {
605  if ( $this->trxRoundId !== false ) {
606  $lb->beginMasterChanges( $this->trxRoundId ); // set DBO_TRX
607  }
608 
609  $lb->setTableAliases( $this->tableAliases );
610  $lb->setIndexAliases( $this->indexAliases );
611  }
612 
613  public function setTableAliases( array $aliases ) {
614  $this->tableAliases = $aliases;
615  }
616 
617  public function setIndexAliases( array $aliases ) {
618  $this->indexAliases = $aliases;
619  }
620 
625  public function setDomainPrefix( $prefix ) {
626  $this->setLocalDomainPrefix( $prefix );
627  }
628 
629  public function setLocalDomainPrefix( $prefix ) {
630  $this->localDomain = new DatabaseDomain(
631  $this->localDomain->getDatabase(),
632  null,
633  $prefix
634  );
635 
636  $this->forEachLB( function ( ILoadBalancer $lb ) use ( $prefix ) {
637  $lb->setLocalDomainPrefix( $prefix );
638  } );
639  }
640 
641  public function redefineLocalDomain( $domain ) {
642  $this->closeAll();
643 
644  $this->localDomain = DatabaseDomain::newFromId( $domain );
645 
646  $this->forEachLB( function ( ILoadBalancer $lb ) {
647  $lb->redefineLocalDomain( $this->localDomain );
648  } );
649  }
650 
651  public function closeAll() {
652  $this->forEachLBCallMethod( 'closeAll', [] );
653  }
654 
655  public function setAgentName( $agent ) {
656  $this->agent = $agent;
657  }
658 
659  public function appendShutdownCPIndexAsQuery( $url, $index ) {
660  $usedCluster = 0;
661  $this->forEachLB( function ( ILoadBalancer $lb ) use ( &$usedCluster ) {
662  $usedCluster |= ( $lb->getServerCount() > 1 );
663  } );
664 
665  if ( !$usedCluster ) {
666  return $url; // no master/replica clusters touched
667  }
668 
669  return strpos( $url, '?' ) === false ? "$url?cpPosIndex=$index" : "$url&cpPosIndex=$index";
670  }
671 
679  public static function makeCookieValueFromCPIndex( $index, $time, $clientId ) {
680  return "$index@$time#$clientId";
681  }
682 
689  public static function getCPInfoFromCookieValue( $value, $minTimestamp ) {
690  static $placeholder = [ 'index' => null, 'clientId' => null ];
691 
692  if ( !preg_match( '/^(\d+)@(\d+)#([0-9a-f]{32})$/', $value, $m ) ) {
693  return $placeholder; // invalid
694  }
695 
696  $index = (int)$m[1];
697  if ( $index <= 0 ) {
698  return $placeholder; // invalid
699  } elseif ( isset( $m[2] ) && $m[2] !== '' && (int)$m[2] < $minTimestamp ) {
700  return $placeholder; // expired
701  }
702 
703  $clientId = ( isset( $m[3] ) && $m[3] !== '' ) ? $m[3] : null;
704 
705  return [ 'index' => $index, 'clientId' => $clientId ];
706  }
707 
708  public function setRequestInfo( array $info ) {
709  if ( $this->chronProt ) {
710  throw new LogicException( 'ChronologyProtector already initialized.' );
711  }
712 
713  $this->requestInfo = $info + $this->requestInfo;
714  }
715 
719  private function assertTransactionRoundStage( $stage ) {
720  if ( $this->trxRoundStage !== $stage ) {
721  throw new DBTransactionError(
722  null,
723  "Transaction round stage must be '$stage' (not '{$this->trxRoundStage}')"
724  );
725  }
726  }
727 
728  function __destruct() {
729  $this->destroy();
730  }
731 }
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:488
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:225
commitAll( $fname=__METHOD__, array $options=[])
Commit open transactions on all connections.
Definition: LBFactory.php:229
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:1996
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
setRequestInfo(array $info)
Definition: LBFactory.php:708
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException' returning false will NOT prevent logging $e
Definition: hooks.txt:2173
hasTransactionRound()
Check if an explicit transaction round is active.
Definition: LBFactory.php:317
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:156
commitAndWaitForReplication( $fname, $ticket, array $opts=[])
Convenience method for safely running commitMasterChanges()/waitForReplication()
Definition: LBFactory.php:457
laggedReplicaUsed()
Detemine if any lagged replica DB connection was used.
Definition: LBFactory.php:357
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:108
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:216
LoggerInterface $connLogger
Definition: LBFactory.php:49
isReadyForRoundOperations()
Check if transaction rounds can be started, committed, or rolled back right now.
Definition: LBFactory.php:321
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1813
commitMasterChanges( $fname=__METHOD__, array $options=[])
Commit changes and clear view snapshots on all master connections.
Definition: LBFactory.php:250
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:348
initLoadBalancer(ILoadBalancer $lb)
Definition: LBFactory.php:604
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:613
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:679
getEmptyTransactionTicket( $fname)
Get a token asserting that no transaction writes are active.
Definition: LBFactory.php:446
hasOrMadeRecentMasterChanges( $age=null)
Determine if any master connection has pending/written changes from this request. ...
Definition: LBFactory.php:366
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:1996
getChronologyProtectorTouched( $dbName)
Definition: LBFactory.php:484
shutdownChronologyProtector(ChronologyProtector $cp, $workCallback, $mode, &$cpIndex=null)
Get and record all of the staged DB positions into persistent memory storage.
Definition: LBFactory.php:537
bool $cliMode
Whether this PHP instance is for a CLI script.
Definition: LBFactory.php:74
WANObjectCache $wanCache
Definition: LBFactory.php:64
appendShutdownCPIndexAsQuery( $url, $index)
Append ?cpPosIndex parameter to a URL for ChronologyProtector purposes if needed. ...
Definition: LBFactory.php:659
setWaitForReplicationListener( $name, callable $callback=null)
Add a callback to be run in every call to waitForReplication() before waiting.
Definition: LBFactory.php:438
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:151
if(defined( 'MW_SETUP_CALLBACK')) $fname
Customization point after all loading (constants, functions, classes, DefaultSettings, LocalSettings).
Definition: Setup.php:121
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:617
waitForReplication(array $opts=[])
Waits for the replica DBs to catch up to the current master position.
Definition: LBFactory.php:374
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:164
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:689
rollbackMasterChanges( $fname=__METHOD__)
Rollback changes on all master connections.
Definition: LBFactory.php:285
baseLoadBalancerParams()
Base parameters to ILoadBalancer::__construct()
Definition: LBFactory.php:567
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:276
beginMasterChanges( $fname=__METHOD__)
Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
Definition: LBFactory.php:235
getMainLB( $domain=false)
newMainLB( $domain=false)
logIfMultiDbTransaction()
Log query info if multi DB transactions are going to be committed now.
Definition: LBFactory.php:328
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:651
pendingMasterChangeCallers()
Get the list of callers that have pending master changes.
assertTransactionRoundStage( $stage)
Definition: LBFactory.php:719
redefineLocalDomain( $domain)
Close all connection and redefine the local domain for testing or schema creation.
Definition: LBFactory.php:641
setLocalDomainPrefix( $prefix)
Set a new table prefix for the existing local domain ID for testing.
Definition: LBFactory.php:629