'PublishStashedFile' => 'PublishStashedFileJob',
'ThumbnailRender' => 'ThumbnailRenderJob',
'recentChangesUpdate' => 'RecentChangesUpdateJob',
- 'refreshLinksPrioritized' => 'RefreshLinksJob', // for cascading protection
'null' => 'NullJob'
);
return array( 'numRows' => $numRows, 'batches' => $batches );
}
-
- /**
- * Get a Title iterator for cascade-protected template/file use backlinks
- *
- * @return TitleArray
- * @since 1.25
- */
- public function getCascadeProtectedLinks() {
- // This method is used to make redudant jobs anyway, so its OK to use
- // a slave. Also, the set of cascade protected pages tends to be stable.
- $dbr = $this->getDB();
-
- $queries = array();
- // @note: UNION filters any duplicate pages
- $queries[] = $dbr->selectSQLText(
- array( 'templatelinks', 'page_restrictions', 'page' ),
- array( 'page_namespace', 'page_title', 'page_id' ),
- array(
- 'tl_namespace' => $this->title->getNamespace(),
- 'tl_title' => $this->title->getDBkey(),
- 'tl_from = pr_page',
- 'pr_cascade' => 1,
- 'page_id = tl_from'
- )
- );
- $queries[] = $dbr->selectSQLText(
- array( 'imagelinks', 'page_restrictions', 'page' ),
- array( 'page_namespace', 'page_title', 'page_id' ),
- array(
- 'il_to' => $this->title->getDBkey(),
- 'il_from = pr_page',
- 'pr_cascade' => 1,
- 'page_id = il_from'
- )
- );
-
- return TitleArray::newFromResult( $dbr->query(
- $dbr->unionQueries( $queries, false ),
- __METHOD__
- ) );
- }
}
}
public function doUpdate() {
+
$job = new HTMLCacheUpdateJob(
$this->mTitle,
array(
$job->run(); // just do the purge query now
} );
}
+
}
}
* Which means do LinksUpdate on all pages that include the current page,
* using the job queue.
*/
- protected function queueRecursiveJobs() {
+ function queueRecursiveJobs() {
self::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
if ( $this->mTitle->getNamespace() == NS_FILE ) {
// Process imagelinks in case the title is or was a redirect
self::queueRecursiveJobsForTable( $this->mTitle, 'imagelinks' );
}
-
- $bc = $this->mTitle->getBacklinkCache();
- // Get jobs for cascade-protected backlinks for a high priority queue.
- // If meta-templates change to using a new template, the new template
- // should be implicitly protected as soon as possible, if applicable.
- // These jobs duplicate a subset of the above ones, but can run sooner.
- // Which ever runs first generally no-ops the other one.
- $jobs = array();
- foreach ( $bc->getCascadeProtectedLinks() as $title ) {
- $jobs[] = new RefreshLinksJob( $title, array( 'prioritize' => true ) );
- }
- JobQueueGroup::singleton()->push( $jobs );
}
/**
"refreshlinks:{$table}:{$title->getPrefixedText()}"
)
);
-
JobQueueGroup::singleton()->push( $job );
JobQueueGroup::singleton()->deduplicateRootJob( $job );
}
function __construct( $title, $params = '' ) {
parent::__construct( 'refreshLinks', $title, $params );
- // A separate type is used just for cascade-protected backlinks
- if ( !empty( $this->params['prioritize'] ) ) {
- $this->command .= 'Prioritized';
- }
// Base backlink update jobs and per-title update jobs can be de-duplicated.
// If template A changes twice before any jobs run, a clean queue will have:
// (A base, A base)
return true;
}
- /**
- * @param Title $title
- * @return bool
- */
protected function runForTitle( Title $title = null ) {
$linkCache = LinkCache::singleton();
$linkCache->clear();
}
# Get the ParserOutput actually *displayed* here.
- # Note that $this->mParserOutput is the *current*/oldid version output.
+ # Note that $this->mParserOutput is the *current* version output.
$pOutput = ( $outputDone instanceof ParserOutput )
? $outputDone // object fetched by hook
: $this->mParserOutput;
}
/**
- * Opportunistically enqueue link update jobs given fresh parser output if useful
+ * Updates cascading protections
*
- * @param ParserOutput $parserOutput Current version page output
- * @return bool Whether a job was pushed
- * @since 1.25
+ * @param ParserOutput $parserOutput ParserOutput object for the current version
*/
- public function triggerOpportunisticLinksUpdate( ParserOutput $parserOutput ) {
- if ( wfReadOnly() ) {
- return false;
+ public function doCascadeProtectionUpdates( ParserOutput $parserOutput ) {
+ if ( wfReadOnly() || !$this->mTitle->areRestrictionsCascading() ) {
+ return;
}
- if ( $this->mTitle->areRestrictionsCascading() ) {
- // If the page is cascade protecting, the links should really be up-to-date
- $params = array( 'prioritize' => true );
- } elseif ( $parserOutput->hasDynamicContent() ) {
- // Assume the output contains time/random based magic words
- $params = array();
- } else {
- // If the inclusions are deterministic, the edit-triggered link jobs are enough
- return false;
+ // templatelinks or imagelinks tables may have become out of sync,
+ // especially if using variable-based transclusions.
+ // For paranoia, check if things have changed and if
+ // so apply updates to the database. This will ensure
+ // that cascaded protections apply as soon as the changes
+ // are visible.
+
+ // Get templates from templatelinks and images from imagelinks
+ $id = $this->getId();
+
+ $dbLinks = array();
+
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( array( 'templatelinks' ),
+ array( 'tl_namespace', 'tl_title' ),
+ array( 'tl_from' => $id ),
+ __METHOD__
+ );
+
+ foreach ( $res as $row ) {
+ $dbLinks["{$row->tl_namespace}:{$row->tl_title}"] = true;
}
- // Check if the last link refresh was before page_touched
- if ( $this->getLinksTimestamp() < $this->getTouched() ) {
- JobQueueGroup::singleton()->push( new RefreshLinksJob( $this->mTitle, $params ) );
- return true;
+ $dbr = wfGetDB( DB_SLAVE );
+ $res = $dbr->select( array( 'imagelinks' ),
+ array( 'il_to' ),
+ array( 'il_from' => $id ),
+ __METHOD__
+ );
+
+ foreach ( $res as $row ) {
+ $dbLinks[NS_FILE . ":{$row->il_to}"] = true;
}
- return false;
+ // Get templates and images from parser output.
+ $poLinks = array();
+ foreach ( $parserOutput->getTemplates() as $ns => $templates ) {
+ foreach ( $templates as $dbk => $id ) {
+ $poLinks["$ns:$dbk"] = true;
+ }
+ }
+ foreach ( $parserOutput->getImages() as $dbk => $id ) {
+ $poLinks[NS_FILE . ":$dbk"] = true;
+ }
+
+ // Get the diff
+ $links_diff = array_diff_key( $poLinks, $dbLinks );
+
+ if ( count( $links_diff ) > 0 ) {
+ // Whee, link updates time.
+ // Note: we are only interested in links here. We don't need to get
+ // other DataUpdate items from the parser output.
+ $u = new LinksUpdate( $this->mTitle, $parserOutput, false );
+ $u->doUpdate();
+ }
}
/**
$this->mLimitReportData[$key] = $value;
}
- /**
- * Check whether the cache TTL was lowered due to dynamic content
- *
- * When content is determined by more than hard state (e.g. page edits),
- * such as template/file transclusions based on the current timestamp or
- * extension tags that generate lists based on queries, this return true.
- *
- * @return bool
- * @since 1.25
- */
- public function hasDynamicContent() {
- global $wgParserCacheExpireTime;
-
- return $this->getCacheExpiry() < $wgParserCacheExpireTime;
- }
-
/**
* Get or set the prevent-clickjacking flag
*
}
if ( $isCurrent ) {
- $this->page->triggerOpportunisticLinksUpdate( $this->parserOutput );
+ $this->page->doCascadeProtectionUpdates( $this->parserOutput );
}
return true;