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)
        {