Aaron Schulz has uploaded a new change for review.
https://gerrit.wikimedia.org/r/239442
Change subject: Improvements to WANObjectCache::getWithSetCallback()
......................................................................
Improvements to WANObjectCache::getWithSetCallback()
* If lockTSE is set, make sure it applies during during
the entire duration of a key being tombstoned. This lets
regenerations happen during that whole time, which lowers
the chance of seeing stale data if the DBs are lagged.
* If lockTSE is not set, do not apply tempTTL (for tomstoned keys).
If traffic is high, a stale value would usually be "stashed" and
used for TEMP_TTL seconds. If the lag was only 1 second, then this
is suboptimal.
* Enable lockTSE by default, since additional overhead is only
incurred a few seconds around invalidations, and it can prevent
DB overhead by avoiding stampedes.
Change-Id: I3b01f0ec67935a238b30e02e42004fd3b2dcfb9d
---
M includes/libs/objectcache/WANObjectCache.php
1 file changed, 21 insertions(+), 13 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core
refs/changes/42/239442/1
diff --git a/includes/libs/objectcache/WANObjectCache.php
b/includes/libs/objectcache/WANObjectCache.php
index 130caeb..85a15e9 100644
--- a/includes/libs/objectcache/WANObjectCache.php
+++ b/includes/libs/objectcache/WANObjectCache.php
@@ -75,6 +75,8 @@
const LOCK_TTL = 5;
/** Default remaining TTL at which to consider pre-emptive regeneration
*/
const LOW_TTL = 10;
+ /** Default time-since-expiry on a miss that makes a key "hot" */
+ const LOCK_TSE = 2;
/** Default TTL for temporarily caching tombstoned keys */
const TEMP_TTL = 5;
@@ -465,6 +467,7 @@
* - lowTTL : consider pre-emptive updates when the current TTL (sec)
* of the key is less than this. It becomes more likely
* over time, becoming a certainty once the key is
expired.
+ * [Default: WANObjectCache::LOW_TTL seconds]
* - lockTSE : if the key is tombstoned or expired (by $checkKeys)
less
* than this many seconds ago, then try to have a single
* thread handle cache regeneration at any given time.
@@ -472,16 +475,18 @@
* If, on miss, the time since expiration is low, the
assumption
* is that the key is hot and that a stampede is worth
avoiding.
* Setting this above WANObjectCache::HOLDOFF_TTL makes
no difference.
+ * [Default: WANObjectCache::LOCK_TSE seconds]
* - tempTTL : TTL of the temp key used to cache values while a key
is tombstoned.
* This avoids excessive regeneration of hot keys on
delete() but may
* result in stale values.
+ * [Default: WANObjectCache::TEMP_TTL seconds]
* @return mixed Value to use for the key
*/
final public function getWithSetCallback(
$key, $callback, $ttl, array $checkKeys = array(), array $opts
= array()
) {
$lowTTL = isset( $opts['lowTTL'] ) ? $opts['lowTTL'] : min(
self::LOW_TTL, $ttl );
- $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : -1;
+ $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] :
self::LOCK_TSE;
$tempTTL = isset( $opts['tempTTL'] ) ? $opts['tempTTL'] :
self::TEMP_TTL;
// Get the current key value
@@ -498,9 +503,14 @@
$isTombstone = ( $curTTL !== null && $value === false );
// Assume a key is hot if requested soon after invalidation
$isHot = ( $curTTL !== null && $curTTL <= 0 && abs( $curTTL )
<= $lockTSE );
+ // Decide whether a single thread should handle regenerations.
+ // This avoids stampedes when $checkKeys are bumped and when
preemptive
+ // renegerations take too long. It also reduces regenerations
while $key
+ // is tombstoned. This balances cache freshness with avoiding
DB load.
+ $useMutex = ( $isHot || ( $isTombstone && $lockTSE > 0 ) );
$lockAcquired = false;
- if ( $isHot ) {
+ if ( $useMutex ) {
// Acquire a cluster-local non-blocking lock
if ( $this->cache->lock( $key, 0, self::LOCK_TTL ) ) {
// Lock acquired; this thread should update the
key
@@ -508,16 +518,14 @@
} elseif ( $value !== false ) {
// If it cannot be acquired; then the stale
value can be used
return $value;
- }
- }
-
- if ( !$lockAcquired && ( $isTombstone || $isHot ) ) {
- // Use the stash value for tombstoned keys to reduce
regeneration load.
- // For hot keys, either another thread has the lock or
the lock failed;
- // use the stash value from the last thread that
regenerated it.
- $value = $this->cache->get( self::STASH_KEY_PREFIX .
$key );
- if ( $value !== false ) {
- return $value;
+ } else {
+ // Use the stash value for tombstoned keys to
reduce regeneration load.
+ // For hot keys, either another thread has the
lock or the lock failed;
+ // use the stash value from the last thread
that regenerated it.
+ $value = $this->cache->get(
self::STASH_KEY_PREFIX . $key );
+ if ( $value !== false ) {
+ return $value;
+ }
}
}
@@ -529,7 +537,7 @@
$value = call_user_func_array( $callback, array( $cValue, &$ttl
) );
// When delete() is called, writes are write-holed by the
tombstone,
// so use a special stash key to pass the new value around
threads.
- if ( $value !== false && ( $isHot || $isTombstone ) && $ttl >=
0 ) {
+ if ( $useMutex && $value !== false && $ttl >= 0 ) {
$this->cache->set( self::STASH_KEY_PREFIX . $key,
$value, $tempTTL );
}
--
To view, visit https://gerrit.wikimedia.org/r/239442
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I3b01f0ec67935a238b30e02e42004fd3b2dcfb9d
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Aaron Schulz <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits