Track clearly whether to run a remote transaction in autocommit or a block
authorPavan Deolasee <pavan.deolasee@gmail.com>
Mon, 9 Apr 2018 10:42:54 +0000 (16:12 +0530)
committerPavan Deolasee <pavan.deolasee@gmail.com>
Fri, 18 May 2018 10:55:41 +0000 (16:25 +0530)
commit0f65a7193da4b6b0a35b6446b4c904a9f5ac9bf6
tree6eabf071e0053f621bcd8f5d0cc4b98075f25cbe
parent565b883f63ed7a122b356948bc2a636940533e9f
Track clearly whether to run a remote transaction in autocommit or a block

Chi Gao and Hengbing Wang reported certain issues around transaction handling
and demonstrated via xlogdump how certain transactions were getting marked
committed/aborted repeatedly on a datanode. When an already committed
transaction is attempted to be aborted again, it results in a PANIC. Upon
investigation, this uncovered a very serious yet long standing bug in
transaction handling.

If the client is running in autocommit mode, we try to avoid starting a
transaction block on the datanode side if only one datanode is going to be
involved in the transaction. This is an optimisation to speed up short queries
touching only a single node. But when the query rewriter transforms a single
statement into multiple statements, we would still (and incorrectly) run each
statement in an autocommit mode on the datanode. This can cause inconsistencies
when one statement commits but the next statement aborts. And it may also lead
to the PANIC situations if we continue to use the same global transaction
identifier for the statements.

This can also happen when the user invokes a user-defined function. If the
function has multiple statements, each statement will run in an autocommit
mode, if it's FQSed, thus again creating inconsistency if a following statement
in the function fails.

We now have a more elaborate mechanism to tackle autocommit and transaction
block needs. The special casing for force_autocommit is now removed, thus
making it more predictable. We also have specific conditions to check to ensure
that we don't mixup autocommit and transaction block for the same global xid.
Finally, if a query rewriter transforms a single statement into multiple
statements, we run those statements in a transaction block. Together these
changes should help us fix the problems.
20 files changed:
contrib/stormstats/stormstats.c
src/backend/access/transam/xact.c
src/backend/commands/analyze.c
src/backend/commands/dbcommands.c
src/backend/commands/explain.c
src/backend/commands/vacuum.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/analyze.c
src/backend/pgxc/locator/redistrib.c
src/backend/pgxc/plan/planner.c
src/backend/pgxc/pool/execRemote.c
src/backend/pgxc/pool/poolutils.c
src/backend/tcop/postgres.c
src/backend/tcop/utility.c
src/backend/utils/adt/dbsize.c
src/backend/utils/misc/guc.c
src/include/access/xact.h
src/include/pgxc/planner.h
src/test/regress/sql/plpgsql.sql