Skip to content
Snippets Groups Projects
Commit 2e73418c authored by catch's avatar catch
Browse files

Issue #3402850 by kristiaanvandeneynde, catch, smustgrave: Fix MemoryCache discovery and DX

parent 7c4decb5
No related branches found
No related tags found
33 merge requests!8528Issue #3456871 by Tim Bozeman: Support NULL services,!8323Fix source code editing and in place front page site studio editing.,!6278Issue #3187770 by godotislate, smustgrave, catch, quietone: Views Rendered...,!3878Removed unused condition head title for views,!38582585169-10.1.x,!3818Issue #2140179: $entity->original gets stale between updates,!3742Issue #3328429: Create item list field formatter for displaying ordered and unordered lists,!3731Claro: role=button on status report items,!3668Resolve #3347842 "Deprecate the trusted",!3651Issue #3347736: Create new SDC component for Olivero (header-search),!3531Issue #3336994: StringFormatter always displays links to entity even if the user in context does not have access,!3502Issue #3335308: Confusing behavior with FormState::setFormState and FormState::setMethod,!3452Issue #3332701: Refactor Claro's tablesort-indicator stylesheet,!3355Issue #3209129: Scrolling problems when adding a block via layout builder,!3226Issue #2987537: Custom menu link entity type should not declare "bundle" entity key,!3154Fixes #2987987 - CSRF token validation broken on routes with optional parameters.,!3147Issue #3328457: Replace most substr($a, $i) where $i is negative with str_ends_with(),!3146Issue #3328456: Replace substr($a, 0, $i) with str_starts_with(),!3133core/modules/system/css/components/hidden.module.css,!2812Issue #3312049: [Followup] Fix Drupal.Commenting.FunctionComment.MissingReturnType returns for NULL,!2614Issue #2981326: Replace non-test usages of \Drupal::logger() with IoC injection,!2378Issue #2875033: Optimize joins and table selection in SQL entity query implementation,!2334Issue #3228209: Add hasRole() method to AccountInterface,!2062Issue #3246454: Add weekly granularity to views date sort,!1105Issue #3025039: New non translatable field on translatable content throws error,!1073issue #3191727: Focus states on mobile second level navigation items fixed,!877Issue #2708101: Default value for link text is not saved,!844Resolve #3036010 "Updaters",!673Issue #3214208: FinishResponseSubscriber could create duplicate headers,!617Issue #3043725: Provide a Entity Handler for user cancelation,!579Issue #2230909: Simple decimals fail to pass validation,!560Move callback classRemove outside of the loop,!555Issue #3202493
Pipeline #65372 passed
+1
......@@ -7,6 +7,7 @@ parameters:
# \Drupal\Core\Cache\ListCacheBinsPass::process() will override this but defining this allows the cache system to
# function properly before that runs.
cache_default_bin_backends: []
memory_cache_default_bin_backends: []
session.storage.options:
gc_probability: 1
gc_divisor: 100
......@@ -194,7 +195,7 @@ services:
cache_factory:
class: Drupal\Core\Cache\CacheFactory
arguments: ['@settings', '%cache_default_bin_backends%']
arguments: ['@settings', '%cache_default_bin_backends%', '%memory_cache_default_bin_backends%']
calls:
- [setContainer, ['@service_container']]
Drupal\Core\Cache\CacheFactoryInterface: '@cache_factory'
......@@ -239,6 +240,8 @@ services:
arguments: ['@cache_tags.invalidator.checksum']
cache.backend.memory:
class: Drupal\Core\Cache\MemoryBackendFactory
cache.backend.memory.memory:
class: Drupal\Core\Cache\MemoryCache\MemoryCacheFactory
# A special cache bin that does not persist beyond the length of the request.
cache.static:
class: Drupal\Core\Cache\CacheBackendInterface
......@@ -289,9 +292,11 @@ services:
factory: ['@cache_factory', 'get']
arguments: [access_policy]
cache.access_policy_memory:
class: Drupal\Core\Cache\MemoryCache\MemoryCache
class: Drupal\Core\Cache\CacheBackendInterface
tags:
- { name: cache_tags_invalidator }
- { name: cache.bin.memory, default_backend: cache.backend.memory.memory }
factory: ['@cache_factory', 'get']
arguments: [access_policy_memory]
cache.data:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
......@@ -308,17 +313,10 @@ services:
class: Drupal\Core\Cache\VariationCacheInterface
factory: ['@variation_cache_factory', 'get']
arguments: [access_policy]
# We cannot use the VariationCacheFactory here because that expects that the
# backend it should wrap a VariationCache around is a proper cache bin. The
# MemoryCache backend, however, is not so we cannot use the factory here.
#
# By instantiating a VariationCache via the container and tagging the cache
# it's wrapping as a cache tags invalidator, it does still behave the way we
# want it to, though.
variation_cache.access_policy_memory:
class: Drupal\Core\Cache\VariationCache
arguments: ['@request_stack', '@cache.access_policy_memory', '@cache_contexts_manager']
Drupal\Core\Cache\VariationCacheInterface: '@variation_cache.access_policy_memory'
class: Drupal\Core\Cache\VariationCacheInterface
factory: ['@variation_cache_factory', 'get']
arguments: [access_policy_memory]
Drupal\Core\Asset\AssetQueryStringInterface: '@asset.query_string'
asset.query_string:
class: Drupal\Core\Asset\AssetQueryString
......
......@@ -126,6 +126,21 @@ public static function getBins() {
return $bins;
}
/**
* Gets all memory cache bin services.
*
* @return \Drupal\Core\Cache\CacheBackendInterface[]
* An array of cache backend objects keyed by memory cache bins.
*/
public static function getMemoryBins(): array {
$bins = [];
$container = \Drupal::getContainer();
foreach ($container->getParameter('memory_cache_bins') as $service_id => $bin) {
$bins[$bin] = $container->get($service_id);
}
return $bins;
}
/**
* Generates a hash from a query object, to be used as part of the cache key.
*
......
......@@ -33,6 +33,17 @@ class CacheFactory implements CacheFactoryInterface, ContainerAwareInterface {
*/
protected $defaultBinBackends;
/**
* A map of cache bin to default cache memory backend service name.
*
* All bin-specific mappings in $settings take precedence over this, but it
* can be used to optimize cache storage for a Drupal installation without
* cache customizations in settings.php.
*
* @var array
*/
protected $memoryDefaultBinBackends;
/**
* Constructs CacheFactory object.
*
......@@ -41,10 +52,14 @@ class CacheFactory implements CacheFactoryInterface, ContainerAwareInterface {
* @param array $default_bin_backends
* (optional) A mapping of bin to backend service name. Mappings in
* $settings take precedence over this.
* @param array $memory_default_bin_backends
* (optional) A mapping of bin to backend service name. Mappings in
* $settings take precedence over this.
*/
public function __construct(Settings $settings, array $default_bin_backends = []) {
public function __construct(Settings $settings, array $default_bin_backends = [], array $memory_default_bin_backends = []) {
$this->settings = $settings;
$this->defaultBinBackends = $default_bin_backends;
$this->memoryDefaultBinBackends = $memory_default_bin_backends;
}
/**
......@@ -72,6 +87,9 @@ public function get($bin) {
elseif (isset($this->defaultBinBackends[$bin])) {
$service_name = $this->defaultBinBackends[$bin];
}
elseif (isset($this->memoryDefaultBinBackends[$bin])) {
$service_name = $this->memoryDefaultBinBackends[$bin];
}
// Third, use configured default backend.
elseif (isset($cache_settings['default'])) {
$service_name = $cache_settings['default'];
......
......@@ -68,10 +68,12 @@ public function addInvalidator(CacheTagsInvalidatorInterface $invalidator) {
*/
protected function getInvalidatorCacheBins() {
$bins = [];
foreach ($this->container->getParameter('cache_bins') as $service_id => $bin) {
$service = $this->container->get($service_id);
if ($service instanceof CacheTagsInvalidatorInterface) {
$bins[$bin] = $service;
foreach (['cache_bins', 'memory_cache_bins'] as $parameter) {
foreach ($this->container->getParameter($parameter) as $service_id => $bin) {
$service = $this->container->get($service_id);
if ($service instanceof CacheTagsInvalidatorInterface) {
$bins[$bin] = $service;
}
}
}
return $bins;
......
......@@ -16,17 +16,29 @@ class ListCacheBinsPass implements CompilerPassInterface {
* Collects the cache bins into the cache_bins parameter.
*/
public function process(ContainerBuilder $container) {
$cache_bins = [];
$cache_default_bin_backends = [];
foreach ($container->findTaggedServiceIds('cache.bin') as $id => $attributes) {
$bin = substr($id, strpos($id, '.') + 1);
$cache_bins[$id] = $bin;
if (isset($attributes[0]['default_backend'])) {
$cache_default_bin_backends[$bin] = $attributes[0]['default_backend'];
$cache_info['cache']['bins'] = [];
$cache_info['cache']['default_bin_backends'] = [];
$cache_info['memory_cache']['bins'] = [];
$cache_info['memory_cache']['default_bin_backends'] = [];
$tag_info = [
'cache.bin' => 'cache',
'cache.bin.memory' => 'memory_cache',
];
foreach ($tag_info as $service_tag => $section) {
foreach ($container->findTaggedServiceIds($service_tag) as $id => $attributes) {
$bin = substr($id, strpos($id, '.') + 1);
$cache_info[$section]['bins'][$id] = $bin;
if (isset($attributes[0]['default_backend'])) {
$cache_info[$section]['default_bin_backends'][$bin] = $attributes[0]['default_backend'];
}
}
}
$container->setParameter('cache_bins', $cache_bins);
$container->setParameter('cache_default_bin_backends', $cache_default_bin_backends);
$container->setParameter('cache_bins', $cache_info['cache']['bins']);
$container->setParameter('cache_default_bin_backends', $cache_info['cache']['default_bin_backends']);
$container->setParameter('memory_cache_bins', $cache_info['memory_cache']['bins']);
$container->setParameter('memory_cache_default_bin_backends', $cache_info['memory_cache']['default_bin_backends']);
}
}
<?php
namespace Drupal\Core\Cache\MemoryCache;
use Drupal\Core\Cache\CacheFactoryInterface;
class MemoryCacheFactory implements CacheFactoryInterface {
/**
* Instantiated memory cache bins.
*
* @var \Drupal\Core\Cache\MemoryBackend[]
*/
protected $bins = [];
/**
* {@inheritdoc}
*/
public function get($bin) {
if (!isset($this->bins[$bin])) {
$this->bins[$bin] = new MemoryCache();
}
return $this->bins[$bin];
}
}
......@@ -30,6 +30,11 @@ protected function refreshVariables() {
$backend->reset();
}
}
foreach (Cache::getMemoryBins() as $backend) {
if (is_callable([$backend, 'reset'])) {
$backend->reset();
}
}
\Drupal::service('config.factory')->reset();
\Drupal::service('state')->resetCache();
......
......@@ -41,7 +41,11 @@ services:
arguments: ['@book.outline_storage', '@entity_type.manager', '@string_translation']
lazy: true
book.memory_cache:
class: Drupal\Core\Cache\MemoryCache\MemoryCache
class: Drupal\Core\Cache\MemoryCache\MemoryCacheInterface
tags:
- { name: cache.bin.memory, default_backend: cache.backend.memory.memory }
factory: ['@cache_factory', 'get']
arguments: [memory_cache]
book.backend_chained_cache:
class: Drupal\Core\Cache\BackendChain
calls:
......@@ -50,4 +54,4 @@ services:
tags:
# This tag ensures that Drupal's cache_tags.invalidator service
# invalidates also this cache data.
- { name: cache.bin }
- { name: cache.bin.memory }
......@@ -125,8 +125,11 @@ services:
# Cache.
cache.jsonapi_memory:
class: Drupal\Core\Cache\MemoryCache\MemoryCache
public: false
class: Drupal\Core\Cache\MemoryCache\MemoryCacheInterface
tags:
- { name: cache.bin.memory, default_backend: cache.backend.memory.memory }
factory: ['@cache_factory', 'get']
arguments: [jsonapi_memory]
# A chained cache with an in-memory cache as the first layer and a database-
# backed cache as the fallback is used. The first layer (memory) is necessary
......@@ -138,7 +141,7 @@ services:
calls:
- [appendBackend, ['@cache.jsonapi_memory']]
- [appendBackend, ['@cache.default']]
tags: [{ name: cache.bin }]
tags: [{ name: cache.bin.memory }]
cache.jsonapi_normalizations:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
......
......@@ -41,10 +41,20 @@ public function testInvalidateTags() {
// a fatal error.
$non_invalidator_cache_bin = $this->createMock('\Drupal\Core\Cache\CacheBackendInterface');
// Repeat the above for memory cache bins.
$invalidator_memory_cache_bin = $this->createMock('\Drupal\Core\Cache\CacheTagsInvalidator');
$invalidator_memory_cache_bin->expects($this->once())
->method('invalidateTags')
->with(['node:1']);
$non_invalidator_memory_cache_bin = $this->createMock('\Drupal\Core\Cache\CacheBackendInterface');
$container = new Container();
$container->set('cache.invalidator_cache_bin', $invalidator_cache_bin);
$container->set('cache.non_invalidator_cache_bin', $non_invalidator_cache_bin);
$container->set('cache.invalidator_memory_cache_bin', $invalidator_memory_cache_bin);
$container->set('cache.non_invalidator_memory_cache_bin', $non_invalidator_memory_cache_bin);
$container->setParameter('cache_bins', ['cache.invalidator_cache_bin' => 'invalidator_cache_bin', 'cache.non_invalidator_cache_bin' => 'non_invalidator_cache_bin']);
$container->setParameter('memory_cache_bins', ['cache.invalidator_memory_cache_bin' => 'invalidator_memory_cache_bin', 'cache.non_invalidator_memory_cache_bin' => 'non_invalidator_memory_cache_bin']);
$cache_tags_invalidator->setContainer($container);
$invalidator = $this->createMock('\Drupal\Core\Cache\CacheTagsInvalidator');
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment