In prep for the next decoupling commit: * Rephrase introduction to state what its actually for in practice. * Remove mentions of implementation details in favour of inline comments, especially stuff relating to databases. Except for 1 thing, every integration with databases is already fully decoupled. Automatic cancellation on rollback works by having the caller pass on an IDatabase object to addCallableUpdate() for that specific update, which works even if it came from an unknown LBFactory or unknown service containter. Oppertunistic execution is triggered by service wiring, where MWLBFactory takes responsibility for having LBFactory notify the DeferredUpdates singleton; not the other way around. Bug: T265749 Change-Id: I048d22ffe2fa3838d9a5f4aa4128c756185a6b2e
66 lines
1.7 KiB
PHP
66 lines
1.7 KiB
PHP
<?php
|
|
|
|
use Wikimedia\Rdbms\IDatabase;
|
|
|
|
/**
|
|
* Deferrable Update for closure/callback updates that should use auto-commit mode
|
|
* @since 1.28
|
|
*/
|
|
class AutoCommitUpdate implements DeferrableUpdate, DeferrableCallback {
|
|
/** @var IDatabase */
|
|
private $dbw;
|
|
/** @var string */
|
|
private $fname;
|
|
/** @var callable|null */
|
|
private $callback;
|
|
|
|
/**
|
|
* @param IDatabase $dbw DB handle; update aborts if a transaction now this rolls back
|
|
* @param string $fname Caller name (usually __METHOD__)
|
|
* @param callable $callback Callback that takes (IDatabase, method name string)
|
|
* @param IDatabase[] $conns Cancel the update if a transaction on these
|
|
* connections is rolled back [optional]
|
|
*/
|
|
public function __construct( IDatabase $dbw, $fname, callable $callback, array $conns = [] ) {
|
|
$this->dbw = $dbw;
|
|
$this->fname = $fname;
|
|
$this->callback = $callback;
|
|
// Register DB connections for which uncommitted changes are related to this update
|
|
$conns[] = $dbw;
|
|
foreach ( $conns as $conn ) {
|
|
if ( $conn->trxLevel() ) {
|
|
$conn->onTransactionResolution( [ $this, 'cancelOnRollback' ], $fname );
|
|
}
|
|
}
|
|
}
|
|
|
|
public function doUpdate() {
|
|
if ( !$this->callback ) {
|
|
return;
|
|
}
|
|
|
|
$autoTrx = $this->dbw->getFlag( DBO_TRX );
|
|
$this->dbw->clearFlag( DBO_TRX );
|
|
try {
|
|
( $this->callback )( $this->dbw, $this->fname );
|
|
} finally {
|
|
if ( $autoTrx ) {
|
|
$this->dbw->setFlag( DBO_TRX );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @internal This method is public so that it works with onTransactionResolution()
|
|
* @param int $trigger
|
|
*/
|
|
public function cancelOnRollback( $trigger ) {
|
|
if ( $trigger === IDatabase::TRIGGER_ROLLBACK ) {
|
|
$this->callback = null;
|
|
}
|
|
}
|
|
|
|
public function getOrigin() {
|
|
return $this->fname;
|
|
}
|
|
}
|