| From: | Ajin Cherian <itsajin(at)gmail(dot)com> |
|---|---|
| To: | Zhijie Hou <houzhijie22(at)gmail(dot)com> |
| Cc: | pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>, Amit Kapila <amit(dot)kapila16(at)gmail(dot)com> |
| Subject: | Re: Avoid using raw xmin of frozen tuples in logicalrep conflict detection |
| Date: | 2026-11-11 02:38:44 |
| Message-ID: | CAFPTHDZ0=GfsYkpgLLz1jK9cJ1WE=saXF5WtSjETZxmsBDk8Tg@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Thu, Nov 5, 2026 at 12:05 AM Zhijie Hou <houzhijie22(at)gmail(dot)com> wrote:
>
> Hi,
>
>
> Once a tuple is frozen, its raw t_xmin is retained only for debugging
> purposes; its commit timestamp entry may no longer be valid, or the
> 32-bit XID may have wrapped around and been reassigned in a later epoch.
> Using the raw xmin of a frozen tuple could therefore trigger spurious
> update_origin_differs or delete_origin_differs conflicts, or report
> bogus transaction ID, origin, and commit timestamp details for unique
> constraint conflicts.
>
I have a question about the basic premise here.
As far as I can see, being frozen doesn't make the raw xmin wrong by
itself. TransactionIdGetCommitTsData() already returns false when the
xid falls outside [oldestCommitTsXid, newestCommitTsXid], so if
commit_ts has been truncated past the xid, we just don't report a
conflict, which is fine. Bogus data only comes back once the same
32-bit value has been reassigned and is back inside the commit_ts
window, which needs on the order of 2^32 XIDs after the tuple was
inserted. Until then, the raw xmin of a frozen tuple gives the correct
origin and commit timestamp.
With the patch, every frozen tuple is treated as having no xmin, so
update_origin_differs / delete_origin_differs are never reported for
it. When a tuple gets frozen depends on vacuum: vacuum_freeze_min_age,
page-level opportunistic freezing since PG16, eager scanning of
all-visible pages in PG18, or a manual VACUUM FREEZE. So for the same
row and the same remote change, whether we report a genuine origin
conflict would depend on whether autovacuum happened to freeze that
page first, which makes it largely non-deterministic. That seems hard
to explain to users, why the behaviour changes from case to case.
The new test shows this. Rows (3,1) and (4,2) are inserted locally on
node A and then frozen, and the subsequent UPDATE/DELETE come from B.
The local origin (0) really does differ from B’s origin, so without
VACUUM FREEZE these would be reported as update_origin_differs and
delete_origin_differs, the mirror image of the delete_origin_differs
case checked later in 035_conflicts.pl. The new test asserts that
these real conflicts are no longer reported.
So my question is whether being frozen is the right criterion, or
whether we should try to address only the XID-reuse case. I don't
immediately see a cheap way to tell a reused xid from the original
with just 32 bits, so maybe the conservative behaviour is the price we
have to pay.
regards,
Ajin Cherian
Fujitsu Australia
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Fujii Masao | 2026-11-11 02:47:43 | Re: pg_basebackup: check timeline history file write failures in ReceiveXlogStream() |
| Previous Message | shihao zhong | 2026-11-11 02:34:20 | Re: Assertion failure in WAL summarizer |