16
16
#include "nodes/extensible.h"
17
17
#include "optimizer/clauses.h"
18
18
#include "optimizer/cost.h"
19
+ #include "optimizer/optimizer.h"
19
20
#include "optimizer/pathnode.h"
20
21
#include "optimizer/paths.h"
21
22
#include "utils/guc.h"
@@ -27,6 +28,9 @@ PG_MODULE_MAGIC;
27
28
#define MODULENAME "tempscan"
28
29
#define NODENAME "nodeCustomTempScan"
29
30
31
+ /* By analogy with Append */
32
+ #define TEMPSCAN_CPU_COST_MULTIPLIER (0.5)
33
+
30
34
static Plan * create_partial_tempscan_plan (PlannerInfo * root ,
31
35
RelOptInfo * rel ,
32
36
CustomPath * best_path ,
@@ -38,6 +42,7 @@ static void BeginTempScan(CustomScanState *node, EState *estate, int eflags);
38
42
static TupleTableSlot * ExecTempScan (CustomScanState * node );
39
43
static void EndTempScan (CustomScanState * node );
40
44
static void ReScanTempScan (CustomScanState * node );
45
+ static Size EstimateDSMTempScan (CustomScanState * node ,ParallelContext * pcxt );
41
46
42
47
static CustomPathMethods path_methods =
43
48
{
@@ -62,7 +67,7 @@ static CustomExecMethods exec_methods =
62
67
.ReScanCustomScan = ReScanTempScan ,
63
68
.MarkPosCustomScan = NULL ,
64
69
.RestrPosCustomScan = NULL ,
65
- .EstimateDSMCustomScan = NULL ,
70
+ .EstimateDSMCustomScan = EstimateDSMTempScan ,
66
71
.InitializeDSMCustomScan = NULL ,
67
72
.ReInitializeDSMCustomScan = NULL ,
68
73
.InitializeWorkerCustomScan = NULL ,
@@ -93,18 +98,22 @@ create_partial_tempscan_path(PlannerInfo *root, RelOptInfo *rel,
93
98
pathnode -> parent = rel ;
94
99
pathnode -> pathtarget = rel -> reltarget ;
95
100
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 ;
99
102
100
103
pathnode -> parallel_safe = true;
101
104
pathnode -> parallel_aware = false;
102
105
pathnode -> parallel_workers = path -> parallel_workers ;
103
106
104
- /* DEBUGGING purposes only */
105
107
pathnode -> startup_cost = path -> startup_cost ;
106
108
pathnode -> total_cost = path -> total_cost ;
107
109
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
+
108
117
cpath -> custom_paths = list_make1 (path );
109
118
cpath -> custom_private = NIL ;
110
119
cpath -> custom_restrictinfo = NIL ;
@@ -121,8 +130,7 @@ create_partial_tempscan_plan(PlannerInfo *root, RelOptInfo *rel,
121
130
CustomScan * cscan = makeNode (CustomScan );
122
131
123
132
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);
126
134
127
135
128
136
cscan -> scan .plan .targetlist = cscan -> custom_scan_tlist = tlist ;
@@ -205,9 +213,9 @@ static void
205
213
try_partial_tempscan (PlannerInfo * root ,RelOptInfo * rel ,Index rti ,
206
214
RangeTblEntry * rte )
207
215
{
208
- int parallel_workers ;
209
216
ListCell * lc ;
210
- List * partial_pathlist_new = NIL ;
217
+ List * parallel_safe_lst = NIL ;
218
+ List * tmplst = rel -> pathlist ;
211
219
212
220
/*
213
221
* 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,
223
231
get_rel_persistence (rte -> relid )!= RELPERSISTENCE_TEMP )
224
232
return ;
225
233
226
- /* HACK */
227
234
if (!is_parallel_safe (root , (Node * )rel -> baserestrictinfo )||
228
235
!is_parallel_safe (root , (Node * )rel -> reltarget -> exprs ))
229
236
return ;
230
237
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 */
239
239
Assert (rel -> partial_pathlist == NIL );
240
240
rel -> consider_parallel = true;
241
241
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
+ */
245
249
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 ));
247
256
create_index_paths (root ,rel );
248
257
create_tidscan_paths (root ,rel );
249
258
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
+ */
253
264
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 ;
258
267
259
268
/*
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
262
270
*/
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
+ }
264
282
265
- Assert ( IsA ( linitial ( rel -> partial_pathlist ), CustomPath ) );
283
+ list_free ( parallel_safe_lst );
266
284
}
267
285
268
286
void
@@ -287,3 +305,21 @@ _PG_init(void)
287
305
288
306
MarkGUCPrefixReserved (MODULENAME );
289
307
}
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
+ }