Add parallel_safe flag to paths, and initialize it appropriately.
authorRobert Haas <[email protected]>
Wed, 21 Oct 2015 17:22:14 +0000 (13:22 -0400)
committerRobert Haas <[email protected]>
Wed, 28 Oct 2015 13:45:22 +0000 (14:45 +0100)
Also, add create_single_copy_gather_path.

src/backend/nodes/outfuncs.c
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/util/pathnode.c
src/include/nodes/relation.h
src/include/optimizer/pathnode.h

index 0030a9b244e45fd2548aea33ec007e0aa4fbeef3..ffdd7dbf83ecebaf6644a3b8c1e99da1ba076fab 100644 (file)
@@ -1585,6 +1585,7 @@ _outPathInfo(StringInfo str, const Path *node)
                _outBitmapset(str, node->param_info->ppi_req_outer);
        else
                _outBitmapset(str, NULL);
+       WRITE_BOOL_FIELD(parallel_safe);
        WRITE_FLOAT_FIELD(rows, "%.0f");
        WRITE_FLOAT_FIELD(startup_cost, "%.2f");
        WRITE_FLOAT_FIELD(total_cost, "%.2f");
index d73e7c0ab0fe4b693d8ec8203a1d7ec9978fddbd..e9f05381694607309daa8ffc69edf6373201c975 100644 (file)
@@ -84,7 +84,8 @@ query_planner(PlannerInfo *root, List *tlist,
 
                /* The only path for it is a trivial Result path */
                add_path(final_rel, (Path *)
-                                create_result_path((List *) parse->jointree->quals));
+                                create_result_path(final_rel,
+                                                                       (List *) parse->jointree->quals));
 
                /* Select cheapest path (pretty easy in this case...) */
                set_cheapest(final_rel);
index 1895a6894a37081b6c8278314cb42af113b8fcf0..d087be9532746716b3fc55aa997cd9ff25565f96 100644 (file)
@@ -704,6 +704,7 @@ create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = NIL;       /* seqscan has unordered result */
 
        cost_seqscan(pathnode, root, rel, pathnode->param_info);
@@ -724,6 +725,7 @@ create_samplescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = NIL;       /* samplescan has unordered result */
 
        cost_samplescan(pathnode, root, rel, pathnode->param_info);
@@ -777,6 +779,7 @@ create_index_path(PlannerInfo *root,
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                                                                                  required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = pathkeys;
 
        /* Convert clauses to indexquals the executor can handle */
@@ -822,6 +825,7 @@ create_bitmap_heap_path(PlannerInfo *root,
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                                                                                  required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = NIL;          /* always unordered */
 
        pathnode->bitmapqual = bitmapqual;
@@ -847,6 +851,7 @@ create_bitmap_and_path(PlannerInfo *root,
        pathnode->path.pathtype = T_BitmapAnd;
        pathnode->path.parent = rel;
        pathnode->path.param_info = NULL;       /* not used in bitmap trees */
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = NIL;          /* always unordered */
 
        pathnode->bitmapquals = bitmapquals;
@@ -871,6 +876,7 @@ create_bitmap_or_path(PlannerInfo *root,
        pathnode->path.pathtype = T_BitmapOr;
        pathnode->path.parent = rel;
        pathnode->path.param_info = NULL;       /* not used in bitmap trees */
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = NIL;          /* always unordered */
 
        pathnode->bitmapquals = bitmapquals;
@@ -895,6 +901,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                                                                                  required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = NIL;          /* always unordered */
 
        pathnode->tidquals = tidquals;
@@ -922,6 +929,7 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer)
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_appendrel_parampathinfo(rel,
                                                                                                                        required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = NIL;          /* result is always considered
                                                                                 * unsorted */
        pathnode->subpaths = subpaths;
@@ -975,6 +983,7 @@ create_merge_append_path(PlannerInfo *root,
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_appendrel_parampathinfo(rel,
                                                                                                                        required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = pathkeys;
        pathnode->subpaths = subpaths;
 
@@ -1042,13 +1051,14 @@ create_merge_append_path(PlannerInfo *root,
  *       This is only used for the case of a query with an empty jointree.
  */
 ResultPath *
-create_result_path(List *quals)
+create_result_path(RelOptInfo *emptyjoinrel, List *quals)
 {
        ResultPath *pathnode = makeNode(ResultPath);
 
        pathnode->path.pathtype = T_Result;
        pathnode->path.parent = NULL;
        pathnode->path.param_info = NULL;       /* there are no other rels... */
+       pathnode->path.parallel_safe = emptyjoinrel->consider_parallel;
        pathnode->path.pathkeys = NIL;
        pathnode->quals = quals;
 
@@ -1082,6 +1092,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
        pathnode->path.pathtype = T_Material;
        pathnode->path.parent = rel;
        pathnode->path.param_info = subpath->param_info;
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.pathkeys = subpath->pathkeys;
 
        pathnode->subpath = subpath;
@@ -1142,6 +1153,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
        pathnode->path.pathtype = T_Unique;
        pathnode->path.parent = rel;
        pathnode->path.param_info = subpath->param_info;
+       pathnode->path.parallel_safe = rel->consider_parallel;
 
        /*
         * Assume the output is unsorted, since we don't necessarily have pathkeys
@@ -1319,14 +1331,55 @@ create_gather_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
 {
        GatherPath *pathnode = makeNode(GatherPath);
 
+       Assert(subpath->parallel_safe);
+
        pathnode->path.pathtype = T_Gather;
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                                                                                  required_outer);
-       pathnode->path.pathkeys = NIL;          /* Gather has unordered result */
+       pathnode->path.parallel_safe = false;
+
+       /*
+        * Without the single-copy flag, a Gather node will destroy the result
+        * ordering.  See create_single_copy_gather_path.
+        */
+       pathnode->path.pathkeys = NIL;
 
        pathnode->subpath = subpath;
        pathnode->num_workers = nworkers;
+       pathnode->single_copy = false;
+
+       cost_gather(pathnode, root, rel, pathnode->path.param_info);
+
+       return pathnode;
+}
+
+/*
+ * create_single_copy_gather_path
+ *
+ *       Creates a path corresponding to a single-copy gather operation,
+ *       returning the pathnode.
+ */
+GatherPath *
+create_single_copy_gather_path(PlannerInfo *root, RelOptInfo *rel,
+                                                          Path *subpath, Relids required_outer)
+{
+       GatherPath *pathnode = makeNode(GatherPath);
+
+       Assert(subpath->parallel_safe);
+
+       pathnode->path.pathtype = T_Gather;
+       pathnode->path.parent = rel;
+       pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
+                                                                                                                 required_outer);
+       pathnode->path.parallel_safe = false;
+
+       /* Subplan is run-once, so we'll preserve its ordering. */
+       pathnode->path.pathkeys = subpath->pathkeys;
+
+       pathnode->subpath = subpath;
+       pathnode->num_workers = 1;
+       pathnode->single_copy = true;
 
        cost_gather(pathnode, root, rel, pathnode->path.param_info);
 
@@ -1378,6 +1431,7 @@ create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = pathkeys;
 
        cost_subqueryscan(pathnode, root, rel, pathnode->param_info);
@@ -1400,6 +1454,7 @@ create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = pathkeys;
 
        cost_functionscan(pathnode, root, rel, pathnode->param_info);
@@ -1422,6 +1477,7 @@ create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = NIL;       /* result is always unordered */
 
        cost_valuesscan(pathnode, root, rel, pathnode->param_info);
@@ -1443,6 +1499,7 @@ create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = NIL;       /* XXX for now, result is always unordered */
 
        cost_ctescan(pathnode, root, rel, pathnode->param_info);
@@ -1465,6 +1522,7 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
        pathnode->parent = rel;
        pathnode->param_info = get_baserel_parampathinfo(root, rel,
                                                                                                         required_outer);
+       pathnode->parallel_safe = rel->consider_parallel;
        pathnode->pathkeys = NIL;       /* result is always unordered */
 
        /* Cost is the same as for a regular CTE scan */
@@ -1496,6 +1554,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
        pathnode->path.parent = rel;
        pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
                                                                                                                  required_outer);
+       pathnode->path.parallel_safe = rel->consider_parallel;
        pathnode->path.rows = rows;
        pathnode->path.startup_cost = startup_cost;
        pathnode->path.total_cost = total_cost;
@@ -1630,6 +1689,7 @@ create_nestloop_path(PlannerInfo *root,
                                                                  sjinfo,
                                                                  required_outer,
                                                                  &restrict_clauses);
+       pathnode->path.parallel_safe = joinrel->consider_parallel;
        pathnode->path.pathkeys = pathkeys;
        pathnode->jointype = jointype;
        pathnode->outerjoinpath = outer_path;
@@ -1687,6 +1747,7 @@ create_mergejoin_path(PlannerInfo *root,
                                                                  sjinfo,
                                                                  required_outer,
                                                                  &restrict_clauses);
+       pathnode->jpath.path.parallel_safe = joinrel->consider_parallel;
        pathnode->jpath.path.pathkeys = pathkeys;
        pathnode->jpath.jointype = jointype;
        pathnode->jpath.outerjoinpath = outer_path;
@@ -1743,6 +1804,7 @@ create_hashjoin_path(PlannerInfo *root,
                                                                  sjinfo,
                                                                  required_outer,
                                                                  &restrict_clauses);
+       pathnode->jpath.path.parallel_safe = joinrel->consider_parallel;
 
        /*
         * A hashjoin never has pathkeys, since its output ordering is
index 41be9b12d7cf65844b06698c5947401267ba70e5..f14ed40826319c6ca1d54a01b23ed8f2cbf3c515 100644 (file)
@@ -754,6 +754,7 @@ typedef struct Path
 
        RelOptInfo *parent;                     /* the relation this path can build */
        ParamPathInfo *param_info;      /* parameterization info, or NULL if none */
+       bool            parallel_safe;  /* can we do this in a parallel worker? */
 
        /* estimated size/costs for path (see costsize.c for more info) */
        double          rows;                   /* estimated number of result tuples */
index 7a4940c7d20bf77a7a21f79bdda096c67d1e8340..3cdce2ac37a935ade3192ea6f38f3b3f7a911539 100644 (file)
@@ -65,13 +65,15 @@ extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
                                                 List *subpaths,
                                                 List *pathkeys,
                                                 Relids required_outer);
-extern ResultPath *create_result_path(List *quals);
+extern ResultPath *create_result_path(RelOptInfo *rel, List *quals);
 extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
 extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
                                   Path *subpath, SpecialJoinInfo *sjinfo);
 extern GatherPath *create_gather_path(PlannerInfo *root,
                                   RelOptInfo *rel, Path *subpath, Relids required_outer,
                                   int nworkers);
+extern GatherPath *create_single_copy_gather_path(PlannerInfo *root,
+                                  RelOptInfo *rel, Path *subpath, Relids required_outer);
 extern Path *create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
                                                 List *pathkeys, Relids required_outer);
 extern Path *create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,