Merge "objectcache: Run preemptive WAN cache refreshes post-send"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 1 Dec 2017 19:08:30 +0000 (19:08 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 1 Dec 2017 19:08:31 +0000 (19:08 +0000)
1  2 
includes/libs/objectcache/WANObjectCache.php

@@@ -93,6 -93,8 +93,8 @@@ class WANObjectCache implements IExpiri
        protected $stats;
        /** @var bool Whether to use "interim" caching while keys are tombstoned */
        protected $useInterimHoldOffCaching = true;
+       /** @var callable|null Function that takes a WAN cache callback and runs it later */
+       protected $asyncHandler;
  
        /** @var int ERR_* constant for the "last error" registry */
        protected $lastRelayError = self::ERR_NONE;
         *   - relayers : Map of (action => EventRelayer object). Actions include "purge".
         *   - logger   : LoggerInterface object
         *   - stats    : LoggerInterface object
+        *   - asyncHandler : A function that takes a callback and runs it later. If supplied,
+        *       whenever a preemptive refresh would be triggered in getWithSetCallback(), the
+        *       current cache value is still used instead. However, the async-handler function
+        *       receives a WAN cache callback that, when run, will execute the value generation
+        *       callback supplied by the getWithSetCallback() caller. The result will be saved
+        *       as normal. The handler is expected to call the WAN cache callback at an opportune
+        *       time (e.g. HTTP post-send), though generally within a few 100ms. [optional]
         */
        public function __construct( array $params ) {
                $this->cache = $params['cache'];
                        : new EventRelayerNull( [] );
                $this->setLogger( isset( $params['logger'] ) ? $params['logger'] : new NullLogger() );
                $this->stats = isset( $params['stats'] ) ? $params['stats'] : new NullStatsdDataFactory();
+               $this->asyncHandler = isset( $params['asyncHandler'] ) ? $params['asyncHandler'] : null;
        }
  
        public function setLogger( LoggerInterface $logger ) {
         *      Default: WANObjectCache::STALE_TTL_NONE
         * @return mixed Value found or written to the key
         * @note Options added in 1.28: version, busyValue, hotTTR, ageNew, pcGroup, minAsOf
 +       * @note Options added in 1.31: staleTTL, graceTTL
         * @note Callable type hints are not used to avoid class-autoloading
         */
        final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
                if ( $value !== false
                        && $this->isAliveOrInGracePeriod( $curTTL, $graceTTL )
                        && $this->isValid( $value, $versioned, $asOf, $minTime )
-                       && !$this->worthRefreshExpiring( $curTTL, $lowTTL )
-                       && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime )
                ) {
-                       $this->stats->increment( "wanobjectcache.$kClass.hit.good" );
+                       $preemptiveRefresh = (
+                               $this->worthRefreshExpiring( $curTTL, $lowTTL ) ||
+                               $this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime )
+                       );
+                       if ( !$preemptiveRefresh ) {
+                               $this->stats->increment( "wanobjectcache.$kClass.hit.good" );
  
-                       return $value;
+                               return $value;
+                       } elseif ( $this->asyncHandler ) {
+                               // Update the cache value later, such during post-send of an HTTP request
+                               $func = $this->asyncHandler;
+                               $func( function () use ( $key, $ttl, $callback, $opts, $asOf ) {
+                                       $opts['minAsOf'] = INF; // force a refresh
+                                       $this->doGetWithSetCallback( $key, $ttl, $callback, $opts, $asOf );
+                               } );
+                               $this->stats->increment( "wanobjectcache.$kClass.hit.refresh" );
+                               return $value;
+                       }
                }
  
                // A deleted key with a negative TTL left must be tombstoned
        }
  
        /**
 -       * Disable the use of brief caching for tombstoned keys
 +       * Enable or disable the use of brief caching for tombstoned keys
         *
         * When a key is purged via delete(), there normally is a period where caching
         * is hold-off limited to an extremely short time. This method will disable that