Revert "objectcache: detect default getWithSetCallback() set options"
[lhc/web/wiklou.git] / includes / libs / objectcache / WANObjectCache.php
index b0a3109..8d3c6d9 100644 (file)
@@ -88,6 +88,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        /** @var int ERR_* constant for the "last error" registry */
        protected $lastRelayError = self::ERR_NONE;
 
+       /** @var integer Callback stack depth for getWithSetCallback() */
+       private $callbackDepth = 0;
        /** @var mixed[] Temporary warm-up cache */
        private $warmupCache = [];
 
@@ -847,8 +849,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
        final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
                $pcTTL = isset( $opts['pcTTL'] ) ? $opts['pcTTL'] : self::TTL_UNCACHEABLE;
 
-               // Try the process cache if enabled
-               if ( $pcTTL >= 0 ) {
+               // Try the process cache if enabled and the cache callback is not within a cache callback.
+               // Process cache use in nested callbacks is not lag-safe with regard to HOLDOFF_TTL since
+               // the in-memory value is further lagged than the shared one since it uses a blind TTL.
+               if ( $pcTTL >= 0 && $this->callbackDepth == 0 ) {
                        $group = isset( $opts['pcGroup'] ) ? $opts['pcGroup'] : self::PC_PRIMARY;
                        $procCache = $this->getProcessCache( $group );
                        $value = $procCache->get( $key );
@@ -939,12 +943,13 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                $cValue = $this->get( $key, $curTTL, $checkKeys, $asOf ); // current value
                $value = $cValue; // return value
 
-               // Determine if a regeneration is desired
+               $preCallbackTime = microtime( true );
+               // Determine if a cached value regeneration is needed or desired
                if ( $value !== false
                        && $curTTL > 0
                        && $this->isValid( $value, $versioned, $asOf, $minTime )
                        && !$this->worthRefreshExpiring( $curTTL, $lowTTL )
-                       && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow )
+                       && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime )
                ) {
                        return $value;
                }
@@ -994,7 +999,12 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
 
                // Generate the new value from the callback...
                $setOpts = [];
-               $value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts, $asOf ] );
+               ++$this->callbackDepth;
+               try {
+                       $value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts, $asOf ] );
+               } finally {
+                       --$this->callbackDepth;
+               }
                // 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 ) {
@@ -1013,8 +1023,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
                }
 
                if ( $value !== false && $ttl >= 0 ) {
-                       // Update the cache; this will fail if the key is tombstoned
                        $setOpts['lockTSE'] = $lockTSE;
+                       // Use best known "since" timestamp if not provided
+                       $setOpts += [ 'since' => $preCallbackTime ];
+                       // Update the cache; this will fail if the key is tombstoned
                        $this->set( $key, $value, $ttl, $setOpts );
                }
 
@@ -1336,10 +1348,11 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
         * @param float $asOf UNIX timestamp of the value
         * @param integer $ageNew Age of key when this might recommend refreshing (seconds)
         * @param integer $timeTillRefresh Age of key when it should be refreshed if popular (seconds)
+        * @param float $now The current UNIX timestamp
         * @return bool
         */
-       protected function worthRefreshPopular( $asOf, $ageNew, $timeTillRefresh ) {
-               $age = microtime( true ) - $asOf;
+       protected function worthRefreshPopular( $asOf, $ageNew, $timeTillRefresh, $now ) {
+               $age = $now - $asOf;
                $timeOld = $age - $ageNew;
                if ( $timeOld <= 0 ) {
                        return false;