Tighten up application of parallel mode checks.
authorRobert Haas <rhaas@postgresql.org>
Fri, 16 Oct 2015 13:59:57 +0000 (09:59 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 16 Oct 2015 13:59:57 +0000 (09:59 -0400)
Commit 924bcf4f16d54c55310b28f77686608684734f42 failed to enforce
parallel mode checks during the commit of a parallel worker, because
we exited parallel mode prior to ending the transaction so that we
could pop the active snapshot.  Re-establish parallel mode during
parallel worker commit.  Without this, it's far too easy for unsafe
actions during the pre-commit sequence to crash the server instead of
hitting the error checks as intended.

Just to be extra paranoid, adjust a couple of the sanity checks in
xact.c to check not only IsInParallelMode() but also
IsParallelWorker().

src/backend/access/transam/xact.c

index 3e24800fbd139b95934c2315b819b5de09194228..47312f6854fb2c83dc54387def99f22f8fea30c0 100644 (file)
@@ -497,7 +497,7 @@ AssignTransactionId(TransactionState s)
     * Workers synchronize transaction state at the beginning of each parallel
     * operation, so we can't account for new XIDs at this point.
     */
-   if (IsInParallelMode())
+   if (IsInParallelMode() || IsParallelWorker())
        elog(ERROR, "cannot assign XIDs during a parallel operation");
 
    /*
@@ -931,7 +931,7 @@ CommandCounterIncrement(void)
         * parallel operation, so we can't account for new commands after that
         * point.
         */
-       if (IsInParallelMode())
+       if (IsInParallelMode() || IsParallelWorker())
            elog(ERROR, "cannot start commands during a parallel operation");
 
        currentCommandId += 1;
@@ -1927,6 +1927,10 @@ CommitTransaction(void)
 
    is_parallel_worker = (s->blockState == TBLOCK_PARALLEL_INPROGRESS);
 
+   /* Enforce parallel mode restrictions during parallel worker commit. */
+   if (is_parallel_worker)
+       EnterParallelMode();
+
    ShowTransactionState("CommitTransaction");
 
    /*
@@ -1971,10 +1975,7 @@ CommitTransaction(void)
 
    /* If we might have parallel workers, clean them up now. */
    if (IsInParallelMode())
-   {
        AtEOXact_Parallel(true);
-       s->parallelModeLevel = 0;
-   }
 
    /* Shut down the deferred-trigger manager */
    AfterTriggerEndXact(true);
@@ -2013,6 +2014,7 @@ CommitTransaction(void)
     * commit processing
     */
    s->state = TRANS_COMMIT;
+   s->parallelModeLevel = 0;
 
    if (!is_parallel_worker)
    {