Re: BUG #17255: Server crashes in index_delete_sort_cmp() due to race condition with vacuum
Peter Geoghegan <pg@bowt.ie>
From: Peter Geoghegan <pg@bowt.ie>
To: Dmitry Dolgov <9erthalion6@gmail.com>
Cc: Alexander Lakhin <exclusion@gmail.com>,
Andres Freund <andres@anarazel.de>, Matthias van de Meent <boekewurm+postgres@gmail.com>, PostgreSQL mailing lists <pgsql-bugs@lists.postgresql.org>
Date: 2021-11-09T23:31:37Z
Lists: pgsql-bugs
Attachments
- v1-0001-Fix-aborted-HOT-update-bug-in-heap-pruning.patch (application/octet-stream) patch v1-0001
On Tue, Nov 9, 2021 at 9:51 AM Peter Geoghegan <pg@bowt.ie> wrote: > I've discussed this privately with Andres -- expect more from him > soon. I came up with more sophisticated instrumentation (better > assertions, really) that shows that the problem begins in VACUUM, not > opportunistic pruning (certainly with the test case we have). Attached is a WIP fix for the bug. The idea here is to follow all HOT chains in an initial pass over the page, while even following LIVE heap-only tuples. Any heap-only tuples that we don't determine are part of some valid HOT chain (following an initial pass over the whole heap page) will now be processed in a second pass over the page. We expect (and assert) that these "disconnected" heap-only tuples will all be either DEAD or RECENTLY_DEAD. We treat them as DEAD either way, on the grounds that they must be from an aborted xact in any case. Note that we sometimes do something very similar already -- we can sometimes consider some tuples from a HOT chain DEAD, even though they're RECENTLY_DEAD (provided a later tuple from the chain really is DEAD). The patch also has more detailed assertions inside heap_page_prune(). These should catch any HOT chain invariant violations at just about the earliest opportunity, at least when assertions are enabled. Especially because we're now following every HOT chain from beginning to end now, even when we already know that there are no more DEAD/RECENTLY_DEAD tuples in the chain to be found. I'm not sure why this seems to have become more of a problem following the snapshot scalability work from Andres -- Alexander mentioned that commit dc7420c2 looked like it was the source of the problem here, but I can't see any reason why that might be true (even though I accept that it might well *appear* to be true). I believe Andres has some theory on that, but I don't know the details myself. AFAICT, this is a live bug on all supported versions. We simply weren't being careful enough about breaking the invariant that an LP_REDIRECT can only point to a valid heap-only tuple. The really surprising thing here is that it took this long for it to visibly break. -- Peter Geoghegan
Commits
-
vacuumlazy.c: Standardize rel_pages terminology.
- e370f100f05d 15.0 landed
-
vacuumlazy.c: document vistest and OldestXmin.
- 73f6ec3d3c8d 15.0 landed
-
heap pruning: Only call BufferGetBlockNumber() once.
- c702d656a283 15.0 landed
-
Fix possible HOT corruption when RECENTLY_DEAD changes to DEAD while pruning.
- dad1539aec28 14.2 landed
- 18b87b201f73 15.0 landed
-
Assert redirect pointers are sensible after heap_page_prune().
- bb42bfb5ccb5 15.0 landed
-
Remove tupgone special case from vacuumlazy.c.
- 8523492d4e34 14.0 cited
-
Recycle nbtree pages deleted during same VACUUM.
- 9dd963ae2534 14.0 cited
-
snapshot scalability: Don't compute global horizons while building snapshots.
- dc7420c2c927 14.0 cited
-
Refactor heap_page_prune so that instead of changing item states on-the-fly,
- 6f10eb21118f 8.4.0 cited