From 5e5a089bc14eb29df8b16da8ebec38344f7fad1c Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Mon, 21 Apr 2025 22:40:57 -0700 Subject: [PATCH v3 2/4] tidstore.c: introduce TidStoreIsMemberMulti. Author: Reviewed-by: Discussion: https://postgr.es/m/ Backpatch-through: --- src/backend/access/common/tidstore.c | 62 +++++++++++++------ src/backend/commands/vacuum.c | 3 +- src/include/access/tidstore.h | 3 +- .../modules/test_tidstore/test_tidstore.c | 11 +++- 4 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c index 5bd75fb499c..270ef260630 100644 --- a/src/backend/access/common/tidstore.c +++ b/src/backend/access/common/tidstore.c @@ -416,20 +416,11 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, local_ts_set(ts->tree.local, blkno, page); } -/* Return true if the given TID is present in the TidStore */ -bool -TidStoreIsMember(TidStore *ts, ItemPointer tid) +static pg_attribute_always_inline int +tidstore_is_member_page(BlocktableEntry *page, OffsetNumber off) { int wordnum; int bitnum; - BlocktableEntry *page; - BlockNumber blk = ItemPointerGetBlockNumber(tid); - OffsetNumber off = ItemPointerGetOffsetNumber(tid); - - if (TidStoreIsShared(ts)) - page = shared_ts_find(ts->tree.shared, blk); - else - page = local_ts_find(ts->tree.local, blk); /* no entry for the blk */ if (page == NULL) @@ -443,19 +434,54 @@ TidStoreIsMember(TidStore *ts, ItemPointer tid) if (page->header.full_offsets[i] == off) return true; } + return false; } - else + + wordnum = WORDNUM(off); + bitnum = BITNUM(off); + + /* no bitmap for the off */ + if (wordnum >= page->header.nwords) + return false; + + return (page->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0; +} + +/* + * Check if the given TIDs are present in the TidStore. Return the number + * of TIDs found in the TidStore. *ismember must have enough space for + * up to 'ntids' elements. + */ +int +TidStoreIsMemberMulti(TidStore *ts, ItemPointer tids, int ntids, bool *ismembers) +{ + BlocktableEntry *page = NULL; + BlockNumber last_blk = InvalidBlockNumber; + int nmembers = 0; + + for (int i = 0; i < ntids; i++) { - wordnum = WORDNUM(off); - bitnum = BITNUM(off); + ItemPointer tid = &(tids[i]); + BlockNumber blk = ItemPointerGetBlockNumber(tid); + OffsetNumber off = ItemPointerGetOffsetNumber(tid); - /* no bitmap for the off */ - if (wordnum >= page->header.nwords) - return false; + if (blk != last_blk) + { + if (TidStoreIsShared(ts)) + page = shared_ts_find(ts->tree.shared, blk); + else + page = local_ts_find(ts->tree.local, blk); + } - return (page->words[wordnum] & ((bitmapword) 1 << bitnum)) != 0; + ismembers[i] = tidstore_is_member_page(page, off); + if (ismembers[i]) + nmembers++; + + last_blk = blk; } + + return nmembers; } /* diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 33a33bf6b1c..e47b61772b1 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2658,6 +2658,7 @@ static bool vac_tid_reaped(ItemPointer itemptr, void *state) { TidStore *dead_items = (TidStore *) state; + bool isdead; - return TidStoreIsMember(dead_items, itemptr); + return TidStoreIsMemberMulti(dead_items, itemptr, 1, &isdead) > 0; } diff --git a/src/include/access/tidstore.h b/src/include/access/tidstore.h index 041091df278..b6137e78780 100644 --- a/src/include/access/tidstore.h +++ b/src/include/access/tidstore.h @@ -40,7 +40,8 @@ extern void TidStoreUnlock(TidStore *ts); extern void TidStoreDestroy(TidStore *ts); extern void TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, int num_offsets); -extern bool TidStoreIsMember(TidStore *ts, ItemPointer tid); +extern int TidStoreIsMemberMulti(TidStore *ts, ItemPointer tids, int ntids, + bool *ismembers); extern TidStoreIter *TidStoreBeginIterate(TidStore *ts); extern TidStoreIterResult *TidStoreIterateNext(TidStoreIter *iter); extern int TidStoreGetBlockOffsets(TidStoreIterResult *result, diff --git a/src/test/modules/test_tidstore/test_tidstore.c b/src/test/modules/test_tidstore/test_tidstore.c index eb16e0fbfa6..277d437e237 100644 --- a/src/test/modules/test_tidstore/test_tidstore.c +++ b/src/test/modules/test_tidstore/test_tidstore.c @@ -222,16 +222,22 @@ check_set_block_offsets(PG_FUNCTION_ARGS) TidStoreIterResult *iter_result; int num_iter_tids = 0; int num_lookup_tids = 0; + bool *ismembers; BlockNumber prevblkno = 0; check_tidstore_available(); /* lookup each member in the verification array */ + ismembers = palloc(sizeof(bool) * items.num_tids); + TidStoreIsMemberMulti(tidstore, items.insert_tids, items.num_tids, ismembers); for (int i = 0; i < items.num_tids; i++) - if (!TidStoreIsMember(tidstore, &items.insert_tids[i])) + { + if (!ismembers[i]) elog(ERROR, "missing TID with block %u, offset %u", ItemPointerGetBlockNumber(&items.insert_tids[i]), ItemPointerGetOffsetNumber(&items.insert_tids[i])); + } + pfree(ismembers); /* * Lookup all possible TIDs for each distinct block in the verification @@ -248,11 +254,12 @@ check_set_block_offsets(PG_FUNCTION_ARGS) for (OffsetNumber offset = FirstOffsetNumber; offset < MaxOffsetNumber; offset++) { ItemPointerData tid; + bool ismember; ItemPointerSet(&tid, blkno, offset); TidStoreLockShare(tidstore); - if (TidStoreIsMember(tidstore, &tid)) + if (TidStoreIsMemberMulti(tidstore, &tid, 1, &ismember) > 0) ItemPointerSet(&items.lookup_tids[num_lookup_tids++], blkno, offset); TidStoreUnlock(tidstore); } -- 2.43.5