34 private $activeUpdate;
38 private $queueByStage;
45 private function __construct(
50 $this->activeStage = $activeStage;
51 $this->activeUpdate = $update;
52 $this->parentScope = $parentScope;
53 $this->queueByStage = array_fill_keys( DeferredUpdates::STAGES, [] );
60 return new self(
null,
null, null );
74 return new self( $activeStage, $update, $parentScope );
83 return $this->activeUpdate;
94 $stageEffective = max( $stage, $this->activeStage );
96 $queue =& $this->queueByStage[$stageEffective];
99 $class = get_class( $update );
100 if ( isset( $queue[$class] ) ) {
102 $existingUpdate = $queue[$class];
103 '@phan-var MergeableUpdate $existingUpdate';
104 $existingUpdate->merge( $update );
107 unset( $queue[$class] );
108 $queue[$class] = $existingUpdate;
110 $queue[$class] = $update;
123 return array_sum( array_map(
'count', $this->queueByStage ) );
133 $matchingQueues = [];
134 foreach ( $this->queueByStage as $queueStage => $queue ) {
135 if ( $stage === DeferredUpdates::ALL || $stage === $queueStage ) {
136 $matchingQueues[] = $queue;
140 return array_merge( ...$matchingQueues );
147 $this->queueByStage = array_fill_keys( array_keys( $this->queueByStage ), [] );
159 $claimedUpdates = [];
160 foreach ( $this->queueByStage as $queueStage => $queue ) {
161 if ( $stage === DeferredUpdates::ALL || $stage === $queueStage ) {
162 foreach ( $queue as $k => $update ) {
163 if ( $update instanceof $class ) {
164 $claimedUpdates[] = $update;
165 unset( $this->queueByStage[$queueStage][$k] );
171 foreach ( $claimedUpdates as $update ) {
172 $callback( $update );
185 if ( $stage === DeferredUpdates::ALL ) {
187 $activeStage = DeferredUpdates::STAGES[count( DeferredUpdates::STAGES ) - 1];
190 $activeStage = max( $stage, $this->activeStage );
194 $processed = $this->upmergeUnreadyUpdates( $activeStage );
195 foreach ( range( DeferredUpdates::STAGES[0], $activeStage ) as $queueStage ) {
196 $processed += $this->processStageQueue( $queueStage, $activeStage, $callback );
198 }
while ( $processed > 0 );
211 private function upmergeUnreadyUpdates( $activeStage ) {
214 if ( !$this->parentScope ) {
218 foreach ( $this->queueByStage as $queueStage => $queue ) {
219 foreach ( $queue as $k => $update ) {
220 if ( $update instanceof
MergeableUpdate || $queueStage > $activeStage ) {
221 unset( $this->queueByStage[$queueStage][$k] );
222 $this->parentScope->addUpdate( $update, $queueStage );
237 private function processStageQueue( $stage, $activeStage, callable $callback ) {
241 $claimedUpdates = $this->queueByStage[$stage];
242 $this->queueByStage[$stage] = [];
245 while ( $claimedUpdates ) {
251 $claimedDataUpdates = [];
252 $claimedGenericUpdates = [];
253 foreach ( $claimedUpdates as $claimedUpdate ) {
255 $claimedDataUpdates[] = $claimedUpdate;
257 $claimedGenericUpdates[] = $claimedUpdate;
263 foreach ( $claimedDataUpdates as $claimedDataUpdate ) {
264 $callback( $claimedDataUpdate, $activeStage );
266 foreach ( $claimedGenericUpdates as $claimedGenericUpdate ) {
267 $callback( $claimedGenericUpdate, $activeStage );
271 $claimedUpdates = $this->queueByStage[$stage];
272 $this->queueByStage[$stage] = [];
Abstract base class for update jobs that do something with some secondary data extracted from article...
DeferredUpdates helper class for managing DeferrableUpdate::doUpdate() nesting levels caused by neste...
consumeMatchingUpdates( $stage, $class, callable $callback)
Remove pending updates of the specified stage/class and pass them to a callback.
static newChildScope( $activeStage, DeferrableUpdate $update, DeferredUpdatesScope $parentScope)
pendingUpdatesCount()
Get the number of pending updates within this scope.
addUpdate(DeferrableUpdate $update, $stage)
Enqueue a deferred update within this scope using the specified "defer until" time.
getPendingUpdates( $stage)
Get pending updates within this scope with the given "defer until" stage.
processUpdates( $stage, callable $callback)
Iteratively, reassign unready pending updates to the parent scope (if applicable) and process the rea...
clearPendingUpdates()
Cancel all pending updates within this scope.
getActiveUpdate()
Get the deferred update that owns this scope (root scope has none)
Interface that deferrable updates should implement.
Interface that deferrable updates can implement to signal that updates can be combined.