diff --git a/core/core.services.yml b/core/core.services.yml index 478329f97e07fe62e87b7e58db7de0991f29be92..ce81212082c1027175a750f6f1db1ebb351f1039 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -232,6 +232,9 @@ services: - { name: cache_tags_invalidator} - { name: backend_overridable } Drupal\Core\Cache\CacheTagsChecksumInterface: '@cache_tags.invalidator.checksum' + cache_tags.preloader: + class: Drupal\Core\Cache\EventSubscriber\CacheTagPreloadSubscriber + autowire: true cache.backend.chainedfast: class: Drupal\Core\Cache\ChainedFastBackendFactory arguments: ['@settings'] @@ -1805,6 +1808,11 @@ services: tags: - { name: service_collector, tag: placeholder_strategy, call: addPlaceholderStrategy } Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface: '@placeholder_strategy' + placeholder_strategy.cached: + class: Drupal\Core\Render\Placeholder\CachedStrategy + arguments: ['@placeholder_strategy', '@render_cache'] + tags: + - { name: placeholder_strategy, priority: 100 } placeholder_strategy.single_flush: class: Drupal\Core\Render\Placeholder\SingleFlushStrategy tags: diff --git a/core/lib/Drupal/Core/Cache/CacheTagsChecksumPreloadInterface.php b/core/lib/Drupal/Core/Cache/CacheTagsChecksumPreloadInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..1167e27501d5f2b2f7635dd12408939ef7df58cc --- /dev/null +++ b/core/lib/Drupal/Core/Cache/CacheTagsChecksumPreloadInterface.php @@ -0,0 +1,22 @@ +<?php + +namespace Drupal\Core\Cache; + +/** + * Allows to register cache tags for preloading. + * + * Implementations of \Drupal\Core\Cache\CacheTagsChecksumInterface that + * support this interface will fetch registered cache tags on the next + * lookup. + */ +interface CacheTagsChecksumPreloadInterface { + + /** + * Register cache tags for preloading. + * + * @param array $cache_tags + * List of cache tags to load. + */ + public function registerCacheTagsForPreload(array $cache_tags): void; + +} diff --git a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php index 00bf806c3dee1df743646160e9f5110fdb3034b4..0a6724fb1cde0db268e8366d9b5e34d514489c68 100644 --- a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php +++ b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php @@ -32,6 +32,11 @@ trait CacheTagsChecksumTrait { */ protected $tagCache = []; + /** + * Registered cache tags to preload. + */ + protected array $preloadTags = []; + /** * Callback to be invoked just after a database transaction gets committed. * @@ -131,13 +136,24 @@ public function isValid($checksum, array $tags) { */ protected function calculateChecksum(array $tags) { $checksum = 0; + // If there are no cache tags, then there is no cache tag to checksum, - // so return early.. + // so return early. if (empty($tags)) { return $checksum; } - $query_tags = array_diff($tags, array_keys($this->tagCache)); + // If there are registered preload tags, add them to the tags list then + // reset the list. This needs to make sure that it only returns the + // requested cache tags, so store the combination of requested and + // preload cache tags in a separate variable. + $tags_with_preload = $tags; + if ($this->preloadTags) { + $tags_with_preload = array_unique(array_merge($tags, $this->preloadTags)); + $this->preloadTags = []; + } + + $query_tags = array_diff($tags_with_preload, array_keys($this->tagCache)); if ($query_tags) { $tag_invalidations = $this->getTagInvalidationCounts($query_tags); $this->tagCache += $tag_invalidations; @@ -160,6 +176,13 @@ public function reset() { $this->invalidatedTags = []; } + /** + * Implements \Drupal\Core\Cache\CacheTagsChecksumPreloadInterface::registerCacheTagsForPreload() + */ + public function registerCacheTagsForPreload(array $cache_tags): void { + $this->preloadTags = array_merge($this->preloadTags, $cache_tags); + } + /** * Fetches invalidation counts for cache tags. * diff --git a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php index aa41952128c240b3d1a4bd00a664dd70834f00fc..cb88c69495a7721314036aacdabb3f4ad59e2bd8 100644 --- a/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php +++ b/core/lib/Drupal/Core/Cache/DatabaseCacheTagsChecksum.php @@ -8,7 +8,7 @@ /** * Cache tags invalidations checksum implementation that uses the database. */ -class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface { +class DatabaseCacheTagsChecksum implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface, CacheTagsChecksumPreloadInterface { use CacheTagsChecksumTrait; diff --git a/core/lib/Drupal/Core/Cache/EventSubscriber/CacheTagPreloadSubscriber.php b/core/lib/Drupal/Core/Cache/EventSubscriber/CacheTagPreloadSubscriber.php new file mode 100644 index 0000000000000000000000000000000000000000..e3a0639cca19f19ea7d81439ac99b3cbb53cfc9a --- /dev/null +++ b/core/lib/Drupal/Core/Cache/EventSubscriber/CacheTagPreloadSubscriber.php @@ -0,0 +1,55 @@ +<?php + +namespace Drupal\Core\Cache\EventSubscriber; + +use Drupal\Core\Cache\CacheTagsChecksumInterface; +use Drupal\Core\Cache\CacheTagsChecksumPreloadInterface; +use Drupal\Core\Site\Settings; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * Provides a path subscriber that converts path aliases. + */ +class CacheTagPreloadSubscriber implements EventSubscriberInterface { + + public function __construct(protected CacheTagsChecksumInterface $cacheTagsChecksum) { + } + + /** + * Preloads common cache tags. + * + * @param \Symfony\Component\HttpKernel\Event\RequestEvent $event + * The request event. + */ + public function onRequest(RequestEvent $event): void { + if ($event->isMainRequest() && $this->cacheTagsChecksum instanceof CacheTagsChecksumPreloadInterface) { + $default_preload_cache_tags = array_merge([ + 'route_match', + 'access_policies', + 'routes', + 'router', + 'entity_types', + 'entity_field_info', + 'entity_bundles', + 'local_task', + 'library_info', + 'user_values', + ], Settings::get('cache_preload_tags', [])); + $this->cacheTagsChecksum->registerCacheTagsForPreload($default_preload_cache_tags); + } + } + + /** + * Registers the methods in this class that should be listeners. + * + * @return array + * An array of event listener definitions. + */ + public static function getSubscribedEvents(): array { + $events[KernelEvents::REQUEST][] = ['onRequest', 500]; + return $events; + } + +} diff --git a/core/lib/Drupal/Core/Cache/VariationCache.php b/core/lib/Drupal/Core/Cache/VariationCache.php index 8b49221ded2916be51331ef901655a4333da538b..0e0bfdd449857d0192afa9ac210da18d78f0a5e1 100644 --- a/core/lib/Drupal/Core/Cache/VariationCache.php +++ b/core/lib/Drupal/Core/Cache/VariationCache.php @@ -36,6 +36,77 @@ public function get(array $keys, CacheableDependencyInterface $initial_cacheabil return array_pop($chain); } + /** + * Retrieves multiple cached items and follows any redirects until resolution. + * + * Given an array of items—each defined by keys and cacheability—this method: + * 1. Generates initial cache IDs (CIDs) for each item. + * 2. Fetches them from the cache in batches. + * 3. If any fetched item indicates a redirect (via a CacheRedirect object), + * updates the CID and repeats the process. + * + * Only items that ultimately resolve to a cached value are returned. Items that + * do not resolve (cache misses after following possible redirects) never appear + * in the returned array. + * + * @param array $items + * An associative array keyed by arbitrary identifiers. Each value is: + * [ (array) $keys, (CacheableDependencyInterface) $cacheability ]. + * + * Example: + * $items = [ + * 'item_a' => [ ['key1', 'key2'], $cacheability_a ], + * 'item_b' => [ ['another_key'], $cacheability_b ], + * ]; + * + * @return array + * An associative array keyed by the same keys as $items, containing only + * the items found in the cache. Items that never resolve are omitted. + */ + public function getMultiple(array $items): array { + // Initialize processing with a map of CIDs to their associated item info. + $cids_to_process = []; + foreach ($items as $item_key => [$keys, $cacheability]) { + $cid = $this->createCacheIdFast($keys, $cacheability); + $cids_to_process[$cid] = [ + 'item_key' => $item_key, + 'keys' => $keys, + ]; + } + + $results = []; + + // Process CIDs until none remain. Each loop fetches all current CIDs, then: + // - Resolves final items. + // - Identifies redirects and prepares them for the next iteration. + while (!empty($cids_to_process)) { + $current_cids = array_keys($cids_to_process); + $fetched_items = $this->cacheBackend->getMultiple($current_cids); + + $next_cids_to_process = []; + + // Process each fetched item. Misses are simply absent from $fetched_items. + foreach ($fetched_items as $cid => $fetched_item) { + $info = $cids_to_process[$cid]; + + // If the item signals a redirect, we'll follow it in the next iteration. + if ($fetched_item->data instanceof CacheRedirect) { + $redirect_cid = $this->createCacheIdFast($info['keys'], $fetched_item->data); + $next_cids_to_process[$redirect_cid] = $info; + continue; + } + + // Otherwise, we've reached a final cached item. Record it. + $results[$info['item_key']] = $fetched_item; + } + + // Only process redirects in subsequent iterations. + $cids_to_process = $next_cids_to_process; + } + + return $results; + } + /** * {@inheritdoc} */ diff --git a/core/lib/Drupal/Core/Render/Placeholder/CachedStrategy.php b/core/lib/Drupal/Core/Render/Placeholder/CachedStrategy.php new file mode 100644 index 0000000000000000000000000000000000000000..b0eead50c7e003a8c983f21bb27704a69296a54f --- /dev/null +++ b/core/lib/Drupal/Core/Render/Placeholder/CachedStrategy.php @@ -0,0 +1,32 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\Core\Render\Placeholder; + +use Drupal\Core\Render\RenderCacheInterface; + +class CachedStrategy implements PlaceholderStrategyInterface { + + public function __construct( + protected readonly PlaceholderStrategyInterface $placeholderStrategy, + protected readonly RenderCacheInterface $renderCache, + ) { + } + + /** + * {@inheritdoc} + */ + public function processPlaceholders(array $placeholders) { + $new_placeholders = []; + + $cached_items = $this->renderCache->getMultiple($placeholders); + + foreach ($cached_items as $placeholder => $elements) { + $new_placeholders[$placeholder] = $elements; + } + + return $new_placeholders; + } + +} diff --git a/core/lib/Drupal/Core/Render/RenderCache.php b/core/lib/Drupal/Core/Render/RenderCache.php index 078c7bbb6e50d7be9f19f9b5418f6074d9430899..230caaca05c98c01982532619d1be5e1c82ad6fc 100644 --- a/core/lib/Drupal/Core/Render/RenderCache.php +++ b/core/lib/Drupal/Core/Render/RenderCache.php @@ -51,6 +51,78 @@ public function get(array $elements) { return FALSE; } + /** + * Retrieves multiple cached render arrays at once, following redirects until resolution. + * + * Steps: + * - For each render element, compute a cache ID (CID) based on its keys and cacheability. + * - Group elements by their cache bin. + * - For each bin, use getMultiple() to fetch all items in one go. + * - Follow any redirects discovered, updating CIDs and refetching until resolved. + * - If the current HTTP request method is not cacheable, skip items tagged + * with 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:'. + * + * Only items that resolve to a final cached value are returned. Misses or + * disallowed items (due to request method constraints) are omitted entirely. + * + * @param array $multiple_elements + * An associative array keyed by arbitrary identifiers. Each value should be + * a render array that includes '#cache' with 'keys' and optionally 'bin', e.g.: + * $multiple_elements = [ + * 'item_a' => [ + * '#cache' => ['keys' => ['key1', 'key2'], 'bin' => 'render'], + * // ... additional render array data ... + * ], + * 'item_b' => [ + * '#cache' => ['keys' => ['another_key']], // defaults to 'render' bin + * // ... additional render array data ... + * ], + * ]; + * + * @return array + * An associative array keyed by the same keys as $multiple_elements for items that + * are found and allowed. Items that never resolve or violate request conditions + * are not returned. + */ + public function getMultiple(array $multiple_elements): array { + $bin_map = []; + foreach ($multiple_elements as $item_key => $elements) { + if (!$this->isElementCacheable($elements)) { + continue; + } + + $bin = $elements['#cache']['bin'] ?? 'render'; + $keys = $elements['#cache']['keys']; + $cacheability = CacheableMetadata::createFromRenderArray($elements); + + $bin_map[$bin][$item_key] = [$keys, $cacheability]; + } + + $results = []; + $is_method_cacheable = $this->requestStack->getCurrentRequest()->isMethodCacheable(); + + foreach ($bin_map as $bin => $items) { + $cache_bin = $this->cacheFactory->get($bin); + if (!$cache_bin) { + continue; + } + + $fetched_items = $cache_bin->getMultiple($items); + + foreach ($fetched_items as $item_key => $cache) { + if ( + !$is_method_cacheable && + !empty(array_filter($cache->tags, fn (string $tag) => str_starts_with($tag, 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:'))) + ) { + continue; + } + $results[$item_key] = $cache->data; + } + } + + return $results; + } + /** * {@inheritdoc} */ diff --git a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php index 148f69be841d4a3e278bed30417addef515e32b5..08394a7b862a9eeb3decdc11b27138341f1331f7 100644 --- a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php +++ b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php @@ -73,16 +73,15 @@ public function testLogin(): void { $expected = [ 'QueryCount' => 4, - 'CacheGetCount' => 61, + 'CacheGetCount' => 58, 'CacheGetCountByBin' => [ 'config' => 11, 'data' => 6, - 'discovery' => 11, + 'discovery' => 10, 'bootstrap' => 6, 'dynamic_page_cache' => 2, - 'render' => 23, + 'render' => 22, 'menu' => 1, - 'default' => 1, ], 'CacheSetCount' => 2, 'CacheSetCountByBin' => [ @@ -98,7 +97,6 @@ public function testLogin(): void { 'StylesheetBytes' => 92000, ]; $this->assertMetrics($expected, $performance_data); - $this->assertSame(['core.extension.list.module'], $performance_data->getCacheOperations()['get']['default']); // Check that the navigation toolbar is cached without any high-cardinality // cache contexts (user, route, query parameters etc.). diff --git a/core/modules/system/tests/modules/performance_test/src/Cache/CacheTagsChecksumDecorator.php b/core/modules/system/tests/modules/performance_test/src/Cache/CacheTagsChecksumDecorator.php index ba01cd809c44ab647dd8f15cc0d2816433876197..dd4675f4b62ef892a6b6903d57f972c0505006fd 100644 --- a/core/modules/system/tests/modules/performance_test/src/Cache/CacheTagsChecksumDecorator.php +++ b/core/modules/system/tests/modules/performance_test/src/Cache/CacheTagsChecksumDecorator.php @@ -5,13 +5,14 @@ namespace Drupal\performance_test\Cache; use Drupal\Core\Cache\CacheTagsChecksumInterface; +use Drupal\Core\Cache\CacheTagsChecksumPreloadInterface; use Drupal\Core\Cache\CacheTagsInvalidatorInterface; use Drupal\performance_test\PerformanceDataCollector; /** * Wraps an existing cache tags checksum invalidator to track calls separately. */ -class CacheTagsChecksumDecorator implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface { +class CacheTagsChecksumDecorator implements CacheTagsChecksumInterface, CacheTagsInvalidatorInterface, CacheTagsChecksumPreloadInterface { public function __construct(protected readonly CacheTagsChecksumInterface $checksumInvalidator, protected readonly PerformanceDataCollector $performanceDataCollector) {} @@ -71,6 +72,13 @@ public function reset() { $this->checksumInvalidator->reset(); } + /** + * {@inheritdoc} + */ + public function registerCacheTagsForPreload(array $cache_tags): void { + $this->checksumInvalidator->registerCacheTagsForPreload($cache_tags); + } + /** * Logs a cache tag operation. * diff --git a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php index 24c7193b0ee0cd61359ecc26adefbcf09440d33f..c96d9fe2e2e70e223d88bfa1049fe09e6fe28840 100644 --- a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php +++ b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php @@ -64,7 +64,7 @@ public function testFrontPageAuthenticatedWarmCache(): void { 'CacheTagChecksumCount' => 0, 'CacheTagIsValidCount' => 10, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 5, + 'CacheTagLookupQueryCount' => 2, '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 ecc905112b37b7b64c7df4bcd8a5ff4591919796..2143b6a99a381289e66149cc0d8569d37b569ca0 100644 --- a/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php +++ b/core/profiles/standard/tests/src/FunctionalJavascript/StandardPerformanceTest.php @@ -145,18 +145,13 @@ protected function testAnonymous(): void { 'CacheTagChecksumCount' => 37, 'CacheTagIsValidCount' => 42, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 29, + 'CacheTagLookupQueryCount' => 22, 'CacheTagGroupedLookups' => [ - ['route_match'], - ['entity_types'], - ['routes'], + ['route_match', 'access_policies', 'routes', 'router', 'entity_types', 'entity_field_info', 'entity_bundles', 'local_task', 'library_info', 'user_values'], ['config:views.view.frontpage'], ['config:core.extension', 'views_data'], - ['entity_field_info'], - ['entity_bundles'], ['node_values'], ['node:1', 'node_list'], - ['user_values'], ['rendered', 'user:0', 'user_view'], ['config:filter.format.restricted_html', 'node_view'], ['block_view', 'config:block.block.stark_site_branding', 'config:system.site'], @@ -167,14 +162,12 @@ protected function testAnonymous(): void { ['config:block.block.stark_breadcrumbs'], ['config:block.block.stark_primary_admin_actions'], ['config:block.block.stark_messages'], - ['local_task'], ['config:block.block.stark_primary_local_tasks'], ['config:block.block.stark_secondary_local_tasks'], ['config:block.block.stark_help'], ['config:block.block.stark_powered'], ['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, @@ -218,14 +211,10 @@ protected function testAnonymous(): void { 'CacheSetCount' => 16, 'CacheDeleteCount' => 0, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 25, + 'CacheTagLookupQueryCount' => 19, 'CacheTagGroupedLookups' => [ - ['route_match'], - ['entity_types'], - ['entity_field_info', 'node_values'], - ['routes'], - ['entity_bundles'], - ['user_values'], + ['route_match', 'access_policies', 'routes', 'router', 'entity_types', 'entity_field_info', 'entity_bundles', 'local_task', 'library_info', 'user_values'], + ['node_values'], ['rendered', 'user:0', 'user_view'], ['config:filter.format.restricted_html', 'node:1', 'node_view'], ['block_view', 'config:block.block.stark_site_branding', 'config:system.site'], @@ -236,14 +225,12 @@ protected function testAnonymous(): void { ['config:block.block.stark_breadcrumbs'], ['config:block.block.stark_primary_admin_actions'], ['config:block.block.stark_messages'], - ['local_task'], ['config:block.block.stark_primary_local_tasks'], ['config:block.block.stark_secondary_local_tasks'], ['config:block.block.stark_help'], ['config:block.block.stark_powered'], ['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, @@ -278,13 +265,13 @@ protected function testAnonymous(): void { $this->assertSame($expected_queries, $recorded_queries); $expected = [ 'QueryCount' => 14, - 'CacheGetCount' => 77, + 'CacheGetCount' => 80, 'CacheSetCount' => 17, 'CacheDeleteCount' => 0, 'CacheTagChecksumCount' => 23, - 'CacheTagIsValidCount' => 31, + 'CacheTagIsValidCount' => 33, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 23, + 'CacheTagLookupQueryCount' => 16, 'StylesheetCount' => 1, 'StylesheetBytes' => 3150, ]; @@ -335,26 +322,18 @@ protected function testLogin(): void { $this->assertSame($expected_queries, $recorded_queries); $expected = [ 'QueryCount' => 17, - 'CacheGetCount' => 82, + 'CacheGetCount' => 85, 'CacheSetCount' => 1, 'CacheDeleteCount' => 1, 'CacheTagChecksumCount' => 1, - 'CacheTagIsValidCount' => 35, + 'CacheTagIsValidCount' => 37, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 26, + 'CacheTagLookupQueryCount' => 17, 'CacheTagGroupedLookups' => [ // Form submission and login. - ['route_match'], - ['routes'], - ['entity_types'], - ['entity_field_info', 'user_values'], + ['route_match', 'access_policies', 'routes', 'router', 'entity_types', 'entity_field_info', 'entity_bundles', 'local_task', 'library_info', 'user_values'], // The user page after the redirect. - ['route_match'], - ['entity_types'], - ['entity_field_info'], - ['entity_bundles'], - ['user_values'], - ['routes'], + ['route_match', 'access_policies', 'routes', 'router', 'entity_types', 'entity_field_info', 'entity_bundles', 'local_task', 'library_info', 'user_values'], ['rendered', 'user:2', 'user_view'], ['block_view', 'config:block.block.stark_site_branding', 'config:system.site'], ['CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:form', 'config:block.block.stark_search_form_narrow', 'config:search.settings'], @@ -365,12 +344,11 @@ protected function testLogin(): void { ['config:block.block.stark_breadcrumbs'], ['config:block.block.stark_primary_admin_actions'], ['config:block.block.stark_messages'], - ['access_policies', 'config:block.block.stark_primary_local_tasks', 'config:user.role.authenticated', 'local_task'], + ['config:block.block.stark_primary_local_tasks', 'config:user.role.authenticated'], ['config:block.block.stark_secondary_local_tasks'], ['config:block.block.stark_help'], ['config:block.block.stark_powered'], ['config:block.block.stark_syndicate'], - ['library_info'], ], ]; $this->assertMetrics($expected, $performance_data); @@ -429,7 +407,7 @@ protected function testLoginBlock(): void { 'CacheTagChecksumCount' => 1, 'CacheTagIsValidCount' => 41, 'CacheTagInvalidationCount' => 0, - 'CacheTagLookupQueryCount' => 27, + 'CacheTagLookupQueryCount' => 20, ]; $this->assertMetrics($expected, $performance_data); }