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 <cenarium.sy...@gmail.com>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to