diff --git a/core/core.services.yml b/core/core.services.yml index 5e63508..385ead7 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -14,6 +14,7 @@ parameters: max-age: 0 contexts: ['session', 'user'] tags: [] + cache.configuration.override_permanent_ttl: 86400 factory.keyvalue: default: keyvalue.database http.response.debug_cacheability_headers: false @@ -207,31 +208,31 @@ services: tags: - { name: cache.bin } factory: cache_factory:get - arguments: [default] + arguments: [default, ['override_permanent_ttl', '%cache.configuration.override_permanent_ttl%']] cache.entity: class: Drupal\Core\Cache\CacheBackendInterface tags: - { name: cache.bin } factory: cache_factory:get - arguments: [entity] + arguments: [entity, ['override_permanent_ttl', '%cache.configuration.override_permanent_ttl%']] cache.menu: class: Drupal\Core\Cache\CacheBackendInterface tags: - { name: cache.bin } factory: cache_factory:get - arguments: [menu] + arguments: [menu, ['override_permanent_ttl', '%cache.configuration.override_permanent_ttl%']] cache.render: class: Drupal\Core\Cache\CacheBackendInterface tags: - { name: cache.bin } factory: cache_factory:get - arguments: [render] + arguments: [render, ['override_permanent_ttl', '%cache.configuration.override_permanent_ttl%']] cache.data: class: Drupal\Core\Cache\CacheBackendInterface tags: - { name: cache.bin } factory: cache_factory:get - arguments: [data] + arguments: [data, ['override_permanent_ttl', '%cache.configuration.override_permanent_ttl%']] cache.discovery: class: Drupal\Core\Cache\CacheBackendInterface tags: diff --git a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php index ca38ca0..6bdda49 100644 --- a/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/ChainedFastBackendFactory.php @@ -12,7 +12,7 @@ /** * Defines the chained fast cache backend factory. */ -class ChainedFastBackendFactory implements CacheFactoryInterface { +class ChainedFastBackendFactory implements ConfigurableCacheFactoryInterface { use ContainerAwareTrait; @@ -68,26 +68,46 @@ public function __construct(Settings $settings = NULL, $consistent_service_name } /** - * Instantiates a chained, fast cache backend class for a given cache bin. - * - * @param string $bin - * The cache bin for which a cache backend object should be returned. - * - * @return \Drupal\Core\Cache\CacheBackendInterface - * The cache backend object associated with the specified bin. + * {@inheritdoc} */ - public function get($bin) { + public function get($bin, array $options = []) { + + $consistent_backend = $this->getCacheBackendWithOptions($bin, $this->consistentServiceName, $options); // Use the chained backend only if there is a fast backend available; // otherwise, just return the consistent backend directly. if (isset($this->fastServiceName)) { + $fast_backend = $this->getCacheBackendWithOptions($bin, $this->fastServiceName, $options); return new ChainedFastBackend( - $this->container->get($this->consistentServiceName)->get($bin), - $this->container->get($this->fastServiceName)->get($bin), + $consistent_backend, + $fast_backend, $bin ); } else { - return $this->container->get($this->consistentServiceName)->get($bin); + return $consistent_backend; + } + } + + /** + * Gets a cache backend with options if it supports it. + * + * @param string $bin + * The cache bin. + * @param string $name + * The service name. + * @param array $options + * The options array to pass in. + * + * @return \Drupal\Core\Cache\CacheBackendInterface + * The cache backend. + */ + protected function getCacheBackendWithOptions($bin, $name, $options) { + $factory = $this->container->get($name); + if ($factory instanceof ConfigurableCacheBackendFactoryInterface) { + return $factory->get($bin, $options); + } + else { + return $factory->get($bin); } } diff --git a/core/lib/Drupal/Core/Cache/ConfigurableCacheFactoryInterface.php b/core/lib/Drupal/Core/Cache/ConfigurableCacheFactoryInterface.php new file mode 100644 index 0000000..a96a087 --- /dev/null +++ b/core/lib/Drupal/Core/Cache/ConfigurableCacheFactoryInterface.php @@ -0,0 +1,23 @@ + $item) { + if (!isset($item['expire']) || $item['expire'] === CacheBackendInterface::CACHE_PERMANENT) { + if ($this->permanentTtl === CacheBackendInterface::CACHE_PERMANENT) { + $item['expire'] = CacheBackendInterface::CACHE_PERMANENT; + } + else { + $item['expire'] = $this->calculatePermanentExpire(); + } + } $item += array( - 'expire' => CacheBackendInterface::CACHE_PERMANENT, 'tags' => array(), ); @@ -240,6 +259,17 @@ protected function doSetMultiple(array $items) { } /** + * Calculates permanent expiry. + * + * @return int + * An expires timestamp based on the TTL with added 'jitter'. + */ + protected function calculatePermanentExpire() { + $minimum = $this->permanentTtl; + return rand($minimum, $minimum * self::JITTER_MULTIPLIER) + REQUEST_TIME; + } + + /** * {@inheritdoc} */ public function delete($cid) { @@ -356,6 +386,13 @@ public function removeBin() { } /** + * {@inheritdoc} + */ + public function setPermanentTtl($ttl) { + $this->permanentTtl = $ttl; + } + + /** * Check if the cache bin exists and create it if not. */ protected function ensureBinExists() { diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php index 59b0b22..05459b2 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php +++ b/core/lib/Drupal/Core/Cache/DatabaseBackendFactory.php @@ -9,7 +9,7 @@ use Drupal\Core\Database\Connection; -class DatabaseBackendFactory implements CacheFactoryInterface { +class DatabaseBackendFactory implements ConfigurableCacheFactoryInterface { /** * The database connection. @@ -39,16 +39,14 @@ function __construct(Connection $connection, CacheTagsChecksumInterface $checksu } /** - * Gets DatabaseBackend for the specified cache bin. - * - * @param $bin - * The cache bin for which the object is created. - * - * @return \Drupal\Core\Cache\DatabaseBackend - * The cache backend object for the specified cache bin. + * {@inheritdoc} */ - function get($bin) { - return new DatabaseBackend($this->connection, $this->checksumProvider, $bin); + function get($bin, array $options = []) { + $class = new DatabaseBackend($this->connection, $this->checksumProvider, $bin); + if (isset($options['override_permanent_ttl'])) { + $class->setOverridePermanentTtl($options['override_permanent_ttl']); + } + return $class; } } diff --git a/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php b/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php index 934fe81..35839ed 100644 --- a/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php +++ b/core/modules/system/src/Tests/Cache/DatabaseBackendUnitTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Cache; +use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\DatabaseBackend; /** @@ -53,4 +54,18 @@ public function testSetGet() { $this->assertIdentical($cached_value_short, $backend->get($cid_short)->data, "Backend contains the correct value for short, non-ASCII cache id."); } + /** + * Test permanent TTL. + */ + function testPermanentTtl() { + $backend = $this->getCacheBackend(); + $backend->setPermanentTtl(2); + $cid = 'test'; + $value = 'test'; + $backend->set($cid, $value); + $item = $backend->get($cid); + $this->assertTrue($item->expire !== CacheBackendInterface::CACHE_PERMANENT); + $this->assertTrue($item->expire <= REQUEST_TIME + 2 * DatabaseBackend::JITTER_MULTIPLIER); + } + }