From 8796218cbcccbab34faf9032de3cd993fa1bd944 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Wed, 15 May 2024 21:57:37 +0200 Subject: [PATCH 1/5] FEATURE: Workspace aware content cache --- Neos.Neos/Classes/Fusion/Cache/CacheTag.php | 44 +++++++------- .../Classes/Fusion/Cache/CacheTagSet.php | 14 ++--- .../Fusion/Cache/ContentCacheFlusher.php | 58 ++++++++++--------- ...phProjectorCatchUpHookForCacheFlushing.php | 18 +++--- .../Fusion/ConvertUrisImplementation.php | 4 +- .../Classes/Fusion/Helper/CachingHelper.php | 11 ++-- .../Features/ContentCache/Nodes.feature | 37 ++++++++++++ 7 files changed, 114 insertions(+), 72 deletions(-) diff --git a/Neos.Neos/Classes/Fusion/Cache/CacheTag.php b/Neos.Neos/Classes/Fusion/Cache/CacheTag.php index 795cb37c9dd..c86e2c30e20 100644 --- a/Neos.Neos/Classes/Fusion/Cache/CacheTag.php +++ b/Neos.Neos/Classes/Fusion/Cache/CacheTag.php @@ -8,7 +8,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\Flow\Annotations as Flow; /** @@ -32,12 +32,12 @@ private function __construct( final public static function forNodeAggregate( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ): self { return new self( 'Node_' - . self::getHashForContentStreamIdAndContentRepositoryId($contentStreamId, $contentRepositoryId) + . self::getHashForWorkspaceNameAndContentRepositoryId($workspaceName, $contentRepositoryId) . '_' . $nodeAggregateId->value ); } @@ -45,20 +45,20 @@ final public static function forNodeAggregate( final public static function forNodeAggregateFromNode(Node $node): self { return self::forNodeAggregate( - $node->subgraphIdentity->contentRepositoryId, - $node->subgraphIdentity->contentStreamId, + $node->contentRepositoryId, + $node->workspaceName, $node->nodeAggregateId ); } final public static function forDescendantOfNode( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ): self { return new self( 'DescendantOf_' - . self::getHashForContentStreamIdAndContentRepositoryId($contentStreamId, $contentRepositoryId) + . self::getHashForWorkspaceNameAndContentRepositoryId($workspaceName, $contentRepositoryId) . '_' . $nodeAggregateId->value ); } @@ -66,20 +66,20 @@ final public static function forDescendantOfNode( final public static function forDescendantOfNodeFromNode(Node $node): self { return self::forDescendantOfNode( - $node->subgraphIdentity->contentRepositoryId, - $node->subgraphIdentity->contentStreamId, - $node->nodeAggregateId + $node->contentRepositoryId, + $node->workspaceName, + $node->aggregateId ); } final public static function forAncestorNode( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ): self { return new self( 'Ancestor_' - . self::getHashForContentStreamIdAndContentRepositoryId($contentStreamId, $contentRepositoryId) + . self::getHashForWorkspaceNameAndContentRepositoryId($workspaceName, $contentRepositoryId) . '_' . $nodeAggregateId->value ); } @@ -87,32 +87,32 @@ final public static function forAncestorNode( final public static function forAncestorNodeFromNode(Node $node): self { return self::forAncestorNode( - $node->subgraphIdentity->contentRepositoryId, - $node->subgraphIdentity->contentStreamId, - $node->nodeAggregateId + $node->contentRepositoryId, + $node->workspaceName, + $node->aggregateId ); } final public static function forNodeTypeName( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeTypeName $nodeTypeName, ): self { return new self( 'NodeType_' - . self::getHashForContentStreamIdAndContentRepositoryId($contentStreamId, $contentRepositoryId) + . self::getHashForWorkspaceNameAndContentRepositoryId($workspaceName, $contentRepositoryId) . '_' . \strtr($nodeTypeName->value, '.:', '_-') ); } final public static function forDynamicNodeAggregate( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ): self { return new self( 'DynamicNodeTag_' - . self::getHashForContentStreamIdAndContentRepositoryId($contentStreamId, $contentRepositoryId) + . self::getHashForWorkspaceNameAndContentRepositoryId($workspaceName, $contentRepositoryId) . '_' . $nodeAggregateId->value ); } @@ -122,10 +122,10 @@ final public static function fromString(string $string): self return new self($string); } - protected static function getHashForContentStreamIdAndContentRepositoryId( - ContentStreamId $contentStreamId, + protected static function getHashForWorkspaceNameAndContentRepositoryId( + WorkspaceName $workspaceName, ContentRepositoryId $contentRepositoryId, ): string { - return sha1($contentStreamId->value . '@' . $contentRepositoryId->value); + return sha1($workspaceName->value . '@' . $contentRepositoryId->value); } } diff --git a/Neos.Neos/Classes/Fusion/Cache/CacheTagSet.php b/Neos.Neos/Classes/Fusion/Cache/CacheTagSet.php index 984364fefa0..b620b062470 100644 --- a/Neos.Neos/Classes/Fusion/Cache/CacheTagSet.php +++ b/Neos.Neos/Classes/Fusion/Cache/CacheTagSet.php @@ -9,7 +9,7 @@ use Neos\ContentRepository\Core\Projection\ContentGraph\Node; use Neos\ContentRepository\Core\Projection\ContentGraph\Nodes; use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\Flow\Annotations as Flow; /** @@ -38,7 +38,7 @@ public static function forDescendantOfNodesFromNodes( Nodes $nodes ): self { return new self(...array_map( - fn(Node $node): CacheTag => CacheTag::forDescendantOfNodeFromNode( + fn (Node $node): CacheTag => CacheTag::forDescendantOfNodeFromNode( $node ), iterator_to_array($nodes) @@ -49,7 +49,7 @@ public static function forNodeAggregatesFromNodes( Nodes $nodes ): self { return new self(...array_map( - fn(Node $node): CacheTag => CacheTag::forNodeAggregateFromNode( + fn (Node $node): CacheTag => CacheTag::forNodeAggregateFromNode( $node ), iterator_to_array($nodes) @@ -59,13 +59,13 @@ public static function forNodeAggregatesFromNodes( public static function forNodeTypeNames( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeTypeNames $nodeTypeNames ): self { return new self(...array_map( - fn(NodeTypeName $nodeTypeName): CacheTag => CacheTag::forNodeTypeName( + fn (NodeTypeName $nodeTypeName): CacheTag => CacheTag::forNodeTypeName( $contentRepositoryId, - $contentStreamId, + $workspaceName, $nodeTypeName ), iterator_to_array($nodeTypeNames) @@ -86,7 +86,7 @@ public function add(CacheTag $cacheTag): self public function toStringArray(): array { return array_map( - fn(CacheTag $tag): string => $tag->value, + fn (CacheTag $tag): string => $tag->value, array_values($this->tags) ); } diff --git a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php index 4cc0154ad12..d78e857b2b9 100644 --- a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php +++ b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php @@ -14,7 +14,6 @@ namespace Neos\Neos\Fusion\Cache; -use Neos\ContentGraph\DoctrineDbalAdapter\Domain\Repository\ContentGraph; use Neos\ContentRepository\Core\ContentRepository; use Neos\ContentRepository\Core\NodeType\NodeType; use Neos\ContentRepository\Core\NodeType\NodeTypeName; @@ -22,7 +21,7 @@ use Neos\ContentRepository\Core\SharedModel\ContentRepository\ContentRepositoryId; use Neos\ContentRepository\Core\SharedModel\Exception\NodeTypeNotFound; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\ContentRepositoryRegistry\ContentRepositoryRegistry; use Neos\Flow\Annotations as Flow; use Neos\Flow\Persistence\PersistenceManagerInterface; @@ -64,20 +63,16 @@ public function __construct( /** * Main entry point to *directly* flush the caches of a given NodeAggregate - * - * @param ContentRepository $contentRepository - * @param ContentStreamId $contentStreamId - * @param NodeAggregateId $nodeAggregateId */ public function flushNodeAggregate( ContentRepository $contentRepository, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId ): void { $tagsToFlush[ContentCache::TAG_EVERYTHING] = 'which were tagged with "Everything".'; $tagsToFlush = array_merge( - $this->collectTagsForChangeOnNodeAggregate($contentRepository, $contentStreamId, $nodeAggregateId), + $this->collectTagsForChangeOnNodeAggregate($contentRepository, $workspaceName, $nodeAggregateId), $tagsToFlush ); @@ -89,15 +84,10 @@ public function flushNodeAggregate( */ private function collectTagsForChangeOnNodeAggregate( ContentRepository $contentRepository, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId ): array { - $workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($contentStreamId); - if (is_null($workspace)) { - return []; - } - $contentGraph = $contentRepository->getContentGraph($workspace->workspaceName); - + $contentGraph = $contentRepository->getContentGraph($workspaceName); $nodeAggregate = $contentGraph->findNodeAggregateById( $nodeAggregateId @@ -106,12 +96,12 @@ private function collectTagsForChangeOnNodeAggregate( // Node Aggregate was removed in the meantime, so no need to clear caches on this one anymore. return []; } - $tagsToFlush = $this->collectTagsForChangeOnNodeIdentifier($contentRepository->id, $contentGraph->getContentStreamId(), $nodeAggregateId); + $tagsToFlush = $this->collectTagsForChangeOnNodeIdentifier($contentRepository->id, $workspaceName, $nodeAggregateId); $tagsToFlush = array_merge($this->collectTagsForChangeOnNodeType( $nodeAggregate->nodeTypeName, $contentRepository->id, - $contentGraph->getContentStreamId(), + $workspaceName, $nodeAggregateId, $contentRepository ), $tagsToFlush); @@ -125,7 +115,7 @@ private function collectTagsForChangeOnNodeAggregate( $parentNodeAggregates[] = $parentNodeAggregate; } // we do not need these variables anymore here - unset($contentStreamId, $nodeAggregateId); + unset($nodeAggregateId); // NOTE: Normally, the content graph cannot contain cycles. However, during the @@ -144,7 +134,7 @@ private function collectTagsForChangeOnNodeAggregate( } $processedNodeAggregateIds[$nodeAggregate->nodeAggregateId->value] = true; - $tagName = CacheTag::forDescendantOfNode($contentRepository->id, $nodeAggregate->contentStreamId, $nodeAggregate->nodeAggregateId); + $tagName = CacheTag::forDescendantOfNode($contentRepository->id, $workspaceName, $nodeAggregate->nodeAggregateId); $tagsToFlush[$tagName->value] = sprintf( 'which were tagged with "%s" because node "%s" has changed.', $tagName->value, @@ -169,24 +159,24 @@ private function collectTagsForChangeOnNodeAggregate( */ private function collectTagsForChangeOnNodeIdentifier( ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId, ): array { $tagsToFlush = []; - $nodeCacheIdentifier = CacheTag::forNodeAggregate($contentRepositoryId, $contentStreamId, $nodeAggregateId); + $nodeCacheIdentifier = CacheTag::forNodeAggregate($contentRepositoryId, $workspaceName, $nodeAggregateId); $tagsToFlush[$nodeCacheIdentifier->value] = sprintf( 'which were tagged with "%s" because that identifier has changed.', $nodeCacheIdentifier->value ); - $dynamicNodeCacheIdentifier = CacheTag::forDynamicNodeAggregate($contentRepositoryId, $contentStreamId, $nodeAggregateId); + $dynamicNodeCacheIdentifier = CacheTag::forDynamicNodeAggregate($contentRepositoryId, $workspaceName, $nodeAggregateId); $tagsToFlush[$dynamicNodeCacheIdentifier->value] = sprintf( 'which were tagged with "%s" because that identifier has changed.', $dynamicNodeCacheIdentifier->value ); - $descendantOfNodeCacheIdentifier = CacheTag::forDescendantOfNode($contentRepositoryId, $contentStreamId, $nodeAggregateId); + $descendantOfNodeCacheIdentifier = CacheTag::forDescendantOfNode($contentRepositoryId, $workspaceName, $nodeAggregateId); $tagsToFlush[$descendantOfNodeCacheIdentifier->value] = sprintf( 'which were tagged with "%s" because node "%s" has changed.', $descendantOfNodeCacheIdentifier->value, @@ -202,7 +192,7 @@ private function collectTagsForChangeOnNodeIdentifier( private function collectTagsForChangeOnNodeType( NodeTypeName $nodeTypeName, ContentRepositoryId $contentRepositoryId, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, ?NodeAggregateId $referenceNodeIdentifier, ContentRepository $contentRepository ): array { @@ -217,7 +207,7 @@ private function collectTagsForChangeOnNodeType( } foreach ($nodeTypesNamesToFlush as $nodeTypeNameToFlush) { - $nodeTypeNameCacheIdentifier = CacheTag::forNodeTypeName($contentRepositoryId, $contentStreamId, NodeTypeName::fromString($nodeTypeNameToFlush)); + $nodeTypeNameCacheIdentifier = CacheTag::forNodeTypeName($contentRepositoryId, $workspaceName, NodeTypeName::fromString($nodeTypeNameToFlush)); $tagsToFlush[$nodeTypeNameCacheIdentifier->value] = sprintf( 'which were tagged with "%s" because node "%s" has changed and was of type "%s".', $nodeTypeNameCacheIdentifier->value, @@ -293,13 +283,29 @@ public function registerAssetChange(AssetInterface $asset): void ->withAsset($this->persistenceManager->getIdentifierByObject($asset)) ->includeVariantsOfAsset(); + + $workspaceNamesByContentStreamId = []; foreach ($this->globalAssetUsageService->findByFilter($filter) as $contentRepositoryId => $usages) { foreach ($usages as $usage) { + + // TODO: Remove when WorkspaceName is part of the AssetUsageProjection + $workspaceName = $workspaceNamesByContentStreamId[$contentRepositoryId][$usage->contentStreamId->value] ?? null; + if ($workspaceName === null) { + $contentRepository = $this->contentRepositoryRegistry->get(ContentRepositoryId::fromString($contentRepositoryId)); + $workspace = $contentRepository->getWorkspaceFinder()->findOneByCurrentContentStreamId($usage->contentStreamId); + if ($workspace === null) { + continue; + } + $workspaceName = $workspace->workspaceName; + $workspaceNamesByContentStreamId[$contentRepositoryId][$usage->contentStreamId->value] = $workspaceName; + } + // + $contentRepository = $this->contentRepositoryRegistry->get(ContentRepositoryId::fromString($contentRepositoryId)); $tagsToFlush = array_merge( $this->collectTagsForChangeOnNodeAggregate( $contentRepository, - $usage->contentStreamId, + $workspace->workspaceName, $usage->nodeAggregateId ), $tagsToFlush diff --git a/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php b/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php index 76f9a024984..c71a2965ca2 100644 --- a/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php +++ b/Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php @@ -20,7 +20,7 @@ use Neos\ContentRepository\Core\Projection\CatchUpHookInterface; use Neos\ContentRepository\Core\Projection\ContentGraph\NodeAggregate; use Neos\ContentRepository\Core\SharedModel\Node\NodeAggregateId; -use Neos\ContentRepository\Core\SharedModel\Workspace\ContentStreamId; +use Neos\ContentRepository\Core\SharedModel\Workspace\WorkspaceName; use Neos\EventStore\Model\EventEnvelope; /** @@ -157,7 +157,7 @@ public function onBeforeEvent(EventInterface $eventInstance, EventEnvelope $even assert($parentNodeAggregate instanceof NodeAggregate); $this->scheduleCacheFlushJobForNodeAggregate( $this->contentRepository, - $parentNodeAggregate->contentStreamId, + $workspace->workspaceName, $parentNodeAggregate->nodeAggregateId ); } @@ -189,12 +189,13 @@ public function onAfterEvent(EventInterface $eventInstance, EventEnvelope $event if ($nodeAggregate) { $this->scheduleCacheFlushJobForNodeAggregate( $this->contentRepository, - $nodeAggregate->contentStreamId, + $workspace->workspaceName, $nodeAggregate->nodeAggregateId ); } } } + /** * @var array> */ @@ -206,13 +207,13 @@ public function onAfterEvent(EventInterface $eventInstance, EventEnvelope $event protected function scheduleCacheFlushJobForNodeAggregate( ContentRepository $contentRepository, - ContentStreamId $contentStreamId, + WorkspaceName $workspaceName, NodeAggregateId $nodeAggregateId ): void { // we store this in an associative array deduplicate. - $this->cacheFlushesOnBeforeBatchCompleted[$contentStreamId->value . '__' . $nodeAggregateId->value] = [ + $this->cacheFlushesOnBeforeBatchCompleted[$workspaceName->value . '__' . $nodeAggregateId->value] = [ 'cr' => $contentRepository, - 'csi' => $contentStreamId, + 'wsn' => $workspaceName, 'nai' => $nodeAggregateId ]; } @@ -220,18 +221,17 @@ protected function scheduleCacheFlushJobForNodeAggregate( public function onBeforeBatchCompleted(): void { foreach ($this->cacheFlushesOnBeforeBatchCompleted as $k => $entry) { - $this->contentCacheFlusher->flushNodeAggregate($entry['cr'], $entry['csi'], $entry['nai']); + $this->contentCacheFlusher->flushNodeAggregate($entry['cr'], $entry['wsn'], $entry['nai']); $this->cacheFlushesOnAfterCatchUp[$k] = $entry; } $this->cacheFlushesOnBeforeBatchCompleted = []; } - public function onAfterCatchUp(): void { foreach ($this->cacheFlushesOnAfterCatchUp as $entry) { - $this->contentCacheFlusher->flushNodeAggregate($entry['cr'], $entry['csi'], $entry['nai']); + $this->contentCacheFlusher->flushNodeAggregate($entry['cr'], $entry['wsn'], $entry['nai']); } $this->cacheFlushesOnAfterCatchUp = []; } diff --git a/Neos.Neos/Classes/Fusion/ConvertUrisImplementation.php b/Neos.Neos/Classes/Fusion/ConvertUrisImplementation.php index 99cc98edb44..d32f795f499 100644 --- a/Neos.Neos/Classes/Fusion/ConvertUrisImplementation.php +++ b/Neos.Neos/Classes/Fusion/ConvertUrisImplementation.php @@ -134,7 +134,7 @@ public function evaluate() } $contentRepository = $this->contentRepositoryRegistry->get( - $node->subgraphIdentity->contentRepositoryId + $node->contentRepositoryId ); $nodeAddress = NodeAddressFactory::create($contentRepository)->createFromNode($node); @@ -169,7 +169,7 @@ public function evaluate() $this->systemLogger->info(sprintf('Could not resolve "%s" to a live node uri. Arguments: %s', $matches[0], json_encode($uriBuilder->getLastArguments())), LogEnvironment::fromMethodName(__METHOD__)); } $this->runtime->addCacheTag( - CacheTag::forDynamicNodeAggregate($contentRepository->id, $nodeAddress->contentStreamId, NodeAggregateId::fromString($matches[2]))->value + CacheTag::forDynamicNodeAggregate($contentRepository->id, $nodeAddress->workspaceName, NodeAggregateId::fromString($matches[2]))->value ); break; case 'asset': diff --git a/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php b/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php index 6da6b577a39..5901939576b 100644 --- a/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php +++ b/Neos.Neos/Classes/Fusion/Helper/CachingHelper.php @@ -62,8 +62,7 @@ public function entryIdentifierForNode(Node $node): NodeCacheEntryIdentifier } /** - * Generate a `@cache` entry tag for a single node identifier. If a Node $contextNode is given the - * entry tag will respect the workspace hash. + * Generate a `@cache` entry tag for a single node identifier. * * @param string $identifier * @param Node $contextNode @@ -72,8 +71,8 @@ public function entryIdentifierForNode(Node $node): NodeCacheEntryIdentifier public function nodeTagForIdentifier(string $identifier, Node $contextNode): string { return CacheTag::forNodeAggregate( - $contextNode->subgraphIdentity->contentRepositoryId, - $contextNode->subgraphIdentity->contentStreamId, + $contextNode->contentRepositoryId, + $contextNode->workspaceName, NodeAggregateId::fromString($identifier) )->value; } @@ -96,8 +95,8 @@ public function nodeTypeTag(string|iterable $nodeTypes, Node $contextNode): arra } return CacheTagSet::forNodeTypeNames( - $contextNode->subgraphIdentity->contentRepositoryId, - $contextNode->subgraphIdentity->contentStreamId, + $contextNode->contentRepositoryId, + $contextNode->workspaceName, NodeTypeNames::fromStringArray($nodeTypes) )->toStringArray(); } diff --git a/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature b/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature index 840166ccdf4..86b8b15bd78 100644 --- a/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature +++ b/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature @@ -45,6 +45,7 @@ Feature: Tests for the ContentCacheFlusher and cache flushing on node and nodety | a1 | a | Neos.Neos:Test.DocumentType1 | {"uriPathSegment": "a1", "title": "Node a1"} | a1 | | a1-1 | a1 | Neos.Neos:Test.DocumentType1 | {"uriPathSegment": "a1-1", "title": "Node a1-1"} | a1-1 | | a2 | a | Neos.Neos:Test.DocumentType2 | {"uriPathSegment": "a2", "title": "Node a2"} | a2 | + | a3 | a | Neos.Neos:Test.DocumentType2 | {"uriPathSegment": "a3", "title": "Node a3"} | a3 | And A site exists for node name "a" and domain "http://localhost" And the sites configuration is: """yaml @@ -82,6 +83,7 @@ Feature: Tests for the ContentCacheFlusher and cache flushing on node and nodety entryTags { 1 = ${Neos.Caching.nodeTag(node)} 2 = ${Neos.Caching.descendantOfTag(node)} + 3 = ${Neos.Caching.nodeTagForIdentifier('a3',node)} } } } @@ -179,6 +181,41 @@ Feature: Tests for the ContentCacheFlusher and cache flushing on node and nodety cacheVerifier=first execution, title=Node a1 """ + Scenario: ContentCache gets flushed when a property of another node has changed that is added as nodeTagForIdentifier + Given I have Fusion content cache enabled + And the Fusion context node is a1 + + And I execute the following Fusion code: + """fusion + test = Neos.Neos:Test.DocumentType1 { + cacheVerifier = ${"first execution"} + } + """ + Then I expect the following Fusion rendering result: + """ + cacheVerifier=first execution, title=Node a1 + """ + + When the command SetNodeProperties is executed with payload: + | Key | Value | + | contentStreamId | "cs-identifier" | + | nodeAggregateId | "a3" | + | propertyValues | {"title": "Node a3 new"} | + And the graph projection is fully up to date + + And the Fusion context node is a1 + And I execute the following Fusion code: + """fusion + test = Neos.Neos:Test.DocumentType1 { + cacheVerifier = ${"second execution"} + } + """ + Then I expect the following Fusion rendering result: + """ + cacheVerifier=second execution, title=Node a1 + """ + + Scenario: ContentCache gets flushed when a property of a node has changed by NodeType name Given I have Fusion content cache enabled And the Fusion context node is a2 From cba1c91b47487953cf87d22029b5b656afab0e45 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Wed, 15 May 2024 22:13:21 +0200 Subject: [PATCH 2/5] FEATURE: Workspace aware content cache --- Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php | 1 - 1 file changed, 1 deletion(-) diff --git a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php index d78e857b2b9..0e741a38be1 100644 --- a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php +++ b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php @@ -287,7 +287,6 @@ public function registerAssetChange(AssetInterface $asset): void $workspaceNamesByContentStreamId = []; foreach ($this->globalAssetUsageService->findByFilter($filter) as $contentRepositoryId => $usages) { foreach ($usages as $usage) { - // TODO: Remove when WorkspaceName is part of the AssetUsageProjection $workspaceName = $workspaceNamesByContentStreamId[$contentRepositoryId][$usage->contentStreamId->value] ?? null; if ($workspaceName === null) { From e3cb4fc33088998ae3b7863687b4e3c726447b12 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Wed, 15 May 2024 22:26:42 +0200 Subject: [PATCH 3/5] FEATURE: Workspace aware content cache --- Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php index 0e741a38be1..daea26cfeec 100644 --- a/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php +++ b/Neos.Neos/Classes/Fusion/Cache/ContentCacheFlusher.php @@ -304,7 +304,7 @@ public function registerAssetChange(AssetInterface $asset): void $tagsToFlush = array_merge( $this->collectTagsForChangeOnNodeAggregate( $contentRepository, - $workspace->workspaceName, + $workspaceName, $usage->nodeAggregateId ), $tagsToFlush From 0787837c93ed420a96c420cb3074fc171012f953 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Wed, 15 May 2024 22:36:58 +0200 Subject: [PATCH 4/5] FEATURE: Workspace aware content cache --- .../Unit/Fusion/Helper/CachingHelperTest.php | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/Neos.Neos/Tests/Unit/Fusion/Helper/CachingHelperTest.php b/Neos.Neos/Tests/Unit/Fusion/Helper/CachingHelperTest.php index 15a787667d8..2f9916b6399 100644 --- a/Neos.Neos/Tests/Unit/Fusion/Helper/CachingHelperTest.php +++ b/Neos.Neos/Tests/Unit/Fusion/Helper/CachingHelperTest.php @@ -57,19 +57,19 @@ public function nodeTypeTagDataProvider() $nodeTypeName3 = 'Neos.Neos:Moo'; return [ - [$nodeTypeName1, ['NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Foo']], + [$nodeTypeName1, ['NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Foo']], [[$nodeTypeName1, $nodeTypeName2, $nodeTypeName3], [ - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Foo', - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Bar', - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Moo', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Foo', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Bar', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Moo', ] ], [(new \ArrayObject([$nodeTypeName1, $nodeTypeName2, $nodeTypeName3])), [ - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Foo', - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Bar', - 'NodeType_90ce081cc57c057ff24ad13818166a6c64a38eda_Neos_Neos-Moo', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Foo', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Bar', + 'NodeType_364cfc8e70b2baa23dbd14503d2bd00e063829e7_Neos_Neos-Moo', ] ], ]; @@ -103,15 +103,15 @@ public function nodeDataProvider() $node2 = $this->createNode(NodeAggregateId::fromString($nodeIdentifier2)); return [ - [$node1, ['Node_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], - [[$node1], ['Node_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], + [$node1, ['Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], + [[$node1], ['Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], [[$node1, $node2], [ - 'Node_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306', - 'Node_90ce081cc57c057ff24ad13818166a6c64a38eda_7005c7cf-4d19-ce36-0873-476b6cadb71a' + 'Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306', + 'Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_7005c7cf-4d19-ce36-0873-476b6cadb71a' ]], [(new \ArrayObject([$node1, $node2])), [ - 'Node_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306', - 'Node_90ce081cc57c057ff24ad13818166a6c64a38eda_7005c7cf-4d19-ce36-0873-476b6cadb71a' + 'Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306', + 'Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_7005c7cf-4d19-ce36-0873-476b6cadb71a' ]] ]; } @@ -142,7 +142,7 @@ public function nodeTagsCanBeInitializedWithAnIdentifierString() $actual = $helper->nodeTagForIdentifier($nodeIdentifier, $node); - self::assertEquals('Node_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306', $actual); + self::assertEquals('Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306', $actual); } /** @@ -156,7 +156,7 @@ public function nodeTagForIdentifierStringWillFallbackToLegacyTagIfNoContextNode $contextNode = $this->createNode(NodeAggregateId::fromString("na")); $actual = $helper->nodeTagForIdentifier($identifier, $contextNode); - self::assertEquals('Node_90ce081cc57c057ff24ad13818166a6c64a38eda_some-uuid-identifier', $actual); + self::assertEquals('Node_364cfc8e70b2baa23dbd14503d2bd00e063829e7_some-uuid-identifier', $actual); } public function descendantOfDataProvider() @@ -169,15 +169,15 @@ public function descendantOfDataProvider() return [ - [$node1, ['DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], - [[$node1], ['DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], + [$node1, ['DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], + [[$node1], ['DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306']], [[$node1, $node2], [ - 'DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306', - 'DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_7005c7cf-4d19-ce36-0873-476b6cadb71a' + 'DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306', + 'DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_7005c7cf-4d19-ce36-0873-476b6cadb71a' ]], [(new \ArrayObject([$node1, $node2])), [ - 'DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_ca511a55-c5c0-f7d7-8d71-8edeffc75306', - 'DescendantOf_90ce081cc57c057ff24ad13818166a6c64a38eda_7005c7cf-4d19-ce36-0873-476b6cadb71a' + 'DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_ca511a55-c5c0-f7d7-8d71-8edeffc75306', + 'DescendantOf_364cfc8e70b2baa23dbd14503d2bd00e063829e7_7005c7cf-4d19-ce36-0873-476b6cadb71a' ]] ]; } From 420e7d65171fc4f514a4d3a93ca842f84810a2a8 Mon Sep 17 00:00:00 2001 From: Denny Lubitz Date: Thu, 16 May 2024 08:53:46 +0200 Subject: [PATCH 5/5] FEATURE: Workspace aware content cache --- Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature | 1 + 1 file changed, 1 insertion(+) diff --git a/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature b/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature index 86b8b15bd78..ee88f83659e 100644 --- a/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature +++ b/Neos.Neos/Tests/Behavior/Features/ContentCache/Nodes.feature @@ -181,6 +181,7 @@ Feature: Tests for the ContentCacheFlusher and cache flushing on node and nodety cacheVerifier=first execution, title=Node a1 """ + # See Neos.Caching.nodeTagForIdentifier('a3',node) in setup and now we will update it Scenario: ContentCache gets flushed when a property of another node has changed that is added as nodeTagForIdentifier Given I have Fusion content cache enabled And the Fusion context node is a1