From 10322daf80c7bbe0e275fe3e8377df268dba5a94 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Mon, 5 Feb 2024 18:46:53 +0000
Subject: [PATCH] Issue #3414349 by deviantintegral, taraskorpach, alexpott,
 smustgrave, catch: Improve the performance of
 \Drupal\Core\Update\UpdateRegistry::getRemovedPostUpdates()

---
 .../lib/Drupal/Core/Update/UpdateRegistry.php | 28 +++++++++++++++----
 1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/core/lib/Drupal/Core/Update/UpdateRegistry.php b/core/lib/Drupal/Core/Update/UpdateRegistry.php
index be0711a5c402..4db46fc36933 100644
--- a/core/lib/Drupal/Core/Update/UpdateRegistry.php
+++ b/core/lib/Drupal/Core/Update/UpdateRegistry.php
@@ -67,6 +67,16 @@ class UpdateRegistry implements EventSubscriberInterface {
    */
   protected $sitePath;
 
+  /**
+   * A static cache of all the extension updates scanned for.
+   *
+   * This array is keyed by Drupal root, site path, extension name and update
+   * type. The value if the extension has been searched for is TRUE.
+   *
+   * @var array
+   */
+  protected static array $loadedFiles = [];
+
   /**
    * Constructs a new UpdateRegistry.
    *
@@ -185,6 +195,7 @@ protected function loadUpdateFile(Extension $extension) {
     if (file_exists($filename)) {
       include_once $filename;
     }
+    self::$loadedFiles[$this->root][$this->sitePath][$extension->getName()][$this->updateType] = TRUE;
   }
 
   /**
@@ -247,12 +258,15 @@ public function registerInvokedUpdates(array $function_names) {
    */
   public function getUpdateFunctions($extension_name) {
     $this->scanExtensionsAndLoadUpdateFiles($extension_name);
-    $all_functions = $this->getAvailableUpdateFunctions();
 
-    return array_filter($all_functions, function ($function_name) use ($extension_name) {
-      [$function_extension_name] = explode("_{$this->updateType}_", $function_name);
-      return $function_extension_name === $extension_name;
-    });
+    $updates = [];
+    $functions = get_defined_functions();
+    foreach (preg_grep('/^' . $extension_name . '_' . $this->updateType . '_/', $functions['user']) as $function) {
+      $updates[] = $function;
+    }
+    // Ensure that the update order is deterministic.
+    sort($updates);
+    return $updates;
   }
 
   /**
@@ -263,6 +277,10 @@ public function getUpdateFunctions($extension_name) {
    *   extension.
    */
   protected function scanExtensionsAndLoadUpdateFiles(string $extension = NULL) {
+    if ($extension !== NULL && isset(self::$loadedFiles[$this->root][$this->sitePath][$extension][$this->updateType])) {
+      // We've already checked for this file and, if it exists, loaded it.
+      return;
+    }
     // Scan for extensions.
     $extension_discovery = new ExtensionDiscovery($this->root, TRUE, [], $this->sitePath);
     $module_extensions = $extension_discovery->scan('module');
-- 
GitLab