X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Fdb%2FDatabase.php;h=3dc6e9213b78efeae22b9daccaf1bbbaff2046d4;hp=16ea219290a38e4908fb20ecd54713545490711d;hb=708c02281e6e8880ae2cebbda7f353ce97841f94;hpb=45267f9f0cfe5349a4cc418fc1ad91ccc130355b diff --git a/includes/db/Database.php b/includes/db/Database.php index 16ea219290..3dc6e9213b 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -58,6 +58,8 @@ abstract class DatabaseBase implements IDatabase { protected $mTrxPreCommitCallbacks = []; /** @var array[] List of (callable, method name) */ protected $mTrxEndCallbacks = []; + /** @var bool Whether to suppress triggering of post-commit callbacks */ + protected $suppressPostCommitCallbacks = false; protected $mTablePrefix; protected $mSchema; @@ -694,9 +696,6 @@ abstract class DatabaseBase implements IDatabase { } public function close() { - if ( count( $this->mTrxIdleCallbacks ) ) { // sanity - throw new MWException( "Transaction idle callbacks still pending." ); - } if ( $this->mConn ) { if ( $this->trxLevel() ) { if ( !$this->mTrxAutomatic ) { @@ -709,6 +708,8 @@ abstract class DatabaseBase implements IDatabase { $closed = $this->closeConnection(); $this->mConn = false; + } elseif ( $this->mTrxIdleCallbacks || $this->mTrxEndCallbacks ) { // sanity + throw new MWException( "Transaction callbacks still pending." ); } else { $closed = true; } @@ -2387,14 +2388,19 @@ abstract class DatabaseBase implements IDatabase { * queries. If a deadlock occurs during the processing, the transaction * will be rolled back and the callback function will be called again. * + * Avoid using this method outside of Job or Maintenance classes. + * * Usage: * $dbw->deadlockLoop( callback, ... ); * * Extra arguments are passed through to the specified callback function. + * This method requires that no transactions are already active to avoid + * causing premature commits or exceptions. * * Returns whatever the callback function returned on its successful, * iteration, or false on error, for example if the retry limit was * reached. + * * @return mixed * @throws DBUnexpectedError * @throws Exception @@ -2450,6 +2456,10 @@ abstract class DatabaseBase implements IDatabase { return false; } + public function serverIsReadOnly() { + return false; + } + final public function onTransactionResolution( callable $callback ) { if ( !$this->mTrxLevel ) { throw new DBUnexpectedError( $this, "No transaction is active." ); @@ -2460,7 +2470,7 @@ abstract class DatabaseBase implements IDatabase { final public function onTransactionIdle( callable $callback ) { $this->mTrxIdleCallbacks[] = [ $callback, wfGetCaller() ]; if ( !$this->mTrxLevel ) { - $this->runOnTransactionIdleCallbacks(); + $this->runOnTransactionIdleCallbacks( self::TRIGGER_IDLE ); } } @@ -2468,16 +2478,43 @@ abstract class DatabaseBase implements IDatabase { if ( $this->mTrxLevel ) { $this->mTrxPreCommitCallbacks[] = [ $callback, wfGetCaller() ]; } else { - $this->onTransactionIdle( $callback ); // this will trigger immediately + // If no transaction is active, then make one for this callback + $this->begin( __METHOD__ ); + try { + call_user_func( $callback ); + $this->commit( __METHOD__ ); + } catch ( Exception $e ) { + $this->rollback( __METHOD__ ); + throw $e; + } } } /** - * Actually any "on transaction idle" callbacks. + * Whether to disable running of post-commit callbacks * + * This method should not be used outside of Database/LoadBalancer + * + * @param bool $suppress + * @since 1.28 + */ + final public function setPostCommitCallbackSupression( $suppress ) { + $this->suppressPostCommitCallbacks = $suppress; + } + + /** + * Actually run and consume any "on transaction idle/resolution" callbacks. + * + * This method should not be used outside of Database/LoadBalancer + * + * @param integer $trigger IDatabase::TRIGGER_* constant * @since 1.20 */ - protected function runOnTransactionIdleCallbacks() { + public function runOnTransactionIdleCallbacks( $trigger ) { + if ( $this->suppressPostCommitCallbacks ) { + return; + } + $autoTrx = $this->getFlag( DBO_TRX ); // automatic begin() enabled? $e = $ePrior = null; // last exception @@ -2486,13 +2523,13 @@ abstract class DatabaseBase implements IDatabase { $this->mTrxIdleCallbacks, $this->mTrxEndCallbacks // include "transaction resolution" callbacks ); - $this->mTrxIdleCallbacks = []; // recursion guard - $this->mTrxEndCallbacks = []; // recursion guard + $this->mTrxIdleCallbacks = []; // consumed (and recursion guard) + $this->mTrxEndCallbacks = []; // consumed (recursion guard) foreach ( $callbacks as $callback ) { try { list( $phpCallback ) = $callback; $this->clearFlag( DBO_TRX ); // make each query its own transaction - call_user_func( $phpCallback ); + call_user_func_array( $phpCallback, [ $trigger ] ); if ( $autoTrx ) { $this->setFlag( DBO_TRX ); // restore automatic begin() } else { @@ -2518,7 +2555,7 @@ abstract class DatabaseBase implements IDatabase { } /** - * Actually any "on transaction pre-commit" callbacks. + * Actually run and consume any "on transaction pre-commit" callbacks. * * This method should not be used outside of Database/LoadBalancer * @@ -2528,7 +2565,7 @@ abstract class DatabaseBase implements IDatabase { $e = $ePrior = null; // last exception do { // callbacks may add callbacks :) $callbacks = $this->mTrxPreCommitCallbacks; - $this->mTrxPreCommitCallbacks = []; // recursion guard + $this->mTrxPreCommitCallbacks = []; // consumed (and recursion guard) foreach ( $callbacks as $callback ) { try { list( $phpCallback ) = $callback; @@ -2563,12 +2600,12 @@ abstract class DatabaseBase implements IDatabase { final public function endAtomic( $fname = __METHOD__ ) { if ( !$this->mTrxLevel ) { - throw new DBUnexpectedError( $this, 'No atomic transaction is open.' ); + throw new DBUnexpectedError( $this, "No atomic transaction is open (got $fname)." ); } if ( !$this->mTrxAtomicLevels || array_pop( $this->mTrxAtomicLevels ) !== $fname ) { - throw new DBUnexpectedError( $this, 'Invalid atomic section ended.' ); + throw new DBUnexpectedError( $this, "Invalid atomic section ended (got $fname)." ); } if ( !$this->mTrxAtomicLevels && $this->mTrxAutomaticAtomic ) { @@ -2623,7 +2660,7 @@ abstract class DatabaseBase implements IDatabase { $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime ); } - $this->runOnTransactionIdleCallbacks(); + $this->runOnTransactionIdleCallbacks( self::TRIGGER_COMMIT ); } // Avoid fatals if close() was called @@ -2636,8 +2673,6 @@ abstract class DatabaseBase implements IDatabase { $this->mTrxAutomatic = false; $this->mTrxAutomaticAtomic = false; $this->mTrxAtomicLevels = []; - $this->mTrxIdleCallbacks = []; - $this->mTrxPreCommitCallbacks = []; $this->mTrxShortId = wfRandomString( 12 ); $this->mTrxWriteDuration = 0.0; $this->mTrxWriteCallers = []; @@ -2699,7 +2734,7 @@ abstract class DatabaseBase implements IDatabase { $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime ); } - $this->runOnTransactionIdleCallbacks(); + $this->runOnTransactionIdleCallbacks( self::TRIGGER_COMMIT ); } /** @@ -2739,7 +2774,7 @@ abstract class DatabaseBase implements IDatabase { $this->mTrxIdleCallbacks = []; // clear $this->mTrxPreCommitCallbacks = []; // clear - $this->runOnTransactionIdleCallbacks(); + $this->runOnTransactionIdleCallbacks( self::TRIGGER_ROLLBACK ); } /**