From 84758e6f107f939f313563964b2b31f4a71efad0 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Thu, 21 May 2015 22:46:25 -0700 Subject: [PATCH] Made WANObjectCache::getCheckKey() automatically init the key * This still allows If-Modified-Since logic but does not need to broadcast initialization values just because a key fell out of cache. The value can differ between DCs anyway via skew, this just lets them drift more. Actual purge events are still broadcasted, which is what matters. * The User class has now been simplified given this change. * Added more general comments to getCheckKeyTime(). Change-Id: Ic1f4bbb1947e0d1dd47499c9e9dc86991c30580c --- includes/User.php | 13 +++++------ includes/libs/objectcache/WANObjectCache.php | 23 +++++++++++++++++-- .../objectcache/WANObjectCacheTest.php | 4 +++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/includes/User.php b/includes/User.php index 46d53b876e..63c0d37e45 100644 --- a/includes/User.php +++ b/includes/User.php @@ -2326,6 +2326,10 @@ class User implements IDBAccessObject { /** * Get the user touched timestamp + * + * Use this value only to validate caches via inequalities + * such as in the case of HTTP If-Modified-Since response logic + * * @return string TS_MW Timestamp */ public function getTouched() { @@ -2334,14 +2338,9 @@ class User implements IDBAccessObject { if ( $this->mId ) { if ( $this->mQuickTouched === null ) { $key = wfMemcKey( 'user-quicktouched', 'id', $this->mId ); + $cache = ObjectCache::getMainWANInstance(); - $timestamp = ObjectCache::getMainWANInstance()->getCheckKeyTime( $key ); - if ( $timestamp ) { - $this->mQuickTouched = wfTimestamp( TS_MW, (int)$timestamp ); - } else { - # Set the timestamp to get HTTP 304 cache hits - $this->touch(); - } + $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) ); } return max( $this->mTouched, $this->mQuickTouched ); diff --git a/includes/libs/objectcache/WANObjectCache.php b/includes/libs/objectcache/WANObjectCache.php index 5d9557a1d6..c32efb9776 100644 --- a/includes/libs/objectcache/WANObjectCache.php +++ b/includes/libs/objectcache/WANObjectCache.php @@ -279,13 +279,32 @@ class WANObjectCache { /** * Fetch the value of a timestamp "check" key * + * The key will be *initialized* to the current time if not set, + * so only call this method if this behavior is actually desired + * + * The timestamp can be used to check whether a cached value is valid. + * Callers should not assume that this returns the same timestamp in + * all datacenters due to relay delays. + * + * The level of staleness can roughly be estimated from this key, but + * if the key was evicted from cache, such calculations may show the + * time since expiry as ~0 seconds. + * * Note that "check" keys won't collide with other regular keys * * @param string $key - * @return float|bool TS_UNIX timestamp of the key; false if not present + * @return float UNIX timestamp of the key */ final public function getCheckKeyTime( $key ) { - return self::parsePurgeValue( $this->cache->get( self::TIME_KEY_PREFIX . $key ) ); + $key = self::TIME_KEY_PREFIX . $key; + + $time = self::parsePurgeValue( $this->cache->get( $key ) ); + if ( $time === false ) { + $time = microtime( true ); + $this->cache->add( $key, self::PURGE_VAL_PREFIX . $time, self::CHECK_KEY_TTL ); + } + + return $time; } /** diff --git a/tests/phpunit/includes/objectcache/WANObjectCacheTest.php b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php index 47a83b3fe2..10f64be716 100644 --- a/tests/phpunit/includes/objectcache/WANObjectCacheTest.php +++ b/tests/phpunit/includes/objectcache/WANObjectCacheTest.php @@ -229,8 +229,10 @@ class WANObjectCacheTest extends MediaWikiTestCase { public function testTouchKeys() { $key = wfRandomString(); + $priorTime = microtime( true ); + usleep( 1 ); $t0 = $this->cache->getCheckKeyTime( $key ); - $this->assertFalse( $t0, 'Check key time is false' ); + $this->assertGreaterThanOrEqual( $priorTime, $t0, 'Check key auto-created' ); $priorTime = microtime( true ); usleep( 1 ); -- 2.20.1