wiki.techinc.nl/includes/deferred/MergeableUpdate.php
Aaron Schulz 4b7ddd3c67 deferred: make DeferredUpdates::doUpdates() recursion more uniform
Follow-up ba6490aa1e.

That patch worked around $executeContext iteration errors due to the
lack of recursion support in doUpdates()/handleUpdateQueue(). Errors
were triggered by MediaWiki::schedulePostSendJobs() enqueueing deferred
updates that invoke JobRunner::run(), which, in turn, invoke doUpdates()
for each job via JobRunner:: doExecuteJob(). The doUpdates() method was
changed to operate on the sub-queue for the in-progress DeferrableUpdate.

Further improve the recursion logic:
* Use classes for the scope stack and scope queues.
* Put *all* updates added during a DeferrableUpdate::doUpdate() call into
  the subqueue, regardless of "defer until" stage or whether it implements
  MergeableUpdate. Now, doUpdate() can run *everything* it enqueued instead
  of a non-obvious subset. Note that the TransactionRoundDefiningUpdate
  that invokes JobRunner was already a POSTSEND update before ba6490aa1eb;
  the only effect of this change is that MergeableUpdate instances from jobs
  will once again run in doExecuteJob().
* Make recursive DeferredUpdates::doUpdate() calls error out immediately
  unless the DeferrableUpdate responsible is a TransactionRoundAwareUpdate
  with the TRX_ROUND_ABSENT flag. This covers the schedulePostSendJobs()
  scenario and only prohibits insane call patterns. Failing early avoids
  the risk of handleUpdateQueue() dropping all the updates due to the same
  DBTransactionError error in DeferredUpdates::attemptUpdate().
* Avoid recursion loop in tryOpportunisticExecute() when JobQueueDB is in
  use and a large number of tasks are pending. This happened due to methods
  like onTransactionPreCommitOrIdle() being used within JobQueueDB.

Mark DeferredUpdates::doUpdates()/tryOpportunisticExecute() as @internal
and create a Maintenance::shutdown() method to avoid a direct call in the
doMaintenance.php file.

Bug: T249069
Bug: T268840
Change-Id: Ib369f0e74243a48ababdb9cd83b155c9a0f5e741
2021-01-14 15:37:58 -08:00

28 lines
1.1 KiB
PHP

<?php
/**
* Interface that deferrable updates can implement to signal that updates can be combined.
*
* DeferredUpdates uses this to merge all pending updates of PHP class into a single update
* by calling merge(). Note that upon merge(), the combined update goes to the back of the FIFO
* queue so that such updates occur after related non-mergeable deferred updates. For example,
* suppose updates that purge URL objects all use the same MergeableUpdate class, updates that
* delete URL objects use a different class, and the calling pattern is:
* - a) DeferredUpdates::addUpdate( $purgeCdnUrlsA );
* - b) DeferredUpdates::addUpdate( $deleteContentUrlsB );
* - c) DeferredUpdates::addUpdate( $purgeCdnUrlsB )
*
* In this case, purges for urls A and B will all happen after the $deleteContentUrlsB update.
*
* @stable to implement
*
* @since 1.27
*/
interface MergeableUpdate extends DeferrableUpdate {
/**
* Merge this enqueued update with a new MergeableUpdate of the same qualified class name
*
* @param MergeableUpdate $update The new update (having the same class)
*/
public function merge( MergeableUpdate $update );
}