From 7ac85df146d771a354f3c6f5cdfcb37aae05b8de Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Sat, 17 Oct 2026 09:23:42 -0400 Subject: [PATCH v1 1/2] Re-read sibling links during nbtree page unlink. _bt_unlink_halfdead_page() neglected to recheck the half-dead leaf page's btpo_prev and btpo_next during the window when no lock is held on that page during a multi-level page deletion. Replay recreates the leaf page from these links. A concurrent split of the leaf's left sibling would therefore change the leaf's btpo_prev on the primary during the window when the leaf lock is not held. The wrong left sibling link was recorded in the unlink WAL record, causing wal_consistency_checking to fail. To fix, re-read btpo_prev (and btpo_next) from the leaf once it has been relocked, just before the links are logged. --- src/backend/access/nbtree/nbtpage.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 410514d8e..0fc9956b3 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -2415,7 +2415,18 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno, * right. */ if (target != leafblkno) + { _bt_lockbuf(rel, leafbuf, BT_WRITE); + + /* + * The leaf page's left sibling may have split while we held no lock + * on the leaf + */ + page = BufferGetPage(leafbuf); + opaque = BTPageGetOpaque(page); + leafleftsib = opaque->btpo_prev; + leafrightsib = opaque->btpo_next; + } if (leftsib != P_NONE) { lbuf = _bt_getbuf(rel, leftsib, BT_WRITE); -- 2.55.0