예제 #1
0
 /**
  * Immediately run/queue a list of updates
  *
  * @param DeferrableUpdate[] &$queue List of DeferrableUpdate objects
  * @param string $mode Use "enqueue" to use the job queue when possible
  * @param integer $stage Class constant (PRESEND, POSTSEND) (since 1.28)
  * @throws ErrorPageError Happens on top-level calls
  * @throws Exception Happens on second-level calls
  */
 protected static function execute(array &$queue, $mode, $stage)
 {
     $services = MediaWikiServices::getInstance();
     $stats = $services->getStatsdDataFactory();
     $lbFactory = $services->getDBLoadBalancerFactory();
     $method = RequestContext::getMain()->getRequest()->getMethod();
     $ticket = $lbFactory->getEmptyTransactionTicket(__METHOD__);
     /** @var ErrorPageError $reportableError */
     $reportableError = null;
     /** @var DeferrableUpdate[] $updates Snapshot of queue */
     $updates = $queue;
     // Keep doing rounds of updates until none get enqueued...
     while ($updates) {
         $queue = [];
         // clear the queue
         if ($mode === 'enqueue') {
             try {
                 // Push enqueuable updates to the job queue and get the rest
                 $updates = self::enqueueUpdates($updates);
             } catch (Exception $e) {
                 // Let other updates have a chance to run if this failed
                 MWExceptionHandler::rollbackMasterChangesAndLog($e);
             }
         }
         // Order will be DataUpdate followed by generic DeferrableUpdate tasks
         $updatesByType = ['data' => [], 'generic' => []];
         foreach ($updates as $du) {
             if ($du instanceof DataUpdate) {
                 $du->setTransactionTicket($ticket);
                 $updatesByType['data'][] = $du;
             } else {
                 $updatesByType['generic'][] = $du;
             }
             $name = $du instanceof DeferrableCallback ? get_class($du) . '-' . $du->getOrigin() : get_class($du);
             $stats->increment('deferred_updates.' . $method . '.' . $name);
         }
         // Execute all remaining tasks...
         foreach ($updatesByType as $updatesForType) {
             foreach ($updatesForType as $update) {
                 self::$executeContext = ['update' => $update, 'stage' => $stage, 'subqueue' => []];
                 /** @var DeferrableUpdate $update */
                 $guiError = self::runUpdate($update, $lbFactory, $stage);
                 $reportableError = $reportableError ?: $guiError;
                 // Do the subqueue updates for $update until there are none
                 while (self::$executeContext['subqueue']) {
                     $subUpdate = reset(self::$executeContext['subqueue']);
                     $firstKey = key(self::$executeContext['subqueue']);
                     unset(self::$executeContext['subqueue'][$firstKey]);
                     if ($subUpdate instanceof DataUpdate) {
                         $subUpdate->setTransactionTicket($ticket);
                     }
                     $guiError = self::runUpdate($subUpdate, $lbFactory, $stage);
                     $reportableError = $reportableError ?: $guiError;
                 }
                 self::$executeContext = null;
             }
         }
         $updates = $queue;
         // new snapshot of queue (check for new entries)
     }
     if ($reportableError) {
         throw $reportableError;
         // throw the first of any GUI errors
     }
 }