From 395b1d62389cf40520a4afd87c11301aa2b17df2 Mon Sep 17 00:00:00 2001 From: "Andrey V. Lepikhov" Date: Tue, 11 May 2021 08:43:03 +0500 Subject: [PATCH] Defer selection of asynchronous subplans to the executor initial phase. --- contrib/postgres_fdw/postgres_fdw.c | 10 +++++++++- src/backend/executor/execAmi.c | 7 +++---- src/backend/executor/nodeAppend.c | 19 +++++++++++++++++++ src/backend/nodes/copyfuncs.c | 1 - src/backend/nodes/outfuncs.c | 1 - src/backend/nodes/readfuncs.c | 1 - src/backend/optimizer/plan/createplan.c | 17 +---------------- src/include/nodes/plannodes.h | 1 - src/include/optimizer/planmain.h | 1 + 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 4ff58d9c27..3e151a6790 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -1245,6 +1245,7 @@ postgresGetForeignPlan(PlannerInfo *root, bool has_final_sort = false; bool has_limit = false; ListCell *lc; + ForeignScan *fsplan; /* * Get FDW private data created by postgresGetForeignUpperPaths(), if any. @@ -1429,7 +1430,7 @@ postgresGetForeignPlan(PlannerInfo *root, * field of the finished plan node; we can't keep them in private state * because then they wouldn't be subject to later planner processing. */ - return make_foreignscan(tlist, + fsplan = make_foreignscan(tlist, local_exprs, scan_relid, params_list, @@ -1437,6 +1438,13 @@ postgresGetForeignPlan(PlannerInfo *root, fdw_scan_tlist, fdw_recheck_quals, outer_plan); + + /* If appropriate, consider participation in async operations */ + fsplan->scan.plan.async_capable = (enable_async_append && + best_path->path.pathkeys == NIL && + !fsplan->scan.plan.parallel_safe && + is_async_capable_path((Path *)best_path)); + return fsplan; } /* diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index b3726a54f3..4e70f4eb54 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -524,6 +524,9 @@ ExecSupportsBackwardScan(Plan *node) if (node->parallel_aware) return false; + if (node->async_capable) + return false; + switch (nodeTag(node)) { case T_Result: @@ -536,10 +539,6 @@ ExecSupportsBackwardScan(Plan *node) { ListCell *l; - /* With async, tuples may be interleaved, so can't back up. */ - if (((Append *) node)->nasyncplans > 0) - return false; - foreach(l, ((Append *) node)->appendplans) { if (!ExecSupportsBackwardScan((Plan *) lfirst(l))) diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c index 3c1f12adaf..363cf9f4a5 100644 --- a/src/backend/executor/nodeAppend.c +++ b/src/backend/executor/nodeAppend.c @@ -117,6 +117,8 @@ ExecInitAppend(Append *node, EState *estate, int eflags) int firstvalid; int i, j; + ListCell *l; + bool consider_async = false; /* check for unsupported flags */ Assert(!(eflags & EXEC_FLAG_MARK)); @@ -197,6 +199,23 @@ ExecInitAppend(Append *node, EState *estate, int eflags) appendplanstates = (PlanState **) palloc(nplans * sizeof(PlanState *)); + /* If appropriate, consider async append */ + consider_async = (list_length(node->appendplans) > 1); + + if (!consider_async) + { + foreach(l, node->appendplans) + { + Plan *subplan = (Plan *) lfirst(l); + + /* Check to see if subplan can be executed asynchronously */ + if (subplan->async_capable) + { + subplan->async_capable = false; + } + } + } + /* * call ExecInitNode on each of the valid plans to be executed and save * the results into the appendplanstates array. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 90770a89b0..a44185d7fc 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -243,7 +243,6 @@ _copyAppend(const Append *from) */ COPY_BITMAPSET_FIELD(apprelids); COPY_NODE_FIELD(appendplans); - COPY_SCALAR_FIELD(nasyncplans); COPY_SCALAR_FIELD(first_partial_plan); COPY_NODE_FIELD(part_prune_info); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 8da8b14f0e..cd5dbce76a 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -433,7 +433,6 @@ _outAppend(StringInfo str, const Append *node) WRITE_BITMAPSET_FIELD(apprelids); WRITE_NODE_FIELD(appendplans); - WRITE_INT_FIELD(nasyncplans); WRITE_INT_FIELD(first_partial_plan); WRITE_NODE_FIELD(part_prune_info); } diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 3772ea07df..3f5879951b 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1717,7 +1717,6 @@ _readAppend(void) READ_BITMAPSET_FIELD(apprelids); READ_NODE_FIELD(appendplans); - READ_INT_FIELD(nasyncplans); READ_INT_FIELD(first_partial_plan); READ_NODE_FIELD(part_prune_info); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 7003238d76..b1f2a493f0 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -82,7 +82,6 @@ static List *get_gating_quals(PlannerInfo *root, List *quals); static Plan *create_gating_plan(PlannerInfo *root, Path *path, Plan *plan, List *gating_quals); static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path); -static bool is_async_capable_path(Path *path); static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags); static Plan *create_merge_append_plan(PlannerInfo *root, MergeAppendPath *best_path, @@ -1097,7 +1096,7 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path) * is_async_capable_path * Check whether a given Path node is async-capable. */ -static bool +bool is_async_capable_path(Path *path) { switch (nodeTag(path)) @@ -1135,7 +1134,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) List *pathkeys = best_path->path.pathkeys; List *subplans = NIL; ListCell *subpaths; - int nasyncplans = 0; RelOptInfo *rel = best_path->path.parent; PartitionPruneInfo *partpruneinfo = NULL; int nodenumsortkeys = 0; @@ -1143,7 +1141,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) Oid *nodeSortOperators = NULL; Oid *nodeCollations = NULL; bool *nodeNullsFirst = NULL; - bool consider_async = false; /* * The subpaths list could be empty, if every child was proven empty by @@ -1207,11 +1204,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) tlist_was_changed = (orig_tlist_length != list_length(plan->plan.targetlist)); } - /* If appropriate, consider async append */ - consider_async = (enable_async_append && pathkeys == NIL && - !best_path->path.parallel_safe && - list_length(best_path->subpaths) > 1); - /* Build the plan for each child */ foreach(subpaths, best_path->subpaths) { @@ -1280,12 +1272,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) subplans = lappend(subplans, subplan); - /* Check to see if subplan can be executed asynchronously */ - if (consider_async && is_async_capable_path(subpath)) - { - subplan->async_capable = true; - ++nasyncplans; - } } /* @@ -1318,7 +1304,6 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path, int flags) } plan->appendplans = subplans; - plan->nasyncplans = nasyncplans; plan->first_partial_plan = best_path->first_partial_path; plan->part_prune_info = partpruneinfo; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 841401be20..00f4f5f8ed 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -251,7 +251,6 @@ typedef struct Append Plan plan; Bitmapset *apprelids; /* RTIs of appendrel(s) formed by this node */ List *appendplans; - int nasyncplans; /* # of asynchronous plans */ /* * All 'appendplans' preceding this index are non-partial plans. All diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index bf1adfc52a..8a96a19e5f 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -115,5 +115,6 @@ extern Plan *set_plan_references(PlannerInfo *root, Plan *plan); extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid); extern void record_plan_type_dependency(PlannerInfo *root, Oid typid); extern bool extract_query_dependencies_walker(Node *node, PlannerInfo *root); +extern bool is_async_capable_path(Path *path); #endif /* PLANMAIN_H */ -- 2.31.1