Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 691b8d5

Browse files
committed
Allow for parallel execution whenever ExecutorRun() is done only once.
Previously, it was unsafe to execute a plan in parallel if ExecutorRun() might be called with a non-zero row count. However, it's quite easy to fix things up so that we can support that case, provided that it is known that we will never call ExecutorRun() a second time for the same QueryDesc. Add infrastructure to signal this, and cross-checks to make sure that a caller who claims this is true doesn't later reneg. While that pattern never happens with queries received directly from a client -- there's no way to know whether multiple Execute messages will be sent unless the first one requests all the rows -- it's pretty common for queries originating from procedural languages, which often limit the result to a single tuple or to a user-specified number of tuples. This commit doesn't actually enable parallelism in any additional cases, because currently none of the places that would be able to benefit from this infrastructure pass CURSOR_OPT_PARALLEL_OK in the first place, but it makes it much more palatable to pass CURSOR_OPT_PARALLEL_OK in places where we currently don't, because it eliminates some cases where we'd end up having to run the parallel plan serially. Patch by me, based on some ideas from Rafia Sabih and corrected by Rafia Sabih based on feedback from Dilip Kumar and myself. Discussion: http://postgr.es/m/CA+TgmobXEhvHbJtWDuPZM9bVSLiTj-kShxQJ2uM5GPDze9fRYA@mail.gmail.com
1 parent 218f515 commit 691b8d5

File tree

19 files changed

+73
-38
lines changed

19 files changed

+73
-38
lines changed

contrib/auto_explain/auto_explain.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void _PG_fini(void);
6161
static void explain_ExecutorStart(QueryDesc *queryDesc, int eflags);
6262
static void explain_ExecutorRun(QueryDesc *queryDesc,
6363
ScanDirection direction,
64-
uint64 count);
64+
uint64 count, bool execute_once);
6565
static void explain_ExecutorFinish(QueryDesc *queryDesc);
6666
static void explain_ExecutorEnd(QueryDesc *queryDesc);
6767

@@ -257,15 +257,16 @@ explain_ExecutorStart(QueryDesc *queryDesc, int eflags)
257257
* ExecutorRun hook: all we need do is track nesting depth
258258
*/
259259
static void
260-
explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
260+
explain_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction,
261+
uint64 count, bool execute_once)
261262
{
262263
nesting_level++;
263264
PG_TRY();
264265
{
265266
if (prev_ExecutorRun)
266-
prev_ExecutorRun(queryDesc, direction, count);
267+
prev_ExecutorRun(queryDesc, direction, count, execute_once);
267268
else
268-
standard_ExecutorRun(queryDesc, direction, count);
269+
standard_ExecutorRun(queryDesc, direction, count, execute_once);
269270
nesting_level--;
270271
}
271272
PG_CATCH();

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ static void pgss_post_parse_analyze(ParseState *pstate, Query *query);
290290
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
291291
static void pgss_ExecutorRun(QueryDesc *queryDesc,
292292
ScanDirection direction,
293-
uint64 count);
293+
uint64 count, bool execute_once);
294294
static void pgss_ExecutorFinish(QueryDesc *queryDesc);
295295
static void pgss_ExecutorEnd(QueryDesc *queryDesc);
296296
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
@@ -871,15 +871,16 @@ pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
871871
* ExecutorRun hook: all we need do is track nesting depth
872872
*/
873873
static void
874-
pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
874+
pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
875+
bool execute_once)
875876
{
876877
nested_level++;
877878
PG_TRY();
878879
{
879880
if (prev_ExecutorRun)
880-
prev_ExecutorRun(queryDesc, direction, count);
881+
prev_ExecutorRun(queryDesc, direction, count, execute_once);
881882
else
882-
standard_ExecutorRun(queryDesc, direction, count);
883+
standard_ExecutorRun(queryDesc, direction, count, execute_once);
883884
nested_level--;
884885
}
885886
PG_CATCH();

src/backend/commands/copy.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,7 @@ CopyTo(CopyState cstate)
20742074
else
20752075
{
20762076
/* run the plan --- the dest receiver will send tuples */
2077-
ExecutorRun(cstate->queryDesc, ForwardScanDirection, 0L);
2077+
ExecutorRun(cstate->queryDesc, ForwardScanDirection, 0L, true);
20782078
processed = ((DR_copy *) cstate->queryDesc->dest)->processed;
20792079
}
20802080

src/backend/commands/createas.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString,
347347
ExecutorStart(queryDesc, GetIntoRelEFlags(into));
348348

349349
/* run the plan to completion */
350-
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
350+
ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
351351

352352
/* save the rowcount if we're given a completionTag to fill */
353353
if (completionTag)

src/backend/commands/explain.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
530530
dir = ForwardScanDirection;
531531

532532
/* run the plan */
533-
ExecutorRun(queryDesc, dir, 0L);
533+
ExecutorRun(queryDesc, dir, 0L, true);
534534

535535
/* run cleanup too */
536536
ExecutorFinish(queryDesc);

src/backend/commands/extension.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -742,7 +742,7 @@ execute_sql_string(const char *sql, const char *filename)
742742
dest, NULL, 0);
743743

744744
ExecutorStart(qdesc, 0);
745-
ExecutorRun(qdesc, ForwardScanDirection, 0);
745+
ExecutorRun(qdesc, ForwardScanDirection, 0, true);
746746
ExecutorFinish(qdesc);
747747
ExecutorEnd(qdesc);
748748

src/backend/commands/matview.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
424424
ExecutorStart(queryDesc, EXEC_FLAG_WITHOUT_OIDS);
425425

426426
/* run the plan */
427-
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
427+
ExecutorRun(queryDesc, ForwardScanDirection, 0L, true);
428428

429429
processed = queryDesc->estate->es_processed;
430430

src/backend/commands/portalcmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ PersistHoldablePortal(Portal portal)
395395
true);
396396

397397
/* Fetch the result set into the tuplestore */
398-
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
398+
ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
399399

400400
(*queryDesc->dest->rDestroy) (queryDesc->dest);
401401
queryDesc->dest = NULL;

src/backend/commands/prepare.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause,
301301
*/
302302
PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
303303

304-
(void) PortalRun(portal, count, false, dest, dest, completionTag);
304+
(void) PortalRun(portal, count, false, true, dest, dest, completionTag);
305305

306306
PortalDrop(portal, false);
307307

src/backend/executor/execMain.c

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ static void ExecutePlan(EState *estate, PlanState *planstate,
8585
bool sendTuples,
8686
uint64 numberTuples,
8787
ScanDirection direction,
88-
DestReceiver *dest);
88+
DestReceiver *dest,
89+
bool execute_once);
8990
static bool ExecCheckRTEPerms(RangeTblEntry *rte);
9091
static bool ExecCheckRTEPermsModified(Oid relOid, Oid userid,
9192
Bitmapset *modifiedCols,
@@ -288,17 +289,18 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
288289
*/
289290
void
290291
ExecutorRun(QueryDesc *queryDesc,
291-
ScanDirection direction, uint64 count)
292+
ScanDirection direction, uint64 count,
293+
bool execute_once)
292294
{
293295
if (ExecutorRun_hook)
294-
(*ExecutorRun_hook) (queryDesc, direction, count);
296+
(*ExecutorRun_hook) (queryDesc, direction, count, execute_once);
295297
else
296-
standard_ExecutorRun(queryDesc, direction, count);
298+
standard_ExecutorRun(queryDesc, direction, count, execute_once);
297299
}
298300

299301
void
300302
standard_ExecutorRun(QueryDesc *queryDesc,
301-
ScanDirection direction, uint64 count)
303+
ScanDirection direction, uint64 count, bool execute_once)
302304
{
303305
EState *estate;
304306
CmdType operation;
@@ -345,14 +347,21 @@ standard_ExecutorRun(QueryDesc *queryDesc,
345347
* run plan
346348
*/
347349
if (!ScanDirectionIsNoMovement(direction))
350+
{
351+
if (execute_once && queryDesc->already_executed)
352+
elog(ERROR, "can't re-execute query flagged for single execution");
353+
queryDesc->already_executed = true;
354+
348355
ExecutePlan(estate,
349356
queryDesc->planstate,
350357
queryDesc->plannedstmt->parallelModeNeeded,
351358
operation,
352359
sendTuples,
353360
count,
354361
direction,
355-
dest);
362+
dest,
363+
execute_once);
364+
}
356365

357366
/*
358367
* shutdown tuple receiver, if we started it
@@ -1595,7 +1604,8 @@ ExecutePlan(EState *estate,
15951604
bool sendTuples,
15961605
uint64 numberTuples,
15971606
ScanDirection direction,
1598-
DestReceiver *dest)
1607+
DestReceiver *dest,
1608+
bool execute_once)
15991609
{
16001610
TupleTableSlot *slot;
16011611
uint64 current_tuple_count;
@@ -1611,12 +1621,12 @@ ExecutePlan(EState *estate,
16111621
estate->es_direction = direction;
16121622

16131623
/*
1614-
* If a tuple count was supplied, we must force the plan to run without
1615-
* parallelism, because we might exit early. Also disable parallelism
1616-
* when writing into a relation, because no database changes are allowed
1617-
* in parallel mode.
1624+
* If the plan might potentially be executed multiple times, we must force
1625+
* it to run without parallelism, because we might exit early. Also
1626+
* disable parallelism when writing into a relation, because no database
1627+
* changes are allowed in parallel mode.
16181628
*/
1619-
if (numberTuples || dest->mydest == DestIntoRel)
1629+
if (!execute_once || dest->mydest == DestIntoRel)
16201630
use_parallel_mode = false;
16211631

16221632
if (use_parallel_mode)
@@ -1687,7 +1697,11 @@ ExecutePlan(EState *estate,
16871697
*/
16881698
current_tuple_count++;
16891699
if (numberTuples && numberTuples == current_tuple_count)
1700+
{
1701+
/* Allow nodes to release or shut down resources. */
1702+
(void) ExecShutdownNode(planstate);
16901703
break;
1704+
}
16911705
}
16921706

16931707
if (use_parallel_mode)

0 commit comments

Comments
 (0)