mirror of
https://github.com/postgres/postgres.git
synced 2025-12-10 00:06:45 -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/predicate.h"
|
||||
#include "storage/procarray.h"
|
||||
#include "utils/injection_point.h"
|
||||
#include "utils/memdebug.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/snapmgr.h"
|
||||
@ -2003,6 +2004,10 @@ _bt_pagedel(Relation rel, Buffer leafbuf, BTVacState *vstate)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
INJECTION_POINT("nbtree-finish-half-dead-page-vacuum", NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
INJECTION_POINT("nbtree-leave-page-half-dead", NULL);
|
||||
|
||||
/*
|
||||
* Check here, as calling loops will have locks held, preventing
|
||||
* 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(),
|
||||
'regress': {
|
||||
'sql': [
|
||||
'nbtree_half_dead_pages',
|
||||
'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