use EmptyBagOStuff;
use WANObjectCache;
use ArrayUtils;
+use UnexpectedValueException;
use InvalidArgumentException;
use RuntimeException;
use Exception;
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;
$this->maxLag = $params['maxLag'];
}
- if ( isset( $params['loadMonitor'] ) ) {
- $this->loadMonitorConfig = $params['loadMonitor'];
- } else {
- $this->loadMonitorConfig = [ 'class' => 'LoadMonitorNull' ];
- }
+ $this->loadMonitorConfig = $params['loadMonitor'] ?? [ 'class' => 'LoadMonitorNull' ];
$this->loadMonitorConfig += [ 'lagWarnThreshold' => $this->maxLag ];
foreach ( $params['servers'] as $i => $server ) {
}
}
- if ( isset( $params['srvCache'] ) ) {
- $this->srvCache = $params['srvCache'];
- } else {
- $this->srvCache = new EmptyBagOStuff();
- }
- if ( isset( $params['wanCache'] ) ) {
- $this->wanCache = $params['wanCache'];
- } else {
- $this->wanCache = WANObjectCache::newEmpty();
- }
+ $this->srvCache = $params['srvCache'] ?? new EmptyBagOStuff();
+ $this->wanCache = $params['wanCache'] ?? WANObjectCache::newEmpty();
$this->profiler = $params['profiler'] ?? null;
- if ( isset( $params['trxProfiler'] ) ) {
- $this->trxProfiler = $params['trxProfiler'];
- } else {
- $this->trxProfiler = new TransactionProfiler();
- }
+ $this->trxProfiler = $params['trxProfiler'] ?? new TransactionProfiler();
$this->errorLogger = $params['errorLogger'] ?? function ( Exception $e ) {
trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
}
}
+ // Final sanity check to make sure the right domain is selected
+ if (
+ $conn instanceof IDatabase &&
+ !$this->localDomain->isCompatible( $conn->getDomainID() )
+ ) {
+ throw new UnexpectedValueException(
+ "Got connection to '{$conn->getDomainID()}', " .
+ "but expected local domain ('{$this->localDomain}')." );
+ }
+
return $conn;
}
* @param int $i Server index
* @param string $domain Domain ID to open
* @param int $flags Class CONN_* constant bitfield
- * @return Database
+ * @return Database|bool Returns false on connection error
+ * @throws DBError When database selection fails
*/
private function openForeignConnection( $i, $domain, $flags = 0 ) {
$domainInstance = DatabaseDomain::newFromId( $domain );
- $dbName = $domainInstance->getDatabase();
- $prefix = $domainInstance->getTablePrefix();
$autoCommit = ( ( $flags & self::CONN_TRX_AUTOCOMMIT ) == self::CONN_TRX_AUTOCOMMIT );
if ( $autoCommit ) {
$connInUseKey = self::KEY_FOREIGN_INUSE;
}
+ /** @var Database $conn */
if ( isset( $this->conns[$connInUseKey][$i][$domain] ) ) {
// Reuse an in-use connection for the same domain
$conn = $this->conns[$connInUseKey][$i][$domain];
// Reuse a free connection from another domain
$conn = reset( $this->conns[$connFreeKey][$i] );
$oldDomain = key( $this->conns[$connFreeKey][$i] );
- if ( strlen( $dbName ) && !$conn->selectDB( $dbName ) ) {
- $this->lastError = "Error selecting database '$dbName' on server " .
- $conn->getServer() . " from client host {$this->hostname}";
- $this->errorConnection = $conn;
- $conn = false;
+ if ( $domainInstance->getDatabase() !== null ) {
+ $conn->selectDomain( $domainInstance );
} else {
- $conn->tablePrefix( $prefix );
- 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" );
+ // 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" );
} else {
if ( !isset( $this->servers[$i] ) || !is_array( $this->servers[$i] ) ) {
throw new InvalidArgumentException( "No server with index '$i'." );
}
}
- // Increment reference count
if ( $conn instanceof IDatabase ) {
+ // Final sanity check to make sure the right domain is selected
+ if ( !$domainInstance->isCompatible( $conn->getDomainID() ) ) {
+ throw new UnexpectedValueException(
+ "Got connection to '{$conn->getDomainID()}', but expected '$domain'." );
+ }
+ // Increment reference count
$refCount = $conn->getLBInfo( 'foreignPoolRefCount' );
$conn->setLBInfo( 'foreignPoolRefCount', $refCount + 1 );
}
}
public function getServerName( $i ) {
- if ( isset( $this->servers[$i]['hostName'] ) ) {
- $name = $this->servers[$i]['hostName'];
- } elseif ( isset( $this->servers[$i]['host'] ) ) {
- $name = $this->servers[$i]['host'];
- } else {
- $name = '';
- }
+ $name = $this->servers[$i]['hostName'] ?? $this->servers[$i]['host'] ?? '';
return ( $name != '' ) ? $name : 'localhost';
}
public function getServerInfo( $i ) {
- if ( isset( $this->servers[$i] ) ) {
- return $this->servers[$i];
- } else {
- return false;
- }
+ return $this->servers[$i] ?? false;
}
public function getServerType( $i ) {
// If atomic sections or explicit transactions are still open, some caller must have
// caught an exception but failed to properly rollback any changes. Detect that and
// throw and error (causing rollback).
- if ( $conn->explicitTrxActive() ) {
- throw new DBTransactionError(
- $conn,
- "Explicit transaction still active. A caller may have caught an error."
- );
- }
+ $conn->assertNoOpenTransactions();
// Assert that the time to replicate the transaction will be sane.
// If this fails, then all DB transactions will be rollback back together.
$time = $conn->pendingWriteQueryDuration( $conn::ESTIMATE_DB_APPLY );