24use Psr\Log\LoggerInterface;
25use Wikimedia\ScopedCallback;
77 [
'replLogger',
'connLogger',
'queryLogger',
'perfLogger' ];
80 $this->localDomain = isset( $conf[
'localDomain'] )
84 if ( isset( $conf[
'readOnlyReason'] ) && is_string( $conf[
'readOnlyReason'] ) ) {
85 $this->readOnlyReason = $conf[
'readOnlyReason'];
88 $this->srvCache = isset( $conf[
'srvCache'] ) ? $conf[
'srvCache'] :
new EmptyBagOStuff();
89 $this->memCache = isset( $conf[
'memCache'] ) ? $conf[
'memCache'] :
new EmptyBagOStuff();
90 $this->wanCache = isset( $conf[
'wanCache'] )
92 : WANObjectCache::newEmpty();
94 foreach ( self::$loggerFields
as $key ) {
95 $this->$key = isset( $conf[$key] ) ? $conf[$key] : new \Psr\Log\NullLogger();
97 $this->errorLogger = isset( $conf[
'errorLogger'] )
98 ? $conf[
'errorLogger']
99 :
function ( Exception
$e ) {
100 trigger_error( E_USER_WARNING, get_class(
$e ) .
': ' .
$e->getMessage() );
103 $this->profiler = isset(
$params[
'profiler'] ) ?
$params[
'profiler'] :
null;
104 $this->trxProfiler = isset( $conf[
'trxProfiler'] )
105 ? $conf[
'trxProfiler']
108 $this->requestInfo = [
109 'IPAddress' => isset( $_SERVER[
'REMOTE_ADDR' ] ) ? $_SERVER[
'REMOTE_ADDR' ] :
'',
110 'UserAgent' => isset( $_SERVER[
'HTTP_USER_AGENT'] ) ? $_SERVER[
'HTTP_USER_AGENT'] :
'',
111 'ChronologyProtection' =>
'true'
114 $this->cliMode = isset(
$params[
'cliMode'] ) ?
$params[
'cliMode'] : PHP_SAPI ===
'cli';
115 $this->hostname = isset( $conf[
'hostname'] ) ? $conf[
'hostname'] : gethostname();
118 $this->ticket = mt_rand();
122 $this->
shutdown( self::SHUTDOWN_NO_CHRONPROT );
127 $mode = self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback =
null
130 if ( $mode === self::SHUTDOWN_CHRONPROT_SYNC ) {
132 } elseif ( $mode === self::SHUTDOWN_CHRONPROT_ASYNC ) {
176 call_user_func_array( [ $loadBalancer, $methodName ],
$args );
178 [ $methodName,
$args ]
192 if ( $this->trxRoundId !==
false ) {
195 "$fname: transaction round '{$this->trxRoundId}' already started."
198 $this->trxRoundId =
$fname;
204 if ( $this->trxRoundId !==
false && $this->trxRoundId !==
$fname ) {
207 "$fname: transaction round '{$this->trxRoundId}' still running."
214 $this->trxRoundId =
false;
231 if (
$e instanceof Exception ) {
237 $this->trxRoundId =
false;
247 return ( $this->trxRoundId !==
false );
259 $callersByDB[$masterName] = $callers;
263 if ( count( $callersByDB ) >= 2 ) {
264 $dbs = implode(
', ', array_keys( $callersByDB ) );
265 $msg =
"Multi-DB transaction [{$dbs}]:\n";
266 foreach ( $callersByDB
as $db => $callers ) {
267 $msg .=
"$db: " . implode(
'; ', $callers ) .
"\n";
269 $this->queryLogger->info( $msg );
304 'ifWritesSince' => null
307 if ( $opts[
'domain'] ===
false && isset( $opts[
'wiki'] ) ) {
308 $opts[
'domain'] = $opts[
'wiki'];
314 if ( $opts[
'cluster'] !==
false ) {
316 } elseif ( $opts[
'domain'] !==
false ) {
317 $lbs[] = $this->
getMainLB( $opts[
'domain'] );
330 $masterPositions = array_fill( 0, count( $lbs ),
false );
331 foreach ( $lbs
as $i => $lb ) {
332 if ( $lb->getServerCount() <= 1 ) {
336 } elseif ( $opts[
'ifWritesSince']
337 && $lb->lastMasterChangeTimestamp() < $opts[
'ifWritesSince']
341 $masterPositions[$i] = $lb->getMasterPos();
346 foreach ( $this->replicationWaitCallbacks
as $callback ) {
351 foreach ( $lbs
as $i => $lb ) {
352 if ( $masterPositions[$i] ) {
354 if ( !$lb->waitForAll( $masterPositions[$i], $opts[
'timeout'] ) ) {
355 $failed[] = $lb->getServerName( $lb->getWriterIndex() );
362 "Could not wait for replica DBs to catch up to " .
363 implode(
', ', $failed )
370 $this->replicationWaitCallbacks[
$name] = $callback;
372 unset( $this->replicationWaitCallbacks[
$name] );
378 $this->queryLogger->error( __METHOD__ .
": $fname does not have outer scope.\n" .
379 (
new RuntimeException() )->getTraceAsString() );
384 return $this->ticket;
388 if (
$ticket !== $this->ticket ) {
389 $this->perfLogger->error( __METHOD__ .
": $fname does not have outer scope.\n" .
390 (
new RuntimeException() )->getTraceAsString() );
397 if ( $this->trxRoundId !==
false &&
$fname !== $this->trxRoundId ) {
398 $this->queryLogger->info(
"$fname: committing on behalf of {$this->trxRoundId}." );
399 $fnameEffective = $this->trxRoundId;
408 if ( $fnameEffective !==
$fname ) {
425 if ( $this->chronProt ) {
426 return $this->chronProt;
432 'ip' => $this->requestInfo[
'IPAddress'],
433 'agent' => $this->requestInfo[
'UserAgent'],
435 isset( $_GET[
'cpPosTime'] ) ? $_GET[
'cpPosTime'] : null
437 $this->chronProt->
setLogger( $this->replLogger );
439 if ( $this->cliMode ) {
440 $this->chronProt->setEnabled(
false );
441 } elseif ( $this->requestInfo[
'ChronologyProtection'] ===
'false' ) {
444 $this->chronProt->setWaitEnabled(
false );
447 $this->replLogger->debug( __METHOD__ .
': using request info ' .
448 json_encode( $this->requestInfo, JSON_PRETTY_PRINT ) );
450 return $this->chronProt;
469 $unsavedPositions = $cp->
shutdown( $workCallback, $mode );
470 if ( $unsavedPositions && $workCallback ) {
480 if ( isset( $unsavedPositions[$masterName] ) ) {
481 $lb->
waitForAll( $unsavedPositions[$masterName] );
492 'localDomain' => $this->localDomain,
493 'readOnlyReason' => $this->readOnlyReason,
494 'srvCache' => $this->srvCache,
495 'wanCache' => $this->wanCache,
496 'profiler' => $this->profiler,
497 'trxProfiler' => $this->trxProfiler,
498 'queryLogger' => $this->queryLogger,
499 'connLogger' => $this->connLogger,
500 'replLogger' => $this->replLogger,
501 'errorLogger' => $this->errorLogger,
502 'hostname' => $this->hostname,
503 'cliMode' => $this->cliMode,
504 'agent' => $this->agent
512 if ( $this->trxRoundId !==
false ) {
519 $this->localDomain->getDatabase(),
543 if ( !$usedCluster ) {
547 return strpos( $url,
'?' ) ===
false ?
"$url?cpPosTime=$time" :
"$url&cpPosTime=$time";
551 $this->requestInfo = $info + $this->requestInfo;
561 if ( PHP_SAPI !=
'cli' ) {
562 $old = ignore_user_abort(
true );
563 return new ScopedCallback(
function ()
use ( $old ) {
564 ignore_user_abort( $old );
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
interface is intended to be more or less compatible with the PHP memcached client.
Class for ensuring a consistent ordering of events as seen by the user, despite replication.
shutdown(callable $workCallback=null, $mode='sync')
Notify the ChronologyProtector that the LBFactory is done calling shutdownLB() for now.
shutdownLB(ILoadBalancer $lb)
Notify the ChronologyProtector that the ILoadBalancer is about to shut down.
setLogger(LoggerInterface $logger)
Exception class for replica DB wait timeouts.
Class to handle database/prefix specification for IDatabase domains.
static newFromId( $domain)
A BagOStuff object with no objects in it.
An interface for generating database load balancers.
forEachLBCallMethod( $methodName, array $args=[])
Call a method of each tracked load balancer.
laggedReplicaUsed()
Detemine if any lagged replica DB connection was used.
shutdownChronologyProtector(ChronologyProtector $cp, $workCallback, $mode)
Get and record all of the staged DB positions into persistent memory storage.
setRequestInfo(array $info)
destroy()
Disables all load balancers.
string $agent
Agent name for query profiling.
shutdown( $mode=self::SHUTDOWN_CHRONPROT_SYNC, callable $workCallback=null)
Prepare all tracked load balancers for shutdown.
commitAndWaitForReplication( $fname, $ticket, array $opts=[])
Convenience method for safely running commitMasterChanges()/waitForReplication()
LoggerInterface $perfLogger
initLoadBalancer(ILoadBalancer $lb)
baseLoadBalancerParams()
Base parameters to LoadBalancer::__construct()
object string $profiler
Class name or object With profileIn/profileOut methods.
__construct(array $conf)
Construct a manager of ILoadBalancer objects.
disableChronologyProtection()
Disable the ChronologyProtector for all load balancers.
rollbackMasterChanges( $fname=__METHOD__)
Rollback changes on all master connections.
ChronologyProtector $chronProt
hasTransactionRound()
Check if a transaction round is active.
hasMasterChanges()
Determine if any master connection has pending changes.
newMainLB( $domain=false)
flushReplicaSnapshots( $fname=__METHOD__)
Commit all replica DB transactions so as to flush any REPEATABLE-READ or SSI snapshot.
commitMasterChanges( $fname=__METHOD__, array $options=[])
Commit changes on all master connections.
callable $errorLogger
Error logger.
LoggerInterface $queryLogger
appendPreShutdownTimeAsQuery( $url, $time)
Append ?cpPosTime parameter to a URL for ChronologyProtector purposes if needed.
setWaitForReplicationListener( $name, callable $callback=null)
Add a callback to be run in every call to waitForReplication() before waiting.
hasOrMadeRecentMasterChanges( $age=null)
Determine if any master connection has pending/written changes from this request.
string bool $trxRoundId
String if a requested DBO_TRX transaction round is active.
getChronologyProtectorTouched( $dbName)
callable[] $replicationWaitCallbacks
getScopedPHPBehaviorForCommit()
Make PHP ignore user aborts/disconnects until the returned value leaves scope.
string $hostname
Local hostname of the app server.
LoggerInterface $replLogger
string bool $readOnlyReason
Reason all LBs are read-only or false if not.
commitAll( $fname=__METHOD__, array $options=[])
Commit open transactions on all connections.
beginMasterChanges( $fname=__METHOD__)
Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
logIfMultiDbTransaction()
Log query info if multi DB transactions are going to be committed now.
getMainLB( $domain=false)
waitForReplication(array $opts=[])
Waits for the replica DBs to catch up to the current master position.
array $requestInfo
Web request information about the client.
getEmptyTransactionTicket( $fname)
Get a token asserting that no transaction writes are active.
bool $cliMode
Whether this PHP instance is for a CLI script.
DatabaseDomain $localDomain
Local domain.
closeAll()
Close all open database connections on all open load balancers.
LoggerInterface $connLogger
setDomainPrefix( $prefix)
Set a new table prefix for the existing local domain ID for testing.
TransactionProfiler $trxProfiler
Helper class that detects high-contention DB queries via profiling calls.
Multi-datacenter aware caching interface.
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
the array() calling protocol came about after MediaWiki 1.4rc1.
see documentation in includes Linker php for Linker::makeImageLink & $time
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
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
Allows to change the fields on the form that will be generated $name
returning false will NOT prevent logging $e
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
An interface for generating database load balancers.
forEachLB( $callback, array $params=[])
Execute a function for each tracked load balancer The callback is called with the load balancer as th...
Database cluster connection, tracking, load balancing, and transaction manager interface.
beginMasterChanges( $fname=__METHOD__)
Flush any master transaction snapshots and set DBO_TRX (if DBO_DEFAULT is set)
getServerCount()
Get the number of defined servers (not the number of open connections)
pendingMasterChangeCallers()
Get the list of callers that have pending master changes.
hasOrMadeRecentMasterChanges( $age=null)
Check if this load balancer object had any recent or still pending writes issued against it by this P...
setDomainPrefix( $prefix)
Set a new table prefix for the existing local domain ID for testing.
runMasterPostTrxCallbacks( $type)
Issue all pending post-COMMIT/ROLLBACK callbacks.
waitForAll( $pos, $timeout=null)
Set the master wait position and wait for ALL replica DBs to catch up to it.
hasMasterChanges()
Determine if there are pending changes in a transaction by this thread.
getServerName( $i)
Get the host name or IP address of the server with the specified index Prefer a readable name if avai...