- // If a regeneration lock is required, threads that do not get the lock will use any
- // available stale or volatile value. If there is none, then the cheap/placeholder
- // value from $busyValue will be used if provided; failing that, all threads will try
- // to regenerate the value and ignore the lock.
- if ( $useRegenerationLock ) {
- $hasLock = $this->cache->add( self::MUTEX_KEY_PREFIX . $key, 1, self::LOCK_TTL );
- if ( !$hasLock ) {
- if ( $this->isValid( $possValue, $possInfo['asOf'], $minAsOf ) ) {
- $this->stats->increment( "wanobjectcache.$kClass.hit.stale" );
-
- return [ $possValue, $possInfo['version'], $curInfo['asOf'] ];
- } elseif ( $busyValue !== null ) {
- $miss = is_infinite( $minAsOf ) ? 'renew' : 'miss';
- $this->stats->increment( "wanobjectcache.$kClass.$miss.busy" );
-
- return [
- is_callable( $busyValue ) ? $busyValue() : $busyValue,
- $version,
- $curInfo['asOf']
- ];
- }
+ // If a regeneration lock is required, threads that do not get the lock will try to use
+ // the stale value, the interim value, or the $busyValue placeholder, in that order. If
+ // none of those are set then all threads will bypass the lock and regenerate the value.
+ $hasLock = $useRegenerationLock && $this->claimStampedeLock( $key );
+ if ( $useRegenerationLock && !$hasLock ) {
+ if ( $this->isValid( $possValue, $possInfo['asOf'], $minAsOf ) ) {
+ $this->stats->increment( "wanobjectcache.$kClass.hit.stale" );
+
+ return [ $possValue, $possInfo['version'], $curInfo['asOf'] ];
+ } elseif ( $busyValue !== null ) {
+ $miss = is_infinite( $minAsOf ) ? 'renew' : 'miss';
+ $this->stats->increment( "wanobjectcache.$kClass.$miss.busy" );
+
+ return [
+ is_callable( $busyValue ) ? $busyValue() : $busyValue,
+ $version,
+ $curInfo['asOf']
+ ];