From 14f664ceea6c256630c41cb8dc7940e7b07c0091 Mon Sep 17 00:00:00 2001 From: Peter Geoghegan Date: Sat, 15 Aug 2026 18:31:18 -0400 Subject: [PATCH v2 1/2] GiST: Deprecate F_TUPLES_DELETED. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also add test coverage of gistprunepage(), which would have caught this issue earlier. Author: Peter Geoghegan Reviewed-by: Michael Paquiër Discussion: https://postgr.es/m/CAH2-WznbTsQCrjmd=eSawfPqcxCjSFUkk6Qzd3z+gpNte5i03Q@mail.gmail.com --- src/include/access/gist.h | 8 ++------ src/backend/access/gist/gistvacuum.c | 1 - src/backend/access/gist/gistxlog.c | 3 --- src/test/regress/expected/gist.out | 26 ++++++++++++++++++++++++++ src/test/regress/sql/gist.sql | 21 +++++++++++++++++++++ 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 9b385b13a..69a7945c5 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -48,8 +48,8 @@ */ #define F_LEAF (1 << 0) /* leaf page */ #define F_DELETED (1 << 1) /* the page has been deleted */ -#define F_TUPLES_DELETED (1 << 2) /* some tuples on the page were - * deleted */ +#define F_TUPLES_DELETED (1 << 2) /* old-style VACUUM FULL flag + * (deprecated) */ #define F_FOLLOW_RIGHT (1 << 3) /* page to the right has no downlink */ #define F_HAS_GARBAGE (1 << 4) /* some tuples on the page are dead, * but not deleted yet */ @@ -174,10 +174,6 @@ typedef struct GISTENTRY #define GistPageIsDeleted(page) ( GistPageGetOpaque(page)->flags & F_DELETED) -#define GistTuplesDeleted(page) ( GistPageGetOpaque(page)->flags & F_TUPLES_DELETED) -#define GistMarkTuplesDeleted(page) ( GistPageGetOpaque(page)->flags |= F_TUPLES_DELETED) -#define GistClearTuplesDeleted(page) ( GistPageGetOpaque(page)->flags &= ~F_TUPLES_DELETED) - #define GistPageHasGarbage(page) ( GistPageGetOpaque(page)->flags & F_HAS_GARBAGE) #define GistMarkPageHasGarbage(page) ( GistPageGetOpaque(page)->flags |= F_HAS_GARBAGE) #define GistClearPageHasGarbage(page) ( GistPageGetOpaque(page)->flags &= ~F_HAS_GARBAGE) diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index 686a04180..b87e98207 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -401,7 +401,6 @@ restart: MarkBufferDirty(buffer); PageIndexMultiDelete(page, todelete, ntodelete); - GistMarkTuplesDeleted(page); if (RelationNeedsWAL(rel)) { diff --git a/src/backend/access/gist/gistxlog.c b/src/backend/access/gist/gistxlog.c index ae538dc81..1f8100f2a 100644 --- a/src/backend/access/gist/gistxlog.c +++ b/src/backend/access/gist/gistxlog.c @@ -114,8 +114,6 @@ gistRedoPageUpdateRecord(XLogReaderState *record) data += sizeof(OffsetNumber) * xldata->ntodelete; PageIndexMultiDelete(page, todelete, xldata->ntodelete); - if (GistPageIsLeaf(page)) - GistMarkTuplesDeleted(page); } /* Add new tuples if any */ @@ -204,7 +202,6 @@ gistRedoDeleteRecord(XLogReaderState *record) PageIndexMultiDelete(page, toDelete, xldata->ntodelete); GistClearPageHasGarbage(page); - GistMarkTuplesDeleted(page); PageSetLSN(page, lsn); MarkBufferDirty(buffer); diff --git a/src/test/regress/expected/gist.out b/src/test/regress/expected/gist.out index ae5b522b3..ac79f94aa 100644 --- a/src/test/regress/expected/gist.out +++ b/src/test/regress/expected/gist.out @@ -423,6 +423,32 @@ select lower(r) = repeat('7', 200)::numeric as lower_ok, (1 row) drop table gist_ios_tupdesc; +-- test deletion of LP_DEAD-marked index tuples +create table gist_prune_tbl (k int, p point); +create index gist_prune_tbl_p_index on gist_prune_tbl using gist (p); +begin; +insert into gist_prune_tbl select i, point(1, i) from generate_series(1, 600) i; +rollback; +set enable_bitmapscan = off; +set enable_indexonlyscan = off; +set enable_seqscan = off; +select count(*) from gist_prune_tbl where p <@ box(point(0,0), point(2,1000)); + count +------- + 0 +(1 row) + +insert into gist_prune_tbl select i, point(1, i) from generate_series(1, 600) i; +select count(*) from gist_prune_tbl where p <@ box(point(0,0), point(2,1000)); + count +------- + 600 +(1 row) + +reset enable_bitmapscan; +reset enable_indexonlyscan; +reset enable_seqscan; +drop table gist_prune_tbl; -- Force an index build using buffering. create index gist_tbl_box_index_forcing_buffering on gist_tbl using gist (p) with (buffering=on, fillfactor=50); diff --git a/src/test/regress/sql/gist.sql b/src/test/regress/sql/gist.sql index 1ebb1d9ee..57dcc0824 100644 --- a/src/test/regress/sql/gist.sql +++ b/src/test/regress/sql/gist.sql @@ -198,6 +198,27 @@ select lower(r) = repeat('7', 200)::numeric as lower_ok, drop table gist_ios_tupdesc; +-- test deletion of LP_DEAD-marked index tuples +create table gist_prune_tbl (k int, p point); +create index gist_prune_tbl_p_index on gist_prune_tbl using gist (p); + +begin; +insert into gist_prune_tbl select i, point(1, i) from generate_series(1, 600) i; +rollback; + +set enable_bitmapscan = off; +set enable_indexonlyscan = off; +set enable_seqscan = off; + +select count(*) from gist_prune_tbl where p <@ box(point(0,0), point(2,1000)); +insert into gist_prune_tbl select i, point(1, i) from generate_series(1, 600) i; +select count(*) from gist_prune_tbl where p <@ box(point(0,0), point(2,1000)); + +reset enable_bitmapscan; +reset enable_indexonlyscan; +reset enable_seqscan; +drop table gist_prune_tbl; + -- Force an index build using buffering. create index gist_tbl_box_index_forcing_buffering on gist_tbl using gist (p) with (buffering=on, fillfactor=50); -- 2.53.0