Merge "HtmlCacheUpdater: Add getUrls() method and support selective purging"
This commit is contained in:
commit
634179e107
5 changed files with 141 additions and 33 deletions
|
|
@ -3529,6 +3529,23 @@ $title: Title object being checked against
|
|||
$user: Current user object
|
||||
&$whitelisted: Boolean value of whether this title is whitelisted
|
||||
|
||||
'HtmlCacheUpdaterAppendUrls': Declare extra URLs to purge from HTTP caches.
|
||||
Use $mode to decide whether to gather all related URLs or only those affected by
|
||||
a re-render of the same content. For example, after a direct revision to the
|
||||
content the history page will need to be purged. However when re-rendering after
|
||||
a cascading change from a template, only URLs that render content need purging.
|
||||
The $mode will be either HtmlCacheUpdater::PURGE_URLS_LINKSUPDATE_ONLY or 0.
|
||||
$title: Title object for the page being purged.
|
||||
$mode: Integer.
|
||||
&$append: Append URLs relating to $title.
|
||||
|
||||
'HtmlCacheUpdaterVaryUrls': Add variants of URLs to purge from HTTP caches.
|
||||
Extensions that provide site-wide variants of all URLs, such as by serving from
|
||||
an alternate domain or path, can use this hook to append alternative URLs for
|
||||
each url in $canonical.
|
||||
$urls: Canonical URLs.
|
||||
&$append: Append alternative URLs for $urls.
|
||||
|
||||
'TitleSquidURLs': Called to determine which URLs to purge from HTTP caches.
|
||||
$title: Title object to purge
|
||||
&$urls: An array of URLs to purge from the caches, to be manipulated.
|
||||
|
|
|
|||
|
|
@ -3551,28 +3551,14 @@ class Title implements LinkTarget, IDBAccessObject {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get a list of URLs to purge from the CDN cache when this
|
||||
* page changes
|
||||
* Get a list of URLs to purge from the CDN cache when this page changes.
|
||||
*
|
||||
* @deprecated 1.35 Use HtmlCacheUpdater
|
||||
* @return string[] Array of String the URLs
|
||||
*/
|
||||
public function getCdnUrls() {
|
||||
$urls = [
|
||||
$this->getInternalURL(),
|
||||
$this->getInternalURL( 'action=history' )
|
||||
];
|
||||
|
||||
// If we are looking at a css/js user subpage, purge the action=raw.
|
||||
if ( $this->isUserJsConfigPage() ) {
|
||||
$urls[] = $this->getInternalURL( 'action=raw&ctype=text/javascript' );
|
||||
} elseif ( $this->isUserJsonConfigPage() ) {
|
||||
$urls[] = $this->getInternalURL( 'action=raw&ctype=application/json' );
|
||||
} elseif ( $this->isUserCssConfigPage() ) {
|
||||
$urls[] = $this->getInternalURL( 'action=raw&ctype=text/css' );
|
||||
}
|
||||
|
||||
Hooks::run( 'TitleSquidURLs', [ $this, &$urls ] );
|
||||
return $urls;
|
||||
$htmlCache = MediaWikiServices::getInstance()->getHtmlCacheUpdater();
|
||||
return $htmlCache->getUrls( $this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3580,8 +3566,8 @@ class Title implements LinkTarget, IDBAccessObject {
|
|||
* @deprecated 1.35 Use HtmlCacheUpdater
|
||||
*/
|
||||
public function purgeSquid() {
|
||||
$hcu = MediaWikiServices::getInstance()->getHtmlCacheUpdater();
|
||||
$hcu->purgeTitleUrls( $this, $hcu::PURGE_INTENT_TXROUND_REFLECTED );
|
||||
$htmlCache = MediaWikiServices::getInstance()->getHtmlCacheUpdater();
|
||||
$htmlCache->purgeTitleUrls( $this, $htmlCache::PURGE_INTENT_TXROUND_REFLECTED );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
74
includes/cache/HtmlCacheUpdater.php
vendored
74
includes/cache/HtmlCacheUpdater.php
vendored
|
|
@ -54,6 +54,16 @@ class HtmlCacheUpdater {
|
|||
*/
|
||||
public const PURGE_INTENT_TXROUND_REFLECTED = self::PURGE_PRESEND | self::PURGE_REBOUND;
|
||||
|
||||
/**
|
||||
* Reduce set of URLs to be purged to only those that may be affected by
|
||||
* change propagation from LinksUpdate (e.g. after a used template was edited).
|
||||
*
|
||||
* Specifically, this means URLs only affected by direct revision edits,
|
||||
* will not be purged.
|
||||
* @var int
|
||||
*/
|
||||
public const PURGE_URLS_LINKSUPDATE_ONLY = 4;
|
||||
|
||||
/**
|
||||
* @param int $reboundDelay $wgCdnReboundPurgeDelay
|
||||
* @param bool $useFileCache $wgUseFileCache
|
||||
|
|
@ -64,6 +74,15 @@ class HtmlCacheUpdater {
|
|||
$this->useFileCache = $useFileCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $flags Bit field
|
||||
* @param int $flag Constant to check for
|
||||
* @return bool If $flags contains $flag
|
||||
*/
|
||||
private function fieldHasFlag( $flags, $flag ) {
|
||||
return ( ( $flags & $flag ) === $flag );
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the CDN for a URL or list of URLs
|
||||
*
|
||||
|
|
@ -74,12 +93,12 @@ class HtmlCacheUpdater {
|
|||
public function purgeUrls( $urls, $flags = self::PURGE_PRESEND ) {
|
||||
$urls = is_string( $urls ) ? [ $urls ] : $urls;
|
||||
|
||||
$reboundDelay = ( ( $flags & self::PURGE_REBOUND ) == self::PURGE_REBOUND )
|
||||
$reboundDelay = $this->fieldHasFlag( $flags, self::PURGE_REBOUND )
|
||||
? $this->reboundDelay
|
||||
: 0; // no second purge
|
||||
|
||||
$update = new CdnCacheUpdate( $urls, [ 'reboundDelay' => $reboundDelay ] );
|
||||
if ( ( $flags & self::PURGE_PRESEND ) == self::PURGE_PRESEND ) {
|
||||
if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
|
||||
DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
|
||||
} else {
|
||||
$update->doUpdate();
|
||||
|
|
@ -101,7 +120,7 @@ class HtmlCacheUpdater {
|
|||
|
||||
if ( $this->useFileCache ) {
|
||||
$update = HtmlFileCacheUpdate::newFromTitles( $titles );
|
||||
if ( ( $flags & self::PURGE_PRESEND ) == self::PURGE_PRESEND ) {
|
||||
if ( $this->fieldHasFlag( $flags, self::PURGE_PRESEND ) ) {
|
||||
DeferredUpdates::addUpdate( $update, DeferredUpdates::PRESEND );
|
||||
} else {
|
||||
$update->doUpdate();
|
||||
|
|
@ -115,4 +134,53 @@ class HtmlCacheUpdater {
|
|||
}
|
||||
$this->purgeUrls( $urls, $flags );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of URLs to purge from the CDN cache when this page changes.
|
||||
*
|
||||
* @param Title $title
|
||||
* @param int $flags Bit field of `PURGE_URLS_*` class constants (optional).
|
||||
* @return string[] URLs
|
||||
*/
|
||||
public function getUrls( Title $title, int $flags = 0 ) : array {
|
||||
// These urls are affected both by direct revisions as well,
|
||||
// as re-rendering of the same content during a LinksUpdate.
|
||||
$urls = [
|
||||
$title->getInternalURL()
|
||||
];
|
||||
// Language variant page views are currently not cached
|
||||
// and thus not purged (T250511).
|
||||
|
||||
// These urls are only affected by direct revisions, and do not require
|
||||
// purging when a LinksUpdate merely rerenders the same content.
|
||||
// This exists to avoid large amounts of redundant PURGE traffic (T250261).
|
||||
if ( !$this->fieldHasFlag( $flags, self::PURGE_URLS_LINKSUPDATE_ONLY ) ) {
|
||||
$urls[] = $title->getInternalURL( 'action=history' );
|
||||
|
||||
// Canonical action=raw URLs for user config pages
|
||||
if ( $title->isUserJsConfigPage() ) {
|
||||
$urls[] = $title->getInternalURL( 'action=raw&ctype=text/javascript' );
|
||||
} elseif ( $title->isUserJsonConfigPage() ) {
|
||||
$urls[] = $title->getInternalURL( 'action=raw&ctype=application/json' );
|
||||
} elseif ( $title->isUserCssConfigPage() ) {
|
||||
$urls[] = $title->getInternalURL( 'action=raw&ctype=text/css' );
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions may add novel ways to access this content
|
||||
$append = [];
|
||||
$mode = $flags & self::PURGE_URLS_LINKSUPDATE_ONLY;
|
||||
Hooks::run( 'HtmlCacheUpdaterAppendUrls', [ $title, $mode, &$append ] );
|
||||
$urls = array_merge( $urls, $append );
|
||||
|
||||
// Extensions may add novel ways to access the site overall
|
||||
$append = [];
|
||||
Hooks::run( 'HtmlCacheUpdaterVaryUrls', [ $urls, &$append ] );
|
||||
$urls = array_merge( $urls, $append );
|
||||
|
||||
// Legacy. TODO: Deprecate this
|
||||
Hooks::run( 'TitleSquidURLs', [ $title, &$urls ] );
|
||||
|
||||
return $urls;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1723,15 +1723,5 @@ class TitleTest extends MediaWikiTestCase {
|
|||
Title::makeTitle( NS_MAIN, 'Example' )->getCdnUrls(),
|
||||
'article'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'https://example.org/wiki/User:Example/foo.js',
|
||||
'https://example.org/w/index.php?title=User:Example/foo.js&action=history',
|
||||
'https://example.org/w/index.php?title=User:Example/foo.js&action=raw&ctype=text/javascript',
|
||||
],
|
||||
Title::makeTitle( NS_USER, 'Example/foo.js' )->getCdnUrls(),
|
||||
'user config page'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
47
tests/phpunit/unit/includes/cache/HtmlCacheUpdaterTest.php
vendored
Normal file
47
tests/phpunit/unit/includes/cache/HtmlCacheUpdaterTest.php
vendored
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group Cache
|
||||
* @covers HtmlCacheUpdater
|
||||
*/
|
||||
class HtmlCacheUpdaterTest extends MediaWikiUnitTestCase {
|
||||
|
||||
public function testGetCdnUrls() {
|
||||
$htmlCache = new HtmlCacheUpdater( 0, false );
|
||||
$title = $this->createMock( Title::class );
|
||||
$title->method( 'getInternalURL' )->will( $this->returnCallback( function ( $query = '' ) {
|
||||
return 'https://test/?title=Example' . ( $query !== '' ? "&$query" : '' );
|
||||
} ) );
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'https://test/?title=Example',
|
||||
'https://test/?title=Example&action=history',
|
||||
],
|
||||
$htmlCache->getUrls( $title ),
|
||||
'all urls for an article'
|
||||
);
|
||||
$this->assertEquals(
|
||||
[
|
||||
'https://test/?title=Example',
|
||||
],
|
||||
$htmlCache->getUrls( $title, $htmlCache::PURGE_URLS_LINKSUPDATE_ONLY ),
|
||||
'linkupdate urls for an article'
|
||||
);
|
||||
|
||||
$title = $this->createMock( Title::class );
|
||||
$title->method( 'getInternalURL' )->will( $this->returnCallback( function ( $query = '' ) {
|
||||
return 'https://test/?title=User:Example/foo.js' . ( $query !== '' ? "&$query" : '' );
|
||||
} ) );
|
||||
$title->method( 'isUserJsConfigPage' )->willReturn( true );
|
||||
$this->assertEquals(
|
||||
[
|
||||
'https://test/?title=User:Example/foo.js',
|
||||
'https://test/?title=User:Example/foo.js&action=history',
|
||||
'https://test/?title=User:Example/foo.js&action=raw&ctype=text/javascript',
|
||||
],
|
||||
$htmlCache->getUrls( $title ),
|
||||
'all urls for a user js page'
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue