Fix concurrent-abort detection for subtransactions of prepared transactions

From: Vaijayanti Bharadwaj <vaijayanti(dot)bharadwaj(at)enterprisedb(dot)com>
To: pgsql-hackers mailing list <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Fix concurrent-abort detection for subtransactions of prepared transactions
Date: 2026-10-22 11:09:12
Message-ID: CAFNcJWXL12YXNau7t-AQWbnyJp4e5jH4P2+bdVfT8Y-8snKrrg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi hackers,

While testing prepared transactions with subtransactions, I saw a prepared
transaction whose changes were all sent downstream even though it had been
rolled back while it was being decoded.
I found that the concurrent-abort check in ReorderBufferProcessTXN() is
skipped for changes made in a subtransaction of a prepared transaction.

When decoding a prepared transaction, ReorderBufferProcessTXN() is meant to
set CheckXidAlive for each change, so a catalog scan notices if the
transaction aborts concurrently. The check does SetupCheckXidLive here:

if (streaming || rbtxn_is_prepared(change->txn))
{
curtxn = change->txn;
SetupCheckXidLive(curtxn->xid);
}
RBTXN_IS_PREPARED is set only on the top-level transaction, in
ReorderBufferRememberPrepareInfo(). For a change made in a subtransaction,
change->txn is the subtransaction's own ReorderBufferTXN, so the test is
false and CheckXidAlive is not set for it. It stays invalid, unless an
earlier top-level change set it. Because it is invalid,
HandleConcurrentAbort() does nothing, so decoding carries on and sends the
changes. The comment above SetupCheckXidLive() says the check covers the
"(sub)transaction", so I believe this is unintended.

The attached patch tests the flag on the top-level transaction:

if (streaming || rbtxn_is_prepared(rbtxn_get_toptxn(change->txn)))

Once the transaction is prepared, its subtransactions commit or abort
together with it. The error handler already tests rbtxn_is_prepared(txn) on
the top-level transaction, so it needs no change.

The patch adds an injection point, and a test using test_decoding that
fails without the fix and passes with it.

I searched the archives but did not see any earlier report. If there is
one, kindly point me to it.

Regards,
Vaijayanti

Attachment Content-Type Size
v1-0001-Fix-concurrent-abort-detection-for-subtransaction.patch application/octet-stream 8.4 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Langote 2026-10-22 11:09:32 Re: PG19: two RI fast-path issues found while testing the batching revert
Previous Message ZizhuanLiu X-MAN 2026-10-22 10:57:13 Re: Optimize mergejoinscansel() by avoiding redundant computations