jenkins-bot has submitted this change and it was merged.
Change subject: Conversion to using WAN cache
......................................................................
Conversion to using WAN cache
* Bumped the key version due to key wrapping
* Removed isValidList() gived the key versioning
* Follow up ba1311c323 by making APC viable;
previously, definition purges would not work
Bug: T93141
Change-Id: I6da3eede044bf4b840b3f9656a1ae8105941dc6b
---
M GadgetHooks.php
M Gadgets_body.php
M tests/GadgetTest.php
3 files changed, 91 insertions(+), 54 deletions(-)
Approvals:
Ori.livneh: Looks good to me, approved
jenkins-bot: Verified
diff --git a/GadgetHooks.php b/GadgetHooks.php
old mode 100644
new mode 100755
index 64c7a3f..c84ad5b
--- a/GadgetHooks.php
+++ b/GadgetHooks.php
@@ -34,7 +34,7 @@
// update cache if MediaWiki:Gadgets-definition was edited
$title = $article->getTitle();
if ( $title->getNamespace() == NS_MEDIAWIKI &&
$title->getText() == 'Gadgets-definition' ) {
- Gadget::loadStructuredList( $text );
+ Gadget::purgeDefinitionCache();
}
return true;
}
diff --git a/Gadgets_body.php b/Gadgets_body.php
old mode 100644
new mode 100755
index ddef5e5..561cff7
--- a/Gadgets_body.php
+++ b/Gadgets_body.php
@@ -19,7 +19,9 @@
/**
* Increment this when changing class structure
*/
- const GADGET_CLASS_VERSION = 7;
+ const GADGET_CLASS_VERSION = 8;
+
+ const CACHE_TTL = 86400;
private $scripts = array(),
$styles = array(),
@@ -33,6 +35,9 @@
$onByDefault = false,
$position = 'bottom',
$category;
+
+ /** @var array|bool Result of loadStructuredList() */
+ private static $definitionCache;
/**
* Creates an instance of this class from definition in
MediaWiki:Gadgets-definition
@@ -307,81 +312,93 @@
}
/**
- * Checks whether gadget list from cache can be used.
- * @param $gadgets array
- * @return Boolean
- */
- private static function isValidList( $gadgets ) {
- if ( !is_array( $gadgets ) ) {
- return false;
- }
- // Check if we have an array of gadgets
- // One check is enough
- /**
- * @var $g Gadget
- */
- foreach ( $gadgets as $list ) {
- foreach ( $list as $g ) {
- return $g instanceof Gadget;
- }
- }
-
- return true; // empty array
- }
-
- /**
* Loads list of gadgets and returns it as associative array of
sections with gadgets
* e.g. array( 'sectionnname1' => array( $gadget1, $gadget2 ),
* 'sectionnname2' => array( $gadget3 ) );
- * @param $forceNewText String: New text of
MediaWiki:gadgets-definition. If specified, will
- * force a purge of cache and recreation of the gadget list.
- * @return Mixed: Array or false
+ * @return array|bool Gadget array or false on failure
*/
- public static function loadStructuredList( $forceNewText = null ) {
- static $gadgets = null;
- if ( $gadgets !== null && $forceNewText === null ) {
- return $gadgets;
+ public static function loadStructuredList() {
+ if ( self::$definitionCache !== null ) {
+ return self::$definitionCache; // process cache hit
}
$config = ConfigFactory::getDefaultInstance()->makeConfig(
'gadgets' );
- $cache = ObjectCache::getInstance( $config->get(
'GadgetsCacheType' ) ?: CACHE_ANYTHING );
+ // Ideally $t1Cache is APC, and $wanCache is memcached
+ $t1Cache = $config->get( 'GadgetsCacheType' )
+ ? ObjectCache::getInstance( $config->get(
'GadgetsCacheType' ) )
+ : ObjectCache::getInstance( CACHE_NONE );
+ $wanCache = ObjectCache::getMainWANInstance();
+
$key = wfMemcKey( 'gadgets-definition',
self::GADGET_CLASS_VERSION );
- if ( $forceNewText === null ) {
- if ( $config->get( 'GadgetsCaching' ) ) {
- // cached?
- $gadgets = $cache->get( $key );
- if ( self::isValidList( $gadgets ) ) {
- return $gadgets;
- }
+ if ( $config->get( 'GadgetsCaching' ) ) {
+ // Cache generated after this time should be up-to-date
+ $ckTime = $wanCache->getCheckKeyTime( $key ) +
WANObjectCache::HOLDOFF_TTL;
+ // Check the tier 1 cache
+ $value = $t1Cache->get( $key );
+ if ( $value && $value['time'] > $ckTime ) {
+ self::$definitionCache = $value['gadgets']; //
process cache
+ return self::$definitionCache;
}
+ // Fetch value from WAN cache or regenerate if needed.
+ // This is hit occasinally and more so when the list
changes.
+ $value = $wanCache->getWithSetCallback(
+ $key,
+ function( $old, &$ttl ) {
+ $now = microtime( true );
+ $gadgets =
Gadget::fetchStructuredList();
+ if ( $gadgets === false ) {
+ $ttl =
WANObjectCache::TTL_UNCACHEABLE;
+ }
+
+ return array( 'gadgets' => $gadgets,
'time' => $now );
+ },
+ self::CACHE_TTL,
+ array( $key ),
+ array( 'lockTSE' => 300 )
+ );
+
+ // Update the tier 1 cache as needed
+ if ( $value['gadgets'] !== false && $value['time'] >
$ckTime ) {
+ // Set a modest TTL to keep the WAN key in cache
+ $t1Cache->set( $key, $value, mt_rand( 300, 600
) );
+ }
+
+ self::$definitionCache = $value['gadgets']; // process
cache
+ } else {
+ self::$definitionCache = self::fetchStructuredList();
// process cache
+ }
+
+ return self::$definitionCache;
+ }
+
+ /**
+ * Fetch list of gadgets and returns it as associative array of
sections with gadgets
+ * e.g. array( 'sectionnname1' => array( $gadget1, $gadget2 ),
+ * 'sectionnname2' => array( $gadget3 ) );
+ * @param $forceNewText String: Injected text of
MediaWiki:gadgets-definition [optional]
+ * @return array|bool
+ */
+ public static function fetchStructuredList( $forceNewText = null ) {
+ if ( $forceNewText === null ) {
$g = wfMessage( "gadgets-definition"
)->inContentLanguage();
if ( !$g->exists() ) {
- $gadgets = false;
- return $gadgets;
+ return false; // don't cache
}
+
$g = $g->plain();
} else {
$g = $forceNewText;
}
$gadgets = self::listFromDefinition( $g );
-
if ( !count( $gadgets ) ) {
- // Don't cache in case we couldn't find any gadgets.
Bug 37228
- $gadgets = false;
- return $gadgets;
+ return false; // don't cache; Bug 37228
}
- if ( !$config->get( 'GadgetsCaching' ) ) {
- return $gadgets;
- }
-
- // cache for a while. gets purged automatically when
MediaWiki:Gadgets-definition is edited
- $cache->set( $key, $gadgets, 60 * 60 * 24 );
$source = $forceNewText !== null ? 'input text' :
'MediaWiki:Gadgets-definition';
- wfDebug( __METHOD__ . ": $source parsed, cache entry $key
updated\n" );
+ wfDebug( __METHOD__ . ": $source parsed, cache entry should be
updated\n" );
return $gadgets;
}
@@ -414,6 +431,23 @@
return $gadgets;
}
+
+ /**
+ * Update MediaWiki:Gadgets-definition cache
+ */
+ public static function purgeDefinitionCache() {
+ $key = wfMemcKey( 'gadgets-definition',
Gadget::GADGET_CLASS_VERSION );
+ ObjectCache::getMainWANInstance()->touchCheckKey( $key );
+ }
+
+ /**
+ * Inject gadgets into the process cache for unit tests
+ *
+ * @param array|bool $cache Result of fetchStructuredList()
+ */
+ public static function injectDefinitionCache( $cache ) {
+ self::$definitionCache = $cache;
+ }
}
/**
diff --git a/tests/GadgetTest.php b/tests/GadgetTest.php
old mode 100644
new mode 100755
index 8fd0929..6dc74f6
--- a/tests/GadgetTest.php
+++ b/tests/GadgetTest.php
@@ -46,13 +46,16 @@
function testPreferences() {
$prefs = array();
- Gadget::loadStructuredList( '* foo | foo.js
+ $gadgets = Gadget::fetchStructuredList( '* foo | foo.js
==keep-section1==
* bar| bar.js
==remove-section==
* baz [rights=embezzle] |baz.js
==keep-section2==
* quux [rights=read] | quux.js' );
+ $this->assertGreaterThanOrEqual( 2, count( $gadgets ), "Gadget
list parsed" );
+
+ Gadget::injectDefinitionCache( $gadgets );
$this->assertTrue( GadgetHooks::getPreferences( new User,
$prefs ), 'GetPrefences hook should return true' );
$options = $prefs['gadgets']['options'];
--
To view, visit https://gerrit.wikimedia.org/r/207730
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I6da3eede044bf4b840b3f9656a1ae8105941dc6b
Gerrit-PatchSet: 10
Gerrit-Project: mediawiki/extensions/Gadgets
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Aaron Schulz <[email protected]>
Gerrit-Reviewer: Alex Monk <[email protected]>
Gerrit-Reviewer: Gilles <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Ori.livneh <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits