* This makes sense when lag being waiting on is caused by the code that does this check.
* In that case, setting "ifWritesSince" can avoid the overhead of waiting for clusters
* that were not changed since the last wait check. To forcefully wait on a specific cluster
- * for a given wiki, use the 'wiki' parameter. To forcefully wait on an "external" cluster,
+ * for a given domain, use the 'domain' parameter. To forcefully wait on an "external" cluster,
* use the "cluster" parameter.
*
* Never call this function after a large DB write that is *still* in a transaction.
* It only makes sense to call this after the possible lag inducing changes were committed.
*
* @param array $opts Optional fields that include:
- * - wiki : wait on the load balancer DBs that handles the given wiki
+ * - domain : wait on the load balancer DBs that handles the given domain ID
* - cluster : wait on the given external load balancer DBs
* - timeout : Max wait time. Default: ~60 seconds
* - ifWritesSince: Only wait if writes were done since this UNIX timestamp
*/
public function waitForReplication( array $opts = [] ) {
$opts += [
- 'wiki' => false,
+ 'domain' => false,
'cluster' => false,
'timeout' => 60,
'ifWritesSince' => null
];
+ if ( $opts['domain'] === false && isset( $opts['wiki'] ) ) {
+ $opts['domain'] = $opts['wiki']; // b/c
+ }
+
// Figure out which clusters need to be checked
/** @var ILoadBalancer[] $lbs */
$lbs = [];
if ( $opts['cluster'] !== false ) {
$lbs[] = $this->getExternalLB( $opts['cluster'] );
- } elseif ( $opts['wiki'] !== false ) {
- $lbs[] = $this->getMainLB( $opts['wiki'] );
+ } elseif ( $opts['domain'] !== false ) {
+ $lbs[] = $this->getMainLB( $opts['domain'] );
} else {
$this->forEachLB( function ( ILoadBalancer $lb ) use ( &$lbs ) {
$lbs[] = $lb;
$this->mReadIndex = -1;
$this->mConns = [
- 'local' => [],
+ 'local' => [],
'foreignUsed' => [],
- 'foreignFree' => [] ];
+ 'foreignFree' => []
+ ];
$this->mLoads = [];
$this->mWaitForPos = false;
$this->mErrorConnection = false;
return;
}
- $dbName = $conn->getDBname();
- $prefix = $conn->tablePrefix();
- if ( strval( $prefix ) !== '' ) {
- $domain = "$dbName-$prefix";
- } else {
- $domain = $dbName;
- }
+ $domain = $conn->getDomainID();
if ( $this->mConns['foreignUsed'][$serverIndex][$domain] !== $conn ) {
- throw new InvalidArgumentException( __METHOD__ . ": connection not found, has " .
- "the connection been freed already?" );
+ throw new InvalidArgumentException( __METHOD__ .
+ ": connection not found, has the connection been freed already?" );
}
$conn->setLBInfo( 'foreignPoolRefCount', --$refCount );
if ( $refCount <= 0 ) {
$this->mConns['foreignFree'][$serverIndex][$domain] = $conn;
unset( $this->mConns['foreignUsed'][$serverIndex][$domain] );
+ if ( !$this->mConns['foreignUsed'][$serverIndex] ) {
+ unset( $this->mConns[ 'foreignUsed' ][$serverIndex] ); // clean up
+ }
$this->connLogger->debug( __METHOD__ . ": freed connection $serverIndex/$domain" );
} else {
$this->connLogger->debug( __METHOD__ .
// Reuse a connection from another domain
$conn = reset( $this->mConns['foreignFree'][$i] );
$oldDomain = key( $this->mConns['foreignFree'][$i] );
-
// The empty string as a DB name means "don't care".
// DatabaseMysqlBase::open() already handle this on connection.
- if ( $dbName !== '' && !$conn->selectDB( $dbName ) ) {
- $this->mLastError = "Error selecting database $dbName on server " .
+ if ( strlen( $dbName ) && !$conn->selectDB( $dbName ) ) {
+ $this->mLastError = "Error selecting database '$dbName' on server " .
$conn->getServer() . " from client host {$this->host}";
$this->mErrorConnection = $conn;
$conn = false;
* @access private
*
* @param array $server
- * @param bool $dbNameOverride
+ * @param string|bool $dbNameOverride Use "" to not select any database
* @return IDatabase
* @throws DBAccessError
* @throws InvalidArgumentException
}
public function setDomainPrefix( $prefix ) {
+ if ( $this->mConns['foreignUsed'] ) {
+ // Do not switch connections to explicit foreign domains unless marked as free
+ $domains = [];
+ foreach ( $this->mConns['foreignUsed'] as $i => $connsByDomain ) {
+ $domains = array_merge( $domains, array_keys( $connsByDomain ) );
+ }
+ $domains = implode( ', ', $domains );
+ throw new DBUnexpectedError( null,
+ "Foreign domain connections are still in use ($domains)." );
+ }
+
$this->localDomain = new DatabaseDomain(
$this->localDomain->getDatabase(),
null,