protected $useInterimHoldOffCaching = true;
/** @var callable|null Function that takes a WAN cache callback and runs it later */
protected $asyncHandler;
+ /** @var float Unix timestamp of the oldest possible valid values */
+ protected $epoch;
/** @var int ERR_* constant for the "last error" registry */
protected $lastRelayError = self::ERR_NONE;
* - mcrouterAware: set as true if mcrouter is the backing store proxy and mcrouter
* is configured to interpret /<region>/<cluster>/ key prefixes as routes. This
* requires that "region" and "cluster" are both set above. [optional]
+ * - epoch: lowest UNIX timestamp a value/tombstone must have to be valid. [optional]
*/
public function __construct( array $params ) {
$this->cache = $params['cache'];
$this->region = $params['region'] ?? 'main';
$this->cluster = $params['cluster'] ?? 'wan-main';
$this->mcrouterAware = !empty( $params['mcrouterAware'] );
+ $this->epoch = $params['epoch'] ?? 1.0;
$this->setLogger( $params['logger'] ?? new NullLogger() );
$this->stats = $params['stats'] ?? new NullStatsdDataFactory();
$curTTL = INF;
}
+ if ( $wrapped[self::FLD_TIME] < $this->epoch ) {
+ // Values this old are ignored
+ return [ false, null ];
+ }
+
return [ $wrapped[self::FLD_VALUE], $curTTL ];
}
}
/**
- * @param string $value Wrapped value like "PURGED:<timestamp>:<holdoff>"
+ * @param string|array|bool $value Possible string of the form "PURGED:<timestamp>:<holdoff>"
* @return array|bool Array containing a UNIX timestamp (float) and holdoff period (integer),
* or false if value isn't a valid purge value
*/
if ( !is_string( $value ) ) {
return false;
}
+
$segments = explode( ':', $value, 3 );
if ( !isset( $segments[0] ) || !isset( $segments[1] )
|| "{$segments[0]}:" !== self::PURGE_VAL_PREFIX
) {
return false;
}
+
if ( !isset( $segments[2] ) ) {
// Back-compat with old purge values without holdoff
$segments[2] = self::HOLDOFF_TTL;
}
+
+ if ( $segments[1] < $this->epoch ) {
+ // Values this old are ignored
+ return false;
+ }
+
return [
self::FLD_TIME => (float)$segments[1],
self::FLD_HOLDOFF => (int)$segments[2],
$wanCache->resetCheckKey( 'test' );
}
+ public function testEpoch() {
+ $bag = new HashBagOStuff();
+ $cache = new WANObjectCache( [ 'cache' => $bag, 'pool' => 'testcache-hash' ] );
+ $key = $cache->makeGlobalKey( 'The whole of the Law' );
+
+ $now = microtime( true );
+ $cache->setMockTime( $now );
+
+ $cache->set( $key, 'Do what thou Wilt' );
+ $cache->touchCheckKey( $key );
+
+ $then = $now;
+ $now += 30;
+ $this->assertEquals( 'Do what thou Wilt', $cache->get( $key ) );
+ $this->assertEquals( $then, $cache->getCheckKeyTime( $key ), 'Check key init', 0.01 );
+
+ $cache = new WANObjectCache( [
+ 'cache' => $bag,
+ 'pool' => 'testcache-hash',
+ 'epoch' => $now - 3600
+ ] );
+ $cache->setMockTime( $now );
+
+ $this->assertEquals( 'Do what thou Wilt', $cache->get( $key ) );
+ $this->assertEquals( $then, $cache->getCheckKeyTime( $key ), 'Check key kept', 0.01 );
+
+ $now += 30;
+ $cache = new WANObjectCache( [
+ 'cache' => $bag,
+ 'pool' => 'testcache-hash',
+ 'epoch' => $now + 3600
+ ] );
+ $cache->setMockTime( $now );
+
+ $this->assertFalse( $cache->get( $key ), 'Key rejected due to epoch' );
+ $this->assertEquals( $now, $cache->getCheckKeyTime( $key ), 'Check key reset', 0.01 );
+ }
+
/**
* @dataProvider provideAdaptiveTTL
* @covers WANObjectCache::adaptiveTTL()