| From: | Peter Geoghegan <pg(at)bowt(dot)ie> |
|---|---|
| To: | PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Cc: | Alexander Korotkov <aekorotkov(at)gmail(dot)com>, Heikki Linnakangas <hlinnaka(at)iki(dot)fi> |
| Subject: | Re: GIN page deletion and page recycling bugs |
| Date: | 2026-08-20 17:52:57 |
| Message-ID: | CAH2-WznTG0ia9e65FarqgesWeG-+ejW=UNjBgxJ0h2dEzZSBZw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On Wed, Aug 19, 2026 at 6:59 PM Peter Geoghegan <pg(at)bowt(dot)ie> wrote:
> nbtree page deletion deals with the same incomplete split problem by
> backing out of deleting the page. Fixing this bug will likely involve
> teaching GIN to do much the same thing. ginScanPostingTreeToDelete
> already avoids deleting both the leftmost and rightmost page; it
> likely needs some additional deletion-is-unsafe tests. Incomplete
> splits are rare, so we can reasonably assume an inserter will complete
> them eventually (again, like nbtree).
Attached patch fixes the bug as outlined. It would be good to get a
GIN expert to review this.
This fix will need some work to be backpatchable; we'll need to work
around refactoring commit fa6f2f624c, which is only on 19 and master.
I simplified the repro that Claude code devised for this, and included
it in this patch. I think that the test case is worth committing.
> The second bug is in page recycling. Apparently, GIN doesn't write a
> WAL record to create a recovery conflict on standbys when a deleted
> page is subsequently recycled on the primary.
I don't have a fix for this one yet. It's likely less complicated than
the incomplete split bug fix, but it is nevertheless a bit more
awkward.
The standard way of fixing this issue is to invent a new GIN record
type that works exactly like XLOG_BTREE_REUSE_PAGE and
XLOG_GIST_PAGE_REUSE. But that seems silly to me: the underlying
structs for both of those existing record types (gistxlogPageReuse and
xl_btree_reuse_page) are already identical. That's because nothing
specific to either index AM is involved, and no buffer is registered
-- we only need to generate a recovery conflict using a given
snapshotConflictHorizon XID. That suggests there should be one generic
WAL record that all 3 index AMs (nbtree, GiST, and now GIN) use,
superseding the existing record types. But that still leaves the back
branches.
On the back branches, it makes sense to avoid inventing a new WAL
record for this (doing so is theoretically allowed, but it needlessly
breaks standbys on older point releases when the primary is on the
latest point release). We could fix the bug on the back branches by
having GIN call a new GiST extern helper function when it recycles a
deleted page on the primary. That helper would create the necessary
conflict based on a snapshotConflictHorizon passed by GIN -- it'd just
write a XLOG_GIST_PAGE_REUSE record to represent GIN's page recycling
action.
--
Peter Geoghegan
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-Fix-GIN-VACUUM-unfinished-split-page-deletion-bug.patch | application/octet-stream | 11.7 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Andrey Borodin | 2026-08-20 18:43:29 | Re: walsummarizer can get stuck when switching timelines |
| Previous Message | Bruce Momjian | 2026-08-20 16:52:44 | Re: toast table corrupted by vacuum - missing chunk number 0 for toast value |