Re: Revert RI fast-path batching from REL_19_STABLE

From: Amit Langote <amitlangote09(at)gmail(dot)com>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Cc: rmt(at)lists(dot)postgresql(dot)org
Subject: Re: Revert RI fast-path batching from REL_19_STABLE
Date: 2026-09-07 13:14:39
Message-ID: CA+HiwqGKKXbfXas+HhdO3-L6exEqwucfuqhwCV74ktA=uB6fNg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Thu, Sep 3, 2026 at 10:36 PM Amit Langote <amitlangote09(at)gmail(dot)com> wrote:
> Attached is a two-patch series to remove batching from the RI fast
> path in REL_19_STABLE, while retaining the per-row fast path. Batching
> accumulates rows from successive foreign-key trigger invocations and
> checks them together against the referenced index when the batch fills
> or the trigger-firing cycle ends, instead of checking each row during
> its trigger invocation. I plan to leave the batched implementation
> unchanged in master for v20 development.
>
> Given the concerns raised about shipping this code in v19 [1], I
> reviewed the fixes made since feature freeze. The batching fixes are
> considerably more concerning than those to the underlying per-row fast
> path, because they have repeatedly had to address how a live batch of
> pending checks interacts with trigger-firing cycles, subtransactions,
> deferred constraints, and SET CONSTRAINTS, rather than merely
> correcting isolated implementation errors. Missing one such
> interaction can leave a foreign key check buffered and never
> performed, allowing a violating row to be committed without an error.
> That fix history, together with the two still-open batching-related
> items, has persuaded me that the concerns about shipping the batching
> code in v19 are justified.
>
> 0001 is the same patch I posted separately at:
>
> https://postgr.es/m/CA+HiwqEhm+_=bs=2wavAJz-UqC+1KebD31++mapJQQGweE8iQQ@mail.gmail.com
>
> It fixes a snapshot-ordering bug in the per-row path that must be
> addressed before 0002 removes batching and makes ordinary DML use that
> path. In READ COMMITTED, ri_FastPathCheck() could take its scan
> snapshot before waiting to lock the referenced relation. A referenced
> row committed during that wait would not be visible to the old
> snapshot, causing a false foreign key violation. Batching currently
> masks this problem because it opens and caches the relations before
> taking the snapshot used for the batch. The SPI path likewise acquires
> the referenced-relation lock before selecting the snapshot used for
> the check.

I asked GPT-6 whether I had missed anything else about snapshot
handling in the per-row fast path compared with SPI. It pointed out
that the fast path did not make the scan snapshot active. SQL executed
inside a STABLE user-defined cast could therefore use an older active
snapshot and miss changes visible to the index scan. I confirmed this
with a reproducer where the fast path rejected a valid foreign key but
SPI accepted it. Updated 0001 also pushes/pops the snapshot and adds a
regression test.

> 0002 removes the batching layer, the per-batch RI cache, and the
> after-trigger callback and subtransaction machinery added to manage
> their lifetime. It restores the affected after-trigger code to its
> pre-batching form.
>
> 0002 removes tests that exercise only the batching implementation and
> its callback and cache lifetime machinery. It retains, and where
> necessary adapts, tests that continue to exercise the underlying RI
> cases through the per-row path, including ALTER TABLE validation,
> scan-key construction, deferred checks, re-entrancy, and metadata
> invalidation. This preserves useful regression coverage in v19 and
> minimizes unnecessary divergence in test coverage, simplifying future
> backpatching of test cases. When I first tested the batching removal,
> the only failure among the retained tests was the injection-point test
> that exposed the snapshot-ordering bug fixed by 0001.

The cross-type recheck isolation test also exercises code retained in
the per-row fast path, so the updated 0002 restores it.

> The per-row path has also required fixes since feature freeze,
> including the snapshot-ordering fix in 0001. So far, however, its fix
> history has not shown the same pattern of complexity as the fixes
> needed to manage the lifetime of batched checks. On that basis, I
> propose retaining the per-row path in v19 while removing the batching
> layer.
>
> Thoughts on removing batching while retaining the per-row fast path in
> v19, and on retaining batching in its current state in master for v20
> development, would be welcome.

I'd like to push 0001 soon. I'll allow a few more days for comments
before committing 0002.

--
Thanks, Amit Langote

Attachment Content-Type Size
v2-0001-Take-RI-fast-path-snapshot-after-locking-referenc.patch application/octet-stream 13.1 KB
v2-0002-Remove-batching-from-RI-fast-path-checks.patch application/octet-stream 98.8 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Andrey Borodin 2026-09-07 13:15:12 Re: CI slowdown due to PG_TEST_INITDB_EXTRA_OPTS
Previous Message Palak Chaturvedi 2026-09-07 13:00:55 Re: Changing shared_buffers without restart