wiki.techinc.nl/includes/deferred/AutoCommitUpdate.php
Timo Tijhof aca3c8203a deferred: Make DeferredUpdates docs more accessible
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
2023-08-25 01:16:17 +01:00

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;
}
}