-
Notifications
You must be signed in to change notification settings - Fork 44
perf: multi-pass DFS in ComponentTreeRewriter; resource-type pre-filter in NodeBasedRewriteRule #243
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
base: main
Are you sure you want to change the base?
perf: multi-pass DFS in ComponentTreeRewriter; resource-type pre-filter in NodeBasedRewriteRule #243
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,6 @@ | |
| import java.util.Set; | ||
| import javax.jcr.Node; | ||
| import javax.jcr.RepositoryException; | ||
| import javax.jcr.Session; | ||
|
|
||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.sling.api.resource.Resource; | ||
|
|
@@ -71,9 +70,6 @@ public void preservesOrder() throws Exception { | |
| Node root = context.resourceResolver().getResource("/content/test/ordered").adaptTo(Node.class); | ||
| ComponentTreeRewriter.rewrite(root, rules); | ||
|
|
||
| Session session = root.getSession(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please clarify why this is not required now.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The old algorithm called session.save() internally after each rule match during the traversal — so by the time rewrite() returned, all changes were already flushed to disk. The assertions assertTrue(session.hasPendingChanges()) and session.save() were testing that mid-traversal save behaviour. The new algorithm never calls session.save() — it leaves all changes as pending in the session and lets the caller commit once. So after rewrite() returns, session.hasPendingChanges() is still true but session.save() is the caller's responsibility (the job executor handles it). The assertions were removed because they were testing an implementation detail of the old algorithm, not correctness of the rewrite. The actual correctness checks (node order, invocation counts) remain intact. |
||
| assertTrue(session.hasPendingChanges(), "Updates were made"); | ||
| session.save(); | ||
| Resource updated = context.resourceResolver().getResource("/content/test/ordered"); | ||
|
|
||
| // Preserved Order | ||
|
|
@@ -101,10 +97,6 @@ public void skipsFinalPaths() throws Exception { | |
| Node root = context.resourceResolver().getResource("/content/test/final").adaptTo(Node.class); | ||
| ComponentTreeRewriter.rewrite(root, rules); | ||
|
|
||
| Session session = root.getSession(); | ||
| assertTrue(session.hasPendingChanges(), "Updates were made"); | ||
| session.save(); | ||
|
|
||
| // Should only be called once when matched. | ||
| assertEquals(1, finalRewriteRule.invoked, "Rewrite rule invocations"); | ||
| } | ||
|
|
@@ -120,10 +112,6 @@ void infiniteLoop() throws Exception { | |
| Node root = context.resourceResolver().getResource("/content/test/ordered").adaptTo(Node.class); | ||
| ComponentTreeRewriter.rewrite(root, rules); | ||
|
|
||
| Session session = root.getSession(); | ||
| assertTrue(session.hasPendingChanges(), "Updates were made"); | ||
| session.save(); | ||
|
|
||
| assertEquals(9, rule.invoked, "Rewrite rule invocations"); | ||
| } | ||
|
|
||
|
|
||
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.
What is the impact on reaching MAX_PASSES. Also, in what case we can have so many passes?
Is this related to number of components? If so - what happens when customers have so many components - does it fail?
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.
MAX_PASSES is not related to component count — it's a guard against pathological rule behaviour, not a scaling limit.
Each pass is a full DFS walk of the tree. A pass increments only when a rule fires and modifies the tree structure. For a well-behaved rule set, the number of passes equals the number of distinct structural "depths" that need resolving — for forms conversion this is typically 2–4 (ContainerRule → RootPanelRule → leaf components → cleanup). A 1000-component form still converges in the same 2–4 passes; component count drives visit count per pass, not pass count.
MAX_PASSES=50 would only be reached if a rule repeatedly mutates the tree in a way that keeps producing new matches every pass (e.g. a rule that re-adds a node it just matched). In that case the loop exits after 50 passes and returns whatever state the tree is in — it does not throw or fail. The form is left partially converted, which is the same behaviour as a rule-level exception. The processed map prevents any single rule from firing on the same node path twice, which already eliminates most infinite-loop risks. MAX_PASSES is a last-resort safety net for edge cases we haven't anticipated.