Commit 685419fa authored by catch's avatar catch

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
......@@ -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']
......
......@@ -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);
}
......
......@@ -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');
}
/**
......
......@@ -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();
}
......
......@@ -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);
......
......@@ -17,6 +17,7 @@
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Entity\EntityFieldManager;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
......@@ -142,6 +143,13 @@ class EntityFieldManagerTest extends UnitTestCase {
*/
protected $entityType;
/**
* The entity last installed schema repository.
*
* @var \Prophecy\Prophecy\ObjectProphecy|\Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
*/
protected $entityLastInstalledSchemaRepository;
/**
* {@inheritdoc}
*/
......@@ -175,8 +183,9 @@ protected function setUp(): void {
$this->entityTypeRepository = $this->prophesize(EntityTypeRepositoryInterface::class);
$this->entityTypeBundleInfo = $this->prophesize(EntityTypeBundleInfoInterface::class);
$this->entityDisplayRepository = $this->prophesize(EntityDisplayRepositoryInterface::class);
$this->entityLastInstalledSchemaRepository = $this->prophesize(EntityLastInstalledSchemaRepositoryInterface::class);
$this->entityFieldManager = new TestEntityFieldManager($this->entityTypeManager->reveal(), $this->entityTypeBundleInfo->reveal(), $this->entityDisplayRepository->reveal(), $this->typedDataManager->reveal(), $this->languageManager->reveal(), $this->keyValueFactory->reveal(), $this->moduleHandler->reveal(), $this->cacheBackend->reveal());
$this->entityFieldManager = new TestEntityFieldManager($this->entityTypeManager->reveal(), $this->entityTypeBundleInfo->reveal(), $this->entityDisplayRepository->reveal(), $this->typedDataManager->reveal(), $this->languageManager->reveal(), $this->keyValueFactory->reveal(), $this->moduleHandler->reveal(), $this->cacheBackend->reveal(), $this->entityLastInstalledSchemaRepository->reveal());
}
/**
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment