1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Separate reinitialization of shared parallel-scan state from ExecReScan.

Previously, the parallel executor logic did reinitialization of shared
state within the ExecReScan code for parallel-aware scan nodes.  This is
problematic, because it means that the ExecReScan call has to occur
synchronously (ie, during the parent Gather node's ReScan call).  That is
swimming very much against the tide so far as the ExecReScan machinery is
concerned; the fact that it works at all today depends on a lot of fragile
assumptions, such as that no plan node between Gather and a parallel-aware
scan node is parameterized.  Another objection is that because ExecReScan
might be called in workers as well as the leader, hacky extra tests are
needed in some places to prevent unwanted shared-state resets.

Hence, let's separate this code into two functions, a ReInitializeDSM
call and the ReScan call proper.  ReInitializeDSM is called only in
the leader and is guaranteed to run before we start new workers.
ReScan is returned to its traditional function of resetting only local
state, which means that ExecReScan's usual habits of delaying or
eliminating child rescan calls are safe again.

As with the preceding commit 7df2c1f8d, it doesn't seem to be necessary
to make these changes in 9.6, which is a good thing because the FDW and
CustomScan APIs are impacted.

Discussion: https://postgr.es/m/CAA4eK1JkByysFJNh9M349u_nNjqETuEnY_y1VUc_kJiU0bxtaQ@mail.gmail.com
This commit is contained in:
Tom Lane
2017-08-30 13:18:16 -04:00
parent 5816ddc707
commit d6a149f4e6
22 changed files with 302 additions and 135 deletions

View File

@ -320,22 +320,39 @@ void (*InitializeDSMCustomScan) (CustomScanState *node,
void *coordinate);
</programlisting>
Initialize the dynamic shared memory that will be required for parallel
operation; <literal>coordinate</> points to an amount of allocated space
equal to the return value of <function>EstimateDSMCustomScan</>.
operation. <literal>coordinate</> points to a shared memory area of
size equal to the return value of <function>EstimateDSMCustomScan</>.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
</para>
<para>
<programlisting>
void (*ReInitializeDSMCustomScan) (CustomScanState *node,
ParallelContext *pcxt,
void *coordinate);
</programlisting>
Re-initialize the dynamic shared memory required for parallel operation
when the custom-scan plan node is about to be re-scanned.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
Recommended practice is that this callback reset only shared state,
while the <function>ReScanCustomScan</> callback resets only local
state. Currently, this callback will be called
before <function>ReScanCustomScan</>, but it's best not to rely on
that ordering.
</para>
<para>
<programlisting>
void (*InitializeWorkerCustomScan) (CustomScanState *node,
shm_toc *toc,
void *coordinate);
</programlisting>
Initialize a parallel worker's custom state based on the shared state
set up in the leader by <literal>InitializeDSMCustomScan</>.
This callback is optional, and needs only be supplied if this
custom path supports parallel execution.
Initialize a parallel worker's local state based on the shared state
set up by the leader during <function>InitializeDSMCustomScan</>.
This callback is optional, and need only be supplied if this custom
scan provider supports parallel execution.
</para>
<para>

View File

@ -1191,12 +1191,12 @@ ImportForeignSchema (ImportForeignSchemaStmt *stmt, Oid serverOid);
<para>
A <structname>ForeignScan</> node can, optionally, support parallel
execution. A parallel <structname>ForeignScan</> will be executed
in multiple processes and should return each row only once across
in multiple processes and must return each row exactly once across
all cooperating processes. To do this, processes can coordinate through
fixed size chunks of dynamic shared memory. This shared memory is not
guaranteed to be mapped at the same address in every process, so pointers
may not be used. The following callbacks are all optional in general,
but required if parallel execution is to be supported.
fixed-size chunks of dynamic shared memory. This shared memory is not
guaranteed to be mapped at the same address in every process, so it
must not contain pointers. The following functions are all optional,
but most are required if parallel execution is to be supported.
</para>
<para>
@ -1215,7 +1215,7 @@ IsForeignScanParallelSafe(PlannerInfo *root, RelOptInfo *rel,
</para>
<para>
If this callback is not defined, it is assumed that the scan must take
If this function is not defined, it is assumed that the scan must take
place within the parallel leader. Note that returning true does not mean
that the scan itself can be done in parallel, only that the scan can be
performed within a parallel worker. Therefore, it can be useful to define
@ -1230,6 +1230,9 @@ EstimateDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt);
Estimate the amount of dynamic shared memory that will be required
for parallel operation. This may be higher than the amount that will
actually be used, but it must not be lower. The return value is in bytes.
This function is optional, and can be omitted if not needed; but if it
is omitted, the next three functions must be omitted as well, because
no shared memory will be allocated for the FDW's use.
</para>
<para>
@ -1239,8 +1242,25 @@ InitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
void *coordinate);
</programlisting>
Initialize the dynamic shared memory that will be required for parallel
operation; <literal>coordinate</> points to an amount of allocated space
equal to the return value of <function>EstimateDSMForeignScan</>.
operation. <literal>coordinate</> points to a shared memory area of
size equal to the return value of <function>EstimateDSMForeignScan</>.
This function is optional, and can be omitted if not needed.
</para>
<para>
<programlisting>
void
ReInitializeDSMForeignScan(ForeignScanState *node, ParallelContext *pcxt,
void *coordinate);
</programlisting>
Re-initialize the dynamic shared memory required for parallel operation
when the foreign-scan plan node is about to be re-scanned.
This function is optional, and can be omitted if not needed.
Recommended practice is that this function reset only shared state,
while the <function>ReScanForeignScan</> function resets only local
state. Currently, this function will be called
before <function>ReScanForeignScan</>, but it's best not to rely on
that ordering.
</para>
<para>
@ -1249,10 +1269,9 @@ void
InitializeWorkerForeignScan(ForeignScanState *node, shm_toc *toc,
void *coordinate);
</programlisting>
Initialize a parallel worker's custom state based on the shared state
set up in the leader by <literal>InitializeDSMForeignScan</>.
This callback is optional, and needs only be supplied if this
custom path supports parallel execution.
Initialize a parallel worker's local state based on the shared state
set up by the leader during <function>InitializeDSMForeignScan</>.
This function is optional, and can be omitted if not needed.
</para>
<para>