This is an automated email from the ASF dual-hosted git repository. morrysnow pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push: new 160d2be0d8 [minimal](Nereids) add more comments for the rewriter (#19788) 160d2be0d8 is described below commit 160d2be0d823496a134ee2031fc4680557c99e9a Author: Chengpeng Yan <41809508+reminisc...@users.noreply.github.com> AuthorDate: Thu May 18 14:47:25 2023 +0800 [minimal](Nereids) add more comments for the rewriter (#19788) Only add some comments to the rewriter. Because it is fewer comments before and it's hard to understand for the newbie. --- .../nereids/jobs/rewrite/CustomRewriteJob.java | 3 ++ .../jobs/rewrite/PlanTreeRewriteBottomUpJob.java | 37 +++++++++++++++++++--- .../jobs/rewrite/PlanTreeRewriteTopDownJob.java | 7 +++- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CustomRewriteJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CustomRewriteJob.java index a05ad215a3..cf163010b7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CustomRewriteJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/CustomRewriteJob.java @@ -31,6 +31,9 @@ import java.util.function.Supplier; /** * Custom rewrite the plan. + * Just pass the plan node to the 'CustomRewriter', and the 'CustomRewriter' rule will handle it. + * The 'CustomRewriter' rule use the 'Visitor' design pattern to implement the rule. + * You can check the 'CustomRewriter' interface to see which rules use this way to do rewrite. */ public class CustomRewriteJob implements RewriteJob { private final RuleType ruleType; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteBottomUpJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteBottomUpJob.java index 8e625b638d..5652298266 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteBottomUpJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteBottomUpJob.java @@ -26,31 +26,50 @@ import java.util.List; import java.util.Objects; import java.util.Optional; -/** PlanTreeRewriteBottomUpJob */ +/** + * PlanTreeRewriteBottomUpJob + * The job is used for bottom-up rewrite. If some rewrite rules can take effect, + * we will process all the rules from the leaf node again. So there are some rules that can take effect interactively, + * we should use the 'Bottom-Up' job to handle it. + */ public class PlanTreeRewriteBottomUpJob extends PlanTreeRewriteJob { + // REWRITE_STATE_KEY represents the key to store the 'RewriteState'. Each plan node has their own 'RewriteState'. + // Different 'RewriteState' has different actions, + // so we will do specified action for each node based on their 'RewriteState'. private static final String REWRITE_STATE_KEY = "rewrite_state"; private RewriteJobContext rewriteJobContext; private List<Rule> rules; enum RewriteState { - ENSURE_CHILDREN_REWRITTEN, REWRITE_THIS, REWRITTEN + // 'REWRITE_THIS' means the current plan node can be handled immediately. If the plan state is 'REWRITE_THIS', + // it means all of its children's state are 'REWRITTEN'. Because we handle the plan tree bottom up. + REWRITE_THIS, + // 'REWRITTEN' means the current plan have been handled already, we don't need to do anything else. + REWRITTEN, + // 'ENSURE_CHILDREN_REWRITTEN' means we need to check the children for the current plan node first. + // It means some plans have changed after rewrite, so we need traverse the plan tree and reset their state. + // All the plan nodes need to be handled again. + ENSURE_CHILDREN_REWRITTEN } public PlanTreeRewriteBottomUpJob(RewriteJobContext rewriteJobContext, JobContext context, List<Rule> rules) { - super(JobType.TOP_DOWN_REWRITE, context); + super(JobType.BOTTOM_UP_REWRITE, context); this.rewriteJobContext = Objects.requireNonNull(rewriteJobContext, "rewriteContext cannot be null"); this.rules = Objects.requireNonNull(rules, "rules cannot be null"); } @Override public void execute() { - // use childrenVisited to judge whether clear the state in the previous batch + // For the bottom-up rewrite job, we need to reset the state of its children + // if the plan has changed after the rewrite. So we use the 'childrenVisited' to check this situation. boolean clearStatePhase = !rewriteJobContext.childrenVisited; if (clearStatePhase) { traverseClearState(); return; } + // We'll do different actions based on their different states. + // You can check the comment in 'RewriteState' structure for more details. Plan plan = rewriteJobContext.plan; RewriteState state = getState(plan); switch (state) { @@ -69,10 +88,13 @@ public class PlanTreeRewriteBottomUpJob extends PlanTreeRewriteJob { } private void traverseClearState() { + // Reset the state for current node. RewriteJobContext clearedStateContext = rewriteJobContext.withChildrenVisited(true); setState(clearedStateContext.plan, RewriteState.REWRITE_THIS); pushJob(new PlanTreeRewriteBottomUpJob(clearedStateContext, context, rules)); + // Generate the new rewrite job for its children. Because the character of stack is 'first in, last out', + // so we can traverse reset the state for the plan node until the leaf node. List<Plan> children = clearedStateContext.plan.children(); for (int i = children.size() - 1; i >= 0; i--) { Plan child = children.get(i); @@ -83,25 +105,30 @@ public class PlanTreeRewriteBottomUpJob extends PlanTreeRewriteJob { } private void rewriteThis() { + // Link the current node with the sub-plan to get the current plan which is used in the rewrite phase later. Plan plan = linkChildren(rewriteJobContext.plan, rewriteJobContext.childrenContext); RewriteResult rewriteResult = rewrite(plan, rules, rewriteJobContext); if (rewriteResult.hasNewPlan) { RewriteJobContext newJobContext = rewriteJobContext.withPlan(rewriteResult.plan); RewriteState state = getState(rewriteResult.plan); - // some eliminate rule will return a rewritten plan + // Some eliminate rule will return a rewritten plan, for example the current node is eliminated + // and return the child plan. So we don't need to handle it again. if (state == RewriteState.REWRITTEN) { newJobContext.setResult(rewriteResult.plan); return; } + // After the rewrite take effect, we should handle the children part again. pushJob(new PlanTreeRewriteBottomUpJob(newJobContext, context, rules)); setState(rewriteResult.plan, RewriteState.ENSURE_CHILDREN_REWRITTEN); } else { + // No new plan is generated, so just set the state of the current plan to 'REWRITTEN'. setState(rewriteResult.plan, RewriteState.REWRITTEN); rewriteJobContext.setResult(rewriteResult.plan); } } private void ensureChildrenRewritten() { + // Similar to the function 'traverseClearState'. Plan plan = rewriteJobContext.plan; setState(plan, RewriteState.REWRITE_THIS); pushJob(new PlanTreeRewriteBottomUpJob(rewriteJobContext, context, rules)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteTopDownJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteTopDownJob.java index e92dd15f27..d280159a01 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteTopDownJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/rewrite/PlanTreeRewriteTopDownJob.java @@ -25,7 +25,11 @@ import org.apache.doris.nereids.trees.plans.Plan; import java.util.List; import java.util.Objects; -/** PlanTreeRewriteTopDownJob */ +/** + * PlanTreeRewriteTopDownJob + * It's easier than the 'BottomUp' job, it handles the plan tree top-down. If some new plans generated after rewrite, + * it only processes the current node again. Otherwise, it just recursively handles its children. + */ public class PlanTreeRewriteTopDownJob extends PlanTreeRewriteJob { private RewriteJobContext rewriteJobContext; private List<Rule> rules; @@ -57,6 +61,7 @@ public class PlanTreeRewriteTopDownJob extends PlanTreeRewriteJob { pushJob(new PlanTreeRewriteTopDownJob(childRewriteJobContext, context, rules)); } } else { + // All the children part are already visited. Just link the children plan to the current node. Plan result = linkChildrenAndParent(rewriteJobContext.plan, rewriteJobContext); if (rewriteJobContext.parentContext == null) { context.getCascadesContext().setRewritePlan(result); --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org