Commit 02e77a7b authored by catch's avatar catch
Browse files

task: #3575642 Always free up old container on rebuild, not only in the installer

By: berdir
By: catch
By: godotislate
By: alexpott
By: tlo405
(cherry picked from commit 73361685)
parent dbd2f63e
Loading
Loading
Loading
Loading
Loading
+18 −1
Changes for core/lib/Drupal/Component/DependencyInjection/Container.php: 18 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -204,7 +204,24 @@ public function get(string $id, int $invalid_behavior = ContainerInterface::EXCE
   * a new instance of the shared service.
   */
  public function reset(): void {
    $this->services = [];
    $this->privateServices = [];
    foreach (array_keys($this->services) as $id) {

      if ($id === 'request_stack') {
        continue;
      }

      $definition = $this->serviceDefinitions[$id] ?? NULL;

      // Definitions can either be a keyed array or a serialized string.
      if (is_string($definition)) {
        $definition = unserialize($definition);
      }

      if (!isset($definition['synthetic']) || $definition['synthetic'] === FALSE) {
        unset($this->services[$id]);
      }
    }
  }

  /**
+16 −0
Changes for core/lib/Drupal/Core/DependencyInjection/ContainerBuilder.php: 16 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -80,4 +80,20 @@ public function __sleep(): array {
    return array_keys(get_object_vars($this));
  }

  /**
   * {@inheritdoc}
   */
  public function reset(): void {
    $persist_services = [];
    foreach (array_keys($this->services) as $id) {
      $definition = $this->hasDefinition($id) ? $this->getDefinition($id) : NULL;

      if ($id === 'request_stack' || $definition?->isSynthetic()) {
        $persist_services[$id] = $this->services[$id];
      }
    }
    parent::reset();
    $this->services = $persist_services;
  }

}
+8 −3
Changes for core/lib/Drupal/Core/DrupalKernel.php: 8 added lines, 3 removed lines.
Original line number Diff line number Diff line
@@ -626,9 +626,6 @@ public function preHandle(Request $request) {
    // Set the allowed protocols.
    UrlHelper::setAllowedProtocols($this->container->getParameter('filter_protocols'));

    // Override of Symfony's MIME type guesser singleton.
    MimeTypeGuesser::registerWithSymfonyGuesser($this->container);

    $this->prepared = TRUE;
  }

@@ -1115,6 +1112,9 @@ protected function initializeContainer() {
      $this->container->get('logger.factory')->get('DrupalKernel')->error('Container cannot be saved to cache.');
    }

    // Override of Symfony's MIME type guesser singleton.
    MimeTypeGuesser::registerWithSymfonyGuesser($this->container);

    return $this->container;
  }

@@ -1464,6 +1464,11 @@ protected function attachSynthetic(ContainerInterface $container) {

    // Set the class loader which was registered as a synthetic service.
    $container->set('class_loader', $this->classLoader);

    // Reset any existing container in order to avoid holding on to old object
    // references, otherwise memory usage grows exponentially with each rebuild.
    $this->container?->reset();

    return $container;
  }

+19 −0
Changes for core/lib/Drupal/Core/Extension/ModuleInstaller.php: 19 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -2,6 +2,7 @@

namespace Drupal\Core\Extension;

use Drupal\Component\DependencyInjection\ReverseContainer;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Config\DefaultConfigMode;
@@ -18,6 +19,7 @@
use Drupal\Core\Update\UpdateHookRegistry;
use Drupal\Core\Utility\Error;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;

@@ -741,6 +743,15 @@ function ($definition) {
   *   The list of installed modules.
   */
  protected function updateKernel($module_filenames) {
    // Identify uninstall validator service ids to fetch them again after
    // the rebuild.
    $uninstall_validator_service_ids = [];

    $reverse_container = $this->kernel->getContainer()->get(ReverseContainer::class);
    foreach ($this->uninstallValidators as $validator) {
      $uninstall_validator_service_ids[] = $reverse_container->getId($validator);
    }

    if (!empty($module_filenames)) {
      // This reboots the kernel to register the module's bundle and its
      // services in the service container. The $module_filenames argument is
@@ -758,6 +769,14 @@ protected function updateKernel($module_filenames) {
    $this->moduleHandler = $container->get('module_handler');
    $this->connection = $container->get('database');
    $this->updateRegistry = $container->get('update.update_hook_registry');

    $this->uninstallValidators = new RewindableGenerator(function () use ($uninstall_validator_service_ids, $container) {
      foreach ($uninstall_validator_service_ids as $id) {
        if ($id && $container->has($id)) {
          yield $id => $container->get($id);
        }
      }
    }, count($uninstall_validator_service_ids));
  }

  /**
+0 −14
Changes for core/lib/Drupal/Core/Installer/InstallerKernel.php: 0 added lines, 14 removed lines.
Original line number Diff line number Diff line
@@ -6,7 +6,6 @@
use Drupal\Core\Extension\Extension;
use Drupal\Core\Extension\ExtensionDiscovery;
use Drupal\Core\Extension\InfoParser;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Extend DrupalKernel to handle force some kernel behaviors.
@@ -115,19 +114,6 @@ public static function installationAttempted() {
    return isset($GLOBALS['install_state']) && empty($GLOBALS['install_state']['installation_finished']);
  }

  /**
   * {@inheritdoc}
   */
  protected function attachSynthetic(ContainerInterface $container): void {
    parent::attachSynthetic($container);

    // Reset any existing container in order to avoid holding on to old object
    // references, otherwise memory usage grows exponentially with each rebuild
    // when multiple modules are being installed.
    // @todo Move this to the parent class after https://www.drupal.org/i/2066993
    $this->container?->reset();
  }

  /**
   * {@inheritdoc}
   */
Loading