diff options
| author | Heikki Linnakangas | 2025-12-02 19:11:05 +0000 |
|---|---|---|
| committer | Heikki Linnakangas | 2025-12-02 19:11:05 +0000 |
| commit | c085aab2781989f487364fab2978d9ee791559a4 (patch) | |
| tree | dfb14ab903624219cce9bbe37f87adede7c78825 /src/test | |
| parent | 6c05ef5729c04d47400660cd994305bc44a3c757 (diff) | |
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
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/modules/nbtree/expected/nbtree_half_dead_pages.out | 71 | ||||
| -rw-r--r-- | src/test/modules/nbtree/meson.build | 1 | ||||
| -rw-r--r-- | src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql | 43 |
3 files changed, 115 insertions, 0 deletions
diff --git a/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out b/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out new file mode 100644 index 00000000000..8fd472f8df2 --- /dev/null +++ b/src/test/modules/nbtree/expected/nbtree_half_dead_pages.out @@ -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) + diff --git a/src/test/modules/nbtree/meson.build b/src/test/modules/nbtree/meson.build index efebf30a16f..1b9a34d37ca 100644 --- a/src/test/modules/nbtree/meson.build +++ b/src/test/modules/nbtree/meson.build @@ -10,6 +10,7 @@ tests += { 'bd': meson.current_build_dir(), 'regress': { 'sql': [ + 'nbtree_half_dead_pages', 'nbtree_incomplete_splits', ], }, diff --git a/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql b/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql new file mode 100644 index 00000000000..d4b9a3f824d --- /dev/null +++ b/src/test/modules/nbtree/sql/nbtree_half_dead_pages.sql @@ -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; |
