1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* nodeAppend.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* routines to handle append nodes.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2018-01-03 05:30:12 +01:00
|
|
|
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/executor/nodeAppend.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
/* INTERFACE ROUTINES
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecInitAppend - initialize the append node
|
2004-09-24 03:36:37 +02:00
|
|
|
* ExecAppend - retrieve the next tuple from the node
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecEndAppend - shut down the append node
|
1998-07-16 00:16:21 +02:00
|
|
|
* ExecReScanAppend - rescan the append node
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* NOTES
|
|
|
|
* Each append node contains a list of one or more subplans which
|
|
|
|
* must be iteratively processed (forwards or backwards).
|
|
|
|
* Tuples are retrieved by executing the 'whichplan'th subplan
|
|
|
|
* until the subplan stops returning tuples, at which point that
|
|
|
|
* plan is shut down and the next started up.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* Append nodes don't make use of their left and right
|
|
|
|
* subtrees, rather they maintain a list of subplans so
|
|
|
|
* a typical append node looks like this in the plan tree:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* ...
|
|
|
|
* /
|
|
|
|
* Append -------+------+------+--- nil
|
|
|
|
* / \ | | |
|
2014-05-06 18:12:18 +02:00
|
|
|
* nil nil ... ... ...
|
1997-09-07 07:04:48 +02:00
|
|
|
* subplans
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2000-11-12 01:37:02 +01:00
|
|
|
* Append nodes are currently used for unions, and to support
|
|
|
|
* inheritance queries, where several relations need to be scanned.
|
1997-09-07 07:04:48 +02:00
|
|
|
* For example, in our standard person/student/employee/student-emp
|
|
|
|
* example, where student and employee inherit from person
|
|
|
|
* and student-emp inherits from student and employee, the
|
|
|
|
* query:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2005-04-24 13:46:21 +02:00
|
|
|
* select name from person
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* generates the plan:
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* |
|
|
|
|
* Append -------+-------+--------+--------+
|
|
|
|
* / \ | | | |
|
|
|
|
* nil nil Scan Scan Scan Scan
|
|
|
|
* | | | |
|
|
|
|
* person employee student student-emp
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1996-10-31 11:12:26 +01:00
|
|
|
|
2000-11-12 01:37:02 +01:00
|
|
|
#include "postgres.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-11-06 07:52:23 +01:00
|
|
|
#include "executor/execdebug.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "executor/nodeAppend.h"
|
2017-07-26 02:37:17 +02:00
|
|
|
#include "miscadmin.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
/* Shared state for parallel-aware Append. */
|
|
|
|
struct ParallelAppendState
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
LWLock pa_lock; /* mutual exclusion to choose next subplan */
|
|
|
|
int pa_next_plan; /* next plan to choose by any worker */
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
* pa_finished[i] should be true if no more workers should select subplan
|
|
|
|
* i. for a non-partial plan, this should be set to true as soon as a
|
|
|
|
* worker selects the plan; for a partial plan, it remains false until
|
|
|
|
* some worker executes the plan to completion.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
bool pa_finished[FLEXIBLE_ARRAY_MEMBER];
|
|
|
|
};
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
#define INVALID_SUBPLAN_INDEX -1
|
|
|
|
|
|
|
|
static TupleTableSlot *ExecAppend(PlanState *pstate);
|
|
|
|
static bool choose_next_subplan_locally(AppendState *node);
|
|
|
|
static bool choose_next_subplan_for_leader(AppendState *node);
|
|
|
|
static bool choose_next_subplan_for_worker(AppendState *node);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecInitAppend
|
|
|
|
*
|
2002-12-05 16:50:39 +01:00
|
|
|
* Begin all of the subscans of the append node.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* (This is potentially wasteful, since the entire result of the
|
|
|
|
* append node may not be scanned, but this way all of the
|
|
|
|
* structures get allocated in the executor's top level memory
|
2004-09-24 03:36:37 +02:00
|
|
|
* block instead of that of the call to ExecAppend.)
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
AppendState *
|
2006-02-28 05:10:28 +01:00
|
|
|
ExecInitAppend(Append *node, EState *estate, int eflags)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-12-05 16:50:39 +01:00
|
|
|
AppendState *appendstate = makeNode(AppendState);
|
|
|
|
PlanState **appendplanstates;
|
1997-09-08 04:41:22 +02:00
|
|
|
int nplans;
|
|
|
|
int i;
|
2009-10-10 03:43:50 +02:00
|
|
|
ListCell *lc;
|
2000-06-10 07:16:38 +02:00
|
|
|
|
2006-02-28 05:10:28 +01:00
|
|
|
/* check for unsupported flags */
|
|
|
|
Assert(!(eflags & EXEC_FLAG_MARK));
|
|
|
|
|
2017-03-21 14:48:04 +01:00
|
|
|
/*
|
2017-05-17 22:31:56 +02:00
|
|
|
* Lock the non-leaf tables in the partition tree controlled by this node.
|
|
|
|
* It's a no-op for non-partitioned parent tables.
|
2017-03-21 14:48:04 +01:00
|
|
|
*/
|
|
|
|
ExecLockNonLeafAppendTables(node->partitioned_rels, estate);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-12-05 16:50:39 +01:00
|
|
|
* Set up empty vector of subplan states
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2004-05-31 01:40:41 +02:00
|
|
|
nplans = list_length(node->appendplans);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* create new AppendState for our append node
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
appendstate->ps.plan = (Plan *) node;
|
|
|
|
appendstate->ps.state = estate;
|
2017-07-17 09:33:49 +02:00
|
|
|
appendstate->ps.ExecProcNode = ExecAppend;
|
2002-12-05 16:50:39 +01:00
|
|
|
appendstate->appendplans = appendplanstates;
|
1998-07-15 16:54:39 +02:00
|
|
|
appendstate->as_nplans = nplans;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* Miscellaneous initialization
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* Append plans don't have expression contexts because they never call
|
|
|
|
* ExecQual or ExecProject.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* append nodes still have Result slots, which hold pointers to tuples, so
|
|
|
|
* we have to initialize them.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecInitResultTupleSlot(estate, &appendstate->ps);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-05-15 02:33:36 +02:00
|
|
|
* call ExecInitNode on each of the plans to be executed and save the
|
2009-10-10 03:43:50 +02:00
|
|
|
* results into the array "appendplans".
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2009-10-10 03:43:50 +02:00
|
|
|
i = 0;
|
|
|
|
foreach(lc, node->appendplans)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2009-10-10 03:43:50 +02:00
|
|
|
Plan *initNode = (Plan *) lfirst(lc);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2006-02-28 05:10:28 +01:00
|
|
|
appendplanstates[i] = ExecInitNode(initNode, estate, eflags);
|
2009-10-10 03:43:50 +02:00
|
|
|
i++;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2009-10-10 03:43:50 +02:00
|
|
|
* initialize output tuple type
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecAssignResultTypeFromTL(&appendstate->ps);
|
|
|
|
appendstate->ps.ps_ProjInfo = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
* Parallel-aware append plans must choose the first subplan to execute by
|
|
|
|
* looking at shared memory, but non-parallel-aware append plans can
|
|
|
|
* always start with the first subplan.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
appendstate->as_whichplan =
|
|
|
|
appendstate->ps.plan->parallel_aware ? INVALID_SUBPLAN_INDEX : 0;
|
|
|
|
|
|
|
|
/* If parallel-aware, this will be overridden later. */
|
|
|
|
appendstate->choose_next_subplan = choose_next_subplan_locally;
|
1999-10-31 01:13:30 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
return appendstate;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
2004-09-24 03:36:37 +02:00
|
|
|
* ExecAppend
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2005-05-23 00:30:20 +02:00
|
|
|
* Handles iteration over multiple subplans.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
2017-07-17 09:33:49 +02:00
|
|
|
static TupleTableSlot *
|
|
|
|
ExecAppend(PlanState *pstate)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2017-07-17 09:33:49 +02:00
|
|
|
AppendState *node = castNode(AppendState, pstate);
|
|
|
|
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
/* If no subplan has been chosen, we must choose one before proceeding. */
|
|
|
|
if (node->as_whichplan == INVALID_SUBPLAN_INDEX &&
|
|
|
|
!node->choose_next_subplan(node))
|
|
|
|
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
|
|
|
|
2005-05-23 00:30:20 +02:00
|
|
|
for (;;)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2005-05-23 00:30:20 +02:00
|
|
|
PlanState *subnode;
|
|
|
|
TupleTableSlot *result;
|
|
|
|
|
2017-07-26 02:37:17 +02:00
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-05-23 00:30:20 +02:00
|
|
|
* figure out which subplan we are currently processing
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
Assert(node->as_whichplan >= 0 && node->as_whichplan < node->as_nplans);
|
2005-05-23 00:30:20 +02:00
|
|
|
subnode = node->appendplans[node->as_whichplan];
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-05-23 00:30:20 +02:00
|
|
|
* get a tuple from the subplan
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-05-23 00:30:20 +02:00
|
|
|
result = ExecProcNode(subnode);
|
|
|
|
|
|
|
|
if (!TupIsNull(result))
|
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If the subplan gave us something then return it as-is. We do
|
|
|
|
* NOT make use of the result slot that was set up in
|
2009-10-10 03:43:50 +02:00
|
|
|
* ExecInitAppend; there's no need for it.
|
2005-05-23 00:30:20 +02:00
|
|
|
*/
|
|
|
|
return result;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
/* choose new subplan; if none, we're done */
|
|
|
|
if (!node->choose_next_subplan(node))
|
2005-05-23 00:30:20 +02:00
|
|
|
return ExecClearTuple(node->ps.ps_ResultTupleSlot);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
1997-09-07 07:04:48 +02:00
|
|
|
* ExecEndAppend
|
|
|
|
*
|
|
|
|
* Shuts down the subscans of the append node.
|
|
|
|
*
|
|
|
|
* Returns nothing of interest.
|
1996-07-09 08:22:35 +02:00
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
2002-12-05 16:50:39 +01:00
|
|
|
ExecEndAppend(AppendState *node)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-12-05 16:50:39 +01:00
|
|
|
PlanState **appendplans;
|
1997-09-08 04:41:22 +02:00
|
|
|
int nplans;
|
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get information from the node
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1998-07-15 16:54:39 +02:00
|
|
|
appendplans = node->appendplans;
|
2002-12-05 16:50:39 +01:00
|
|
|
nplans = node->as_nplans;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2009-10-10 03:43:50 +02:00
|
|
|
* shut down each of the subscans
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < nplans; i++)
|
2009-10-10 03:43:50 +02:00
|
|
|
ExecEndNode(appendplans[i]);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2000-11-12 01:37:02 +01:00
|
|
|
|
1998-07-16 00:16:21 +02:00
|
|
|
void
|
2010-07-12 19:01:06 +02:00
|
|
|
ExecReScanAppend(AppendState *node)
|
1998-07-16 00:16:21 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
int i;
|
1998-07-16 00:16:21 +02:00
|
|
|
|
2009-10-10 03:43:50 +02:00
|
|
|
for (i = 0; i < node->as_nplans; i++)
|
1998-07-16 00:16:21 +02:00
|
|
|
{
|
2003-08-04 02:43:34 +02:00
|
|
|
PlanState *subnode = node->appendplans[i];
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-05-08 21:47:02 +02:00
|
|
|
/*
|
|
|
|
* ExecReScan doesn't know about my subplans, so I have to do
|
|
|
|
* changed-parameter signaling myself.
|
|
|
|
*/
|
2003-02-09 01:30:41 +01:00
|
|
|
if (node->ps.chgParam != NULL)
|
|
|
|
UpdateChangedParamSet(subnode, node->ps.chgParam);
|
2001-10-25 07:50:21 +02:00
|
|
|
|
2001-05-08 21:47:02 +02:00
|
|
|
/*
|
2006-02-05 03:59:17 +01:00
|
|
|
* If chgParam of subnode is not null then plan will be re-scanned by
|
2010-07-12 19:01:06 +02:00
|
|
|
* first ExecProcNode.
|
2001-05-08 21:47:02 +02:00
|
|
|
*/
|
2010-07-12 19:01:06 +02:00
|
|
|
if (subnode->chgParam == NULL)
|
|
|
|
ExecReScan(subnode);
|
1998-07-16 00:16:21 +02:00
|
|
|
}
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
|
|
|
|
node->as_whichplan =
|
|
|
|
node->ps.plan->parallel_aware ? INVALID_SUBPLAN_INDEX : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* Parallel Append Support
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecAppendEstimate
|
|
|
|
*
|
|
|
|
* Compute the amount of space we'll need in the parallel
|
|
|
|
* query DSM, and inform pcxt->estimator about our needs.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAppendEstimate(AppendState *node,
|
|
|
|
ParallelContext *pcxt)
|
|
|
|
{
|
|
|
|
node->pstate_len =
|
|
|
|
add_size(offsetof(ParallelAppendState, pa_finished),
|
|
|
|
sizeof(bool) * node->as_nplans);
|
|
|
|
|
|
|
|
shm_toc_estimate_chunk(&pcxt->estimator, node->pstate_len);
|
|
|
|
shm_toc_estimate_keys(&pcxt->estimator, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecAppendInitializeDSM
|
|
|
|
*
|
|
|
|
* Set up shared state for Parallel Append.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAppendInitializeDSM(AppendState *node,
|
|
|
|
ParallelContext *pcxt)
|
|
|
|
{
|
|
|
|
ParallelAppendState *pstate;
|
|
|
|
|
|
|
|
pstate = shm_toc_allocate(pcxt->toc, node->pstate_len);
|
|
|
|
memset(pstate, 0, node->pstate_len);
|
|
|
|
LWLockInitialize(&pstate->pa_lock, LWTRANCHE_PARALLEL_APPEND);
|
|
|
|
shm_toc_insert(pcxt->toc, node->ps.plan->plan_node_id, pstate);
|
|
|
|
|
|
|
|
node->as_pstate = pstate;
|
|
|
|
node->choose_next_subplan = choose_next_subplan_for_leader;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecAppendReInitializeDSM
|
|
|
|
*
|
|
|
|
* Reset shared state before beginning a fresh scan.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAppendReInitializeDSM(AppendState *node, ParallelContext *pcxt)
|
|
|
|
{
|
|
|
|
ParallelAppendState *pstate = node->as_pstate;
|
|
|
|
|
|
|
|
pstate->pa_next_plan = 0;
|
|
|
|
memset(pstate->pa_finished, 0, sizeof(bool) * node->as_nplans);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* ExecAppendInitializeWorker
|
|
|
|
*
|
|
|
|
* Copy relevant information from TOC into planstate, and initialize
|
|
|
|
* whatever is required to choose and execute the optimal subplan.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ExecAppendInitializeWorker(AppendState *node, ParallelWorkerContext *pwcxt)
|
|
|
|
{
|
|
|
|
node->as_pstate = shm_toc_lookup(pwcxt->toc, node->ps.plan->plan_node_id, false);
|
|
|
|
node->choose_next_subplan = choose_next_subplan_for_worker;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* choose_next_subplan_locally
|
|
|
|
*
|
|
|
|
* Choose next subplan for a non-parallel-aware Append,
|
|
|
|
* returning false if there are no more.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
choose_next_subplan_locally(AppendState *node)
|
|
|
|
{
|
|
|
|
int whichplan = node->as_whichplan;
|
|
|
|
|
|
|
|
/* We should never see INVALID_SUBPLAN_INDEX in this case. */
|
|
|
|
Assert(whichplan >= 0 && whichplan <= node->as_nplans);
|
|
|
|
|
|
|
|
if (ScanDirectionIsForward(node->ps.state->es_direction))
|
|
|
|
{
|
|
|
|
if (whichplan >= node->as_nplans - 1)
|
|
|
|
return false;
|
|
|
|
node->as_whichplan++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (whichplan <= 0)
|
|
|
|
return false;
|
|
|
|
node->as_whichplan--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* choose_next_subplan_for_leader
|
|
|
|
*
|
|
|
|
* Try to pick a plan which doesn't commit us to doing much
|
|
|
|
* work locally, so that as much work as possible is done in
|
|
|
|
* the workers. Cheapest subplans are at the end.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
choose_next_subplan_for_leader(AppendState *node)
|
|
|
|
{
|
|
|
|
ParallelAppendState *pstate = node->as_pstate;
|
|
|
|
Append *append = (Append *) node->ps.plan;
|
|
|
|
|
|
|
|
/* Backward scan is not supported by parallel-aware plans */
|
|
|
|
Assert(ScanDirectionIsForward(node->ps.state->es_direction));
|
|
|
|
|
|
|
|
LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
|
|
|
|
|
|
|
|
if (node->as_whichplan != INVALID_SUBPLAN_INDEX)
|
|
|
|
{
|
|
|
|
/* Mark just-completed subplan as finished. */
|
|
|
|
node->as_pstate->pa_finished[node->as_whichplan] = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Start with last subplan. */
|
|
|
|
node->as_whichplan = node->as_nplans - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop until we find a subplan to execute. */
|
|
|
|
while (pstate->pa_finished[node->as_whichplan])
|
|
|
|
{
|
|
|
|
if (node->as_whichplan == 0)
|
|
|
|
{
|
|
|
|
pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
|
|
|
|
node->as_whichplan = INVALID_SUBPLAN_INDEX;
|
|
|
|
LWLockRelease(&pstate->pa_lock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
node->as_whichplan--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If non-partial, immediately mark as finished. */
|
|
|
|
if (node->as_whichplan < append->first_partial_plan)
|
|
|
|
node->as_pstate->pa_finished[node->as_whichplan] = true;
|
|
|
|
|
|
|
|
LWLockRelease(&pstate->pa_lock);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------------------------------------------------------------
|
|
|
|
* choose_next_subplan_for_worker
|
|
|
|
*
|
|
|
|
* Choose next subplan for a parallel-aware Append, returning
|
|
|
|
* false if there are no more.
|
|
|
|
*
|
|
|
|
* We start from the first plan and advance through the list;
|
|
|
|
* when we get back to the end, we loop back to the first
|
|
|
|
* nonpartial plan. This assigns the non-partial plans first
|
|
|
|
* in order of descending cost and then spreads out the
|
|
|
|
* workers as evenly as possible across the remaining partial
|
|
|
|
* plans.
|
|
|
|
* ----------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
choose_next_subplan_for_worker(AppendState *node)
|
|
|
|
{
|
|
|
|
ParallelAppendState *pstate = node->as_pstate;
|
|
|
|
Append *append = (Append *) node->ps.plan;
|
|
|
|
|
|
|
|
/* Backward scan is not supported by parallel-aware plans */
|
|
|
|
Assert(ScanDirectionIsForward(node->ps.state->es_direction));
|
|
|
|
|
|
|
|
LWLockAcquire(&pstate->pa_lock, LW_EXCLUSIVE);
|
|
|
|
|
|
|
|
/* Mark just-completed subplan as finished. */
|
|
|
|
if (node->as_whichplan != INVALID_SUBPLAN_INDEX)
|
|
|
|
node->as_pstate->pa_finished[node->as_whichplan] = true;
|
|
|
|
|
|
|
|
/* If all the plans are already done, we have nothing to do */
|
|
|
|
if (pstate->pa_next_plan == INVALID_SUBPLAN_INDEX)
|
|
|
|
{
|
|
|
|
LWLockRelease(&pstate->pa_lock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Loop until we find a subplan to execute. */
|
|
|
|
while (pstate->pa_finished[pstate->pa_next_plan])
|
|
|
|
{
|
|
|
|
if (pstate->pa_next_plan < node->as_nplans - 1)
|
|
|
|
{
|
|
|
|
/* Advance to next plan. */
|
|
|
|
pstate->pa_next_plan++;
|
|
|
|
}
|
|
|
|
else if (append->first_partial_plan < node->as_nplans)
|
|
|
|
{
|
|
|
|
/* Loop back to first partial plan. */
|
|
|
|
pstate->pa_next_plan = append->first_partial_plan;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* At last plan, no partial plans, arrange to bail out. */
|
|
|
|
pstate->pa_next_plan = node->as_whichplan;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pstate->pa_next_plan == node->as_whichplan)
|
|
|
|
{
|
|
|
|
/* We've tried everything! */
|
|
|
|
pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
|
|
|
|
LWLockRelease(&pstate->pa_lock);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pick the plan we found, and advance pa_next_plan one more time. */
|
|
|
|
node->as_whichplan = pstate->pa_next_plan++;
|
|
|
|
if (pstate->pa_next_plan >= node->as_nplans)
|
|
|
|
{
|
2017-12-06 14:42:50 +01:00
|
|
|
if (append->first_partial_plan < node->as_nplans)
|
|
|
|
pstate->pa_next_plan = append->first_partial_plan;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We have only non-partial plans, and we already chose the last
|
|
|
|
* one; so arrange for the other workers to immediately bail out.
|
|
|
|
*/
|
|
|
|
pstate->pa_next_plan = INVALID_SUBPLAN_INDEX;
|
|
|
|
}
|
Support Parallel Append plan nodes.
When we create an Append node, we can spread out the workers over the
subplans instead of piling on to each subplan one at a time, which
should typically be a bit more efficient, both because the startup
cost of any plan executed entirely by one worker is paid only once and
also because of reduced contention. We can also construct Append
plans using a mix of partial and non-partial subplans, which may allow
for parallelism in places that otherwise couldn't support it.
Unfortunately, this patch doesn't handle the important case of
parallelizing UNION ALL by running each branch in a separate worker;
the executor infrastructure is added here, but more planner work is
needed.
Amit Khandekar, Robert Haas, Amul Sul, reviewed and tested by
Ashutosh Bapat, Amit Langote, Rafia Sabih, Amit Kapila, and
Rajkumar Raghuwanshi.
Discussion: http://postgr.es/m/CAJ3gD9dy0K_E8r727heqXoBmWZ83HwLFwdcaSSmBQ1+S+vRuUQ@mail.gmail.com
2017-12-05 23:28:39 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If non-partial, immediately mark as finished. */
|
|
|
|
if (node->as_whichplan < append->first_partial_plan)
|
|
|
|
node->as_pstate->pa_finished[node->as_whichplan] = true;
|
|
|
|
|
|
|
|
LWLockRelease(&pstate->pa_lock);
|
|
|
|
|
|
|
|
return true;
|
1998-07-16 00:16:21 +02:00
|
|
|
}
|