diff options
author | Aaron Schulz <aschulz@wikimedia.org> | 2019-03-14 17:23:26 -0700 |
---|---|---|
committer | James D. Forrester <jforrester@wikimedia.org> | 2019-08-06 13:45:27 -0700 |
commit | 35da1bbd7cb8b4414c4fbcf331473f1024bc638d (patch) | |
tree | f903765d437301b1bff67ebea4fd895ce64132d9 | |
parent | a6b45d2a20c9be095431ac60ba0a4f5951b5f387 (diff) | |
download | mediawikicore-35da1bbd7cb8b4414c4fbcf331473f1024bc638d.tar.gz mediawikicore-35da1bbd7cb8b4414c4fbcf331473f1024bc638d.zip |
Add small HtmlCacheUpdater service class to normalize purging code
The purge() method handles purging of both file cache and CDN, using
a PRESEND deferred update. This avoids code duplication and missing
file cache purge calls.
Also:
* Migrate HTMLCacheUpdate callers to just directly using HTMLCacheUpdateJob
* Add HtmlFileCacheUpdate class and defer such updates just like with CDN
* Simplify HTMLCacheUpdate constructor parameters
* Remove BacklinkCache::clear() calls which do nothing since the backlink
query does not actually happen until the job runs
Change-Id: Ic453b189a40109a73a9426538608eea87a76befa
-rw-r--r-- | RELEASE-NOTES-1.34 | 3 | ||||
-rw-r--r-- | autoload.php | 2 | ||||
-rw-r--r-- | includes/MediaWikiServices.php | 9 | ||||
-rw-r--r-- | includes/ServiceWiring.php | 4 | ||||
-rw-r--r-- | includes/Title.php | 21 | ||||
-rw-r--r-- | includes/cache/HTMLFileCache.php | 24 | ||||
-rw-r--r-- | includes/cache/HtmlCacheUpdater.php | 94 | ||||
-rw-r--r-- | includes/deferred/CdnCacheUpdate.php | 14 | ||||
-rw-r--r-- | includes/deferred/HTMLCacheUpdate.php | 27 | ||||
-rw-r--r-- | includes/deferred/HtmlFileCacheUpdate.php | 61 | ||||
-rw-r--r-- | includes/deferred/LinksUpdate.php | 9 | ||||
-rw-r--r-- | includes/filerepo/file/File.php | 9 | ||||
-rw-r--r-- | includes/filerepo/file/LocalFile.php | 35 | ||||
-rw-r--r-- | includes/jobqueue/jobs/HTMLCacheUpdateJob.php | 23 | ||||
-rw-r--r-- | includes/page/PageArchive.php | 8 | ||||
-rw-r--r-- | includes/page/WikiFilePage.php | 7 | ||||
-rw-r--r-- | includes/page/WikiPage.php | 55 | ||||
-rw-r--r-- | includes/revisiondelete/RevDelFileList.php | 5 | ||||
-rw-r--r-- | includes/revisiondelete/RevDelRevisionList.php | 6 |
19 files changed, 298 insertions, 118 deletions
diff --git a/RELEASE-NOTES-1.34 b/RELEASE-NOTES-1.34 index 8ecc469d67b0..56a886e44729 100644 --- a/RELEASE-NOTES-1.34 +++ b/RELEASE-NOTES-1.34 @@ -92,6 +92,8 @@ For notes on 1.33.x and older releases, see HISTORY. to add fields to Special:Mute. * (T100896) Skin authors can define custom OOUI themes using OOUIThemePaths. See <https://www.mediawiki.org/wiki/OOUI/Themes> for details. +* The HtmlCacheUpdater service was added to unify the logic of purging CDN cache + and HTML file cache to simplify callers and make them more consistent. === External library changes in 1.34 === @@ -435,6 +437,7 @@ because of Phabricator reports. * SearchEngine::textAlreadyUpdatedForIndex() is deprecated, given the deprecation above this method is no longer needed/called and should not be implemented by SearchEngine implementation. +* Title::purgeSquid is deprecated. Use MediaWikiServices::getHtmlCacheUpdater. === Other changes in 1.34 === * … diff --git a/autoload.php b/autoload.php index 0208a6d783aa..ed6bb12aa642 100644 --- a/autoload.php +++ b/autoload.php @@ -642,6 +642,8 @@ $wgAutoloadLocalClasses = [ 'Hooks' => __DIR__ . '/includes/Hooks.php', 'Html' => __DIR__ . '/includes/Html.php', 'HtmlArmor' => __DIR__ . '/includes/libs/HtmlArmor.php', + 'HtmlCacheUpdater' => __DIR__ . '/includes/cache/HtmlCacheUpdater.php', + 'HtmlFileCacheUpdate' => __DIR__ . '/includes/deferred/HtmlFileCacheUpdate.php', 'Http' => __DIR__ . '/includes/http/Http.php', 'HttpError' => __DIR__ . '/includes/exception/HttpError.php', 'HttpStatus' => __DIR__ . '/includes/libs/HttpStatus.php', diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index 7fda45280ac5..fb30199ffe79 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -68,6 +68,7 @@ use Wikimedia\Services\NoSuchServiceException; use MediaWiki\Interwiki\InterwikiLookup; use MagicWordFactory; use MediaWiki\Storage\PageEditStash; +use HtmlCacheUpdater; /** * Service locator for MediaWiki core services. @@ -596,6 +597,14 @@ class MediaWikiServices extends ServiceContainer { } /** + * @return HtmlCacheUpdater + * @since 1.34 + */ + public function getHtmlCacheUpdater() { + return $this->getService( 'HtmlCacheUpdater' ); + } + + /** * @since 1.31 * @return HttpRequestFactory */ diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index 9073de1c0eac..d6b4d65433ce 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -218,6 +218,10 @@ return [ return new GenderCache( $services->getNamespaceInfo() ); }, + 'HtmlCacheUpdater' => function ( MediaWikiServices $services ) : HtmlCacheUpdater { + return new HtmlCacheUpdater(); + }, + 'HttpRequestFactory' => function ( MediaWikiServices $services ) : HttpRequestFactory { return new HttpRequestFactory(); diff --git a/includes/Title.php b/includes/Title.php index 281f75bac1e7..674767d37b7b 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -3432,12 +3432,10 @@ class Title implements LinkTarget, IDBAccessObject { /** * Purge all applicable CDN URLs + * @deprecated 1.34 Use HtmlCacheUpdater */ public function purgeSquid() { - DeferredUpdates::addUpdate( - new CdnCacheUpdate( $this->getCdnUrls() ), - DeferredUpdates::PRESEND - ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $this->getCdnUrls() ); } /** @@ -4245,12 +4243,21 @@ class Title implements LinkTarget, IDBAccessObject { * on the number of links. Typically called on create and delete. */ public function touchLinks() { - DeferredUpdates::addUpdate( new HTMLCacheUpdate( $this, 'pagelinks', 'page-touch' ) ); + $jobs = []; + $jobs[] = HTMLCacheUpdateJob::newForBacklinks( + $this, + 'pagelinks', + [ 'causeAction' => 'page-touch' ] + ); if ( $this->mNamespace == NS_CATEGORY ) { - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $this, 'categorylinks', 'category-touch' ) + $jobs[] = HTMLCacheUpdateJob::newForBacklinks( + $this, + 'categorylinks', + [ 'causeAction' => 'category-touch' ] ); } + + JobQueueGroup::singleton()->lazyPush( $jobs ); } /** diff --git a/includes/cache/HTMLFileCache.php b/includes/cache/HTMLFileCache.php index a0d61b259efd..6d0b87e6e66c 100644 --- a/includes/cache/HTMLFileCache.php +++ b/includes/cache/HTMLFileCache.php @@ -220,20 +220,32 @@ class HTMLFileCache extends FileCacheBase { } /** + * @param string[] $prefixedDbKeys List of prefixed DB keys for pages to purge + * @since 1.34 + */ + public static function purge( array $prefixedDbKeys ) { + foreach ( $prefixedDbKeys as $prefixedDbKey ) { + foreach ( self::cacheablePageActions() as $type ) { + $fc = new self( $prefixedDbKey, $type ); + $fc->clearCache(); + } + } + } + + /** * Clear the file caches for a page for all actions - * @param Title $title + * @param Traversable|Title[]|Title $titles * @return bool Whether $wgUseFileCache is enabled */ - public static function clearFileCache( Title $title ) { + public static function clearFileCache( $titles ) { $config = MediaWikiServices::getInstance()->getMainConfig(); - if ( !$config->get( 'UseFileCache' ) ) { return false; } - foreach ( self::cacheablePageActions() as $type ) { - $fc = new self( $title, $type ); - $fc->clearCache(); + $titleIterator = ( $titles instanceof Title ) ? [ $titles ] : $titles; + foreach ( $titleIterator as $title ) { + self::purge( [ $title->getPrefixedDBkey() ] ); } return true; diff --git a/includes/cache/HtmlCacheUpdater.php b/includes/cache/HtmlCacheUpdater.php new file mode 100644 index 000000000000..b04428c99b38 --- /dev/null +++ b/includes/cache/HtmlCacheUpdater.php @@ -0,0 +1,94 @@ +<?php +/** + * HTML/file cache invalidation of cacheable variant/action URLs for a page + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ + +/** + * Class to invalidate the HTML/file cache of cacheable variant/action URLs for a page + * + * @ingroup Cache + * @since 1.34 + */ +class HtmlCacheUpdater { + /** @var int Purge after the main transaction round and respect $wgCdnReboundPurgeDelay */ + const ISOLATION_AND_LAG_AWARE = 1; + /** @var int Purge immediately and only once (ignore $wgCdnReboundPurgeDelay) */ + const IMMEDIATE_WITHOUT_REBOUND = 2; + + /** + * Purge CDN/HTMLFileCache for a URL, Title, or iteratable of URL or Title entries + * + * String entries will be treated as URLs to be purged from the CDN layer. + * For Title entries, all cacheable canonical URLs associated with the page + * will be purged from the CDN and HTMLFileCache. + * + * The cache purges are queued as PRESEND deferred updates so that they run after the + * main database transaction round of LBFactory. This reduces the chance of race conditions + * where a stale value is re-populated before commit. Depending on $wgCdnReboundPurgeDelay, + * a secondary set of purges might be issued several seconds later through the use of a + * delayed job. This is used to mitigate the effects of DB replication lag as well as + * multiple layers of CDN proxies. All deferred CDN purges are combined and de-duplicated + * into a single DeferrableUpdate instance. This improves HTTP PURGE request pipelining. + * + * Use the IMMEDIATE_WITHOUT_REBOUND class constant to instantly issue the purges instead + * and skip the use of any secondary purges regardless of $wgCdnReboundPurgeDelay. + * + * @param Traversable|Title[]|Title|string[]|string $entries + * @param int $mode ISOLATION_AND_LAG_AWARE or IMMEDIATE_WITHOUT_REBOUND class constant + */ + public function purge( $entries, $mode = self::ISOLATION_AND_LAG_AWARE ) { + $urls = []; + $titles = []; + if ( is_string( $entries ) ) { + $urls = [ $entries ]; + } elseif ( $entries instanceof Title ) { + $titles = [ $entries ]; + } elseif ( $entries instanceof TitleArray ) { + $titles = $entries; // save memory + } else { + foreach ( $entries as $entry ) { + if ( is_string( $entry ) ) { + $urls[] = $entry; + } else { + $titles[] = $entry; + } + } + } + + if ( $mode === self::IMMEDIATE_WITHOUT_REBOUND ) { + HTMLFileCache::clearFileCache( $titles ); + foreach ( $titles as $title ) { + /** @var Title $title */ + $urls = array_merge( $urls, $title->getCdnUrls() ); + } + CdnCacheUpdate::purge( $urls ); // purge once (no "rebound" purges) + } else { + DeferredUpdates::addUpdate( + HtmlFileCacheUpdate::newFromTitles( $titles ), + DeferredUpdates::PRESEND + ); + DeferredUpdates::addUpdate( + CdnCacheUpdate::newFromTitles( $titles, $urls ), + DeferredUpdates::PRESEND + ); + } + } +} diff --git a/includes/deferred/CdnCacheUpdate.php b/includes/deferred/CdnCacheUpdate.php index 66ce9a3ddf83..a867f2062ef4 100644 --- a/includes/deferred/CdnCacheUpdate.php +++ b/includes/deferred/CdnCacheUpdate.php @@ -24,12 +24,12 @@ use Wikimedia\Assert\Assert; use MediaWiki\MediaWikiServices; /** - * Handles purging appropriate CDN URLs given a title (or titles) + * Handles purging the appropriate CDN objects given a list of URLs or Title instances * @ingroup Cache */ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate { /** @var string[] Collection of URLs to purge */ - protected $urls = []; + private $urls = []; /** * @param string[] $urlArr Collection of URLs to purge @@ -59,12 +59,9 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate { $urlArr = array_merge( $urlArr, $title->getCdnUrls() ); } - return new CdnCacheUpdate( $urlArr ); + return new self( $urlArr ); } - /** - * Purges the list of URLs passed to the constructor. - */ public function doUpdate() { global $wgCdnReboundPurgeDelay; @@ -98,10 +95,9 @@ class CdnCacheUpdate implements DeferrableUpdate, MergeableUpdate { wfDebugLog( 'squid', __METHOD__ . ': ' . implode( ' ', $urlArr ) ); // Reliably broadcast the purge to all edge nodes - $relayer = MediaWikiServices::getInstance()->getEventRelayerGroup() - ->getRelayer( 'cdn-url-purges' ); $ts = microtime( true ); - $relayer->notifyMulti( + $relayerGroup = MediaWikiServices::getInstance()->getEventRelayerGroup(); + $relayerGroup->getRelayer( 'cdn-url-purges' )->notifyMulti( 'cdn-url-purges', array_map( function ( $url ) use ( $ts ) { diff --git a/includes/deferred/HTMLCacheUpdate.php b/includes/deferred/HTMLCacheUpdate.php index 29846bfb77f8..3dd533db7e78 100644 --- a/includes/deferred/HTMLCacheUpdate.php +++ b/includes/deferred/HTMLCacheUpdate.php @@ -22,39 +22,32 @@ */ /** - * Class to invalidate the HTML cache of all the pages linking to a given title. + * Class to invalidate the HTML/file cache of all the pages linking to a given title. * * @ingroup Cache + * @deprecated Since 1.34; Enqueue jobs from HTMLCacheUpdateJob::newForBacklinks instead */ class HTMLCacheUpdate extends DataUpdate { /** @var Title */ - public $mTitle; - + private $title; /** @var string */ - public $mTable; + private $table; /** - * @param Title $titleTo + * @param Title $title * @param string $table - * @param string $causeAction Triggering action - * @param string $causeAgent Triggering user */ - function __construct( - Title $titleTo, $table, $causeAction = 'unknown', $causeAgent = 'unknown' - ) { - $this->mTitle = $titleTo; - $this->mTable = $table; - $this->causeAction = $causeAction; - $this->causeAgent = $causeAgent; + public function __construct( Title $title, $table ) { + $this->title = $title; + $this->table = $table; } public function doUpdate() { $job = HTMLCacheUpdateJob::newForBacklinks( - $this->mTitle, - $this->mTable, + $this->title, + $this->table, [ 'causeAction' => $this->getCauseAction(), 'causeAgent' => $this->getCauseAgent() ] ); - JobQueueGroup::singleton()->lazyPush( $job ); } } diff --git a/includes/deferred/HtmlFileCacheUpdate.php b/includes/deferred/HtmlFileCacheUpdate.php new file mode 100644 index 000000000000..7be8b61eaba9 --- /dev/null +++ b/includes/deferred/HtmlFileCacheUpdate.php @@ -0,0 +1,61 @@ +<?php +/** + * HTMLFileCache cache purging + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + */ + +use MediaWiki\MediaWikiServices; + +/** + * Handles purging the appropriate HTMLFileCache files given a list of titles + * @ingroup Cache + */ +class HtmlFileCacheUpdate implements DeferrableUpdate { + /** @var string[] Collection of prefixed DB keys for the pages to purge */ + private $prefixedDbKeys = []; + + /** + * @param string[] $prefixedDbKeys + */ + public function __construct( array $prefixedDbKeys ) { + $this->prefixedDbKeys = $prefixedDbKeys; + } + + /** + * Create an update object from an array of Title objects, or a TitleArray object + * + * @param Traversable|Title[] $titles + * @return HtmlFileCacheUpdate + */ + public static function newFromTitles( $titles ) { + $prefixedDbKeys = []; + foreach ( $titles as $title ) { + $prefixedDbKeys[] = $title->getPrefixedDBkey(); + } + + return new self( $prefixedDbKeys ); + } + + public function doUpdate() { + $config = MediaWikiServices::getInstance()->getMainConfig(); + if ( $config->get( 'UseFileCache' ) ) { + HTMLFileCache::purge( $this->prefixedDbKeys ); + } + } +} diff --git a/includes/deferred/LinksUpdate.php b/includes/deferred/LinksUpdate.php index 74e236fd4d74..ff293cb9d87c 100644 --- a/includes/deferred/LinksUpdate.php +++ b/includes/deferred/LinksUpdate.php @@ -1066,6 +1066,7 @@ class LinksUpdate extends DataUpdate { private function invalidateProperties( $changed ) { global $wgPagePropLinkInvalidations; + $jobs = []; foreach ( $changed as $name => $value ) { if ( isset( $wgPagePropLinkInvalidations[$name] ) ) { $inv = $wgPagePropLinkInvalidations[$name]; @@ -1073,12 +1074,16 @@ class LinksUpdate extends DataUpdate { $inv = [ $inv ]; } foreach ( $inv as $table ) { - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $this->mTitle, $table, 'page-props' ) + $jobs[] = HTMLCacheUpdateJob::newForBacklinks( + $this->mTitle, + $table, + [ 'causeAction' => 'page-props' ] ); } } } + + JobQueueGroup::singleton()->lazyPush( $jobs ); } /** diff --git a/includes/filerepo/file/File.php b/includes/filerepo/file/File.php index ee7ee6f90dcd..eca546494255 100644 --- a/includes/filerepo/file/File.php +++ b/includes/filerepo/file/File.php @@ -1453,7 +1453,7 @@ abstract class File implements IDBAccessObject { $title = $this->getTitle(); if ( $title ) { $title->invalidateCache(); - $title->purgeSquid(); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $title ); } } @@ -1469,9 +1469,12 @@ abstract class File implements IDBAccessObject { // Purge cache of all pages using this file $title = $this->getTitle(); if ( $title ) { - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $title, 'imagelinks', 'file-purge' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $title, + 'imagelinks', + [ 'causeAction' => 'file-purge' ] ); + JobQueueGroup::singleton()->lazyPush( $job ); } } diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php index 54fc251f4bd1..989d22283fc4 100644 --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@ -1047,10 +1047,7 @@ class LocalFile extends File { $this->purgeThumbnails( $options ); // Purge CDN cache for this file - DeferredUpdates::addUpdate( - new CdnCacheUpdate( [ $this->getUrl() ] ), - DeferredUpdates::PRESEND - ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $this->getUrl() ); } /** @@ -1073,7 +1070,7 @@ class LocalFile extends File { foreach ( $files as $file ) { $urls[] = $this->getArchiveThumbUrl( $archiveName, $file ); } - DeferredUpdates::addUpdate( new CdnCacheUpdate( $urls ), DeferredUpdates::PRESEND ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $urls ); } /** @@ -1105,7 +1102,7 @@ class LocalFile extends File { $this->purgeThumbList( $dir, $files ); // Purge the CDN - DeferredUpdates::addUpdate( new CdnCacheUpdate( $urls ), DeferredUpdates::PRESEND ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $urls ); } /** @@ -1725,8 +1722,9 @@ class LocalFile extends File { } } else { # Existing file page: invalidate description page cache - $wikiPage->getTitle()->invalidateCache(); - $wikiPage->getTitle()->purgeSquid(); + $title = $wikiPage->getTitle(); + $title->invalidateCache(); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $title ); # Allow the new file version to be patrolled from the page footer Article::purgePatrolFooterCache( $descId ); } @@ -1774,10 +1772,8 @@ class LocalFile extends File { # Delete old thumbnails $this->purgeThumbnails(); # Remove the old file from the CDN cache - DeferredUpdates::addUpdate( - new CdnCacheUpdate( [ $this->getUrl() ] ), - DeferredUpdates::PRESEND - ); + MediaWikiServices::getInstance() + ->getHtmlCacheUpdater()->purge( $this->getUrl() ); } else { # Update backlink pages pointing to this title if created LinksUpdate::queueRecursiveJobsForTable( @@ -1800,9 +1796,12 @@ class LocalFile extends File { } # Invalidate cache for all pages using this file - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $this->getTitle(), 'imagelinks', 'file-upload' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $this->getTitle(), + 'imagelinks', + [ 'causeAction' => 'file-upload', 'causeAgent' => $user->getName() ] ); + JobQueueGroup::singleton()->lazyPush( $job ); return Status::newGood(); } @@ -2004,7 +2003,7 @@ class LocalFile extends File { foreach ( $archiveNames as $archiveName ) { $purgeUrls[] = $this->getArchiveUrl( $archiveName ); } - DeferredUpdates::addUpdate( new CdnCacheUpdate( $purgeUrls ), DeferredUpdates::PRESEND ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $purgeUrls ); return $status; } @@ -2041,10 +2040,8 @@ class LocalFile extends File { $this->purgeDescription(); } - DeferredUpdates::addUpdate( - new CdnCacheUpdate( [ $this->getArchiveUrl( $archiveName ) ] ), - DeferredUpdates::PRESEND - ); + $url = $this->getArchiveUrl( $archiveName ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $url ); return $status; } diff --git a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php index 73fa947790bb..a2e47343db21 100644 --- a/includes/jobqueue/jobs/HTMLCacheUpdateJob.php +++ b/includes/jobqueue/jobs/HTMLCacheUpdateJob.php @@ -25,7 +25,7 @@ use MediaWiki\MediaWikiServices; /** - * Job to purge the cache for all pages that link to or use another page or file + * Job to purge the HTML/file cache for all pages that link to or use another page or file * * This job comes in a few variants: * - a) Recursive jobs to purge caches for backlink pages for a given title. @@ -110,7 +110,7 @@ class HTMLCacheUpdateJob extends Job { * @param array $pages Map of (page ID => (namespace, DB key)) entries */ protected function invalidateTitles( array $pages ) { - global $wgUpdateRowsPerQuery, $wgUseFileCache, $wgPageLanguageUseDB; + global $wgUpdateRowsPerQuery, $wgPageLanguageUseDB; // Get all page IDs in this query into an array $pageIds = array_keys( $pages ); @@ -160,20 +160,11 @@ class HTMLCacheUpdateJob extends Job { __METHOD__ ) ); - // Update CDN; call purge() directly so as to not bother with secondary purges - $urls = []; - foreach ( $titleArray as $title ) { - /** @var Title $title */ - $urls = array_merge( $urls, $title->getCdnUrls() ); - } - CdnCacheUpdate::purge( $urls ); - - // Update file cache - if ( $wgUseFileCache ) { - foreach ( $titleArray as $title ) { - HTMLFileCache::clearFileCache( $title ); - } - } + // Update CDN and file caches (avoiding secondary purge overhead) + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( + $titleArray, + HtmlCacheUpdater::IMMEDIATE_WITHOUT_REBOUND + ); } public function getDeduplicationInfo() { diff --git a/includes/page/PageArchive.php b/includes/page/PageArchive.php index d69a433d9ce8..19e417abe466 100644 --- a/includes/page/PageArchive.php +++ b/includes/page/PageArchive.php @@ -756,10 +756,14 @@ class PageArchive { Hooks::run( 'ArticleUndelete', [ &$this->title, $created, $comment, $oldPageId, $restoredPages ] ); + if ( $this->title->getNamespace() == NS_FILE ) { - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $this->title, 'imagelinks', 'file-restore' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $this->title, + 'imagelinks', + [ 'causeAction' => 'imagelinks', 'causeAgent' => 'file-restore' ] ); + JobQueueGroup::singleton()->lazyPush( $job ); } } diff --git a/includes/page/WikiFilePage.php b/includes/page/WikiFilePage.php index acd506ba79a0..fd9f7b24d8f3 100644 --- a/includes/page/WikiFilePage.php +++ b/includes/page/WikiFilePage.php @@ -176,9 +176,12 @@ class WikiFilePage extends WikiPage { if ( $this->mFile->exists() ) { wfDebug( 'ImagePage::doPurge purging ' . $this->mFile->getName() . "\n" ); - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $this->mTitle, 'imagelinks', 'file-purge' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $this->mTitle, + 'imagelinks', + [ 'causeAction' => 'file-purge' ] ); + JobQueueGroup::singleton()->lazyPush( $job ); } else { wfDebug( 'ImagePage::doPurge no image for ' . $this->mFile->getName() . "; limiting purge to cache only\n" ); diff --git a/includes/page/WikiPage.php b/includes/page/WikiPage.php index 3bc9f7c0f8d7..33fd4721d4bf 100644 --- a/includes/page/WikiPage.php +++ b/includes/page/WikiPage.php @@ -1294,13 +1294,8 @@ class WikiPage implements Page, IDBAccessObject { $this->mTitle->invalidateCache(); - // Clear file cache - HTMLFileCache::clearFileCache( $this->getTitle() ); - // Send purge after above page_touched update was committed - DeferredUpdates::addUpdate( - new CdnCacheUpdate( $this->mTitle->getCdnUrls() ), - DeferredUpdates::PRESEND - ); + // Clear file cache and send purge after above page_touched update was committed + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $this->mTitle ); if ( $this->mTitle->getNamespace() == NS_MEDIAWIKI ) { $messageCache = MessageCache::singleton(); @@ -3384,18 +3379,20 @@ class WikiPage implements Page, IDBAccessObject { // Update existence markers on article/talk tabs... $other = $title->getOtherPage(); - $other->purgeSquid(); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( [ $title, $other ] ); $title->touchLinks(); - $title->purgeSquid(); $title->deleteTitleProtection(); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title ); // Invalidate caches of articles which include this page - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $title, 'templatelinks', 'page-create' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $title, + 'templatelinks', + [ 'causeAction' => 'page-create' ] ); + JobQueueGroup::singleton()->lazyPush( $job ); if ( $title->getNamespace() == NS_CATEGORY ) { // Load the Category object, which will schedule a job to create @@ -3415,19 +3412,14 @@ class WikiPage implements Page, IDBAccessObject { // TODO: move this into a PageEventEmitter service // Update existence markers on article/talk tabs... - // Clear Backlink cache first so that purge jobs use more up-to-date backlink information - BacklinkCache::get( $title )->clear(); $other = $title->getOtherPage(); - $other->purgeSquid(); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( [ $title, $other ] ); $title->touchLinks(); - $title->purgeSquid(); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title ); - // File cache - HTMLFileCache::clearFileCache( $title ); InfoAction::invalidateCache( $title ); // Messages @@ -3437,9 +3429,12 @@ class WikiPage implements Page, IDBAccessObject { // Images if ( $title->getNamespace() == NS_FILE ) { - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $title, 'imagelinks', 'page-delete' ) + $job = HTMLCacheUpdateJob::newForBacklinks( + $title, + 'imagelinks', + [ 'causeAction' => 'page-delete' ] ); + JobQueueGroup::singleton()->lazyPush( $job ); } // User talk pages @@ -3472,26 +3467,28 @@ class WikiPage implements Page, IDBAccessObject { ) { // TODO: move this into a PageEventEmitter service - if ( $slotsChanged === null || in_array( SlotRecord::MAIN, $slotsChanged ) ) { + $jobs = []; + if ( $slotsChanged === null || in_array( SlotRecord::MAIN, $slotsChanged ) ) { // Invalidate caches of articles which include this page. // Only for the main slot, because only the main slot is transcluded. // TODO: MCR: not true for TemplateStyles! [SlotHandler] - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $title, 'templatelinks', 'page-edit' ) + $jobs[] = HTMLCacheUpdateJob::newForBacklinks( + $title, + 'templatelinks', + [ 'causeAction' => 'page-edit' ] ); } - // Invalidate the caches of all pages which redirect here - DeferredUpdates::addUpdate( - new HTMLCacheUpdate( $title, 'redirect', 'page-edit' ) + $jobs[] = HTMLCacheUpdateJob::newForBacklinks( + $title, + 'redirect', + [ 'causeAction' => 'page-edit' ] ); + JobQueueGroup::singleton()->lazyPush( $jobs ); MediaWikiServices::getInstance()->getLinkCache()->invalidateTitle( $title ); - // Purge CDN for this page only - $title->purgeSquid(); - // Clear file cache for this page only - HTMLFileCache::clearFileCache( $title ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $title ); // Purge ?action=info cache $revid = $revision ? $revision->getId() : null; diff --git a/includes/revisiondelete/RevDelFileList.php b/includes/revisiondelete/RevDelFileList.php index ca7bc040d0fa..d69fa36ca5f0 100644 --- a/includes/revisiondelete/RevDelFileList.php +++ b/includes/revisiondelete/RevDelFileList.php @@ -122,10 +122,7 @@ class RevDelFileList extends RevDelList { $file->purgeOldThumbnails( $archiveName ); $purgeUrls[] = $file->getArchiveUrl( $archiveName ); } - DeferredUpdates::addUpdate( - new CdnCacheUpdate( $purgeUrls ), - DeferredUpdates::PRESEND - ); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $purgeUrls ); return Status::newGood(); } diff --git a/includes/revisiondelete/RevDelRevisionList.php b/includes/revisiondelete/RevDelRevisionList.php index 0705503e9bec..1eaf0cc96c89 100644 --- a/includes/revisiondelete/RevDelRevisionList.php +++ b/includes/revisiondelete/RevDelRevisionList.php @@ -19,6 +19,7 @@ * @ingroup RevisionDelete */ +use MediaWiki\MediaWikiServices; use MediaWiki\Storage\RevisionRecord; use Wikimedia\Rdbms\FakeResultWrapper; use Wikimedia\Rdbms\IDatabase; @@ -177,9 +178,10 @@ class RevDelRevisionList extends RevDelList { } public function doPostCommitUpdates( array $visibilityChangeMap ) { - $this->title->purgeSquid(); + MediaWikiServices::getInstance()->getHtmlCacheUpdater()->purge( $this->title ); // Extensions that require referencing previous revisions may need this - Hooks::run( 'ArticleRevisionVisibilitySet', [ $this->title, $this->ids, $visibilityChangeMap ] ); + Hooks::run( 'ArticleRevisionVisibilitySet', + [ $this->title, $this->ids, $visibilityChangeMap ] ); return Status::newGood(); } } |