": server {host} is not replicating?", [ 'host' => $host ] );
unset( $loads[$i] );
} elseif ( $lag > $maxServerLag ) {
- $this->replLogger->info(
+ $this->replLogger->debug(
__METHOD__ .
": server {host} has {lag} seconds of lag (>= {maxlag})",
[ 'host' => $host, 'lag' => $lag, 'maxlag' => $maxServerLag ]
}
/** @var Database $conn */
+ $conn = null;
+
if ( isset( $this->conns[$connInUseKey][$i][$domain] ) ) {
// Reuse an in-use connection for the same domain
$conn = $this->conns[$connInUseKey][$i][$domain];
$this->conns[$connInUseKey][$i][$domain] = $conn;
$this->connLogger->debug( __METHOD__ . ": reusing free connection $i/$domain" );
} elseif ( !empty( $this->conns[$connFreeKey][$i] ) ) {
- // Reuse a free connection from another domain
- $conn = reset( $this->conns[$connFreeKey][$i] );
- $oldDomain = key( $this->conns[$connFreeKey][$i] );
- if ( $domainInstance->getDatabase() !== null ) {
- $conn->selectDomain( $domainInstance );
- } else {
- // Stay on the current database, but update the schema/prefix
- $conn->dbSchema( $domainInstance->getSchema() );
- $conn->tablePrefix( $domainInstance->getTablePrefix() );
+ // Reuse a free connection from another domain if possible
+ foreach ( $this->conns[$connFreeKey][$i] as $oldDomain => $conn ) {
+ if ( $domainInstance->getDatabase() !== null ) {
+ // Check if changing the database will require a new connection.
+ // In that case, leave the connection handle alone and keep looking.
+ // This prevents connections from being closed mid-transaction and can
+ // also avoid overhead if the same database will later be requested.
+ if (
+ $conn->databasesAreIndependent() &&
+ $conn->getDBname() !== $domainInstance->getDatabase()
+ ) {
+ continue;
+ }
+ // Select the new database, schema, and prefix
+ $conn->selectDomain( $domainInstance );
+ } else {
+ // Stay on the current database, but update the schema/prefix
+ $conn->dbSchema( $domainInstance->getSchema() );
+ $conn->tablePrefix( $domainInstance->getTablePrefix() );
+ }
+ unset( $this->conns[$connFreeKey][$i][$oldDomain] );
+ // Note that if $domain is an empty string, getDomainID() might not match it
+ $this->conns[$connInUseKey][$i][$conn->getDomainId()] = $conn;
+ $this->connLogger->debug( __METHOD__ .
+ ": reusing free connection from $oldDomain for $domain" );
+ break;
}
- unset( $this->conns[$connFreeKey][$i][$oldDomain] );
- // Note that if $domain is an empty string, getDomainID() might not match it
- $this->conns[$connInUseKey][$i][$conn->getDomainId()] = $conn;
- $this->connLogger->debug( __METHOD__ .
- ": reusing free connection from $oldDomain for $domain" );
- } else {
+ }
+
+ if ( !$conn ) {
if ( !isset( $this->servers[$i] ) || !is_array( $this->servers[$i] ) ) {
throw new InvalidArgumentException( "No server with index '$i'." );
}
}
public function closeConnection( IDatabase $conn ) {
+ if ( $conn instanceof DBConnRef ) {
+ // Avoid calling close() but still leaving the handle in the pool
+ throw new RuntimeException( __METHOD__ . ': got DBConnRef instance.' );
+ }
+
$serverIndex = $conn->getLBInfo( 'serverIndex' );
foreach ( $this->conns as $type => $connsByServer ) {
if ( !isset( $connsByServer[$serverIndex] ) ) {
$failures = [];
/** @noinspection PhpUnusedLocalVariableInspection */
- $scope = $this->getScopedPHPBehaviorForCommit(); // try to ignore client aborts
+ $scope = ScopedCallback::newScopedIgnoreUserAbort(); // try to ignore client aborts
$restore = ( $this->trxRoundId !== false );
$this->trxRoundId = false;
$this->indexAliases = $aliases;
}
+ /**
+ * @param string $prefix
+ * @deprecated Since 1.33
+ */
public function setDomainPrefix( $prefix ) {
+ $this->setLocalDomainPrefix( $prefix );
+ }
+
+ public function setLocalDomainPrefix( $prefix ) {
// Find connections to explicit foreign domains still marked as in-use...
$domainsInUse = [];
$this->forEachOpenConnection( function ( IDatabase $conn ) use ( &$domainsInUse ) {
} );
}
+ public function redefineLocalDomain( $domain ) {
+ $this->closeAll();
+
+ $this->setLocalDomain( DatabaseDomain::newFromId( $domain ) );
+ }
+
/**
* @param DatabaseDomain $domain
*/
}
}
- /**
- * Make PHP ignore user aborts/disconnects until the returned
- * value leaves scope. This returns null and does nothing in CLI mode.
- *
- * @return ScopedCallback|null
- */
- final protected function getScopedPHPBehaviorForCommit() {
- if ( PHP_SAPI != 'cli' ) { // https://bugs.php.net/bug.php?id=47540
- $old = ignore_user_abort( true ); // avoid half-finished operations
- return new ScopedCallback( function () use ( $old ) {
- ignore_user_abort( $old );
- } );
- }
-
- return null;
- }
-
function __destruct() {
// Avoid connection leaks for sanity
$this->disable();