-
-
Notifications
You must be signed in to change notification settings - Fork 222
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FEATURE: Overhaul ContentCacheFlusher #5221
FEATURE: Overhaul ContentCacheFlusher #5221
Conversation
public function nodeTagForIdentifier(string $identifier, Node $contextNode): array | ||
{ | ||
return CacheTag::forNodeAggregate( | ||
$contextNode->contentRepositoryId, | ||
$contextNode->workspaceName, | ||
NodeAggregateId::fromString($identifier) | ||
)->value; | ||
return [ | ||
CacheTag::forNodeAggregate( | ||
$contextNode->contentRepositoryId, | ||
$contextNode->workspaceName, | ||
NodeAggregateId::fromString($identifier) | ||
)->value, | ||
CacheTag::forNodeAggregate( | ||
$contextNode->contentRepositoryId, | ||
CacheTagWorkspaceName::ANY, | ||
NodeAggregateId::fromString($identifier) | ||
)->value, | ||
CacheTag::forWorkspaceName( | ||
$contextNode->contentRepositoryId, | ||
$contextNode->workspaceName | ||
)->value | ||
]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to change the return type here, to be able to generate also the workspace tags for identifiers, which is breaking if someone relies on a string. But it works without any changes in the @cache.entryTags
Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php
Show resolved
Hide resolved
public function onBeforeBatchCompleted(): void | ||
{ | ||
foreach ($this->flushNodeAggregateRequestsOnBeforeBatchCompleted as $index => $request) { | ||
$this->contentCacheFlusher->flushNodeAggregate($request, CacheFlushingStrategy::IMMEDIATELY); | ||
$this->flushNodeAggregateRequestsOnAfterCatchUp[$index] = $request; | ||
} | ||
$this->flushNodeAggregateRequestsOnBeforeBatchCompleted = []; | ||
|
||
foreach ($this->flushWorkspaceRequestsOnBeforeBatchCompleted as $index => $request) { | ||
$this->contentCacheFlusher->flushWorkspace($request, CacheFlushingStrategy::IMMEDIATELY); | ||
$this->flushWorkspaceRequestsOnAfterCatchUp[$index] = $request; | ||
} | ||
$this->flushWorkspaceRequestsOnBeforeBatchCompleted = []; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We might need to discuss this "double-cache-flush" approach. See Sebastians description in the head of this file (eventual consistency) vs. performance considerations.
// Prevent infinite loops | ||
if (!$collectedParentNodeAggregateIds->contain($parentNodeAggregateId)) { | ||
$collectedParentNodeAggregateIds = $collectedParentNodeAggregateIds->merge(NodeAggregateIds::create($parentNodeAggregateId)); | ||
$collectedParentNodeAggregateIds = $this->determineParentNodeAggregateIds($workspaceName, $parentNodeAggregateId, $collectedParentNodeAggregateIds); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to prevent infinite loops here, but just for a theroretical case. AFAIR we do not allow circular dependencies, BUT we have a test case which creates that case to test, that it doesn't happen. 🤷♂️
@@ -120,6 +155,27 @@ public function __construct( | |||
) { | |||
} | |||
|
|||
public function canHandle(EventInterface $event): bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is just a workaround, to reduce the subset of possible events, as we are not able to "detect" events, which provide a workspaceName. Also this brings a bit of clearity, which events this catchup hook actually expects.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 by 👀 – just a nitpick and a question.
Neos.Neos/Classes/Fusion/Cache/GraphProjectorCatchUpHookForCacheFlushing.php
Show resolved
Hide resolved
* | ||
* @throws NodeTypeNotFound | ||
*/ | ||
public function registerAssetChange(AssetInterface $asset): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the tests, asset handling still works, but… why? 😳
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some post-merge comments as discussed
Neos.ContentGraph.DoctrineDbalAdapter/src/DoctrineDbalContentGraphProjection.php
Show resolved
Hide resolved
@@ -70,7 +70,7 @@ Feature: ForkContentStream Without Dimensions | |||
|
|||
And the event NodePropertiesWereSet was published with payload: | |||
| Key | Value | | |||
| workspaceName | "user" | | |||
| workspaceName | "user-test" | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why was this test affected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it was wrong the whole time, but the test did't fail.
private function determineParentNodeAggregateIds(ContentRepository $contentRepository, WorkspaceName $workspaceName, NodeAggregateId $childNodeAggregateId, NodeAggregateIds $collectedParentNodeAggregateIds): NodeAggregateIds | ||
{ | ||
$parentNodeAggregates = $contentRepository->getContentGraph($workspaceName)->findParentNodeAggregates($childNodeAggregateId); | ||
$parentNodeAggregateIds = NodeAggregateIds::fromArray( | ||
array_map(static fn (NodeAggregate $parentNodeAggregate) => $parentNodeAggregate->nodeAggregateId, iterator_to_array($parentNodeAggregates)) | ||
); | ||
|
||
foreach ($parentNodeAggregateIds as $parentNodeAggregateId) { | ||
// Prevent infinite loops | ||
if (!$collectedParentNodeAggregateIds->contain($parentNodeAggregateId)) { | ||
$collectedParentNodeAggregateIds = $collectedParentNodeAggregateIds->merge(NodeAggregateIds::create($parentNodeAggregateId)); | ||
$collectedParentNodeAggregateIds = $this->determineParentNodeAggregateIds($contentRepository, $workspaceName, $parentNodeAggregateId, $collectedParentNodeAggregateIds); | ||
} | ||
} | ||
|
||
|
||
return $collectedParentNodeAggregateIds; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are the ancestorNodeAggregateIds to be correct.
And, if we touch this again, I would suggest to streamline it a bit. Using iteration instead of recursion would make this easier to read and faster, e.g.:
private function determineAncestorNodeAggregateIds(ContentRepository $contentRepository, WorkspaceName $workspaceName, NodeAggregateId $childNodeAggregateId): NodeAggregateIds
{
$contentGraph = $contentRepository->getContentGraph($workspaceName);
/** @var array<NodeAggregate> $stack */
$stack = iterator_to_array($contentGraph->findParentNodeAggregates($childNodeAggregateId));
$ancestorNodeAggregateIds = [];
do {
$nodeAggregate = array_shift($stack);
$ancestorNodeAggregateIds[] = $nodeAggregate->nodeAggregateId;
array_push($stack, ...iterator_to_array($contentGraph->findParentNodeAggregates($nodeAggregate->nodeAggregateId)));
} while ($stack !== []);
return NodeAggregateIds::fromArray($ancestorNodeAggregateIds);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
btw: Maybe it makes sense to add this method to the ContentGraphInterface
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We discussed something similar with @kitsunet and @mhsdesign last week. findAncestorNodes
on ContentGraphInterface. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented via #5261
public WorkspaceName $workspaceName, | ||
public NodeAggregateId $nodeAggregateId, | ||
public NodeTypeName $nodeTypeName, | ||
public NodeAggregateIds $parentNodeAggregateIds, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be $ancestorNodeAggregateIds
here as well
WorkspaceName $workspaceName, | ||
NodeAggregateId $nodeAggregateId, | ||
NodeTypeName $nodeTypeName, | ||
NodeAggregateIds $parentNodeAggregateIds |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and here :)
Cleanup ContentCacheFlusher
ContentCacheFlusher
is now only responsible for creatingCacheTags
and flushing them, based on aFlush**Request
. No node traversing within theContentCacheFlusher
anymore.CacheFlushingStrategy
to control the time of "real" flushing, but keeping the interface clean and equal for different cases (immediately or on shutdown).AssetChangeHandlerForCacheFlushing
GraphProjectorCatchUpHookForCacheFlushing
ContentCacheFlusher
.Workspace*Discard
events.Workspace*Discard
events.CacheTag
CacheTag
which allows to flush all cache entries of a workspace.NodeCacheEntryIdentifier
AssetChangeHandlerForCacheFlushing
AssetService::assetUpdated
signal, to handle asset changes.ContentCacheFlusher
.Tests
Added tests for:
Resolves #5175 and related issues