Re: Bug in logical decoding with DDL and subtransactions

From: Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com>
To: "alvherre(at)kurilemu(dot)de" <alvherre(at)kurilemu(dot)de>
Cc: Bingshuai Li <lucian1412(at)outlook(dot)com>, Zhijie Hou <houzhijie22(at)gmail(dot)com>, "Hayato Kuroda (Fujitsu)" <kuroda(dot)hayato(at)fujitsu(dot)com>, Michael Paquier <michael(at)paquier(dot)xyz>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Alexander Lakhin <exclusion(at)gmail(dot)com>, "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>, "mark(dot)dilger(at)enterprisedb(dot)com" <mark(dot)dilger(at)enterprisedb(dot)com>, Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com>, Andrey Rachitskiy <pl0h0yp1(at)gmail(dot)com>, "a(dot)kozhemyakin(at)postgrespro(dot)ru" <a(dot)kozhemyakin(at)postgrespro(dot)ru>
Subject: Re: Bug in logical decoding with DDL and subtransactions
Date: 2026-10-17 05:45:54
Message-ID: CAJTYsWXAQmRfNi1zg7-yeuMc56yeOkq22eyxDiQa_Q+2tD+sGg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

I noticed that with beff3cd0098, we scan the whole tuplecid list even
when the aborted subtransaction only did DML. If there's DDL earlier in
the same transaction, we keep walking the list without removing anything.

Could we skip that scan when none of the aborting xids has catalog changes?
Something like this:

diff --git a/src/backend/replication/logical/reorderbuffer.c
b/src/backend/replication/logical/reorderbuffer.c
index 6c4eadc9972..57a72553d03 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -3297,6 +3297,23 @@ ReorderBufferCleanupAbortedTupleCids(ReorderBuffer *rb,
if (txn == NULL || !rbtxn_is_known_subxact(txn))
return;

+ /*
+ * SnapBuildProcessNewCid() marks each xid that queues tuplecids as having
+ * catalog changes. Skip the scan unless an aborting xid has that flag.
+ * Check subcommitted children too, since their parent may not have made
+ * catalog changes itself.
+ */
+ if (!rbtxn_has_catalog_changes(txn))
+ {
+ int subidx;
+
+ for (subidx = 0; subidx < nsubxacts; subidx++)
+ if (ReorderBufferXidHasCatalogChanges(rb, subxacts[subidx]))
+ break;
+ if (subidx == nsubxacts)
+ return;
+ }
+
/* Get the top-level transaction whose tuplecid list we're to clean */
toptxn = rbtxn_get_toptxn(txn);

Without the loop over the children, the cmin assertion fails if I add an
insert at the outer savepoint in tuplecid_nested.

This should save some work when a transaction has built up a long tuplecid
list and then hits lots of DML-only subtransaction aborts. I can prepare a
patch if the direction looks right.

Regards,
Ayush

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Sho Ito 2026-10-17 07:12:16 Re: PG19: flat-copied RelOptInfos share extension_state with the original rel
Previous Message shihao zhong 2026-10-17 05:13:37 [PG19] CREATE SCHEMA puts an index or trigger on a same-named temp table