Merge "rdbms: remove DB domain parameter from various lag/read-only methods"
This commit is contained in:
commit
11de30462e
4 changed files with 39 additions and 59 deletions
|
|
@ -137,10 +137,7 @@ class ExternalStoreDB extends ExternalStoreMedium {
|
|||
return true;
|
||||
}
|
||||
|
||||
$lb = $this->getLoadBalancer( $location );
|
||||
$domainId = $this->getDomainId( $lb->getServerInfo( $lb->getWriterIndex() ) );
|
||||
|
||||
return ( $lb->getReadOnlyReason( $domainId ) !== false );
|
||||
return ( $this->getLoadBalancer( $location )->getReadOnlyReason() !== false );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1060,15 +1060,17 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
public function wasErrorReissuable();
|
||||
|
||||
/**
|
||||
* Wait for the replica DB to catch up to a given primary DB position
|
||||
* Wait for the replica server to catch up to a given primary server position
|
||||
*
|
||||
* Note that this does not start any new transactions. If any existing transaction
|
||||
* is flushed, and this is called, then queries will reflect the point the DB was synced
|
||||
* up to (on success) without interference from REPEATABLE-READ snapshots.
|
||||
* Note that this does not start any new transactions.
|
||||
*
|
||||
* Callers might want to flush any existing transaction before invoking this method.
|
||||
* Upon success, this assures that replica server queries will reflect all changes up
|
||||
* to the given position, without interference from prior REPEATABLE-READ snapshots.
|
||||
*
|
||||
* @param DBPrimaryPos $pos
|
||||
* @param int $timeout The maximum number of seconds to wait for synchronisation
|
||||
* @return int|null Zero if the replica DB was past that position already,
|
||||
* @return int|null Zero if the replica DB server was past that position already,
|
||||
* greater than zero if we waited for some period of time, less than
|
||||
* zero if it timed out, and null on error
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
|
|
@ -1094,7 +1096,7 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
public function getPrimaryPos();
|
||||
|
||||
/**
|
||||
* @return bool Whether the DB is marked as read-only server-side
|
||||
* @return bool Whether the DB server is marked as read-only server-side
|
||||
* @throws DBError If an error occurs, {@see query}
|
||||
* @since 1.28
|
||||
*/
|
||||
|
|
@ -1350,8 +1352,8 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
*
|
||||
* Note that a call to IDatabase::rollback() will also roll back any open atomic sections.
|
||||
*
|
||||
* @note As a micro-optimization to save a few DB calls, this method may only
|
||||
* be called when startAtomic() was called with the ATOMIC_CANCELABLE flag.
|
||||
* @note As an optimization to save rountrips, this method may only be called
|
||||
* when startAtomic() was called with the ATOMIC_CANCELABLE flag.
|
||||
* @since 1.31
|
||||
* @see IDatabase::startAtomic
|
||||
* @param string $fname
|
||||
|
|
@ -1423,7 +1425,7 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* @see Database::cancelAtomic
|
||||
*
|
||||
* @param string $fname Caller name (usually __METHOD__)
|
||||
* @param callable $callback Callback that issues DB updates
|
||||
* @param callable $callback Callback that issues write queries
|
||||
* @param string $cancelable Pass self::ATOMIC_CANCELABLE to use a
|
||||
* savepoint and enable self::cancelAtomic() for this section.
|
||||
* @return mixed Result of the callback (since 1.28)
|
||||
|
|
@ -1524,7 +1526,8 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
* This is intended for clearing out REPEATABLE-READ snapshots so that callers can
|
||||
* see a new point-in-time of the database. This is useful when one of many transaction
|
||||
* rounds finished and significant time will pass in the script's lifetime. It is also
|
||||
* useful to call on a replica DB after waiting on replication to catch up to the primary DB.
|
||||
* useful to call on a replica server after waiting on replication to catch up to the
|
||||
* primary server.
|
||||
*
|
||||
* @param string $fname Calling function name
|
||||
* @param string $flush Flush flag, set to situationally valid IDatabase::FLUSHING_*
|
||||
|
|
@ -1558,7 +1561,7 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
public function getLag();
|
||||
|
||||
/**
|
||||
* Get the replica DB lag when the current transaction started
|
||||
* Get the replica server lag when the current transaction started
|
||||
* or a general lag estimate if not transaction is active
|
||||
*
|
||||
* This is useful when transactions might use snapshot isolation
|
||||
|
|
@ -1649,7 +1652,7 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
/**
|
||||
* Acquire a named lock, flush any transaction, and return an RAII style unlocker object
|
||||
*
|
||||
* Only call this from outer transaction scope and when only one DB will be affected.
|
||||
* Only call this from outer transaction scope and when only one DB server will be affected.
|
||||
* See https://www.mediawiki.org/wiki/Database_transactions for details.
|
||||
*
|
||||
* This is suitable for transactions that need to be serialized using cooperative locks,
|
||||
|
|
@ -1689,7 +1692,7 @@ interface IDatabase extends ISQLPlatform, DbQuoter, IDatabaseFlags {
|
|||
public function setBigSelects( $value = true );
|
||||
|
||||
/**
|
||||
* @return bool Whether this DB is read-only
|
||||
* @return bool Whether this DB server is read-only
|
||||
* @since 1.27
|
||||
*/
|
||||
public function isReadOnly();
|
||||
|
|
|
|||
|
|
@ -517,10 +517,9 @@ interface ILoadBalancer {
|
|||
|
||||
/**
|
||||
* @note This method will trigger a DB connection if not yet done
|
||||
* @param string|false $domain DB domain ID or false for the local domain
|
||||
* @return bool Whether the database for generic connections this request is highly "lagged"
|
||||
*/
|
||||
public function getLaggedReplicaMode( $domain = false );
|
||||
public function getLaggedReplicaMode();
|
||||
|
||||
/**
|
||||
* Checks whether the database for generic connections this request was both:
|
||||
|
|
@ -534,7 +533,7 @@ interface ILoadBalancer {
|
|||
|
||||
/**
|
||||
* @note This method may trigger a DB connection if not yet done
|
||||
* @param string|false $domain DB domain ID or false for the local domain
|
||||
* @param string|false $domain DB domain ID or false (unused and deprecated since 1.40)
|
||||
* @return string|false Reason the primary is read-only or false if it is not
|
||||
*/
|
||||
public function getReadOnlyReason( $domain = false );
|
||||
|
|
@ -551,10 +550,9 @@ interface ILoadBalancer {
|
|||
* May attempt to open connections to replica DBs on the default DB. If there is
|
||||
* no lag, the maximum lag will be reported as -1.
|
||||
*
|
||||
* @param string|false $domain Domain ID or false for the default database
|
||||
* @return array{0:string,1:float|int|false,2:int} (host, max lag, index of max lagged host)
|
||||
*/
|
||||
public function getMaxLag( $domain = false );
|
||||
public function getMaxLag();
|
||||
|
||||
/**
|
||||
* Get an estimate of replication lag (in seconds) for each server
|
||||
|
|
@ -563,10 +561,9 @@ interface ILoadBalancer {
|
|||
*
|
||||
* Values may be "false" if replication is too broken to estimate
|
||||
*
|
||||
* @param string|false $domain
|
||||
* @return float[]|int[]|false[] Map of (server index => lag) in order of server index
|
||||
*/
|
||||
public function getLagTimes( $domain = false );
|
||||
public function getLagTimes();
|
||||
|
||||
/**
|
||||
* Wait for a replica DB to reach a specified primary position
|
||||
|
|
|
|||
|
|
@ -447,12 +447,11 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
|
||||
/**
|
||||
* @param array $loads
|
||||
* @param string $domain Resolved DB domain
|
||||
* @param int|float $maxLag Restrict the maximum allowed lag to this many seconds, or INF for no max
|
||||
* @return int|string|false
|
||||
*/
|
||||
private function getRandomNonLagged( array $loads, string $domain, $maxLag = INF ) {
|
||||
$lags = $this->getLagTimes( $domain );
|
||||
private function getRandomNonLagged( array $loads, $maxLag = INF ) {
|
||||
$lags = $this->getLagTimes();
|
||||
|
||||
# Unset excessively lagged servers
|
||||
foreach ( $lags as $i => $lag ) {
|
||||
|
|
@ -645,11 +644,11 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
// avoid lagged servers so as to avoid excessive delay in that method.
|
||||
$ago = microtime( true ) - $this->waitForPos->asOfTime();
|
||||
// Aim for <= 1 second of waiting (being too picky can backfire)
|
||||
$i = $this->getRandomNonLagged( $currentLoads, $domain, $ago + 1 );
|
||||
$i = $this->getRandomNonLagged( $currentLoads, $ago + 1 );
|
||||
}
|
||||
if ( $i === false ) {
|
||||
// Any server with less lag than it's 'max lag' param is preferable
|
||||
$i = $this->getRandomNonLagged( $currentLoads, $domain );
|
||||
$i = $this->getRandomNonLagged( $currentLoads );
|
||||
}
|
||||
if ( $i === false && count( $currentLoads ) ) {
|
||||
// All replica DBs lagged. Switch to read-only mode
|
||||
|
|
@ -956,7 +955,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
if (
|
||||
$conn &&
|
||||
$serverIndex === $this->getWriterIndex() &&
|
||||
$this->getLaggedReplicaMode( $domain ) &&
|
||||
$this->getLaggedReplicaMode() &&
|
||||
!is_string( $conn->getLBInfo( $conn::LB_READ_ONLY_REASON ) )
|
||||
) {
|
||||
$genericIndex = $this->getExistingReaderIndex( self::GROUP_GENERIC );
|
||||
|
|
@ -1348,7 +1347,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
? ( $domain->getDatabase() ?? $server['dbname'] ?? null )
|
||||
: $domain->getDatabase(),
|
||||
// Override the $server default schema with that of $domain if specified
|
||||
'schema' => $domain->getSchema() ?? $server['schema'] ?? null,
|
||||
'schema' => $domain->getSchema(),
|
||||
// Use the table prefix specified in $domain
|
||||
'tablePrefix' => $domain->getTablePrefix(),
|
||||
// Participate in transaction rounds if $server does not specify otherwise
|
||||
|
|
@ -2101,9 +2100,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function getLaggedReplicaMode( $domain = false ) {
|
||||
$domain = $this->resolveDomainID( $domain );
|
||||
|
||||
public function getLaggedReplicaMode() {
|
||||
if ( $this->laggedReplicaMode ) {
|
||||
// Stay in lagged replica mode once it is observed on any domain
|
||||
return true;
|
||||
|
|
@ -2111,7 +2108,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
|
||||
if ( $this->hasStreamingReplicaServers() ) {
|
||||
// This will set "laggedReplicaMode" as needed
|
||||
$this->getReaderIndex( self::GROUP_GENERIC, $domain );
|
||||
$this->getReaderIndex( self::GROUP_GENERIC, self::DOMAIN_ANY );
|
||||
}
|
||||
|
||||
return $this->laggedReplicaMode;
|
||||
|
|
@ -2122,13 +2119,11 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
}
|
||||
|
||||
public function getReadOnlyReason( $domain = false ) {
|
||||
$domainInstance = DatabaseDomain::newFromId( $this->resolveDomainID( $domain ) );
|
||||
|
||||
if ( $this->readOnlyReason !== false ) {
|
||||
return $this->readOnlyReason;
|
||||
} elseif ( $this->isPrimaryRunningReadOnly( $domainInstance ) ) {
|
||||
} elseif ( $this->isPrimaryRunningReadOnly() ) {
|
||||
return 'The primary database server is running in read-only mode.';
|
||||
} elseif ( $this->getLaggedReplicaMode( $domain ) ) {
|
||||
} elseif ( $this->getLaggedReplicaMode() ) {
|
||||
$genericIndex = $this->getExistingReaderIndex( self::GROUP_GENERIC );
|
||||
|
||||
return ( $genericIndex !== self::READER_INDEX_NONE )
|
||||
|
|
@ -2147,12 +2142,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
*/
|
||||
private function isPrimaryConnectionReadOnly( IDatabase $conn, $flags = 0 ) {
|
||||
// Note that table prefixes are not related to server-side read-only mode
|
||||
$key = $this->srvCache->makeGlobalKey(
|
||||
'rdbms-server-readonly',
|
||||
$conn->getServerName(),
|
||||
(string)$conn->getDBname(),
|
||||
(string)$conn->dbSchema()
|
||||
);
|
||||
$key = $this->srvCache->makeGlobalKey( 'rdbms-server-readonly', $conn->getServerName() );
|
||||
|
||||
if ( self::fieldHasBit( $flags, self::CONN_REFRESH_READ_ONLY ) ) {
|
||||
// Refresh the local server cache. This is useful when the caller is
|
||||
|
|
@ -2184,28 +2174,25 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
|
||||
/**
|
||||
* @note This method suppresses DBError exceptions in order to avoid severe downtime
|
||||
* @param DatabaseDomain $domain
|
||||
* @return bool Whether the entire primary DB server or the local domain DB is read-only
|
||||
*/
|
||||
private function isPrimaryRunningReadOnly( DatabaseDomain $domain ) {
|
||||
private function isPrimaryRunningReadOnly() {
|
||||
// Context will often be HTTP GET/HEAD; heavily cache the results
|
||||
return (bool)$this->wanCache->getWithSetCallback(
|
||||
// Note that table prefixes are not related to server-side read-only mode
|
||||
$this->wanCache->makeGlobalKey(
|
||||
'rdbms-server-readonly',
|
||||
$this->getPrimaryServerName(),
|
||||
$domain->getDatabase(),
|
||||
(string)$domain->getSchema()
|
||||
$this->getPrimaryServerName()
|
||||
),
|
||||
self::TTL_CACHE_READONLY,
|
||||
function () use ( $domain ) {
|
||||
function () {
|
||||
$scope = $this->trxProfiler->silenceForScope();
|
||||
|
||||
$index = $this->getWriterIndex();
|
||||
// Refresh the local server cache as well. This is done in order to avoid
|
||||
// backfilling the WANCache with data that is already significantly stale
|
||||
$flags = self::CONN_SILENCE_ERRORS | self::CONN_REFRESH_READ_ONLY;
|
||||
$conn = $this->getServerConnection( $index, $domain->getId(), $flags );
|
||||
$conn = $this->getServerConnection( $index, self::DOMAIN_ANY, $flags );
|
||||
if ( $conn ) {
|
||||
try {
|
||||
$readOnly = (int)$this->isPrimaryConnectionReadOnly( $conn );
|
||||
|
|
@ -2314,15 +2301,13 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
return $count;
|
||||
}
|
||||
|
||||
public function getMaxLag( $domain = false ) {
|
||||
$domain = $this->resolveDomainID( $domain );
|
||||
|
||||
public function getMaxLag() {
|
||||
$host = '';
|
||||
$maxLag = -1;
|
||||
$maxIndex = 0;
|
||||
|
||||
if ( $this->hasReplicaServers() ) {
|
||||
$lagTimes = $this->getLagTimes( $domain );
|
||||
$lagTimes = $this->getLagTimes();
|
||||
foreach ( $lagTimes as $i => $lag ) {
|
||||
if ( $this->groupLoads[self::GROUP_GENERIC][$i] > 0 && $lag > $maxLag ) {
|
||||
$maxLag = $lag;
|
||||
|
|
@ -2335,9 +2320,7 @@ class LoadBalancer implements ILoadBalancerForOwner {
|
|||
return [ $host, $maxLag, $maxIndex ];
|
||||
}
|
||||
|
||||
public function getLagTimes( $domain = false ) {
|
||||
$domain = $this->resolveDomainID( $domain );
|
||||
|
||||
public function getLagTimes() {
|
||||
if ( !$this->hasReplicaServers() ) {
|
||||
return [ $this->getWriterIndex() => 0 ]; // no replication = no lag
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue