Re: Tepid: selective index updates for heap relations

From: "Greg Burd" <greg(at)burd(dot)me>
To: pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Tepid: selective index updates for heap relations
Date: 2026-07-13 21:06:49
Message-ID: efe30c88-cf01-4c48-b76e-777547babcea@app.fastmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

Attached is v64, rebased onto current master (3ed29c42a40), this time as
a .tar.gz attachment to avoid getting moderated. What changed vs v63
(posted hours ago... apologies for the churn)?

Three patches changed in content; the other seven differ only by rebase-
induced hunk offsets. All three changes address findings from an automated
review of v63, each verified against the code (reproduced before accepting)
rather than taken on faith. Two were real and are fixed; one was declined
with reasoning below.

0005: BitmapAnd/BitmapOr false negative -- amcheck false positive fixed

bt_index_check(..., heapallindexed => true) could raise a spurious "heap
tuple ... lacks matching index tuple" on an index maintained by HOT-indexed
(SIU) updates, when nbtree deduplication had merged the fresh entries into a
posting list.

A HOT-indexed fresh entry is inserted with the may-be-stale marker
(ItemPointerSIUMaybeStaleFlag, bit 14 of the offset) set on its heap TID.
verify_nbtree already strips that marker before fingerprinting a plain leaf
tuple, so its bloom image matches the unflagged heap TID from the heap scan.
But when many such entries share one key, deduplication copies the flagged
heap TIDs verbatim into a posting list's heap-TID array, and the posting
branch fingerprinted each element without stripping -- so a flagged element
never matched the plain heap TID and heapallindexed reported a false
positive. (My earlier belief that only plain leaf tuples carry the marker
was wrong; the fix and a corrected comment reflect that.)

Fix: strip the marker per element on the palloc'd plain tuple that
bt_posting_plain_tuple() produces, mirroring the existing plain-tuple strip.
Deterministic reproducer (fails before, passes after): a two-index table,
fillfactor=10, all rows UPDATEd to a single key value twice so the SIU fresh
entries dedup into one posting list of flagged live TIDs, then
bt_index_check(heapallindexed => true). Added as a regression test in 0008.

0007: amcheck HOT-indexed chain recognition -- over-broad exemption tightened

verify_heapam's "HOT chains should not intersect" check exempts the case
where several redirects legitimately converge on one live tuple (a collapsed
SIU chain: the root and each entry-bearing dead member become a redirect to
the survivor). v63 keyed that exemption on the target merely carrying
HEAP_INDEXED_UPDATED, which is set on any SIU-produced HOT tuple -- so a
genuinely corrupt page where two unrelated redirects converge on such a
tuple would have been silently accepted, defeating exactly the check amcheck
exists to make.

The fix was to exempt only the actual collapse shape -- the target is a
heap-only HOT-indexed survivor (heap-only was already verified) AND the
other predecessor forwarding to it is itself a redirect or a collapse
stub. An ordinary tuple converging there, or a non-HOT-indexed target, is
still reported. Verified this does not regress legitimate collapse: a
multi-redirect-to-survivor page still passes verify_heapam cleanly.

0008: statistics + comprehensive test suite

- Adds the posting-list-dedup heapallindexed regression test for the 0005
fix above (section 34).

best.

-greg

Attachment Content-Type Size
v64-tepid.tar.gz application/gzip 200.8 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Robert Haas 2026-07-13 21:42:46 Re: incremental backup issue
Previous Message Robert Haas 2026-07-13 20:39:16 walsummarizer can get stuck when switching timelines