diff --git a/core/lib/Drupal/Core/Cache/CacheOptionalInterface.php b/core/lib/Drupal/Core/Cache/CacheOptionalInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..e27545a69c5f30ad391fc171a989c2c05bf0e9cf --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheOptionalInterface.php @@ -0,0 +1,20 @@ +<?php + +namespace Drupal\Core\Cache; + +/** + * Indicates that caching is optional. + * + * This interface can be used to suggest that certain implementations are fast + * enough that they do not require additional caching. + * + * If and how exactly this is implemented and used depends on the specific + * system. + * + * Examples: + * - If all active access policies implement this interface, + * \Drupal\Core\Session\AccessPolicyProcessor will skip the persistent cache. + */ +interface CacheOptionalInterface { + +} diff --git a/core/lib/Drupal/Core/Session/AccessPolicyProcessor.php b/core/lib/Drupal/Core/Session/AccessPolicyProcessor.php index 6dc0e359bc0690410c4d816c88a94d7299fb3810..d381fcc5d18de6b414fc1f2f2730d5d55dd86bef 100644 --- a/core/lib/Drupal/Core/Session/AccessPolicyProcessor.php +++ b/core/lib/Drupal/Core/Session/AccessPolicyProcessor.php @@ -2,6 +2,7 @@ namespace Drupal\Core\Session; +use Drupal\Core\Cache\CacheOptionalInterface; use Drupal\Core\Cache\CacheableMetadata; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Cache\VariationCacheInterface; @@ -82,7 +83,7 @@ public function processAccessPolicies(AccountInterface $account, string $scope = } // Retrieve the permissions from the persistent cache if available. - if ($cache = $this->variationCache->get($cache_keys, $initial_cacheability)) { + if ($this->needsPersistentCache() && $cache = $this->variationCache->get($cache_keys, $initial_cacheability)) { $calculated_permissions = $cache->data; $cacheability = CacheableMetadata::createFromObject($calculated_permissions); @@ -134,7 +135,9 @@ public function processAccessPolicies(AccountInterface $account, string $scope = // we had stored a CalculatedPermissions object, we would no longer be // able to ask for its cache contexts. $cacheability = CacheableMetadata::createFromObject($calculated_permissions); - $this->variationCache->set($cache_keys, $calculated_permissions, $cacheability, $initial_cacheability); + if ($this->needsPersistentCache()) { + $this->variationCache->set($cache_keys, $calculated_permissions, $cacheability, $initial_cacheability); + } // Then convert the calculated permissions to an immutable value object // and store it in the static cache so that we don't have to do the same @@ -200,4 +203,20 @@ protected function validateScope(string $scope, CalculatedPermissionsInterface $ return empty($actual_scopes) || $actual_scopes === [$scope]; } + /** + * Returns whether the persistent cache is necessary. + * + * @return bool + * TRUE if cache should be used (at least one policy requires cache), FALSE + * if not. + */ + protected function needsPersistentCache(): bool { + foreach ($this->accessPolicies as $access_policy) { + if (!$access_policy instanceof CacheOptionalInterface) { + return TRUE; + } + } + return FALSE; + } + } diff --git a/core/lib/Drupal/Core/Session/SuperUserAccessPolicy.php b/core/lib/Drupal/Core/Session/SuperUserAccessPolicy.php index d8692e2728fbb2b457198159ff311b968b2c67c5..2b9cd3043648f854a1baeae38022524dca0c949c 100644 --- a/core/lib/Drupal/Core/Session/SuperUserAccessPolicy.php +++ b/core/lib/Drupal/Core/Session/SuperUserAccessPolicy.php @@ -4,10 +4,12 @@ namespace Drupal\Core\Session; +use Drupal\Core\Cache\CacheOptionalInterface; + /** * Grants user 1 an all access pass. */ -final class SuperUserAccessPolicy extends AccessPolicyBase { +final class SuperUserAccessPolicy extends AccessPolicyBase implements CacheOptionalInterface { /** * {@inheritdoc} diff --git a/core/lib/Drupal/Core/Session/UserRolesAccessPolicy.php b/core/lib/Drupal/Core/Session/UserRolesAccessPolicy.php index 9e972d802abe51fa0e8bae0ce01683095738c539..18102b1eb4b25b09a3e30736301cd6bb1f31b09c 100644 --- a/core/lib/Drupal/Core/Session/UserRolesAccessPolicy.php +++ b/core/lib/Drupal/Core/Session/UserRolesAccessPolicy.php @@ -4,12 +4,13 @@ namespace Drupal\Core\Session; +use Drupal\Core\Cache\CacheOptionalInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; /** * Grants permissions based on a user's roles. */ -final class UserRolesAccessPolicy extends AccessPolicyBase { +final class UserRolesAccessPolicy extends AccessPolicyBase implements CacheOptionalInterface { public function __construct(protected EntityTypeManagerInterface $entityTypeManager) {} diff --git a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php index ddd9bc7d684e3070d89ff9988ec0fc04fa6cc310..85ce146e2d256e04ccbab67690ebbec0eb90b4d5 100644 --- a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php +++ b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php @@ -75,12 +75,11 @@ public function testLogin(): void { 'QueryCount' => 4, 'CacheGetCount' => 61, 'CacheGetCountByBin' => [ - 'config' => 10, + 'config' => 11, 'data' => 6, - 'access_policy' => 1, + 'discovery' => 11, 'bootstrap' => 6, 'dynamic_page_cache' => 2, - 'discovery' => 11, 'render' => 23, 'menu' => 1, 'default' => 1, @@ -91,7 +90,7 @@ public function testLogin(): void { ], 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 3, - 'CacheTagIsValidCount' => 31, + 'CacheTagIsValidCount' => 30, 'CacheTagInvalidationCount' => 0, 'ScriptCount' => 2, 'ScriptBytes' => 215500, diff --git a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php index b6dc3a500a33b203579f6c7a222d0cadb95b31d5..24c7193b0ee0cd61359ecc26adefbcf09440d33f 100644 --- a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php +++ b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php @@ -53,9 +53,8 @@ public function testFrontPageAuthenticatedWarmCache(): void { 'QueryCount' => 4, 'CacheGetCount' => 40, 'CacheGetCountByBin' => [ - 'config' => 20, + 'config' => 22, 'discovery' => 5, - 'access_policy' => 2, 'data' => 7, 'bootstrap' => 4, 'dynamic_page_cache' => 2, @@ -63,9 +62,9 @@ public function testFrontPageAuthenticatedWarmCache(): void { 'CacheSetCount' => 0, 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 0, - 'CacheTagIsValidCount' => 11, + 'CacheTagIsValidCount' => 10, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 6, + 'CacheTagLookupQueryCount' => 5, 'ScriptCount' => 1, 'ScriptBytes' => 123850, 'StylesheetCount' => 2, diff --git a/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php b/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php index 9026bca418ae28c7eab36085f128ac9d9c47db5b..ecc905112b37b7b64c7df4bcd8a5ff4591919796 100644 --- a/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php +++ b/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php @@ -130,12 +130,11 @@ protected function testAnonymous(): void { 'CacheGetCount' => 122, 'CacheGetCountByBin' => [ 'page' => 1, - 'config' => 20, + 'config' => 21, 'data' => 8, - 'access_policy' => 1, + 'discovery' => 38, 'bootstrap' => 8, 'dynamic_page_cache' => 2, - 'discovery' => 38, 'render' => 35, 'default' => 5, 'entity' => 2, @@ -144,14 +143,13 @@ protected function testAnonymous(): void { 'CacheSetCount' => 45, 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 37, - 'CacheTagIsValidCount' => 43, + 'CacheTagIsValidCount' => 42, 'CacheTagInvalidationCount' => 0, 'CacheTagLookupQueryCount' => 29, 'CacheTagGroupedLookups' => [ ['route_match'], - ['access_policies', 'config:user.role.anonymous'], - ['routes'], ['entity_types'], + ['routes'], ['config:views.view.frontpage'], ['config:core.extension', 'views_data'], ['entity_field_info'], @@ -177,6 +175,7 @@ protected function testAnonymous(): void { ['config:block.block.stark_syndicate'], ['config:block.block.stark_content', 'config:block.block.stark_page_title', 'config:block_list', 'http_response'], ['library_info'], + ['config:user.role.anonymous'], ], 'StylesheetCount' => 1, 'StylesheetBytes' => 3450, @@ -212,7 +211,7 @@ protected function testAnonymous(): void { $recorded_queries = $performance_data->getQueries(); $this->assertSame($expected_queries, $recorded_queries); $this->assertCountBetween(24, 25, $performance_data->getCacheTagChecksumCount()); - $this->assertCountBetween(39, 40, $performance_data->getCacheTagIsValidCount()); + $this->assertCountBetween(38, 39, $performance_data->getCacheTagIsValidCount()); $expected = [ 'QueryCount' => 10, 'CacheGetCount' => 92, @@ -224,7 +223,6 @@ protected function testAnonymous(): void { ['route_match'], ['entity_types'], ['entity_field_info', 'node_values'], - ['access_policies', 'config:user.role.anonymous'], ['routes'], ['entity_bundles'], ['user_values'], @@ -246,6 +244,7 @@ protected function testAnonymous(): void { ['config:block.block.stark_syndicate'], ['config:block.block.stark_content', 'config:block.block.stark_page_title', 'config:block_list', 'http_response'], ['library_info'], + ['config:user.role.anonymous'], ], 'StylesheetCount' => 1, 'StylesheetBytes' => 3150, @@ -283,9 +282,9 @@ protected function testAnonymous(): void { 'CacheSetCount' => 17, 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 23, - 'CacheTagIsValidCount' => 32, + 'CacheTagIsValidCount' => 31, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 24, + 'CacheTagLookupQueryCount' => 23, 'StylesheetCount' => 1, 'StylesheetBytes' => 3150, ]; @@ -340,15 +339,14 @@ protected function testLogin(): void { 'CacheSetCount' => 1, 'CacheDeleteCount' => 1, 'CacheTagChecksumCount' => 1, - 'CacheTagIsValidCount' => 37, + 'CacheTagIsValidCount' => 35, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 28, + 'CacheTagLookupQueryCount' => 26, 'CacheTagGroupedLookups' => [ // Form submission and login. ['route_match'], ['routes'], ['entity_types'], - ['access_policies', 'config:user.role.anonymous'], ['entity_field_info', 'user_values'], // The user page after the redirect. ['route_match'], @@ -356,7 +354,6 @@ protected function testLogin(): void { ['entity_field_info'], ['entity_bundles'], ['user_values'], - ['access_policies', 'config:user.role.authenticated'], ['routes'], ['rendered', 'user:2', 'user_view'], ['block_view', 'config:block.block.stark_site_branding', 'config:system.site'], @@ -368,7 +365,7 @@ protected function testLogin(): void { ['config:block.block.stark_breadcrumbs'], ['config:block.block.stark_primary_admin_actions'], ['config:block.block.stark_messages'], - ['config:block.block.stark_primary_local_tasks', 'local_task'], + ['access_policies', 'config:block.block.stark_primary_local_tasks', 'config:user.role.authenticated', 'local_task'], ['config:block.block.stark_secondary_local_tasks'], ['config:block.block.stark_help'], ['config:block.block.stark_powered'], @@ -430,9 +427,9 @@ protected function testLoginBlock(): void { 'CacheSetCount' => 1, 'CacheDeleteCount' => 1, 'CacheTagChecksumCount' => 1, - 'CacheTagIsValidCount' => 43, + 'CacheTagIsValidCount' => 41, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 29, + 'CacheTagLookupQueryCount' => 27, ]; $this->assertMetrics($expected, $performance_data); }