1616#include "nodes/extensible.h"
1717#include "optimizer/clauses.h"
1818#include "optimizer/cost.h"
19+ #include "optimizer/optimizer.h"
1920#include "optimizer/pathnode.h"
2021#include "optimizer/paths.h"
2122#include "utils/guc.h"
@@ -27,6 +28,9 @@ PG_MODULE_MAGIC;
2728#define MODULENAME "tempscan"
2829#define NODENAME "nodeCustomTempScan"
2930
31+ /* By analogy with Append */
32+ #define TEMPSCAN_CPU_COST_MULTIPLIER (0.5)
33+
3034static Plan * create_partial_tempscan_plan (PlannerInfo * root ,
3135 RelOptInfo * rel ,
3236 CustomPath * best_path ,
@@ -38,6 +42,7 @@ static void BeginTempScan(CustomScanState *node, EState *estate, int eflags);
3842static TupleTableSlot * ExecTempScan (CustomScanState * node );
3943static void EndTempScan (CustomScanState * node );
4044static void ReScanTempScan (CustomScanState * node );
45+ static Size EstimateDSMTempScan (CustomScanState * node , ParallelContext * pcxt );
4146
4247static CustomPathMethods path_methods =
4348{
@@ -62,7 +67,7 @@ static CustomExecMethods exec_methods =
6267 .ReScanCustomScan = ReScanTempScan ,
6368 .MarkPosCustomScan = NULL ,
6469 .RestrPosCustomScan = NULL ,
65- .EstimateDSMCustomScan = NULL ,
70+ .EstimateDSMCustomScan = EstimateDSMTempScan ,
6671 .InitializeDSMCustomScan = NULL ,
6772 .ReInitializeDSMCustomScan = NULL ,
6873 .InitializeWorkerCustomScan = NULL ,
@@ -93,18 +98,22 @@ create_partial_tempscan_path(PlannerInfo *root, RelOptInfo *rel,
9398 pathnode -> parent = rel ;
9499 pathnode -> pathtarget = rel -> reltarget ;
95100 pathnode -> rows = path -> rows ; /* Don't use rel->rows! Remember semantics of this field in the parallel case */
96-
97- /* XXX: Just for now */
98- pathnode -> param_info = NULL ;
101+ pathnode -> param_info = path -> param_info ;
99102
100103 pathnode -> parallel_safe = true;
101104 pathnode -> parallel_aware = false;
102105 pathnode -> parallel_workers = path -> parallel_workers ;
103106
104- /* DEBUGGING purposes only */
105107 pathnode -> startup_cost = path -> startup_cost ;
106108 pathnode -> total_cost = path -> total_cost ;
107109
110+ /*
111+ * Although TempScan does not do any selection or projection, it's not free;
112+ * add a small per-tuple overhead.
113+ */
114+ pathnode -> total_cost +=
115+ cpu_tuple_cost * TEMPSCAN_CPU_COST_MULTIPLIER * path -> rows ;
116+
108117 cpath -> custom_paths = list_make1 (path );
109118 cpath -> custom_private = NIL ;
110119 cpath -> custom_restrictinfo = NIL ;
@@ -121,8 +130,7 @@ create_partial_tempscan_plan(PlannerInfo *root, RelOptInfo *rel,
121130 CustomScan * cscan = makeNode (CustomScan );
122131
123132 Assert (list_length (custom_plans ) == 1 );
124- Assert (best_path -> path .parallel_safe = true &&
125- best_path -> path .parallel_workers > 0 );
133+ Assert (best_path -> path .parallel_safe = true);
126134
127135
128136 cscan -> scan .plan .targetlist = cscan -> custom_scan_tlist = tlist ;
@@ -205,9 +213,9 @@ static void
205213try_partial_tempscan (PlannerInfo * root , RelOptInfo * rel , Index rti ,
206214 RangeTblEntry * rte )
207215{
208- int parallel_workers ;
209216 ListCell * lc ;
210- List * partial_pathlist_new = NIL ;
217+ List * parallel_safe_lst = NIL ;
218+ List * tmplst = rel -> pathlist ;
211219
212220 /*
213221 * Some extension intercept this hook earlier. Allow it to do a work
@@ -223,46 +231,56 @@ try_partial_tempscan(PlannerInfo *root, RelOptInfo *rel, Index rti,
223231 get_rel_persistence (rte -> relid ) != RELPERSISTENCE_TEMP )
224232 return ;
225233
226- /* HACK */
227234 if (!is_parallel_safe (root , (Node * ) rel -> baserestrictinfo ) ||
228235 !is_parallel_safe (root , (Node * ) rel -> reltarget -> exprs ))
229236 return ;
230237
231- parallel_workers = compute_parallel_worker (rel , rel -> pages , -1 ,
232- max_parallel_workers_per_gather );
233-
234- /* If any limit was set to zero, the user doesn't want a parallel scan. */
235- if (parallel_workers <= 0 )
236- return ;
237-
238- /* Enable parallel paths generation for this relation */
238+ /* Enable parallel safe paths generation for this relation */
239239 Assert (rel -> partial_pathlist == NIL );
240240 rel -> consider_parallel = true;
241241
242- /* Add partial sequental scan path. */
243- add_partial_path (rel , (Path * )
244- create_seqscan_path (root , rel , NULL , parallel_workers ));
242+ /*
243+ * Now we have a problem:
244+ * should generate parallel safe paths. But they will have the same cost as
245+ * previously added non-parallel ones and, being safe, will definitely crowd
246+ * out non-safe ones.
247+ * So, we need a HACK: add new safe paths with cost of custom node.
248+ */
245249
246- /* Add there more specific paths too */
250+ rel -> pathlist = NIL ;
251+
252+ /*
253+ * Build possibly parallel paths other temporary table
254+ */
255+ add_path (rel , create_seqscan_path (root , rel , NULL , 0 ));
247256 create_index_paths (root , rel );
248257 create_tidscan_paths (root , rel );
249258
250- foreach (lc , rel -> partial_pathlist )
251- {
252- Path * path = lfirst (lc );
259+ /*
260+ * Dangerous zone. But we assume it is strictly local. What about extension
261+ * which could call ours and may have desire to add some partial paths after
262+ * us?
263+ */
253264
254- partial_pathlist_new =
255- lappend (partial_pathlist_new ,
256- (void * ) create_partial_tempscan_path (root , rel , path ));
257- }
265+ list_free (rel -> partial_pathlist );
266+ rel -> partial_pathlist = NIL ;
258267
259268 /*
260- * Dangerous zone. But we assume it is strictly local. What about extension
261- * which could call ours and add some paths after us?
269+ * Set guard over each parallel_safe path
262270 */
263- rel -> partial_pathlist = partial_pathlist_new ;
271+ parallel_safe_lst = rel -> pathlist ;
272+ rel -> pathlist = tmplst ;
273+ foreach (lc , parallel_safe_lst )
274+ {
275+ Path * path = lfirst (lc );
276+
277+ if (!path -> parallel_safe )
278+ continue ;
279+
280+ add_path (rel , (Path * ) create_partial_tempscan_path (root , rel , path ));
281+ }
264282
265- Assert ( IsA ( linitial ( rel -> partial_pathlist ), CustomPath ) );
283+ list_free ( parallel_safe_lst );
266284}
267285
268286void
@@ -287,3 +305,21 @@ _PG_init(void)
287305
288306 MarkGUCPrefixReserved (MODULENAME );
289307}
308+
309+ /* *****************************************************************************
310+ *
311+ * Parallel transport stuff
312+ *
313+ **************************************************************************** */
314+
315+ /* copy from execParallel.c */
316+ #define PARALLEL_TUPLE_QUEUE_SIZE 65536
317+
318+ static Size
319+ EstimateDSMTempScan (CustomScanState * node , ParallelContext * pcxt )
320+ {
321+ Size size ;
322+
323+ size = mul_size (PARALLEL_TUPLE_QUEUE_SIZE , pcxt -> nworkers );
324+ return size ;
325+ }
0 commit comments