* Updates that work through this system will be more likely to complete by the time the client
* makes their next request after this one than with the JobQueue system.
*
- * In CLI mode, updates run immediately if no DB writes are pending. Otherwise, they run when:
- * - a) Any waitForReplication() call if no writes are pending on any DB
- * - b) A commit happens on Maintenance::getDB( DB_MASTER ) if no writes are pending on any DB
- * - c) EnqueueableDataUpdate tasks may enqueue on commit of Maintenance::getDB( DB_MASTER )
- * - d) At the completion of Maintenance::execute()
+ * In CLI mode, deferred updates will run:
+ * - a) During DeferredUpdates::addUpdate if no LBFactory DB handles have writes pending
+ * - b) On commit of an LBFactory DB handle if no other such handles have writes pending
+ * - c) During an LBFactory::waitForReplication call if no LBFactory DBs have writes pending
+ * - d) When the queue is large and an LBFactory DB handle commits (EnqueueableDataUpdate only)
+ * - e) At the completion of Maintenance::execute()
+ *
+ * @see Maintenance::setLBFactoryTriggers
*
* When updates are deferred, they go into one two FIFO "top-queues" (one for pre-send and one
* for post-send). Updates enqueued *during* doUpdate() of a "top" update go into the "sub-queue"
public static function addUpdate( DeferrableUpdate $update, $stage = self::POSTSEND ) {
global $wgCommandLineMode;
- if ( self::$executeContext && self::$executeContext['stage'] >= $stage ) {
+ if (
+ self::$executeContext &&
+ self::$executeContext['stage'] >= $stage &&
+ !( $update instanceof MergeableUpdate )
+ ) {
// This is a sub-DeferredUpdate; run it right after its parent update.
// Also, while post-send updates are running, push any "pre-send" jobs to the
// active post-send queue to make sure they get run this round (or at all).
*/
public static function doUpdates( $mode = 'run', $stage = self::ALL ) {
$stageEffective = ( $stage === self::ALL ) ? self::POSTSEND : $stage;
+ // For ALL mode, make sure that any PRESEND updates added along the way get run.
+ // Normally, these use the subqueue, but that isn't true for MergeableUpdate items.
+ do {
+ if ( $stage === self::ALL || $stage === self::PRESEND ) {
+ self::execute( self::$preSendUpdates, $mode, $stageEffective );
+ }
- if ( $stage === self::ALL || $stage === self::PRESEND ) {
- self::execute( self::$preSendUpdates, $mode, $stageEffective );
- }
-
- if ( $stage === self::ALL || $stage == self::POSTSEND ) {
- self::execute( self::$postSendUpdates, $mode, $stageEffective );
- }
- }
-
- /**
- * @param bool $value Whether to just immediately run updates in addUpdate()
- * @since 1.28
- * @deprecated 1.29 Causes issues in Web-executed jobs - see T165714 and T100085.
- */
- public static function setImmediateMode( $value ) {
- wfDeprecated( __METHOD__, '1.29' );
+ if ( $stage === self::ALL || $stage == self::POSTSEND ) {
+ self::execute( self::$postSendUpdates, $mode, $stageEffective );
+ }
+ } while ( $stage === self::ALL && self::$preSendUpdates );
}
/**
/** @var MergeableUpdate $existingUpdate */
$existingUpdate = $queue[$class];
$existingUpdate->merge( $update );
+ // Move the update to the end to handle things like mergeable purge
+ // updates that might depend on the prior updates in the queue running
+ unset( $queue[$class] );
+ $queue[$class] = $existingUpdate;
} else {
$queue[$class] = $update;
}
/**
* Run all deferred updates immediately if there are no DB writes active
*
- * If $mode is 'run' but there are busy databates, EnqueueableDataUpdate
- * tasks will be enqueued anyway for the sake of progress.
+ * If there are many deferred updates pending, $mode is 'run', and there
+ * are still busy LBFactory database handles, then any EnqueueableDataUpdate
+ * tasks might be enqueued as jobs to be executed later.
*
* @param string $mode Use "enqueue" to use the job queue when possible
* @return bool Whether updates were allowed to run
*/
private static function areDatabaseTransactionsActive() {
$lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
- if ( $lbFactory->hasTransactionRound() ) {
+ if ( $lbFactory->hasTransactionRound() || !$lbFactory->isReadyForRoundOperations() ) {
return true;
}