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: Andres Freund <andres@anarazel.de>
Cc: Dmitry Dolgov <9erthalion6@gmail.com>,
Alexander Lakhin <exclusion@gmail.com>, Matthias van de Meent <boekewurm+postgres@gmail.com>, PostgreSQL mailing lists <pgsql-bugs@lists.postgresql.org>
Date: 2021-11-10T21:04:43Z
Lists: pgsql-bugs
On Wed, Nov 10, 2021 at 11:20 AM Andres Freund <andres@anarazel.de> wrote: > The way this definitely breaks - I have been able to reproduce this in > isolation - is when one tuple is processed twice by heap_prune_chain(), and > the result of HeapTupleSatisfiesVacuum() changes from > HEAPTUPLE_DELETE_IN_PROGRESS to DEAD. I had no idea that that was now possible. I really think that this ought to be documented centrally. As you know, I don't like the way that vacuumlazy.c doesn't explain anything about the relationship between OldestXmin (which still exists, but isn't used for pruning), and the similar GlobalVisState state (used only during pruning). Surely this deserves to be addressed, because we expect these two things to agree in certain specific ways. But not necessarily in others. > Note that there are several paths < 14, that cause HTSV()'s answer to change > for the same xid. E.g. when the transaction inserting a tuple version aborts, > we go from HEAPTUPLE_INSERT_IN_PROGRESS to DEAD. Right -- that one I certainly knew about. After all, the tupgone-ectomy work from my commit 8523492d specifically targeted this case. > But I haven't quite found a > path to trigger problems with that, because there won't be redirects to a > tuple version that is HEAPTUPLE_INSERT_IN_PROGRESS (but there can be redirects > to a HEAPTUPLE_DELETE_IN_PROGRESS or RECENTLY_DEAD). That explains why the snapshot scalability either made these problems possible for the first time, or at the very least made them far far more likely in practice. The relevant code in pruneheap.c was always incredibly fragile -- no question. Even still, there is really no good reason to believe that that was actually a problem before commit dc7420c2. Even if we assume that there's a problem before 14, the surface area is vastly smaller than on 14 -- the relevant pruneheap.c code hasn't really ever changed since HOT went in. And so I think that the most sensible course of action here is this: commit a fix to Postgres 14 + HEAD only -- no backpatch to earlier versions. We could go back further than that, but ISTM that the risk of causing new problems far outweighs the benefits. Whereas I feel pretty confident that we need to do something on 14. -- 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