1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-31 05:54:36 +03:00

Reorderbuffer: handle catalog-change-bearing aborted subxacts better

When constructing a historic snapshot for logical decoding,
reorderbuffer needs to keep track of movement of tuples in catalog
tables.  For the most part this works correctly, except that when a
subtransaction that wrote a catalog tuple aborts, we failed to "forget"
about that change.  There's no known reports of anything actually
breaking except assertion failures, but it is likely possible to
construct cases where historical snapshots produce bogus visibility
answers, potentially causing incorrect decoding output.

To fix, have the decode of a subtransaction abort go over the TUPLECID
list that has been accumulated on the ReorderBufferTXN for its topmost
parent transaction, and remove all the entries that were marked as
originating from the aborted subtransaction or its children.  There are
some little details in which various devils lie, which the added code
comments explain (we hope).

Add a couple of isolation test cases that trip the assertions with the
original coding.  They're not ideal test design, because they pass in
non-assert builds without the fix.  But we'd rather have the fix be
verified in that limited scenario than nowhere at all, and they are
cheap enough.

This bug is sibling to the one fixed in commit 8c67d29fd5 and, like
that one, it goes all the way back to the introduction of
reorderbuffers, so backpatch to all live branches.

While reviewing this, I (Álvaro) was bothered by the snapmgr.c
tuplecid_data file-scoped variable, as it's easily confused with a
function parameter used widely in reorderbuffer.c.  In branches 19 and
master, rename that to avoid confusion.

Reported-by: Arseny Sher <a.sher@postgrespro.ru>
Reported-by: Mark Dilger <mark.dilger@enterprisedb.com>
Reported-by: Alexander Kozhemyakin <a.kozhemyakin@postgrespro.ru>
Author: Bingshuai Li <lucian1412@outlook.com>
Author: Hayato Kuroda <kuroda.hayato@fujitsu.com>
Author: Zhijie Hou <houzhijie22@gmail.com>
Backpatch-through: 14
Bug: #19555
Discussion: https://postgr.es/m/87r2c8xocq.fsf@ars-thinkpad
Discussion: https://postgr.es/m/CAHgHdKu5e3XY5e90Tuaxq_R4WrKxSV734Q%2BLwo5y39Omp2A-Gg@mail.gmail.com
Discussion: https://postgr.es/m/19555-3c700f40a13045cd@postgresql.org
This commit is contained in:
Álvaro Herrera
2026-10-14 19:42:04 +02:00
parent 4118012791
commit beff3cd009
11 changed files with 389 additions and 13 deletions

View File

@@ -136,8 +136,12 @@ typedef struct ReorderBufferChange
CommandId command_id;
/*
* New cid mapping for catalog changing transaction, set when action
* == *_INTERNAL_TUPLECID.
* tuplecid changes are used to follow catalog tuple movements (i.e.,
* DDL changes); we need them to create the HistoricTupleCidHash table
* used with historical snapshots. For historical reasons we store
* these with the toplevel txn, not each subtxn; and yet we need to
* remove them on subxact aborts, so we record the subxid separately.
* Set when action == *_INTERNAL_TUPLECID.
*/
struct
{
@@ -146,6 +150,7 @@ typedef struct ReorderBufferChange
CommandId cmin;
CommandId cmax;
CommandId combocid;
TransactionId subxid;
} tuplecid;
/* Invalidation. */
@@ -740,6 +745,10 @@ extern void ReorderBufferAbort(ReorderBuffer *rb, TransactionId xid, XLogRecPtr
TimestampTz abort_time);
extern void ReorderBufferAbortOld(ReorderBuffer *rb, TransactionId oldestRunningXid);
extern void ReorderBufferForget(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn);
extern void ReorderBufferCleanupAbortedTupleCids(ReorderBuffer *rb,
TransactionId xid,
int nsubxacts,
TransactionId *subxacts);
extern void ReorderBufferInvalidate(ReorderBuffer *rb, TransactionId xid, XLogRecPtr lsn);
extern void ReorderBufferSetBaseSnapshot(ReorderBuffer *rb, TransactionId xid,
@@ -749,6 +758,7 @@ extern void ReorderBufferAddSnapshot(ReorderBuffer *rb, TransactionId xid,
extern void ReorderBufferAddNewCommandId(ReorderBuffer *rb, TransactionId xid,
XLogRecPtr lsn, CommandId cid);
extern void ReorderBufferAddNewTupleCids(ReorderBuffer *rb, TransactionId xid,
TransactionId subxid,
XLogRecPtr lsn, RelFileLocator locator,
ItemPointerData tid,
CommandId cmin, CommandId cmax, CommandId combocid);