Cenarium has uploaded a new change for review.
https://gerrit.wikimedia.org/r/218265
Change subject: Overhaul caching of tag usage statistics
......................................................................
Overhaul caching of tag usage statistics
Caching is overhauled so that we can have a cached list of tags
applied at least once for T27909. A short term, reactive cache
is used for the statistics displayed at Special:Tags, which is
purged every time tags are updated, unless the tag has more hits
than a number specified in config (so that tags like mobile edit
don't cause cache purges every few second). A longer term, stable
cache is introduced for drop down menus, which is purged only when
a tag is added for the first time or when deleting tags.
Change-Id: I1b6838b975917fadc2c60998cce26ab490f22a31
---
M includes/DefaultSettings.php
M includes/changetags/ChangeTags.php
M includes/changetags/ChangeTagsContext.php
3 files changed, 96 insertions(+), 9 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/65/218265/1
diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index 24c910f..8cbe4c7 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -6162,6 +6162,13 @@
$wgTagUsageCacheDuration = 60*60*24;
/**
+ * Set this to a positive integer and tags with more than this many hits
+ * will not trigger a cache purge when applied. This means they won't be
+ * updated, but also less db queries and faster loading of Special:Tags.
+ */
+$wgTagMaxHitcountUpdate = 0;
+
+/**
* Expiry to use for the caching of tags registered by extensions
* 24 hours by default
*/
diff --git a/includes/changetags/ChangeTags.php
b/includes/changetags/ChangeTags.php
index e5b7e14..271600e 100644
--- a/includes/changetags/ChangeTags.php
+++ b/includes/changetags/ChangeTags.php
@@ -238,7 +238,7 @@
$dbw->delete( 'change_tag', $conds, __METHOD__
);
}
}
- ChangeTagsContext::purgeTagUsageCache();
+ ChangeTagsContext::clearCachesAfterUpdate( $tagsToAdd,
$tagsToRemove );
return array( $tagsToAdd, $tagsToRemove, $prevTags );
}
@@ -631,7 +631,7 @@
) {
global $wgUseTagFilter;
- $tagList = ChangeTagsContext::tagStats();
+ $tagList = ChangeTagsContext::cachedTagStats();
// check config and if the list of tags is not empty
if ( !$wgUseTagFilter || !count( $tagList ) ) {
return $fullForm ? '' : array();
diff --git a/includes/changetags/ChangeTagsContext.php
b/includes/changetags/ChangeTagsContext.php
index d5c8ee3..5d5c898 100644
--- a/includes/changetags/ChangeTagsContext.php
+++ b/includes/changetags/ChangeTagsContext.php
@@ -215,7 +215,9 @@
* Does not include tags defined somewhere but not applied
*
* The result is cached, and the cache is invalidated every time an
- * operation on change_tag is performed.
+ * operation on change_tag is performed unless $wgMaxTagHitcountUpdate
+ * is > 0. In that case, tags with a greater hitcount do not trigger
+ * a cache purge and therefore are not updated.
* The cache expires after 24 hours by default
($wgTagUsageCacheDuration).
*
* @return array Array of tags mapped to their hitcount
@@ -246,15 +248,92 @@
return $changeTags;
};
- $key = wfMemcKey( 'ChangeTags', 'tag-stats' );
+ $keyReactive = wfMemcKey( 'ChangeTags', 'tag-stats-reactive' );
return ObjectCache::getMainWANInstance()->getWithSetCallback(
- $key,
+ $keyReactive,
$callBack,
$wgTagUsageCacheDuration,
- array( $key ),
+ array( $keyReactive, $keyStable ),
array( 'lockTSE' => INF )
);
+ }
+
+ /**
+ * Returns a map of any tags used on the wiki to number of edits
+ * tagged with them, ordered descending by the hitcount as of the
+ * latest caching.
+ * Does not include tags defined somewhere but not applied
+ *
+ * This cache is invalidated only for first hits of a tag.
+ * Updates may be delayed by up to 48 hours by default
+ * (twice $wgTagUsageCacheDuration).
+ *
+ * @return array Array of tags mapped to their hitcount
+ * @since 1.26
+ */
+ public static function cachedTagStats() {
+ global $wgTagUsageCacheDuration;
+ $keyStable = wfMemcKey( 'ChangeTags', 'tag-stats-stable' );
+
+ $callBack = function () {
+ return self::tagStats();
+ };
+
+ return ObjectCache::getMainWANInstance()->getWithSetCallback(
+ $keyStable,
+ $callBack,
+ $wgTagUsageCacheDuration,
+ array( $keyStable ),
+ array( 'lockTSE' => INF )
+ );
+ }
+
+ /**
+ * Clear caches after tags have been updated
+ * This should be called after writes on the change_tag table.
+ *
+ * @param array $tagsToAdd: tags that were added
+ * @param array $tagsToRemove: tags that were removed
+ * @since 1.26
+ */
+ public static function clearCachesAfterUpdate( $tagsToAdd,
$tagsToRemove ) {
+ global $wgTagMaxHitcountUpdate;
+ $cache = ObjectCache::getMainWANInstance();
+ $key = wfMemcKey( 'ChangeTags', 'tag-stats-reactive' );
+
+ // Retrieve cached stats
+ $stats = $cache->get( $key, $ttl );
+
+ // We do the basic purge of the reactive cache unless all of
the added tags
+ // have more hits than $wgTagMaxHitcountUpdate.
+ $doBasicPurge = true;
+ // If the reactive cache was no longer valid, or one of the
added tags doesn't
+ // appear in it, we purge the stable cache too since it might
be a newly
+ // defined tag applied for the first time.
+ // We also purge the cache of extensions since they might not
have purged it
+ // and we don't want the tag to appear out of nowhere at
Special:Tags.
+ $doExtraPurge = ( $ttl === null ) || ( $ttl < 0 );
+ if ( count( $tagsToAdd ) && ( $wgTagMaxHitcountUpdate > 0 ||
!$doExtraPurge ) ) {
+ foreach ( $tagsToAdd as $tag ) {
+ if ( !isset( $stats[$tag] ) ) {
+ $doBasicPurge = true;
+ $doExtraPurge = true;
+ break;
+ } elseif ( $stats[$tag] >
$wgTagMaxHitcountUpdate ) {
+ $doBasicPurge = false;
+ } else {
+ $doBasicPurge = true;
+ }
+ }
+ }
+ if ( $doBasicPurge ) {
+ $cache->touchCheckKey( $key );
+ if ( $doExtraPurge ) {
+ $cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'tag-stats-stable' ) );
+ $cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'valid-tags-hook' ) );
+ }
+ }
}
/**
@@ -284,14 +363,14 @@
}
/**
- * Invalidates the cache of tag usage stats.
+ * Invalidates the reactive cache of tag usage stats.
* This should be called when we really need the up to date stats (e.g.
deletion).
*
* @since 1.26
*/
public static function purgeTagUsageCache() {
$cache = ObjectCache::getMainWANInstance();
- $cache->touchCheckKey( wfMemcKey( 'ChangeTags', 'tag-stats' ) );
+ $cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'tag-stats-reactive' ) );
}
/**
@@ -304,6 +383,7 @@
$cache = ObjectCache::getMainWANInstance();
$cache->touchCheckKey( wfMemcKey( 'ChangeTags', 'valid-tags-db'
) );
$cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'valid-tags-hook' ) );
- $cache->touchCheckKey( wfMemcKey( 'ChangeTags', 'tag-stats' ) );
+ $cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'tag-stats-reactive' ) );
+ $cache->touchCheckKey( wfMemcKey( 'ChangeTags',
'tag-stats-stable' ) );
}
}
--
To view, visit https://gerrit.wikimedia.org/r/218265
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I1b6838b975917fadc2c60998cce26ab490f22a31
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Cenarium <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits