Commit 685419fa authored by catch's avatar catch
Browse files

Issue #3131585 by Berdir, alexpott, daffie: Performance regression caused by...

Issue #3131585 by Berdir, alexpott, daffie: Performance regression caused by using the last installed entity definitions
parent 0762491d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -582,7 +582,7 @@ services:
    arguments: ['@entity_type.manager', '@module_handler', '@cache.discovery', '@language_manager']
  entity_field.manager:
    class: Drupal\Core\Entity\EntityFieldManager
    arguments: ['@entity_type.manager', '@entity_type.bundle.info', '@entity_display.repository', '@typed_data_manager', '@language_manager', '@keyvalue', '@module_handler', '@cache.discovery']
    arguments: ['@entity_type.manager', '@entity_type.bundle.info', '@entity_display.repository', '@typed_data_manager', '@language_manager', '@keyvalue', '@module_handler', '@cache.discovery', '@entity.last_installed_schema.repository']
  entity_type.listener:
    class: Drupal\Core\Entity\EntityTypeListener
    arguments: ['@entity_type.manager', '@entity_field.manager', '@event_dispatcher', '@entity.last_installed_schema.repository']
@@ -599,7 +599,7 @@ services:
    arguments: ['@entity_type.manager', '@entity.last_installed_schema.repository', '@entity_field.manager', '@entity_type.listener', '@field_storage_definition.listener']
  entity.last_installed_schema.repository:
    class: Drupal\Core\Entity\EntityLastInstalledSchemaRepository
    arguments: ['@keyvalue']
    arguments: ['@keyvalue', '@cache.discovery']
  entity_field.deleted_fields_repository:
    class: Drupal\Core\Field\DeletedFieldsRepository
    arguments: ['@state']
+16 −2
Original line number Diff line number Diff line
@@ -131,6 +131,13 @@ class EntityFieldManager implements EntityFieldManagerInterface {
   */
  protected $entityDisplayRepository;

  /**
   * The entity last installed schema repository.
   *
   * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
   */
  protected $entityLastInstalledSchemaRepository;

  /**
   * Constructs a new EntityFieldManager.
   *
@@ -150,8 +157,10 @@ class EntityFieldManager implements EntityFieldManagerInterface {
   *   The module handler.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
   *   The cache backend.
   * @param \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository
   *   The entity last installed schema repository.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityDisplayRepositoryInterface $entity_display_repository, TypedDataManagerInterface $typed_data_manager, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend) {
  public function __construct(EntityTypeManagerInterface $entity_type_manager, EntityTypeBundleInfoInterface $entity_type_bundle_info, EntityDisplayRepositoryInterface $entity_display_repository, TypedDataManagerInterface $typed_data_manager, LanguageManagerInterface $language_manager, KeyValueFactoryInterface $key_value_factory, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository = NULL) {
    $this->entityTypeManager = $entity_type_manager;
    $this->entityTypeBundleInfo = $entity_type_bundle_info;
    $this->entityDisplayRepository = $entity_display_repository;
@@ -161,6 +170,11 @@ public function __construct(EntityTypeManagerInterface $entity_type_manager, Ent
    $this->keyValueFactory = $key_value_factory;
    $this->moduleHandler = $module_handler;
    $this->cacheBackend = $cache_backend;
    if (!$entity_last_installed_schema_repository) {
      @trigger_error('The entity.last_installed_schema.repository service must be passed to EntityFieldManager::__construct(), it is required before drupal:10.0.0.', E_USER_DEPRECATED);
      $entity_last_installed_schema_repository = \Drupal::service('entity.last_installed_schema.repository');
    }
    $this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
  }

  /**
@@ -465,7 +479,7 @@ public function getFieldStorageDefinitions($entity_type_id) {
   */
  public function getActiveFieldStorageDefinitions($entity_type_id) {
    if (!isset($this->activeFieldStorageDefinitions[$entity_type_id])) {
      $this->activeFieldStorageDefinitions[$entity_type_id] = $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.field_storage_definitions', []);
      $this->activeFieldStorageDefinitions[$entity_type_id] = $this->entityLastInstalledSchemaRepository->getLastInstalledFieldStorageDefinitions($entity_type_id);
    }
    return $this->activeFieldStorageDefinitions[$entity_type_id] ?: $this->getFieldStorageDefinitions($entity_type_id);
  }
+47 −4
Original line number Diff line number Diff line
@@ -2,6 +2,8 @@

namespace Drupal\Core\Entity;

use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;

@@ -17,27 +19,56 @@ class EntityLastInstalledSchemaRepository implements EntityLastInstalledSchemaRe
   */
  protected $keyValueFactory;

  /**
   * The cache backend.
   *
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cacheBackend;

  /**
   * The loaded installed entity type definitions.
   *
   * @var array|null
   */
  protected $entityTypeDefinitions = NULL;

  /**
   * Constructs a new EntityLastInstalledSchemaRepository.
   *
   * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
   *   The key-value factory.
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   *   The cache backend.
   */
  public function __construct(KeyValueFactoryInterface $key_value_factory) {
  public function __construct(KeyValueFactoryInterface $key_value_factory, CacheBackendInterface $cache = NULL) {
    $this->keyValueFactory = $key_value_factory;
    if (!$cache) {
      @trigger_error('The cache.discovery service must be passed to EntityLastInstalledSchemaRepository::__construct(), it is required before drupal:10.0.0.', E_USER_DEPRECATED);
      $cache = \Drupal::cache('discovery');
    }
    $this->cacheBackend = $cache;
  }

  /**
   * {@inheritdoc}
   */
  public function getLastInstalledDefinition($entity_type_id) {
    return $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.entity_type');
    return $this->getLastInstalledDefinitions()[$entity_type_id] ?? NULL;
  }

  /**
   * {@inheritdoc}
   */
  public function getLastInstalledDefinitions() {
    if ($this->entityTypeDefinitions) {
      return $this->entityTypeDefinitions;
    }
    elseif ($cache = $this->cacheBackend->get('entity_type_definitions.installed')) {
      $this->entityTypeDefinitions = $cache->data;
      return $this->entityTypeDefinitions;
    }

    $all_definitions = $this->keyValueFactory->get('entity.definitions.installed')->getAll();

    // Filter out field storage definitions.
@@ -53,7 +84,9 @@ public function getLastInstalledDefinitions() {
      return $parts[0];
    }, $keys);

    return array_combine($keys, $entity_type_definitions);
    $this->entityTypeDefinitions = array_combine($keys, $entity_type_definitions);
    $this->cacheBackend->set('entity_type_definitions.installed', $this->entityTypeDefinitions, Cache::PERMANENT);
    return $this->entityTypeDefinitions;
  }

  /**
@@ -62,6 +95,8 @@ public function getLastInstalledDefinitions() {
  public function setLastInstalledDefinition(EntityTypeInterface $entity_type) {
    $entity_type_id = $entity_type->id();
    $this->keyValueFactory->get('entity.definitions.installed')->set($entity_type_id . '.entity_type', $entity_type);
    $this->cacheBackend->delete('entity_type_definitions.installed');
    $this->entityTypeDefinitions = NULL;
    return $this;
  }

@@ -74,6 +109,8 @@ public function deleteLastInstalledDefinition($entity_type_id) {
    // isn't currently fieldable, there might be legacy definitions or an
    // empty array stored from when it was.
    $this->keyValueFactory->get('entity.definitions.installed')->delete($entity_type_id . '.field_storage_definitions');
    $this->cacheBackend->deleteMultiple(['entity_type_definitions.installed', $entity_type_id . '.field_storage_definitions.installed']);
    $this->entityTypeDefinitions = NULL;
    return $this;
  }

@@ -81,7 +118,12 @@ public function deleteLastInstalledDefinition($entity_type_id) {
   * {@inheritdoc}
   */
  public function getLastInstalledFieldStorageDefinitions($entity_type_id) {
    return $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.field_storage_definitions', []);
    if ($cache = $this->cacheBackend->get($entity_type_id . '.field_storage_definitions.installed')) {
      return $cache->data;
    }
    $definitions = $this->keyValueFactory->get('entity.definitions.installed')->get($entity_type_id . '.field_storage_definitions', []);
    $this->cacheBackend->set($entity_type_id . '.field_storage_definitions.installed', $definitions, Cache::PERMANENT);
    return $definitions;
  }

  /**
@@ -89,6 +131,7 @@ public function getLastInstalledFieldStorageDefinitions($entity_type_id) {
   */
  public function setLastInstalledFieldStorageDefinitions($entity_type_id, array $storage_definitions) {
    $this->keyValueFactory->get('entity.definitions.installed')->set($entity_type_id . '.field_storage_definitions', $storage_definitions);
    $this->cacheBackend->delete($entity_type_id . '.field_storage_definitions.installed');
  }

  /**
+2 −14
Original line number Diff line number Diff line
@@ -65,13 +65,6 @@ class EntityTypeManager extends DefaultPluginManager implements EntityTypeManage
   */
  protected $entityLastInstalledSchemaRepository;

  /**
   * A list of entity type definitions that are active for the current request.
   *
   * @var \Drupal\Core\Entity\EntityTypeInterface[]
   */
  protected $activeDefinitions;

  /**
   * Constructs a new Entity plugin manager.
   *
@@ -162,11 +155,8 @@ public function getDefinition($entity_type_id, $exception_on_invalid = TRUE) {
   * @internal
   */
  public function getActiveDefinition($entity_type_id) {
    if (!isset($this->activeDefinitions[$entity_type_id])) {
      $this->activeDefinitions[$entity_type_id] = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
    }

    return $this->activeDefinitions[$entity_type_id] ?: $this->getDefinition($entity_type_id);
    $definition = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
    return $definition ?: $this->getDefinition($entity_type_id);
  }

  /**
@@ -174,7 +164,6 @@ public function getActiveDefinition($entity_type_id) {
   */
  public function clearCachedDefinitions() {
    parent::clearCachedDefinitions();
    $this->activeDefinitions = [];
    $this->handlers = [];
  }

@@ -184,7 +173,6 @@ public function clearCachedDefinitions() {
  public function useCaches($use_caches = FALSE) {
    parent::useCaches($use_caches);
    if (!$use_caches) {
      $this->activeDefinitions = [];
      $this->handlers = [];
      $this->container->get('entity.memory_cache')->reset();
    }
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ public function testUninstallingWorkspace() {
    $this->assertFalse(\Drupal::database()->schema()->fieldExists('node_revision', 'workspace'));

    // Verify that the revision metadata key has been removed.
    $this->rebuildContainer();
    $entity_type = \Drupal::entityDefinitionUpdateManager()->getEntityType('node');
    $revision_metadata_keys = $entity_type->get('revision_metadata_keys');
    $this->assertArrayNotHasKey('workspace', $revision_metadata_keys);
Loading