X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=blobdiff_plain;f=includes%2Flibs%2Fobjectcache%2FWANObjectCache.php;h=0531d7f7095ad117bc91b2bf0775f2318959ffcb;hp=1f757a41e9ff4703427bf8c3bf331ae820282626;hb=f73f2b320d8fe1eb03f78671584d455a2ff9f292;hpb=53ecf20db8bfc2109553e80bf932dac7321d63ec diff --git a/includes/libs/objectcache/WANObjectCache.php b/includes/libs/objectcache/WANObjectCache.php index 1f757a41e9..0531d7f709 100644 --- a/includes/libs/objectcache/WANObjectCache.php +++ b/includes/libs/objectcache/WANObjectCache.php @@ -686,8 +686,11 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * having to inspect a "current time left" variable (e.g. $curTTL, $curTTLs), a cache * regeneration will automatically be triggered using the callback. * - * The simplest way to avoid stampedes for hot keys is to use - * the 'lockTSE' option in $opts. If cache purges are needed, also: + * The $ttl argument and "hotTTR" option (in $opts) use time-dependant randomization + * to avoid stampedes. Keys that are slow to regenerate and either heavily used + * or subject to explicit (unpredictable) purges, may need additional mechanisms. + * The simplest way to avoid stampedes for such keys is to use 'lockTSE' (in $opts). + * If explicit purges are needed, also: * - a) Pass $key into $checkKeys * - b) Use touchCheckKey( $key ) instead of delete( $key ) * @@ -839,11 +842,13 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * This is useful if the source of a key is suspected of having possibly changed * recently, and the caller wants any such changes to be reflected. * Default: WANObjectCache::MIN_TIMESTAMP_NONE. - * - hotTTR: Expected time-till-refresh for keys that average ~1 hit/second. - * This should be greater than "ageNew". Keys with higher hit rates will regenerate - * more often. This is useful when a popular key is changed but the cache purge was - * delayed or lost. Seldom used keys are rarely affected by this setting, unless an - * extremely low "hotTTR" value is passed in. + * - hotTTR: Expected time-till-refresh (TTR) for keys that average ~1 hit/second (1 Hz). + * Keys with a hit rate higher than 1Hz will refresh sooner than this TTR and vise versa. + * Such refreshes won't happen until keys are "ageNew" seconds old. The TTR is useful at + * reducing the impact of missed cache purges, since the effect of a heavily referenced + * key being stale is worse than that of a rarely referenced key. Unlike simply lowering + * $ttl, seldomly used keys are largely unaffected by this option, which makes it possible + * to have a high hit rate for the "long-tail" of less-used keys. * Default: WANObjectCache::HOT_TTR. * - lowTTL: Consider pre-emptive updates when the current TTL (seconds) of the key is less * than this. It becomes more likely over time, becoming certain once the key is expired. @@ -964,6 +969,10 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { // A deleted key with a negative TTL left must be tombstoned $isTombstone = ( $curTTL !== null && $value === false ); + if ( $isTombstone && $lockTSE <= 0 ) { + // Use the INTERIM value for tombstoned keys to reduce regeneration load + $lockTSE = 1; + } // Assume a key is hot if requested soon after invalidation $isHot = ( $curTTL !== null && $curTTL <= 0 && abs( $curTTL ) <= $lockTSE ); // Use the mutex if there is no value and a busy fallback is given @@ -987,11 +996,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { // Use the INTERIM value for tombstoned keys to reduce regeneration load. // For hot keys, either another thread has the lock or the lock failed; // use the INTERIM value from the last thread that regenerated it. - $wrapped = $this->cache->get( self::INTERIM_KEY_PREFIX . $key ); - list( $value ) = $this->unwrap( $wrapped, microtime( true ) ); - if ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) { - $asOf = $wrapped[self::FLD_TIME]; - + $value = $this->getInterimValue( $key, $versioned, $minTime, $asOf ); + if ( $value !== false ) { return $value; } // Use the busy fallback value if nothing else @@ -1013,24 +1019,19 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { } finally { --$this->callbackDepth; } + $valueIsCacheable = ( $value !== false && $ttl >= 0 ); + // 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 ) { + if ( ( $isTombstone && $lockTSE > 0 ) && $valueIsCacheable ) { $tempTTL = max( 1, (int)$lockTSE ); // set() expects seconds $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, - function () use ( $wrapped ) { - return $wrapped; - }, - $tempTTL, - 1 - ); + $this->setInterimValue( $key, $wrapped, $tempTTL ); } - if ( $value !== false && $ttl >= 0 ) { + if ( $valueIsCacheable ) { $setOpts['lockTSE'] = $lockTSE; // Use best known "since" timestamp if not provided $setOpts += [ 'since' => $preCallbackTime ]; @@ -1040,12 +1041,47 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { if ( $lockAcquired ) { // Avoid using delete() to avoid pointless mcrouter broadcasting - $this->cache->changeTTL( self::MUTEX_KEY_PREFIX . $key, 1 ); + $this->cache->changeTTL( self::MUTEX_KEY_PREFIX . $key, (int)$preCallbackTime - 60 ); } return $value; } + /** + * @param string $key + * @param bool $versioned + * @param float $minTime + * @param mixed $asOf + * @return mixed + */ + protected function getInterimValue( $key, $versioned, $minTime, &$asOf ) { + $wrapped = $this->cache->get( self::INTERIM_KEY_PREFIX . $key ); + list( $value ) = $this->unwrap( $wrapped, microtime( true ) ); + if ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) { + $asOf = $wrapped[self::FLD_TIME]; + + return $value; + } + + return false; + } + + /** + * @param string $key + * @param array $wrapped + * @param int $tempTTL + */ + protected function setInterimValue( $key, $wrapped, $tempTTL ) { + $this->cache->merge( + self::INTERIM_KEY_PREFIX . $key, + function () use ( $wrapped ) { + return $wrapped; + }, + $tempTTL, + 1 + ); + } + /** * Method to fetch multiple cache keys at once with regeneration * @@ -1083,7 +1119,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * $setOpts += Database::getCacheSetOptions( $dbr ); * * // Load the row for this file - * $row = $dbr->selectRow( 'file', '*', [ 'id' => $id ], __METHOD__ ); + * $row = $dbr->selectRow( 'file', File::selectFields(), [ 'id' => $id ], __METHOD__ ); * * return $row ? (array)$row : false; * }, @@ -1169,7 +1205,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { * * // Load the rows for these files * $rows = []; - * $res = $dbr->select( 'file', '*', [ 'id' => $ids ], __METHOD__ ); + * $res = $dbr->select( 'file', File::selectFields(), [ 'id' => $ids ], __METHOD__ ); * foreach ( $res as $row ) { * $rows[$row->id] = $row; * $mtime = wfTimestamp( TS_UNIX, $row->timestamp ); @@ -1315,8 +1351,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { /** * @see BagOStuff::makeKey() - * @param string $keys,... Key component - * @return string + * @param string $keys,... Key component (starting with a key collection name) + * @return string Colon-delimited list of $keyspace followed by escaped components of $args * @since 1.27 */ public function makeKey() { @@ -1325,8 +1361,8 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { /** * @see BagOStuff::makeGlobalKey() - * @param string $keys,... Key component - * @return string + * @param string $keys,... Key component (starting with a key collection name) + * @return string Colon-delimited list of $keyspace followed by escaped components of $args * @since 1.27 */ public function makeGlobalKey() { @@ -1507,7 +1543,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { } /** - * Check if a key should be regenerated (using random probability) + * Check if a key is nearing expiration and thus due for randomized regeneration * * This returns false if $curTTL >= $lowTTL. Otherwise, the chance * of returning true increases steadily from 0% to 100% as the $curTTL @@ -1724,7 +1760,7 @@ class WANObjectCache implements IExpiringStore, LoggerAwareInterface { return array_diff( $keys, $keysFound ); } - /** + /** * @param array $keys * @param array $checkKeys * @return array Map of (cache key => mixed)