From 5f2f58f0ef539701f285c63fd4c4ef2b7df297cf Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Fri, 31 Jan 2025 18:39:05 +0000
Subject: [PATCH 1/9] Update assertions in navigation performance test.

---
 .../tests/src/FunctionalJavascript/PerformanceTest.php           | 1 +
 1 file changed, 1 insertion(+)

diff --git a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
index 7b50dbd0da79..4ce9833aa77f 100644
--- a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
+++ b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
@@ -81,6 +81,7 @@ public function testLogin(): void {
         'bootstrap' => 6,
         'dynamic_page_cache' => 2,
         'render' => 23,
+        'discovery' => 10,
         'menu' => 1,
       ],
       'CacheSetCount' => 2,
-- 
GitLab


From 148621352b7d658364988293e49bd160b1b7a8d2 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 6 Feb 2025 17:25:53 +0000
Subject: [PATCH 2/9] Add cache tag preloading in ::getMultiple

---
 core/lib/Drupal/Core/Cache/ApcuBackend.php     | 15 +++++++++++++++
 core/lib/Drupal/Core/Cache/DatabaseBackend.php | 16 +++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php
index a275fe904567..e9b9d6b715b3 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackend.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php
@@ -98,6 +98,21 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     $result = apcu_fetch(array_keys($map));
     $cache = [];
     if ($result) {
+      // Before checking the validity of each item individually, register the
+      // cache tags for all returned cache items for preloading, this allows the
+      // cache tag service to optimize cache tag lookups.
+      if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
+        $tags = [];
+        foreach ($result as $item) {
+          if ($item->tags) {
+            $tags = $tags + explode(' ', $item->tags);
+          }
+        }
+        if ($tags) {
+          $this->checksumProvider->registerCacheTagsForPreload($tags);
+        }
+      }
+
       foreach ($result as $key => $item) {
         $item = $this->prepareItem($item, $allow_invalid);
         if ($item) {
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index efae811b7679..8730f7d6af48 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -128,11 +128,25 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     // ::select() is a much smaller proportion of the request.
     $result = [];
     try {
-      $result = $this->connection->query('SELECT [cid], [data], [created], [expire], [serialized], [tags], [checksum] FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE [cid] IN ( :cids[] ) ORDER BY [cid]', [':cids[]' => array_keys($cid_mapping)]);
+      $result = $this->connection->query('SELECT [cid], [data], [created], [expire], [serialized], [tags], [checksum] FROM {' . $this->connection->escapeTable($this->bin) . '} WHERE [cid] IN ( :cids[] ) ORDER BY [cid]', [':cids[]' => array_keys($cid_mapping)])->fetchAll();
     }
     catch (\Exception) {
       // Nothing to do.
     }
+    // Before checking the validity of each item individually, register the
+    // cache tags for all returned cache items for preloading, this allows the
+    // cache tag service to optimize cache tag lookups.
+    if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
+      $tags = [];
+      foreach ($result as $item) {
+        if ($item->tags) {
+          $tags = $tags + explode(' ', $item->tags);
+        }
+      }
+      if ($tags) {
+        $this->checksumProvider->registerCacheTagsForPreload($tags);
+      }
+    }
     $cache = [];
     foreach ($result as $item) {
       // Map the cache ID back to the original.
-- 
GitLab


From 22473bb7492cd7dad83d5ff2d0d445c5c87a117e Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 6 Feb 2025 20:29:06 +0000
Subject: [PATCH 3/9] Just call the method instead of trying to merge.

---
 core/lib/Drupal/Core/Cache/ApcuBackend.php                 | 7 +------
 core/lib/Drupal/Core/Cache/DatabaseBackend.php             | 6 +-----
 .../tests/src/FunctionalJavascript/PerformanceTest.php     | 1 -
 3 files changed, 2 insertions(+), 12 deletions(-)

diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php
index e9b9d6b715b3..9d945b8f1294 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackend.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php
@@ -102,17 +102,12 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
       // cache tags for all returned cache items for preloading, this allows the
       // cache tag service to optimize cache tag lookups.
       if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
-        $tags = [];
         foreach ($result as $item) {
           if ($item->tags) {
-            $tags = $tags + explode(' ', $item->tags);
+            $this->checksumProvider->registerCacheTagsForPreload(explode(' ', $item->tags));
           }
         }
-        if ($tags) {
-          $this->checksumProvider->registerCacheTagsForPreload($tags);
-        }
       }
-
       foreach ($result as $key => $item) {
         $item = $this->prepareItem($item, $allow_invalid);
         if ($item) {
diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 8730f7d6af48..56100971d8dd 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -137,15 +137,11 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     // cache tags for all returned cache items for preloading, this allows the
     // cache tag service to optimize cache tag lookups.
     if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
-      $tags = [];
       foreach ($result as $item) {
         if ($item->tags) {
-          $tags = $tags + explode(' ', $item->tags);
+          $this->checksumProvider->registerCacheTagsForPreload(explode(' ', $item->tags));
         }
       }
-      if ($tags) {
-        $this->checksumProvider->registerCacheTagsForPreload($tags);
-      }
     }
     $cache = [];
     foreach ($result as $item) {
diff --git a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
index 4ce9833aa77f..7b50dbd0da79 100644
--- a/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
+++ b/core/modules/navigation/tests/src/FunctionalJavascript/PerformanceTest.php
@@ -81,7 +81,6 @@ public function testLogin(): void {
         'bootstrap' => 6,
         'dynamic_page_cache' => 2,
         'render' => 23,
-        'discovery' => 10,
         'menu' => 1,
       ],
       'CacheSetCount' => 2,
-- 
GitLab


From 6d03ae758ad9bf078d925ad8fdc0206dab7b885c Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Wed, 5 Mar 2025 09:40:30 +0000
Subject: [PATCH 4/9] Fix delayed tags handling.

---
 core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
index 28af2ae2b8d2..3d462c6bc1ec 100644
--- a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
+++ b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
@@ -182,7 +182,11 @@ public function reset() {
    * Implements \Drupal\Core\Cache\CacheTagsChecksumPreloadInterface::registerCacheTagsForPreload()
    */
   public function registerCacheTagsForPreload(array $cache_tags): void {
-    $this->preloadTags = array_merge($this->preloadTags, $cache_tags);
+    // Don't preload delayed tags that are awaiting invalidation.
+    $preloadable_tags = array_diff($cache_tags, $this->delayedTags);
+    if ($preloadable_tags) {
+      $this->preloadTags = array_merge($this->preloadTags, $preloadable_tags);
+    }
   }
 
   /**
-- 
GitLab


From 5de94c878ed0d51b591f0a668cbf3a64db299ac6 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 13 Mar 2025 11:24:21 +0000
Subject: [PATCH 5/9] Apply 1 suggestion(s) to 1 file(s)

Co-authored-by: Kristiaan Van den Eynde <23190-kristiaanvandeneynde@users.noreply.drupalcode.org>
---
 core/lib/Drupal/Core/Cache/ApcuBackend.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php
index 9d945b8f1294..e95ada0fc19b 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackend.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php
@@ -102,11 +102,13 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
       // cache tags for all returned cache items for preloading, this allows the
       // cache tag service to optimize cache tag lookups.
       if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
+        $tags_for_preload = [];
         foreach ($result as $item) {
           if ($item->tags) {
-            $this->checksumProvider->registerCacheTagsForPreload(explode(' ', $item->tags));
+            tags_for_preload[] = explode(' ', $item->tags);
           }
         }
+        $this->checksumProvider->registerCacheTagsForPreload(array_merge(...$tags_for_preload));
       }
       foreach ($result as $key => $item) {
         $item = $this->prepareItem($item, $allow_invalid);
-- 
GitLab


From 314e36c19157ddea8005d1db8edd11c16fe798f9 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 13 Mar 2025 11:25:28 +0000
Subject: [PATCH 6/9] Return early if cache tags are empty.

---
 core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
index 3d462c6bc1ec..a227b3da78f7 100644
--- a/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
+++ b/core/lib/Drupal/Core/Cache/CacheTagsChecksumTrait.php
@@ -182,6 +182,9 @@ public function reset() {
    * Implements \Drupal\Core\Cache\CacheTagsChecksumPreloadInterface::registerCacheTagsForPreload()
    */
   public function registerCacheTagsForPreload(array $cache_tags): void {
+    if (empty($cache_tags)) {
+      return;
+    }
     // Don't preload delayed tags that are awaiting invalidation.
     $preloadable_tags = array_diff($cache_tags, $this->delayedTags);
     if ($preloadable_tags) {
-- 
GitLab


From c98ac67abba26a1c2f046a5df5a823b9c9fc1e56 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 13 Mar 2025 11:31:28 +0000
Subject: [PATCH 7/9] Send all tags at once to registerCacheTagsForPreload

---
 core/lib/Drupal/Core/Cache/DatabaseBackend.php | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Cache/DatabaseBackend.php b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
index 56100971d8dd..d5c9150dd389 100644
--- a/core/lib/Drupal/Core/Cache/DatabaseBackend.php
+++ b/core/lib/Drupal/Core/Cache/DatabaseBackend.php
@@ -137,11 +137,13 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
     // cache tags for all returned cache items for preloading, this allows the
     // cache tag service to optimize cache tag lookups.
     if ($this->checksumProvider instanceof CacheTagsChecksumPreloadInterface) {
+      $tags_for_preload = [];
       foreach ($result as $item) {
         if ($item->tags) {
-          $this->checksumProvider->registerCacheTagsForPreload(explode(' ', $item->tags));
+          $tags_for_preload[] = explode(' ', $item->tags);
         }
       }
+      $this->checksumProvider->registerCacheTagsForPreload(array_merge(...$tags_for_preload));
     }
     $cache = [];
     foreach ($result as $item) {
-- 
GitLab


From dc641e960c3031c9a09253d60621ce63da1a96b2 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Thu, 13 Mar 2025 11:34:32 +0000
Subject: [PATCH 8/9] Missing $

---
 core/lib/Drupal/Core/Cache/ApcuBackend.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/lib/Drupal/Core/Cache/ApcuBackend.php b/core/lib/Drupal/Core/Cache/ApcuBackend.php
index e95ada0fc19b..bf5e4d98ca9e 100644
--- a/core/lib/Drupal/Core/Cache/ApcuBackend.php
+++ b/core/lib/Drupal/Core/Cache/ApcuBackend.php
@@ -105,7 +105,7 @@ public function getMultiple(&$cids, $allow_invalid = FALSE) {
         $tags_for_preload = [];
         foreach ($result as $item) {
           if ($item->tags) {
-            tags_for_preload[] = explode(' ', $item->tags);
+            $tags_for_preload[] = explode(' ', $item->tags);
           }
         }
         $this->checksumProvider->registerCacheTagsForPreload(array_merge(...$tags_for_preload));
-- 
GitLab


From e28c09d32c3d3f7dcd3f2daf355567de1a5b82a7 Mon Sep 17 00:00:00 2001
From: catch <6915-catch@users.noreply.drupalcode.org>
Date: Tue, 18 Mar 2025 11:48:22 +0000
Subject: [PATCH 9/9] One less database query.

---
 .../OpenTelemetryAuthenticatedPerformanceTest.php               | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php
index cccdaec2608f..2eebd63b88ae 100644
--- a/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php
+++ b/core/profiles/demo_umami/tests/src/FunctionalJavascript/OpenTelemetryAuthenticatedPerformanceTest.php
@@ -63,7 +63,7 @@ public function testFrontPageAuthenticatedWarmCache(): void {
       'CacheSetCount' => 0,
       'CacheDeleteCount' => 0,
       'CacheTagInvalidationCount' => 0,
-      'CacheTagLookupQueryCount' => 4,
+      'CacheTagLookupQueryCount' => 3,
       'ScriptCount' => 2,
       'ScriptBytes' => 123850,
       'StylesheetCount' => 2,
-- 
GitLab