Fix amcheck's handling of half-dead B-tree pages

amcheck incorrectly reported the following error if there were any
half-dead pages in the index:

ERROR:  mismatch between parent key and child high key in index
"amchecktest_id_idx"

It's expected that a half-dead page does not have a downlink in the
parent level, so skip the test.

Reported-by: Konstantin Knizhnik <knizhnik@garret.ru>
Reviewed-by: Peter Geoghegan <pg@bowt.ie>
Reviewed-by: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Discussion: https://www.postgresql.org/message-id/33e39552-6a2a-46f3-8b34-3f9f8004451f@garret.ru
Backpatch-through: 14
pull/255/head
Heikki Linnakangas 2 weeks ago
parent c085aab278
commit cbe04e5d72
  1. 2
      contrib/amcheck/verify_nbtree.c
  2. 14
      src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
  3. 5
      src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql

@ -2268,7 +2268,7 @@ bt_child_highkey_check(BtreeCheckState *state,
* If we visit page with high key, check that it is equal to the
* target key next to corresponding downlink.
*/
if (!rightsplit && !P_RIGHTMOST(opaque))
if (!rightsplit && !P_RIGHTMOST(opaque) && !P_ISHALFDEAD(opaque))
{
BTPageOpaque topaque;
IndexTuple highkey;

@ -11,6 +11,7 @@
-- This uses injection points to interrupt some page deletions
set client_min_messages TO 'warning';
create extension if not exists injection_points;
create extension if not exists amcheck;
reset client_min_messages;
-- Make all injection points local to this process, for concurrency.
SELECT injection_points_set_local();
@ -57,6 +58,13 @@ select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
120001
(4 rows)
-- Also check the index with amcheck
select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
bt_index_parent_check
-----------------------
(1 row)
-- Finish the deletion and re-check
vacuum nbtree_half_dead_pages;
NOTICE: notice triggered for injection point nbtree-finish-half-dead-page-vacuum
@ -69,3 +77,9 @@ select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
120001
(4 rows)
select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
bt_index_parent_check
-----------------------
(1 row)

@ -12,6 +12,7 @@
-- This uses injection points to interrupt some page deletions
set client_min_messages TO 'warning';
create extension if not exists injection_points;
create extension if not exists amcheck;
reset client_min_messages;
-- Make all injection points local to this process, for concurrency.
@ -38,6 +39,10 @@ SELECT injection_points_detach('nbtree-leave-page-half-dead');
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
-- Also check the index with amcheck
select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);
-- Finish the deletion and re-check
vacuum nbtree_half_dead_pages;
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
select bt_index_parent_check('nbtree_half_dead_pages_id_idx'::regclass, true, true);

Loading…
Cancel
Save