if ( isset( $params['chronologyCallback'] ) ) {
$this->chronologyCallback = $params['chronologyCallback'];
}
+
+ if ( isset( $params['roundStage'] ) ) {
+ if ( $params['roundStage'] === self::STAGE_POSTCOMMIT_CALLBACKS ) {
+ $this->trxRoundStage = self::ROUND_COMMIT_CALLBACKS;
+ } elseif ( $params['roundStage'] === self::STAGE_POSTROLLBACK_CALLBACKS ) {
+ $this->trxRoundStage = self::ROUND_ROLLBACK_CALLBACKS;
+ }
+ }
}
/**
return ( $name != '' ) ? $name : 'localhost';
}
+ public function getServerInfo( $i ) {
+ if ( isset( $this->servers[$i] ) ) {
+ return $this->servers[$i];
+ } else {
+ return false;
+ }
+ }
+
public function getServerType( $i ) {
return isset( $this->servers[$i]['type'] ) ? $this->servers[$i]['type'] : 'unknown';
}
}
public function finalizeMasterChanges() {
- $this->assertTransactionRoundStage( self::ROUND_CURSORY );
+ $this->assertTransactionRoundStage( [ self::ROUND_CURSORY, self::ROUND_FINALIZED ] );
$this->trxRoundStage = self::ROUND_ERROR; // "failed" until proven otherwise
// Loop until callbacks stop adding callbacks on other connections
+ $total = 0;
do {
$count = 0; // callbacks execution attempts
$this->forEachOpenMasterConnection( function ( Database $conn ) use ( &$count ) {
// Any error should cause all (peer) transactions to be rolled back together.
$count += $conn->runOnTransactionPreCommitCallbacks();
} );
+ $total += $count;
} while ( $count > 0 );
// Defer post-commit callbacks until after COMMIT/ROLLBACK happens on all handles
$this->forEachOpenMasterConnection( function ( Database $conn ) {
$conn->setTrxEndCallbackSuppression( true );
} );
$this->trxRoundStage = self::ROUND_FINALIZED;
+
+ return $total;
}
public function approveMasterChanges( array $options ) {
if ( $conn->writesPending() ) {
// A callback from another handle wrote to this one and DBO_TRX is set
$this->queryLogger->warning( __METHOD__ . ": found writes pending." );
+ $fnames = implode( ', ', $conn->pendingWriteAndCallbackCallers() );
+ $this->queryLogger->warning(
+ __METHOD__ . ": found writes pending ($fnames).",
+ [
+ 'db_server' => $conn->getServer(),
+ 'db_name' => $conn->getDBname()
+ ]
+ );
} elseif ( $conn->trxLevel() ) {
// A callback from another handle read from this one and DBO_TRX is set,
// which can easily happen if there is only one DB (no replicas)
}
/**
- * @param string $stage
+ * @param string|string[] $stage
*/
private function assertTransactionRoundStage( $stage ) {
- if ( $this->trxRoundStage !== $stage ) {
+ $stages = (array)$stage;
+
+ if ( !in_array( $this->trxRoundStage, $stages, true ) ) {
+ $stageList = implode(
+ '/',
+ array_map( function ( $v ) {
+ return "'$v'";
+ }, $stages )
+ );
throw new DBTransactionError(
null,
- "Transaction round stage must be '$stage' (not '{$this->trxRoundStage}')"
+ "Transaction round stage must be $stageList (not '{$this->trxRoundStage}')"
);
}
}
} );
}
- private function flushMasterSnapshots( $fname = __METHOD__ ) {
+ public function flushMasterSnapshots( $fname = __METHOD__ ) {
$this->forEachOpenMasterConnection( function ( IDatabase $conn ) use ( $fname ) {
$conn->flushSnapshot( $fname );
} );
}
}
+/**
+ * @deprecated since 1.29
+ */
class_alias( LoadBalancer::class, 'LoadBalancer' );