From a1789ddde42033f1b05cc4929491214ee6e79383 Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Thu, 17 Dec 2015 09:15:42 +0100 Subject: Update to MediaWiki 1.26.0 --- includes/jobqueue/jobs/ActivityUpdateJob.php | 75 ++++++++++++++++++++++ includes/jobqueue/jobs/AssembleUploadChunksJob.php | 2 +- includes/jobqueue/jobs/DoubleRedirectJob.php | 20 +++--- includes/jobqueue/jobs/DuplicateJob.php | 2 +- includes/jobqueue/jobs/EmaillingJob.php | 4 +- includes/jobqueue/jobs/EnotifNotifyJob.php | 2 +- includes/jobqueue/jobs/EnqueueJob.php | 21 ++++-- includes/jobqueue/jobs/HTMLCacheUpdateJob.php | 2 +- includes/jobqueue/jobs/NullJob.php | 2 +- includes/jobqueue/jobs/PublishStashedFileJob.php | 2 +- includes/jobqueue/jobs/RecentChangesUpdateJob.php | 8 ++- includes/jobqueue/jobs/RefreshLinksJob.php | 51 ++++++++++----- includes/jobqueue/jobs/ThumbnailRenderJob.php | 14 ++-- includes/jobqueue/jobs/UploadFromUrlJob.php | 6 +- 14 files changed, 159 insertions(+), 52 deletions(-) create mode 100644 includes/jobqueue/jobs/ActivityUpdateJob.php (limited to 'includes/jobqueue/jobs') diff --git a/includes/jobqueue/jobs/ActivityUpdateJob.php b/includes/jobqueue/jobs/ActivityUpdateJob.php new file mode 100644 index 00000000..f146e6e8 --- /dev/null +++ b/includes/jobqueue/jobs/ActivityUpdateJob.php @@ -0,0 +1,75 @@ +removeDuplicates = true; + } + + public function run() { + if ( $this->params['type'] === 'updateWatchlistNotification' ) { + $this->updateWatchlistNotification(); + } else { + throw new Exception( "Invalid 'type' parameter '{$this->params['type']}'." ); + } + + return true; + } + + protected function updateWatchlistNotification() { + $casTimestamp = ( $this->params['notifTime'] !== null ) + ? $this->params['notifTime'] + : $this->params['curTime']; + + $dbw = wfGetDB( DB_MASTER ); + $dbw->update( 'watchlist', + array( + 'wl_notificationtimestamp' => $dbw->timestampOrNull( $this->params['notifTime'] ) + ), + array( + 'wl_user' => $this->params['userid'], + 'wl_namespace' => $this->title->getNamespace(), + 'wl_title' => $this->title->getDBkey(), + // Add a "check and set" style comparison to handle conflicts. + // The inequality always avoids updates when the current value + // is already NULL per ANSI SQL. This is desired since NULL means + // that the user is "caught up" on edits already. When the field + // is non-NULL, make sure not to set it back in time or set it to + // NULL when newer revisions were in fact added to the page. + 'wl_notificationtimestamp < ' . $dbw->addQuotes( $dbw->timestamp( $casTimestamp ) ) + ), + __METHOD__ + ); + } +} diff --git a/includes/jobqueue/jobs/AssembleUploadChunksJob.php b/includes/jobqueue/jobs/AssembleUploadChunksJob.php index b7f09e77..a1de77e6 100644 --- a/includes/jobqueue/jobs/AssembleUploadChunksJob.php +++ b/includes/jobqueue/jobs/AssembleUploadChunksJob.php @@ -27,7 +27,7 @@ * @ingroup Upload */ class AssembleUploadChunksJob extends Job { - public function __construct( $title, $params ) { + public function __construct( Title $title, array $params ) { parent::__construct( 'AssembleUploadChunks', $title, $params ); $this->removeDuplicates = true; } diff --git a/includes/jobqueue/jobs/DoubleRedirectJob.php b/includes/jobqueue/jobs/DoubleRedirectJob.php index 2561f2f1..ab638967 100644 --- a/includes/jobqueue/jobs/DoubleRedirectJob.php +++ b/includes/jobqueue/jobs/DoubleRedirectJob.php @@ -40,6 +40,16 @@ class DoubleRedirectJob extends Job { /** @var User */ private static $user; + /** + * @param Title $title + * @param array $params + */ + function __construct( Title $title, array $params ) { + parent::__construct( 'fixDoubleRedirect', $title, $params ); + $this->reason = $params['reason']; + $this->redirTitle = Title::newFromText( $params['redirTitle'] ); + } + /** * Insert jobs into the job queue to fix redirects to the given title * @param string $reason The reason for the fix, see message @@ -81,16 +91,6 @@ class DoubleRedirectJob extends Job { JobQueueGroup::singleton()->push( $jobs ); } - /** - * @param Title $title - * @param array|bool $params - */ - function __construct( $title, $params = false ) { - parent::__construct( 'fixDoubleRedirect', $title, $params ); - $this->reason = $params['reason']; - $this->redirTitle = Title::newFromText( $params['redirTitle'] ); - } - /** * @return bool */ diff --git a/includes/jobqueue/jobs/DuplicateJob.php b/includes/jobqueue/jobs/DuplicateJob.php index c5e3a234..068d5319 100644 --- a/includes/jobqueue/jobs/DuplicateJob.php +++ b/includes/jobqueue/jobs/DuplicateJob.php @@ -33,7 +33,7 @@ final class DuplicateJob extends Job { * @param Title $title * @param array $params Job parameters */ - function __construct( $title, $params ) { + function __construct( Title $title, array $params ) { parent::__construct( 'duplicate', $title, $params ); } diff --git a/includes/jobqueue/jobs/EmaillingJob.php b/includes/jobqueue/jobs/EmaillingJob.php index df8ae63e..beeb0673 100644 --- a/includes/jobqueue/jobs/EmaillingJob.php +++ b/includes/jobqueue/jobs/EmaillingJob.php @@ -28,7 +28,7 @@ * @ingroup JobQueue */ class EmaillingJob extends Job { - function __construct( $title, $params ) { + function __construct( Title $title = null, array $params ) { parent::__construct( 'sendMail', Title::newMainPage(), $params ); } @@ -38,7 +38,7 @@ class EmaillingJob extends Job { $this->params['from'], $this->params['subj'], $this->params['body'], - $this->params['replyto'] + array( 'replyTo' => $this->params['replyto'] ) ); return $status->isOK(); diff --git a/includes/jobqueue/jobs/EnotifNotifyJob.php b/includes/jobqueue/jobs/EnotifNotifyJob.php index 1ed99a58..9a5c3c72 100644 --- a/includes/jobqueue/jobs/EnotifNotifyJob.php +++ b/includes/jobqueue/jobs/EnotifNotifyJob.php @@ -27,7 +27,7 @@ * @ingroup JobQueue */ class EnotifNotifyJob extends Job { - function __construct( $title, $params ) { + function __construct( Title $title, array $params ) { parent::__construct( 'enotifNotify', $title, $params ); } diff --git a/includes/jobqueue/jobs/EnqueueJob.php b/includes/jobqueue/jobs/EnqueueJob.php index 46fb2aa7..c7ee9b65 100644 --- a/includes/jobqueue/jobs/EnqueueJob.php +++ b/includes/jobqueue/jobs/EnqueueJob.php @@ -40,13 +40,13 @@ final class EnqueueJob extends Job { * @param Title $title * @param array $params Job parameters */ - function __construct( $title, $params ) { + function __construct( Title $title, array $params ) { parent::__construct( 'enqueue', $title, $params ); } /** - * @param Job|JobSpecification|array $jobs - * @return JobRouteJob + * @param JobSpecification|JobSpecification[] $jobs + * @return EnqueueJob */ public static function newFromLocalJobs( $jobs ) { $jobs = is_array( $jobs ) ? $jobs : array( $jobs ); @@ -56,9 +56,11 @@ final class EnqueueJob extends Job { /** * @param array $jobsByWiki Map of (wiki => JobSpecification list) - * @return JobRouteJob + * @return EnqueueJob */ public static function newFromJobsByWiki( array $jobsByWiki ) { + $deduplicate = true; + $jobMapsByWiki = array(); foreach ( $jobsByWiki as $wiki => $jobs ) { $jobMapsByWiki[$wiki] = array(); @@ -68,10 +70,19 @@ final class EnqueueJob extends Job { } else { throw new InvalidArgumentException( "Jobs must be of type JobSpecification." ); } + $deduplicate = $deduplicate && $job->ignoreDuplicates(); } } - return new self( Title::newMainPage(), array( 'jobsByWiki' => $jobMapsByWiki ) ); + $eJob = new self( + Title::makeTitle( NS_SPECIAL, 'Badtitle/' . __CLASS__ ), + array( 'jobsByWiki' => $jobMapsByWiki ) + ); + // If *all* jobs to be pushed are to be de-duplicated (a common case), then + // de-duplicate this whole job itself to avoid build up in high traffic cases + $eJob->removeDuplicates = $deduplicate; + + return $eJob; } public function run() { diff --git a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php index e5e521c3..a9010c25 100644 --- a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php +++ b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php @@ -34,7 +34,7 @@ * @ingroup JobQueue */ class HTMLCacheUpdateJob extends Job { - function __construct( $title, $params = '' ) { + function __construct( Title $title, array $params ) { parent::__construct( 'htmlCacheUpdate', $title, $params ); // Base backlink purge jobs can be de-duplicated $this->removeDuplicates = ( !isset( $params['range'] ) && !isset( $params['pages'] ) ); diff --git a/includes/jobqueue/jobs/NullJob.php b/includes/jobqueue/jobs/NullJob.php index f94d6ebc..26d3c5c8 100644 --- a/includes/jobqueue/jobs/NullJob.php +++ b/includes/jobqueue/jobs/NullJob.php @@ -49,7 +49,7 @@ class NullJob extends Job { * @param Title $title * @param array $params Job parameters (lives, usleep) */ - function __construct( $title, $params ) { + function __construct( Title $title, array $params ) { parent::__construct( 'null', $title, $params ); if ( !isset( $this->params['lives'] ) ) { $this->params['lives'] = 1; diff --git a/includes/jobqueue/jobs/PublishStashedFileJob.php b/includes/jobqueue/jobs/PublishStashedFileJob.php index a922dd3d..8a180ec3 100644 --- a/includes/jobqueue/jobs/PublishStashedFileJob.php +++ b/includes/jobqueue/jobs/PublishStashedFileJob.php @@ -29,7 +29,7 @@ * @ingroup JobQueue */ class PublishStashedFileJob extends Job { - public function __construct( $title, $params ) { + public function __construct( Title $title, array $params ) { parent::__construct( 'PublishStashedFile', $title, $params ); $this->removeDuplicates = true; } diff --git a/includes/jobqueue/jobs/RecentChangesUpdateJob.php b/includes/jobqueue/jobs/RecentChangesUpdateJob.php index cc04595d..d6fa26b8 100644 --- a/includes/jobqueue/jobs/RecentChangesUpdateJob.php +++ b/includes/jobqueue/jobs/RecentChangesUpdateJob.php @@ -27,7 +27,7 @@ * @since 1.25 */ class RecentChangesUpdateJob extends Job { - function __construct( $title, $params ) { + function __construct( Title $title, array $params ) { parent::__construct( 'recentChangesUpdate', $title, $params ); if ( !isset( $params['type'] ) ) { @@ -75,11 +75,13 @@ class RecentChangesUpdateJob extends Job { $lockKey = wfWikiID() . ':recentchanges-prune'; $dbw = wfGetDB( DB_MASTER ); - if ( !$dbw->lock( $lockKey, __METHOD__, 1 ) ) { + if ( !$dbw->lockIsFree( $lockKey, __METHOD__ ) + || !$dbw->lock( $lockKey, __METHOD__, 1 ) + ) { return; // already in progress } - $batchSize = 100; // Avoid slave lag + $batchSize = 100; // avoid slave lag $cutoff = $dbw->timestamp( time() - $wgRCMaxAge ); do { $rcIds = $dbw->selectFieldValues( 'recentchanges', diff --git a/includes/jobqueue/jobs/RefreshLinksJob.php b/includes/jobqueue/jobs/RefreshLinksJob.php index 1252b0b5..935d2fb1 100644 --- a/includes/jobqueue/jobs/RefreshLinksJob.php +++ b/includes/jobqueue/jobs/RefreshLinksJob.php @@ -37,7 +37,9 @@ class RefreshLinksJob extends Job { const PARSE_THRESHOLD_SEC = 1.0; - function __construct( $title, $params = '' ) { + const CLOCK_FUDGE = 10; + + function __construct( Title $title, array $params ) { parent::__construct( 'refreshLinks', $title, $params ); // A separate type is used just for cascade-protected backlinks if ( !empty( $this->params['prioritize'] ) ) { @@ -109,9 +111,6 @@ class RefreshLinksJob extends Job { * @return bool */ protected function runForTitle( Title $title = null ) { - $linkCache = LinkCache::singleton(); - $linkCache->clear(); - if ( is_null( $title ) ) { $this->setLastError( "refreshLinks: Invalid title" ); return false; @@ -124,14 +123,18 @@ class RefreshLinksJob extends Job { wfGetLB()->waitFor( $this->params['masterPos'] ); } - $page = WikiPage::factory( $title ); + // Clear out title cache data from prior job transaction snapshots + $linkCache = LinkCache::singleton(); + $linkCache->clear(); - // Fetch the current revision... + // Fetch the current page and revision... + $page = WikiPage::factory( $title ); $revision = Revision::newFromTitle( $title, false, Revision::READ_NORMAL ); if ( !$revision ) { $this->setLastError( "refreshLinks: Article not found {$title->getPrefixedDBkey()}" ); return false; // XXX: what if it was just deleted? } + $content = $revision->getContent( Revision::RAW ); if ( !$content ) { // If there is no content, pretend the content is empty @@ -140,34 +143,50 @@ class RefreshLinksJob extends Job { $parserOutput = false; $parserOptions = $page->makeParserOptions( 'canonical' ); - // If page_touched changed after this root job (with a good slave lag skew factor), - // then it is likely that any views of the pages already resulted in re-parses which - // are now in cache. This can be reused to avoid expensive parsing in some cases. + // If page_touched changed after this root job, then it is likely that + // any views of the pages already resulted in re-parses which are now in + // cache. The cache can be reused to avoid expensive parsing in some cases. if ( isset( $this->params['rootJobTimestamp'] ) ) { - $skewedTimestamp = wfTimestamp( TS_UNIX, $this->params['rootJobTimestamp'] ) + 5; - if ( $page->getLinksTimestamp() > wfTimestamp( TS_MW, $skewedTimestamp ) ) { + $opportunistic = !empty( $this->params['isOpportunistic'] ); + + $skewedTimestamp = $this->params['rootJobTimestamp']; + if ( $opportunistic ) { + // Neither clock skew nor DB snapshot/slave lag matter much for such + // updates; focus on reusing the (often recently updated) cache + } else { + // For transclusion updates, the template changes must be reflected + $skewedTimestamp = wfTimestamp( TS_MW, + wfTimestamp( TS_UNIX, $skewedTimestamp ) + self::CLOCK_FUDGE + ); + } + + if ( $page->getLinksTimestamp() > $skewedTimestamp ) { // Something already updated the backlinks since this job was made return true; } - if ( $page->getTouched() > wfTimestamp( TS_MW, $skewedTimestamp ) ) { + + if ( $page->getTouched() >= $skewedTimestamp || $opportunistic ) { + // Something bumped page_touched since this job was made + // or the cache is otherwise suspected to be up-to-date $parserOutput = ParserCache::singleton()->getDirty( $page, $parserOptions ); - if ( $parserOutput && $parserOutput->getCacheTime() <= $skewedTimestamp ) { + if ( $parserOutput && $parserOutput->getCacheTime() < $skewedTimestamp ) { $parserOutput = false; // too stale } } } + // Fetch the current revision and parse it if necessary... if ( $parserOutput == false ) { $start = microtime( true ); // Revision ID must be passed to the parser output to get revision variables correct $parserOutput = $content->getParserOutput( $title, $revision->getId(), $parserOptions, false ); - $ellapsed = microtime( true ) - $start; + $elapsed = microtime( true ) - $start; // If it took a long time to render, then save this back to the cache to avoid // wasted CPU by other apaches or job runners. We don't want to always save to // cache as this can cause high cache I/O and LRU churn when a template changes. - if ( $ellapsed >= self::PARSE_THRESHOLD_SEC - && $page->isParserCacheUsed( $parserOptions, $revision->getId() ) + if ( $elapsed >= self::PARSE_THRESHOLD_SEC + && $page->shouldCheckParserCache( $parserOptions, $revision->getId() ) && $parserOutput->isCacheable() ) { $ctime = wfTimestamp( TS_MW, (int)$start ); // cache time diff --git a/includes/jobqueue/jobs/ThumbnailRenderJob.php b/includes/jobqueue/jobs/ThumbnailRenderJob.php index ab381388..f558c488 100644 --- a/includes/jobqueue/jobs/ThumbnailRenderJob.php +++ b/includes/jobqueue/jobs/ThumbnailRenderJob.php @@ -27,7 +27,7 @@ * @ingroup JobQueue */ class ThumbnailRenderJob extends Job { - public function __construct( $title, $params ) { + public function __construct( Title $title, array $params ) { parent::__construct( 'ThumbnailRender', $title, $params ); } @@ -50,16 +50,16 @@ class ThumbnailRenderJob extends Job { return false; } } elseif ( $wgUploadThumbnailRenderMethod === 'http' ) { - $status = $this->hitThumbUrl( $file, $transformParams ); + $thumbUrl = ''; + $status = $this->hitThumbUrl( $file, $transformParams, $thumbUrl ); wfDebug( __METHOD__ . ": received status {$status}\n" ); - if ( $status === 200 || $status === 301 || $status === 302 ) { + // 400 happens when requesting a size greater or equal than the original + if ( $status === 200 || $status === 301 || $status === 302 || $status === 400 ) { return true; } elseif ( $status ) { - // Note that this currently happens (500) when requesting sizes larger then or - // equal to the original, which is harmless. - $this->setLastError( __METHOD__ . ': incorrect HTTP status ' . $status ); + $this->setLastError( __METHOD__ . ': incorrect HTTP status ' . $status . ' when hitting ' . $thumbUrl ); return false; } else { $this->setLastError( __METHOD__ . ': HTTP request failure' ); @@ -75,7 +75,7 @@ class ThumbnailRenderJob extends Job { } } - protected function hitThumbUrl( $file, $transformParams ) { + protected function hitThumbUrl( $file, $transformParams, &$thumbUrl ) { global $wgUploadThumbnailRenderHttpCustomHost, $wgUploadThumbnailRenderHttpCustomDomain; $thumbName = $file->thumbName( $transformParams ); diff --git a/includes/jobqueue/jobs/UploadFromUrlJob.php b/includes/jobqueue/jobs/UploadFromUrlJob.php index d15fd025..ade48106 100644 --- a/includes/jobqueue/jobs/UploadFromUrlJob.php +++ b/includes/jobqueue/jobs/UploadFromUrlJob.php @@ -39,7 +39,7 @@ class UploadFromUrlJob extends Job { /** @var User */ protected $user; - public function __construct( $title, $params ) { + public function __construct( Title $title, array $params ) { parent::__construct( 'uploadFromUrl', $title, $params ); } @@ -166,11 +166,11 @@ class UploadFromUrlJob extends Job { } /** - * Initialize the session data. Sets the intial result to queued. + * Initialize the session data. Sets the initial result to queued. */ public function initializeSessionData() { $session =& self::getSessionData( $this->params['sessionKey'] ); - $$session['result'] = 'Queued'; + $session['result'] = 'Queued'; } /** -- cgit v1.2.3-54-g00ecf