mirror of
https://github.com/postgres/postgres.git
synced 2025-12-12 00:04:53 -05:00
Add a test for half-dead pages in B-tree indexes
To increase our test coverage in general, and because I will use this in the next commit to test a bug we currently have in amcheck. Reviewed-by: Peter Geoghegan <pg@bowt.ie> Discussion: https://www.postgresql.org/message-id/33e39552-6a2a-46f3-8b34-3f9f8004451f@garret.ru
This commit is contained in:
parent
6c05ef5729
commit
c085aab278
@ -33,6 +33,7 @@
|
|||||||
#include "storage/indexfsm.h"
|
#include "storage/indexfsm.h"
|
||||||
#include "storage/predicate.h"
|
#include "storage/predicate.h"
|
||||||
#include "storage/procarray.h"
|
#include "storage/procarray.h"
|
||||||
|
#include "utils/injection_point.h"
|
||||||
#include "utils/memdebug.h"
|
#include "utils/memdebug.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
@ -2003,6 +2004,10 @@ _bt_pagedel(Relation rel, Buffer leafbuf, BTVacState *vstate)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
INJECTION_POINT("nbtree-finish-half-dead-page-vacuum", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Then unlink it from its siblings. Each call to
|
* Then unlink it from its siblings. Each call to
|
||||||
@ -2349,6 +2354,8 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
|
|||||||
|
|
||||||
_bt_unlockbuf(rel, leafbuf);
|
_bt_unlockbuf(rel, leafbuf);
|
||||||
|
|
||||||
|
INJECTION_POINT("nbtree-leave-page-half-dead", NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check here, as calling loops will have locks held, preventing
|
* Check here, as calling loops will have locks held, preventing
|
||||||
* interrupts from being processed.
|
* interrupts from being processed.
|
||||||
|
|||||||
71
src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
Normal file
71
src/test/modules/nbtree/expected/nbtree_half_dead_pages.out
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
--
|
||||||
|
-- Test half-dead pages in B-tree indexes.
|
||||||
|
--
|
||||||
|
-- Half-dead pages is an intermediate state while vacuum is deleting a
|
||||||
|
-- page. You can encounter them if you query concurrently with vacuum,
|
||||||
|
-- or if vacuum is interrupted while it's deleting a page. A B-tree
|
||||||
|
-- with half-dead pages is a valid state, but they rarely observed by
|
||||||
|
-- other backends in practice because, so it's good to have some
|
||||||
|
-- targeted tests to exercise them.
|
||||||
|
--
|
||||||
|
-- This uses injection points to interrupt some page deletions
|
||||||
|
set client_min_messages TO 'warning';
|
||||||
|
create extension if not exists injection_points;
|
||||||
|
reset client_min_messages;
|
||||||
|
-- Make all injection points local to this process, for concurrency.
|
||||||
|
SELECT injection_points_set_local();
|
||||||
|
injection_points_set_local
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Use the index for all the queries
|
||||||
|
set enable_seqscan=off;
|
||||||
|
-- Print a NOTICE whenever a half-dead page is deleted
|
||||||
|
SELECT injection_points_attach('nbtree-finish-half-dead-page-vacuum', 'notice');
|
||||||
|
injection_points_attach
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
create table nbtree_half_dead_pages(id bigint) with (autovacuum_enabled = off);
|
||||||
|
insert into nbtree_half_dead_pages SELECT g from generate_series(1, 150000) g;
|
||||||
|
create index nbtree_half_dead_pages_id_idx on nbtree_half_dead_pages using btree (id);
|
||||||
|
delete from nbtree_half_dead_pages where id > 100000 and id < 120000;
|
||||||
|
-- Run VACUUM and interrupt it so that it leaves behind a half-dead page
|
||||||
|
SELECT injection_points_attach('nbtree-leave-page-half-dead', 'error');
|
||||||
|
injection_points_attach
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
vacuum nbtree_half_dead_pages;
|
||||||
|
ERROR: error triggered for injection point nbtree-leave-page-half-dead
|
||||||
|
CONTEXT: while vacuuming index "nbtree_half_dead_pages_id_idx" of relation "public.nbtree_half_dead_pages"
|
||||||
|
SELECT injection_points_detach('nbtree-leave-page-half-dead');
|
||||||
|
injection_points_detach
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
|
||||||
|
id
|
||||||
|
--------
|
||||||
|
99999
|
||||||
|
100000
|
||||||
|
120000
|
||||||
|
120001
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
-- Finish the deletion and re-check
|
||||||
|
vacuum nbtree_half_dead_pages;
|
||||||
|
NOTICE: notice triggered for injection point nbtree-finish-half-dead-page-vacuum
|
||||||
|
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
|
||||||
|
id
|
||||||
|
--------
|
||||||
|
99999
|
||||||
|
100000
|
||||||
|
120000
|
||||||
|
120001
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ tests += {
|
|||||||
'bd': meson.current_build_dir(),
|
'bd': meson.current_build_dir(),
|
||||||
'regress': {
|
'regress': {
|
||||||
'sql': [
|
'sql': [
|
||||||
|
'nbtree_half_dead_pages',
|
||||||
'nbtree_incomplete_splits',
|
'nbtree_incomplete_splits',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
43
src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql
Normal file
43
src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
--
|
||||||
|
-- Test half-dead pages in B-tree indexes.
|
||||||
|
--
|
||||||
|
-- Half-dead pages is an intermediate state while vacuum is deleting a
|
||||||
|
-- page. You can encounter them if you query concurrently with vacuum,
|
||||||
|
-- or if vacuum is interrupted while it's deleting a page. A B-tree
|
||||||
|
-- with half-dead pages is a valid state, but they rarely observed by
|
||||||
|
-- other backends in practice because, so it's good to have some
|
||||||
|
-- targeted tests to exercise them.
|
||||||
|
--
|
||||||
|
|
||||||
|
-- This uses injection points to interrupt some page deletions
|
||||||
|
set client_min_messages TO 'warning';
|
||||||
|
create extension if not exists injection_points;
|
||||||
|
reset client_min_messages;
|
||||||
|
|
||||||
|
-- Make all injection points local to this process, for concurrency.
|
||||||
|
SELECT injection_points_set_local();
|
||||||
|
|
||||||
|
-- Use the index for all the queries
|
||||||
|
set enable_seqscan=off;
|
||||||
|
|
||||||
|
-- Print a NOTICE whenever a half-dead page is deleted
|
||||||
|
SELECT injection_points_attach('nbtree-finish-half-dead-page-vacuum', 'notice');
|
||||||
|
|
||||||
|
create table nbtree_half_dead_pages(id bigint) with (autovacuum_enabled = off);
|
||||||
|
|
||||||
|
insert into nbtree_half_dead_pages SELECT g from generate_series(1, 150000) g;
|
||||||
|
|
||||||
|
create index nbtree_half_dead_pages_id_idx on nbtree_half_dead_pages using btree (id);
|
||||||
|
|
||||||
|
delete from nbtree_half_dead_pages where id > 100000 and id < 120000;
|
||||||
|
|
||||||
|
-- Run VACUUM and interrupt it so that it leaves behind a half-dead page
|
||||||
|
SELECT injection_points_attach('nbtree-leave-page-half-dead', 'error');
|
||||||
|
vacuum nbtree_half_dead_pages;
|
||||||
|
SELECT injection_points_detach('nbtree-leave-page-half-dead');
|
||||||
|
|
||||||
|
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
|
||||||
|
|
||||||
|
-- Finish the deletion and re-check
|
||||||
|
vacuum nbtree_half_dead_pages;
|
||||||
|
select * from nbtree_half_dead_pages where id > 99998 and id < 120002;
|
||||||
Loading…
x
Reference in New Issue
Block a user