Unverified Commit 7bba7982 authored by Fabianx's avatar Fabianx Committed by damiankloip
Browse files

Issue #2996946 by Fabianx, catch: Remove stampede protection: lock->release()...

Issue #2996946 by Fabianx, catch: Remove stampede protection: lock->release() is never called explicitly + can't return expired items in D8 + move stampede protection into subclass / decorator
parent df437885
......@@ -83,32 +83,6 @@ The bin/cluster/server model can be described as follows:
- If a bin can not be found it will map to 'default'.
### Stampede Protection ###
Memcache includes stampede protection for rebuilding expired and invalid cache
items. To enable stampede protection, add the following config in settings.php:
$settings['memcache']['stampede_protection'] = TRUE;
To avoid lock stampedes, it is important that you enable the memcache lock
implementation when enabling stampede protection -- enabling stampede protection
without enabling the Memcache lock implementation can cause worse performance.
Only change the following values if you're sure you know what you're doing,
which requires reading the memcachie.inc code.
The value passed to Drupal\Core\Lock\LockBackendInterface::wait(), defaults to 5:
$settings['memcache']['stampede_wait_time'] = 5;
The maximum number of calls to Drupal\Core\Lock\LockBackendInterface::wait() due
to stampede protection during a single request, defaults to 3:
$settings['memcache']['stampede_wait_limit'] = 3;
When adjusting these variables, be aware that:
- wait_time * wait_limit is designed to default to a number less than
standard web server timeouts (i.e. 15 seconds vs. apache's default of
30 seconds).
### Prefixing ###
If you want to have multiple Drupal installations share memcached instances,
......@@ -195,17 +169,13 @@ if ($memcache_exists || $memcached_exists) {
'factory' => ['@memcache.backend.cache.factory', 'get'],
'arguments' => ['container'],
],
'lock.container' => [
'class' => 'Drupal\memcache\Lock\MemcacheLockBackend',
'arguments' => ['container', '@memcache.backend.cache.container'],
],
'cache_tags_provider.container' => [
'class' => 'Drupal\Core\Cache\DatabaseCacheTagsChecksum',
'arguments' => ['@database'],
],
'cache.container' => [
'class' => 'Drupal\memcache\MemcacheBackend',
'arguments' => ['container', '@memcache.backend.cache.container', '@lock.container', '@memcache.config', '@cache_tags_provider.container'],
'arguments' => ['container', '@memcache.backend.cache.container', '@cache_tags_provider.container'],
],
],
];
......
......@@ -7,7 +7,7 @@ services:
arguments: ['@memcache.config']
cache.backend.memcache:
class: Drupal\memcache\MemcacheBackendFactory
arguments: ['@lock', '@memcache.config', '@memcache.factory', '@cache_tags.invalidator.checksum']
arguments: ['@memcache.factory', '@cache_tags.invalidator.checksum']
memcache.lock.factory:
class: Drupal\memcache\Lock\MemcacheLockFactory
arguments: ['@memcache.factory']
......@@ -26,13 +26,6 @@ class MemcacheBackend implements CacheBackendInterface {
*/
protected $lastBinDeletionTime;
/**
* The lock count.
*
* @var int
*/
protected $lockCount = 0;
/**
* The memcache wrapper object.
*
......@@ -40,20 +33,6 @@ class MemcacheBackend implements CacheBackendInterface {
*/
protected $memcache;
/**
* The lock backend that should be used.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lock;
/**
* The Settings instance.
*
* @var \Drupal\memcache\DrupalMemcacheConfig
*/
protected $settings;
/**
* The cache tags checksum provider.
*
......@@ -68,18 +47,12 @@ class MemcacheBackend implements CacheBackendInterface {
* The bin name.
* @param \Drupal\memcache\DrupalMemcacheInterface $memcache
* The memcache object.
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* The lock backend.
* @param \Drupal\memcache\DrupalMemcacheConfig $settings
* The settings instance.
* @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
* The cache tags checksum service.
*/
public function __construct($bin, DrupalMemcacheInterface $memcache, LockBackendInterface $lock, DrupalMemcacheConfig $settings, CacheTagsChecksumInterface $checksum_provider) {
public function __construct($bin, DrupalMemcacheInterface $memcache, CacheTagsChecksumInterface $checksum_provider) {
$this->bin = $bin;
$this->memcache = $memcache;
$this->lock = $lock;
$this->settings = $settings;
$this->checksumProvider = $checksum_provider;
$this->ensureBinDeletionTimeIsSet();
......@@ -136,49 +109,11 @@ class MemcacheBackend implements CacheBackendInterface {
* @return bool
*/
protected function valid($cid, \stdClass $cache) {
$lock_key = "memcache:$this->bin:$cid";
$cache->valid = FALSE;
if ($cache) {
// Items that have expired are invalid.
if (isset($cache->expire) && ($cache->expire != CacheBackendInterface::CACHE_PERMANENT) && ($cache->expire <= REQUEST_TIME)) {
// If the memcache_stampede_protection variable is set, allow one
// process to rebuild the cache entry while serving expired content to
// the rest.
if ($this->settings->get('stampede_protection', FALSE)) {
// The process that acquires the lock will get a cache miss, all
// others will get a cache hit.
if (!$this->lock->acquire($lock_key, $this->settings->get('stampede_semaphore', 15))) {
$cache->valid = TRUE;
}
}
}
else {
$cache->valid = TRUE;
}
}
// On cache misses, attempt to avoid stampedes when the
// memcache_stampede_protection variable is enabled.
else {
if ($this->settings->get('stampede_protection', FALSE) && !$this->lock->acquire($lock_key, $this->settings->get('stampede_semaphore', 15))) {
// Prevent any single request from waiting more than three times due to
// stampede protection. By default this is a maximum total wait of 15
// seconds. This accounts for two possibilities - a cache and lock miss
// more than once for the same item. Or a cache and lock miss for
// different items during the same request.
// @todo: it would be better to base this on time waited rather than
// number of waits, but the lock API does not currently provide this
// information. Currently the limit will kick in for three waits of 25ms
// or three waits of 5000ms.
$this->lockCount++;
if ($this->lockCount <= $this->settings->get('stampede_wait_limit', 3)) {
// The memcache_stampede_semaphore variable was used in previous
// releases of memcache, but the max_wait variable was not, so by
// default divide the semaphore value by 3 (5 seconds).
$this->lock->wait($lock_key, $this->settings->get('stampede_wait_time', 5));
$cache = $this->get($cid);
}
}
$cache->valid = TRUE;
// Items that have expired are invalid.
if ($cache->expire != CacheBackendInterface::CACHE_PERMANENT && $cache->expire <= REQUEST_TIME) {
$cache->valid = FALSE;
}
// Check if invalidateTags() has been called with any of the items's tags.
......@@ -186,7 +121,7 @@ class MemcacheBackend implements CacheBackendInterface {
$cache->valid = FALSE;
}
return (bool) $cache->valid;
return $cache->valid;
}
/**
......
......@@ -7,7 +7,6 @@
namespace Drupal\memcache;
use Drupal\Core\Lock\LockBackendInterface;
use Drupal\Core\Cache\CacheFactoryInterface;
use Drupal\Core\Cache\CacheTagsChecksumInterface;
......@@ -16,20 +15,6 @@ use Drupal\Core\Cache\CacheTagsChecksumInterface;
*/
class MemcacheBackendFactory implements CacheFactoryInterface {
/**
* The lock backend that should be used.
*
* @var \Drupal\Core\Lock\LockBackendInterface
*/
protected $lock;
/**
* The settings object.
*
* @var \Drupal\memcache\DrupalMemcacheConfig
*/
protected $settings;
/**
* The memcache factory object.
*
......@@ -47,13 +32,10 @@ class MemcacheBackendFactory implements CacheFactoryInterface {
/**
* Constructs the DatabaseBackendFactory object.
*
* @param \Drupal\Core\Lock\LockBackendInterface $lock
* @param \Drupal\memcache\DrupalMemcacheConfig $settings
* @param \Drupal\memcache\DrupalMemcacheFactory $memcache_factory
* @param \Drupal\Core\Cache\CacheTagsChecksumInterface $checksum_provider
*/
function __construct(LockBackendInterface $lock, DrupalMemcacheConfig $settings, DrupalMemcacheFactory $memcache_factory, CacheTagsChecksumInterface $checksum_provider) {
$this->lock = $lock;
$this->settings = $settings;
function __construct(DrupalMemcacheFactory $memcache_factory, CacheTagsChecksumInterface $checksum_provider) {
$this->memcacheFactory = $memcache_factory;
$this->checksumProvider = $checksum_provider;
}
......@@ -71,8 +53,6 @@ class MemcacheBackendFactory implements CacheFactoryInterface {
return new MemcacheBackend(
$bin,
$this->memcacheFactory->get($bin),
$this->lock,
$this->settings,
$this->checksumProvider
);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment