private $srvCache;
/** @var WANObjectCache */
private $wanCache;
- /** @var object|string Class name or object With profileIn/profileOut methods */
+ /** @var mixed Class name or object With profileIn/profileOut methods */
private $profiler;
/** @var TransactionProfiler */
private $trxProfiler;
}
/** @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'." );
}
$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;
}
}
- /**
- * 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();