* - $oldValue : current cache value or false if not present
* - &$ttl : a reference to the TTL which can be altered
* - &$setOpts : a reference to options for set() which can be altered
+ * - $oldAsOf : generation UNIX timestamp of $oldValue or null if not present (since 1.28)
*
* It is strongly recommended to set the 'lag' and 'since' fields to avoid race conditions
* that can cause stale values to get stuck at keys. Usually, callbacks ignore the current
$cur = $this->doGetWithSetCallback(
$key,
$ttl,
- function ( $oldValue, &$ttl, &$setOpts ) use ( $callback, $version ) {
+ function ( $oldValue, &$ttl, &$setOpts, $oldAsOf )
+ use ( $callback, $version ) {
if ( is_array( $oldValue )
&& array_key_exists( self::VFLD_DATA, $oldValue )
) {
}
return [
- self::VFLD_DATA => $callback( $oldData, $ttl, $setOpts ),
+ self::VFLD_DATA => $callback( $oldData, $ttl, $setOpts, $oldAsOf ),
self::VFLD_VERSION => $version
];
},
// Generate the new value from the callback...
$setOpts = [];
- $value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts ] );
- $asOf = microtime( true );
+ $value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts, $asOf ] );
// When delete() is called, writes are write-holed by the tombstone,
// so use a special INTERIM key to pass the new value around threads.
if ( ( $isTombstone && $lockTSE > 0 ) && $value !== false && $ttl >= 0 ) {
$tempTTL = max( 1, (int)$lockTSE ); // set() expects seconds
- $wrapped = $this->wrap( $value, $tempTTL, $asOf );
+ $newAsOf = microtime( true );
+ $wrapped = $this->wrap( $value, $tempTTL, $newAsOf );
// Avoid using set() to avoid pointless mcrouter broadcasting
$this->cache->merge(
self::INTERIM_KEY_PREFIX . $key,
$cKey1 = wfRandomString();
$cKey2 = wfRandomString();
+ $priorValue = null;
+ $priorAsOf = null;
$wasSet = 0;
- $func = function( $old, &$ttl ) use ( &$wasSet, $value ) {
+ $func = function( $old, &$ttl, &$opts, $asOf )
+ use ( &$wasSet, &$priorValue, &$priorAsOf, $value )
+ {
++$wasSet;
+ $priorValue = $old;
+ $priorAsOf = $asOf;
$ttl = 20; // override with another value
return $value;
};
$v = $cache->getWithSetCallback( $key, 30, $func, [ 'lockTSE' => 5 ] + $extOpts );
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 1, $wasSet, "Value regenerated" );
+ $this->assertFalse( $priorValue, "No prior value" );
+ $this->assertNull( $priorAsOf, "No prior value" );
$curTTL = null;
$cache->get( $key, $curTTL );
);
$this->assertEquals( $value, $v, "Value returned" );
$this->assertEquals( 1, $wasSet, "Value regenerated due to check keys" );
+ $this->assertEquals( $value, $priorValue, "Has prior value" );
+ $this->assertType( 'float', $priorAsOf, "Has prior value" );
$t1 = $cache->getCheckKeyTime( $cKey1 );
$this->assertGreaterThanOrEqual( $priorTime, $t1, 'Check keys generated on miss' );
$t2 = $cache->getCheckKeyTime( $cKey2 );