This is an automated email from the ASF dual-hosted git repository. yangzhg pushed a commit to branch branch-1.1-lts in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-1.1-lts by this push: new 7199b9ffc9 [cherry-pick-1.1](fix-expr) refractor create_tree_from_thrift to avoid stack overflow (#18514) 7199b9ffc9 is described below commit 7199b9ffc93bbc4d49949dd5a1764e7883795940 Author: camby <zhuxiaol...@baidu.com> AuthorDate: Wed Apr 12 10:35:56 2023 +0800 [cherry-pick-1.1](fix-expr) refractor create_tree_from_thrift to avoid stack overflow (#18514) * cherry-pick pr18214 and also refractor create_tree_from_thrift in non-vectorized engine * update --- be/src/exprs/agg_fn_evaluator.cpp | 3 +- be/src/exprs/expr.cpp | 61 +++++++++++++++++++++------------ be/src/exprs/expr.h | 4 +-- be/src/vec/exec/vanalytic_eval_node.cpp | 4 +-- be/src/vec/exprs/vectorized_agg_fn.cpp | 3 +- be/src/vec/exprs/vexpr.cpp | 61 +++++++++++++++++++++------------ be/src/vec/exprs/vexpr.h | 6 ++-- 7 files changed, 88 insertions(+), 54 deletions(-) diff --git a/be/src/exprs/agg_fn_evaluator.cpp b/be/src/exprs/agg_fn_evaluator.cpp index ecd0b6e666..38a8a59b01 100644 --- a/be/src/exprs/agg_fn_evaluator.cpp +++ b/be/src/exprs/agg_fn_evaluator.cpp @@ -91,8 +91,7 @@ Status AggFnEvaluator::create(ObjectPool* pool, const TExpr& desc, bool is_analy ++node_idx; Expr* expr = nullptr; ExprContext* ctx = nullptr; - RETURN_IF_ERROR( - Expr::create_tree_from_thrift(pool, desc.nodes, nullptr, &node_idx, &expr, &ctx)); + RETURN_IF_ERROR(Expr::create_tree_from_thrift(pool, desc.nodes, &node_idx, &expr, &ctx)); (*result)->_input_exprs_ctxs.push_back(ctx); } return Status::OK(); diff --git a/be/src/exprs/expr.cpp b/be/src/exprs/expr.cpp index 7429068959..4e46829ac8 100644 --- a/be/src/exprs/expr.cpp +++ b/be/src/exprs/expr.cpp @@ -20,6 +20,7 @@ #include <thrift/protocol/TDebugProtocol.h> #include <sstream> +#include <stack> #include <vector> #include "common/object_pool.h" @@ -249,7 +250,7 @@ Status Expr::create_expr_tree(ObjectPool* pool, const TExpr& texpr, ExprContext* } int node_idx = 0; Expr* e = nullptr; - Status status = create_tree_from_thrift(pool, texpr.nodes, nullptr, &node_idx, &e, ctx); + Status status = create_tree_from_thrift(pool, texpr.nodes, &node_idx, &e, ctx); if (status.ok() && node_idx + 1 != texpr.nodes.size()) { status = Status::InternalError( "Expression tree only partially reconstructed. Not all thrift nodes were used."); @@ -274,33 +275,51 @@ Status Expr::create_expr_trees(ObjectPool* pool, const std::vector<TExpr>& texpr } Status Expr::create_tree_from_thrift(ObjectPool* pool, const std::vector<TExprNode>& nodes, - Expr* parent, int* node_idx, Expr** root_expr, - ExprContext** ctx) { + int* node_idx, Expr** root_expr, ExprContext** ctx) { // propagate error case if (*node_idx >= nodes.size()) { return Status::InternalError("Failed to reconstruct expression tree from thrift."); } - int num_children = nodes[*node_idx].num_children; - Expr* expr = nullptr; - RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &expr)); - DCHECK(expr != nullptr); - if (parent != nullptr) { - parent->add_child(expr); - } else { - DCHECK(root_expr != nullptr); - DCHECK(ctx != nullptr); - *root_expr = expr; - *ctx = pool->add(new ExprContext(expr)); - } - for (int i = 0; i < num_children; i++) { - *node_idx += 1; - RETURN_IF_ERROR(create_tree_from_thrift(pool, nodes, expr, node_idx, nullptr, nullptr)); - // we are expecting a child, but have used all nodes - // this means we have been given a bad tree and must fail - if (*node_idx >= nodes.size()) { + + // create root expr + int root_children = nodes[*node_idx].num_children; + Expr* root = nullptr; + RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &root)); + DCHECK(root != nullptr); + + DCHECK(root_expr != nullptr); + DCHECK(ctx != nullptr); + *root_expr = root; + *ctx = pool->add(new ExprContext(root)); + // short path for leaf node + if (root_children <= 0) { + return Status::OK(); + } + + // non-recursive traversal + std::stack<std::pair<Expr*, int>> s; + s.push({root, root_children}); + while (!s.empty()) { + auto& parent = s.top(); + if (parent.second > 1) { + parent.second -= 1; + } else { + s.pop(); + } + if (++*node_idx >= nodes.size()) { return Status::InternalError("Failed to reconstruct expression tree from thrift."); } + + Expr* expr = nullptr; + RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &expr)); + DCHECK(expr != nullptr); + parent.first->add_child(expr); + int num_children = nodes[*node_idx].num_children; + if (num_children > 0) { + s.push({expr, num_children}); + } } + return Status::OK(); } diff --git a/be/src/exprs/expr.h b/be/src/exprs/expr.h index f8b4aa286f..6ae3274e69 100644 --- a/be/src/exprs/expr.h +++ b/be/src/exprs/expr.h @@ -399,7 +399,6 @@ private: /// Creates an expr tree for the node rooted at 'node_idx' via depth-first traversal. /// parameters /// nodes: vector of thrift expression nodes to be translated - /// parent: parent of node at node_idx (or nullptr for node_idx == 0) /// node_idx: /// in: root of TExprNode tree /// out: next node in 'nodes' that isn't part of tree @@ -409,8 +408,7 @@ private: /// status.ok() if successful /// !status.ok() if tree is inconsistent or corrupt static Status create_tree_from_thrift(ObjectPool* pool, const std::vector<TExprNode>& nodes, - Expr* parent, int* node_idx, Expr** root_expr, - ExprContext** ctx); + int* node_idx, Expr** root_expr, ExprContext** ctx); /// Static wrappers around the virtual Get*Val() functions. Calls the appropriate /// Get*Val() function on expr, passing it the context and row arguments. diff --git a/be/src/vec/exec/vanalytic_eval_node.cpp b/be/src/vec/exec/vanalytic_eval_node.cpp index 858e330efe..e397491f7b 100644 --- a/be/src/vec/exec/vanalytic_eval_node.cpp +++ b/be/src/vec/exec/vanalytic_eval_node.cpp @@ -118,8 +118,8 @@ Status VAnalyticEvalNode::init(const TPlanNode& tnode, RuntimeState* state) { ++node_idx; VExpr* expr = nullptr; VExprContext* ctx = nullptr; - RETURN_IF_ERROR(VExpr::create_tree_from_thrift(_pool, desc.nodes, nullptr, &node_idx, - &expr, &ctx)); + RETURN_IF_ERROR( + VExpr::create_tree_from_thrift(_pool, desc.nodes, &node_idx, &expr, &ctx)); _agg_expr_ctxs[i].emplace_back(ctx); } diff --git a/be/src/vec/exprs/vectorized_agg_fn.cpp b/be/src/vec/exprs/vectorized_agg_fn.cpp index cab89ae7ff..aebf627cea 100644 --- a/be/src/vec/exprs/vectorized_agg_fn.cpp +++ b/be/src/vec/exprs/vectorized_agg_fn.cpp @@ -59,8 +59,7 @@ Status AggFnEvaluator::create(ObjectPool* pool, const TExpr& desc, AggFnEvaluato ++node_idx; VExpr* expr = nullptr; VExprContext* ctx = nullptr; - RETURN_IF_ERROR( - VExpr::create_tree_from_thrift(pool, desc.nodes, NULL, &node_idx, &expr, &ctx)); + RETURN_IF_ERROR(VExpr::create_tree_from_thrift(pool, desc.nodes, &node_idx, &expr, &ctx)); agg_fn_evaluator->_input_exprs_ctxs.push_back(ctx); } return Status::OK(); diff --git a/be/src/vec/exprs/vexpr.cpp b/be/src/vec/exprs/vexpr.cpp index 6fbdfb1fa7..750bc136ec 100644 --- a/be/src/vec/exprs/vexpr.cpp +++ b/be/src/vec/exprs/vexpr.cpp @@ -20,6 +20,7 @@ #include <fmt/format.h> #include <memory> +#include <stack> #include "exprs/anyval_util.h" #include "gen_cpp/Exprs_types.h" @@ -152,32 +153,50 @@ Status VExpr::create_expr(doris::ObjectPool* pool, const doris::TExprNode& texpr } Status VExpr::create_tree_from_thrift(doris::ObjectPool* pool, - const std::vector<doris::TExprNode>& nodes, VExpr* parent, - int* node_idx, VExpr** root_expr, VExprContext** ctx) { + const std::vector<doris::TExprNode>& nodes, int* node_idx, + VExpr** root_expr, VExprContext** ctx) { // propagate error case if (*node_idx >= nodes.size()) { return Status::InternalError("Failed to reconstruct expression tree from thrift."); } - int num_children = nodes[*node_idx].num_children; - VExpr* expr = nullptr; - RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &expr)); - DCHECK(expr != nullptr); - if (parent != nullptr) { - parent->add_child(expr); - } else { - DCHECK(root_expr != nullptr); - DCHECK(ctx != nullptr); - *root_expr = expr; - *ctx = pool->add(new VExprContext(expr)); - } - for (int i = 0; i < num_children; i++) { - *node_idx += 1; - RETURN_IF_ERROR(create_tree_from_thrift(pool, nodes, expr, node_idx, nullptr, nullptr)); - // we are expecting a child, but have used all nodes - // this means we have been given a bad tree and must fail - if (*node_idx >= nodes.size()) { + + // create root expr + int root_children = nodes[*node_idx].num_children; + VExpr* root = nullptr; + RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &root)); + DCHECK(root != nullptr); + + DCHECK(root_expr != nullptr); + DCHECK(ctx != nullptr); + *root_expr = root; + *ctx = pool->add(new VExprContext(root)); + // short path for leaf node + if (root_children <= 0) { + return Status::OK(); + } + + // non-recursive traversal + std::stack<std::pair<VExpr*, int>> s; + s.push({root, root_children}); + while (!s.empty()) { + auto& parent = s.top(); + if (parent.second > 1) { + parent.second -= 1; + } else { + s.pop(); + } + + if (++*node_idx >= nodes.size()) { return Status::InternalError("Failed to reconstruct expression tree from thrift."); } + VExpr* expr = nullptr; + RETURN_IF_ERROR(create_expr(pool, nodes[*node_idx], &expr)); + DCHECK(expr != nullptr); + parent.first->add_child(expr); + int num_children = nodes[*node_idx].num_children; + if (num_children > 0) { + s.push({expr, num_children}); + } } return Status::OK(); } @@ -190,7 +209,7 @@ Status VExpr::create_expr_tree(doris::ObjectPool* pool, const doris::TExpr& texp } int node_idx = 0; VExpr* e = nullptr; - Status status = create_tree_from_thrift(pool, texpr.nodes, nullptr, &node_idx, &e, ctx); + Status status = create_tree_from_thrift(pool, texpr.nodes, &node_idx, &e, ctx); if (status.ok() && node_idx + 1 != texpr.nodes.size()) { status = Status::InternalError( "Expression tree only partially reconstructed. Not all thrift nodes were used."); diff --git a/be/src/vec/exprs/vexpr.h b/be/src/vec/exprs/vexpr.h index 7ebe597a0f..77e5557cc1 100644 --- a/be/src/vec/exprs/vexpr.h +++ b/be/src/vec/exprs/vexpr.h @@ -113,9 +113,9 @@ public: static Status create_expr(ObjectPool* pool, const TExprNode& texpr_node, VExpr** expr); - static Status create_tree_from_thrift(ObjectPool* pool, const std::vector<TExprNode>& nodes, - VExpr* parent, int* node_idx, VExpr** root_expr, - VExprContext** ctx); + static Status create_tree_from_thrift(doris::ObjectPool* pool, + const std::vector<doris::TExprNode>& nodes, int* node_idx, + VExpr** root_expr, VExprContext** ctx); const std::vector<VExpr*>& children() const { return _children; } void set_children(std::vector<VExpr*> children) { _children = children; } virtual std::string debug_string() const; --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org