|
48 | 48 | #include"storage/dsm_impl.h"
|
49 | 49 | #include"utils/rel.h"
|
50 | 50 | #include"utils/selfuncs.h"
|
| 51 | +#include"utils/syscache.h" |
51 | 52 |
|
52 | 53 |
|
53 |
| -/* GUCparameter */ |
| 54 | +/* GUCparameters */ |
54 | 55 | doublecursor_tuple_fraction=DEFAULT_CURSOR_TUPLE_FRACTION;
|
| 56 | +intforce_parallel_mode=FORCE_PARALLEL_OFF; |
55 | 57 |
|
56 | 58 | /* Hook for plugins to get control in planner() */
|
57 | 59 | planner_hook_typeplanner_hook=NULL;
|
@@ -230,25 +232,31 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
230 | 232 | !has_parallel_hazard((Node*)parse, true);
|
231 | 233 |
|
232 | 234 | /*
|
233 |
| - * glob->parallelModeOK should tell us whether it's necessary to impose |
234 |
| - * the parallel mode restrictions, but we don't actually want to impose |
235 |
| - * them unless we choose a parallel plan, so that people who mislabel |
236 |
| - * their functions but don't use parallelism anyway aren't harmed. |
237 |
| - * However, it's useful for testing purposes to be able to force the |
238 |
| - * restrictions to be imposed whenever a parallel plan is actually chosen |
239 |
| - * or not. |
| 235 | + * glob->parallelModeNeeded should tell us whether it's necessary to |
| 236 | + * impose the parallel mode restrictions, but we don't actually want to |
| 237 | + * impose them unless we choose a parallel plan, so that people who |
| 238 | + * mislabel their functions but don't use parallelism anyway aren't |
| 239 | + * harmed. But when force_parallel_mode is set, we enable the restrictions |
| 240 | + * whenever possible for testing purposes. |
240 | 241 | *
|
241 |
| - * (It's been suggested that we should always impose these restrictions |
242 |
| - * whenever glob->parallelModeOK is true, so that it's easier to notice |
243 |
| - * incorrectly-labeled functions sooner. That might be the right thing to |
244 |
| - * do, but for now I've taken this approach. We could also control this |
245 |
| - * with a GUC.) |
| 242 | + * glob->wholePlanParallelSafe should tell us whether it's OK to stick a |
| 243 | + * Gather node on top of the entire plan. However, it only needs to be |
| 244 | + * accurate when force_parallel_mode is 'on' or 'regress', so we don't |
| 245 | + * bother doing the work otherwise. The value we set here is just a |
| 246 | + * preliminary guess; it may get changed from true to false later, but |
| 247 | + * not visca versa. |
246 | 248 | */
|
247 |
| -#ifdefFORCE_PARALLEL_MODE |
248 |
| -glob->parallelModeNeeded=glob->parallelModeOK; |
249 |
| -#else |
250 |
| -glob->parallelModeNeeded= false; |
251 |
| -#endif |
| 249 | +if (force_parallel_mode==FORCE_PARALLEL_OFF|| !glob->parallelModeOK) |
| 250 | +{ |
| 251 | +glob->parallelModeNeeded= false; |
| 252 | +glob->wholePlanParallelSafe= false;/* either false or don't care */ |
| 253 | +} |
| 254 | +else |
| 255 | +{ |
| 256 | +glob->parallelModeNeeded= true; |
| 257 | +glob->wholePlanParallelSafe= |
| 258 | +!has_parallel_hazard((Node*)parse, false); |
| 259 | +} |
252 | 260 |
|
253 | 261 | /* Determine what fraction of the plan is likely to be scanned */
|
254 | 262 | if (cursorOptions&CURSOR_OPT_FAST_PLAN)
|
@@ -292,6 +300,35 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
|
292 | 300 | top_plan=materialize_finished_plan(top_plan);
|
293 | 301 | }
|
294 | 302 |
|
| 303 | +/* |
| 304 | + * At present, we don't copy subplans to workers. The presence of a |
| 305 | + * subplan in one part of the plan doesn't preclude the use of parallelism |
| 306 | + * in some other part of the plan, but it does preclude the possibility of |
| 307 | + * regarding the entire plan parallel-safe. |
| 308 | + */ |
| 309 | +if (glob->subplans!=NULL) |
| 310 | +glob->wholePlanParallelSafe= false; |
| 311 | + |
| 312 | +/* |
| 313 | + * Optionally add a Gather node for testing purposes, provided this is |
| 314 | + * actually a safe thing to do. |
| 315 | + */ |
| 316 | +if (glob->wholePlanParallelSafe&& |
| 317 | +force_parallel_mode!=FORCE_PARALLEL_OFF) |
| 318 | +{ |
| 319 | +Gather*gather=makeNode(Gather); |
| 320 | + |
| 321 | +gather->plan.targetlist=top_plan->targetlist; |
| 322 | +gather->plan.qual=NIL; |
| 323 | +gather->plan.lefttree=top_plan; |
| 324 | +gather->plan.righttree=NULL; |
| 325 | +gather->num_workers=1; |
| 326 | +gather->single_copy= true; |
| 327 | +gather->invisible= (force_parallel_mode==FORCE_PARALLEL_REGRESS); |
| 328 | +root->glob->parallelModeNeeded= true; |
| 329 | +top_plan=&gather->plan; |
| 330 | +} |
| 331 | + |
295 | 332 | /*
|
296 | 333 | * If any Params were generated, run through the plan tree and compute
|
297 | 334 | * each plan node's extParam/allParam sets. Ideally we'd merge this into
|
|