From 88d911bc032a04bc5e935353fdd0a35fcb981a34 Mon Sep 17 00:00:00 2001 From: Matthias van de Meent Date: Mon, 22 Jun 2026 13:34:11 +0200 Subject: [PATCH v2 2/2] nbtree: Use cleanup locks in redo for IOS interlock We need to interlock tuple clean with IOS' page pins on the primary, and this is no different on a hot standby replica. This naturally requires btree_xlog_delete to use a Cleanup lock on the buffer it's removing tuples from. Additionally, because page splits can remove tuples from a page that IOS still holds a pin on, and those removed tuples can then be deleted from the index without an interlock with the split page, btree_xlog_split must also use a cleanup lock for page splits. Reported-by: Peter Geoghegan --- src/backend/access/nbtree/nbtxlog.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c index dff7d286fc8..8940db7de34 100644 --- a/src/backend/access/nbtree/nbtxlog.c +++ b/src/backend/access/nbtree/nbtxlog.c @@ -300,7 +300,13 @@ btree_xlog_split(bool newitemonleft, XLogReaderState *record) MarkBufferDirty(rbuf); /* Now reconstruct original page (left half of split) */ - if (XLogReadBufferForRedo(record, 0, &buf) == BLK_NEEDS_REDO) + /* + * Note: We're moving tuples off the page that a concurrent IOS won't + * get a cleanup interlock with if they're DELETE-d, so we must do that + * interlock here and now to avoid IOScans losing a vacuum interlock. + */ + if (XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, + &buf) == BLK_NEEDS_REDO) { /* * To retain the same physical order of the tuples that they had, we @@ -664,7 +670,8 @@ btree_xlog_delete(XLogReaderState *record) * We don't need to take a cleanup lock to apply these changes. See * nbtree/README for details. */ - if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO) + if (XLogReadBufferForRedoExtended(record, 0, RBM_NORMAL, true, + &buffer) == BLK_NEEDS_REDO) { char *ptr = XLogRecGetBlockData(record, 0, NULL); -- 2.50.1 (Apple Git-155)