Fix nbtree multi-level page deletion WAL record bug.

The second phase of a multi-level nbtree page deletion operation marks a
"top parent" internal page fully deleted, and updates the to-be-deleted
subtree's half-dead page.  The leaf page needs to have its top parent
link updated in preparation for marking the next top parent page (the
subtree page one level down) fully deleted.  The second phase reads the
leaf page's sibling links and releases its lock on the leaf, relocking
it only after it has examined the target page.  This created a small
window where stale information could be WAL logged.

It was just about possible for a concurrent split of the half-dead
page's left sibling page to update the half-dead page's left sibling
link.  _bt_unlink_halfdead_page neglected to re-copy the leaf page's
sibling links when it reacquired a lock on that page.  The atomic action
that the WAL record represents doesn't really need to change any of its
sibling links, so this shouldn't have been a problem.  However, since we
use REGBUF_WILL_INIT for the half-dead leaf page's buffer, using a stale
value led to corrupted half-dead leaf pages on standbys.  This bug has
been shown to cause wal_consistency_checking failures.

To fix, re-read btpo_prev (and btpo_next) from the leaf once it has been
relocked, before the links are logged.  That way we'll reliably WAL log
the current leafleftsib.

In practice this bug was very hard to hit.  It required a concurrent
split at just the right/wrong time, with a multi-level page deletion.
Even then, the resulting corruption on standbys only persisted until the
half-dead page was marked fully deleted -- which typically happened
immediately after the corruption was introduced.

Oversight in commit efada2b8e9, which fixed a race condition in nbtree
page deletion.

Author: Peter Geoghegan <[email protected]>
Discussion: 
https://postgr.es/m/CAH2-Wznr2Gw5OQE9KMP_Xd92F9mV=gv7qe9q6taavfrkqse...@mail.gmail.com
Backpatch-through: 14

Branch
------
REL_14_STABLE

Details
-------
https://git.postgresql.org/pg/commitdiff/3651d7c58bc1d6d4f2ed398f96961524c3ba035e

Modified Files
--------------
src/backend/access/nbtree/nbtpage.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)

Reply via email to