From 4d5eb7a2dc80542cf8c04fecfdce90fa6f553265 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Mon, 21 Apr 2025 22:41:33 -0700 Subject: [PATCH v2 3/4] Convert IndexBulkDeleteCallback to process TIDs in batch. Author: Reviewed-by: Discussion: https://postgr.es/m/ Backpatch-through: --- contrib/bloom/blvacuum.c | 4 +++- src/backend/access/gin/ginvacuum.c | 3 ++- src/backend/access/gist/gistvacuum.c | 3 ++- src/backend/access/hash/hash.c | 3 ++- src/backend/access/nbtree/nbtree.c | 8 ++++++-- src/backend/access/spgist/spgvacuum.c | 13 ++++++++----- src/backend/catalog/index.c | 21 ++++++++++++++------- src/backend/commands/vacuum.c | 11 +++++------ src/include/access/genam.h | 8 ++++++-- 9 files changed, 48 insertions(+), 26 deletions(-) diff --git a/contrib/bloom/blvacuum.c b/contrib/bloom/blvacuum.c index 86b15a75f6f..93089456855 100644 --- a/contrib/bloom/blvacuum.c +++ b/contrib/bloom/blvacuum.c @@ -83,8 +83,10 @@ blbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, OffsetNumberNext(BloomPageGetMaxOffset(page))); while (itup < itupEnd) { + bool dead; + /* Do we have to delete this tuple? */ - if (callback(&itup->heapPtr, callback_state)) + if (callback(&itup->heapPtr, 1, &dead, callback_state) > 0) { /* Yes; adjust count of tuples that will be left on page */ BloomPageGetOpaque(page)->maxoff--; diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index fbbe3a6dd70..336f100261b 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -56,7 +56,8 @@ ginVacuumItemPointers(GinVacuumState *gvs, ItemPointerData *items, */ for (i = 0; i < nitem; i++) { - if (gvs->callback(items + i, gvs->callback_state)) + bool deletable; + if (gvs->callback(items + i, 1, &deletable, gvs->callback_state) > 0) { gvs->result->tuples_removed += 1; if (!tmpitems) diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c index dca236b6e57..ab2dfa7fa86 100644 --- a/src/backend/access/gist/gistvacuum.c +++ b/src/backend/access/gist/gistvacuum.c @@ -384,8 +384,9 @@ restart: { ItemId iid = PageGetItemId(page, off); IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid); + bool deletable; - if (callback(&(idxtuple->t_tid), callback_state)) + if (callback(&(idxtuple->t_tid), 1, &deletable, callback_state) > 0) todelete[ntodelete++] = off; } } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 53061c819fb..e0fffadf698 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -734,6 +734,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, IndexTuple itup; Bucket bucket; bool kill_tuple = false; + bool dead; itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offno)); @@ -743,7 +744,7 @@ hashbucketcleanup(Relation rel, Bucket cur_bucket, Buffer bucket_buf, * To remove the dead tuples, we strictly want to rely on results * of callback function. refer btvacuumpage for detailed reason. */ - if (callback && callback(htup, callback_state)) + if (callback && callback(htup, 1, &dead, callback_state) > 0) { kill_tuple = true; if (tuples_removed) diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 765659887af..342dad0ef91 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -1486,8 +1486,10 @@ backtrack: Assert(!BTreeTupleIsPivot(itup)); if (!BTreeTupleIsPosting(itup)) { + bool dead; + /* Regular tuple, standard table TID representation */ - if (callback(&itup->t_tid, callback_state)) + if (callback(&itup->t_tid, 1, &dead, callback_state) > 0) { deletable[ndeletable++] = offnum; nhtidsdead++; @@ -1671,7 +1673,9 @@ btreevacuumposting(BTVacState *vstate, IndexTuple posting, for (int i = 0; i < nitem; i++) { - if (!vstate->callback(items + i, vstate->callback_state)) + bool dead; + + if (vstate->callback(items + i, 1, &dead, vstate->callback_state) == 0) { /* Live table TID */ live++; diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index 2678f7ab782..1af1dd8ff01 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -153,9 +153,11 @@ vacuumLeafPage(spgBulkDeleteState *bds, Relation index, Buffer buffer, PageGetItemId(page, i)); if (lt->tupstate == SPGIST_LIVE) { + bool dead; + Assert(ItemPointerIsValid(<->heapPtr)); - if (bds->callback(<->heapPtr, bds->callback_state)) + if (bds->callback(<->heapPtr, 1, &dead, bds->callback_state) > 0) { bds->stats->tuples_removed += 1; deletable[i] = true; @@ -425,9 +427,10 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer) PageGetItemId(page, i)); if (lt->tupstate == SPGIST_LIVE) { + bool dead; Assert(ItemPointerIsValid(<->heapPtr)); - if (bds->callback(<->heapPtr, bds->callback_state)) + if (bds->callback(<->heapPtr, 1, &dead, bds->callback_state) > 0) { bds->stats->tuples_removed += 1; toDelete[xlrec.nDelete] = i; @@ -966,10 +969,10 @@ spgbulkdelete(IndexVacuumInfo *info, IndexBulkDeleteResult *stats, } /* Dummy callback to delete no tuples during spgvacuumcleanup */ -static bool -dummy_callback(ItemPointer itemptr, void *state) +static int +dummy_callback(ItemPointer itemptrs, int nitem, bool *deletable, void *state) { - return false; + return 0; } /* diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 739a92bdcc1..fc40317728f 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -126,7 +126,8 @@ static void index_update_stats(Relation rel, static void IndexCheckExclusion(Relation heapRelation, Relation indexRelation, IndexInfo *indexInfo); -static bool validate_index_callback(ItemPointer itemptr, void *opaque); +static int validate_index_callback(ItemPointer itemptrs, int nitem, bool *deletable, + void *opaque); static bool ReindexIsCurrentlyProcessingIndex(Oid indexOid); static void SetReindexProcessing(Oid heapOid, Oid indexOid); static void ResetReindexProcessing(void); @@ -3479,15 +3480,21 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot) /* * validate_index_callback - bulkdelete callback to collect the index TIDs */ -static bool -validate_index_callback(ItemPointer itemptr, void *opaque) +static int +validate_index_callback(ItemPointer itemptrs, int nitem, bool *deletable, + void *opaque) { ValidateIndexState *state = (ValidateIndexState *) opaque; - int64 encoded = itemptr_encode(itemptr); - tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false); - state->itups += 1; - return false; /* never actually delete anything */ + for (int i = 0; i < nitem; i++) + { + int64 encoded = itemptr_encode(&(itemptrs[i])); + + tuplesort_putdatum(state->tuplesort, Int64GetDatum(encoded), false); + } + state->itups += nitem; + + return 0; /* never actually delete anything */ } /* diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index e47b61772b1..f93ea87f1c3 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -127,7 +127,7 @@ static bool vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params, BufferAccessStrategy bstrategy); static double compute_parallel_delay(void); static VacOptValue get_vacoptval_from_boolean(DefElem *def); -static bool vac_tid_reaped(ItemPointer itemptr, void *state); +static int vac_tid_reaped(ItemPointer itemptrs, int nitem, bool *deletable, void *state); /* * GUC check function to ensure GUC value specified is within the allowable @@ -2650,15 +2650,14 @@ vac_cleanup_one_index(IndexVacuumInfo *ivinfo, IndexBulkDeleteResult *istat) } /* - * vac_tid_reaped() -- is a particular tid deletable? + * vac_tid_reaped() -- are the given TIDs deletable? * * This has the right signature to be an IndexBulkDeleteCallback. */ -static bool -vac_tid_reaped(ItemPointer itemptr, void *state) +static int +vac_tid_reaped(ItemPointer itemptrs, int nitem, bool *deletable, void *state) { TidStore *dead_items = (TidStore *) state; - bool isdead; - return TidStoreIsMemberMulti(dead_items, itemptr, 1, &isdead) > 0; + return TidStoreIsMemberMulti(dead_items, itemptrs, nitem, deletable); } diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 5b2ab181b5f..f96619cf658 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -106,8 +106,12 @@ typedef struct IndexBulkDeleteResult BlockNumber pages_free; /* # pages available for reuse */ } IndexBulkDeleteResult; -/* Typedef for callback function to determine if a tuple is bulk-deletable */ -typedef bool (*IndexBulkDeleteCallback) (ItemPointer itemptr, void *state); +/* + * Typedef for callback function to determine if tuples are bulk-deletable. + * The function returns the number of deletable tuples. + */ +typedef int (*IndexBulkDeleteCallback) (ItemPointer itemptr, int nitem, + bool *deletable, void *state); /* struct definitions appear in relscan.h */ typedef struct IndexScanDescData *IndexScanDesc; -- 2.43.5