From ef8cb2c089ad9474a6da309593029c08f71b0bb9 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Fri, 29 Mar 2024 21:36:37 -0400 Subject: [PATCH v11 5/7] Set hastup in heap_page_prune lazy_scan_prune() loops through the line pointers and tuple visibility information for each tuple on a page, setting hastup to true if there are any LP_REDIRECT line pointers or tuples with storage which will not be removed. We want to remove this extra loop from lazy_scan_prune(), and we know about non-removable tuples during heap_page_prune() anyway. Set hastup when recording LP_REDIRECT line pointers in heap_prune_chain() and when LP_NORMAL line pointers refer to tuples whose visibility status is not HEAPTUPLE_DEAD. --- src/backend/access/heap/pruneheap.c | 24 ++++++++++++++++++++++-- src/backend/access/heap/vacuumlazy.c | 17 +---------------- src/include/access/heapam.h | 8 ++++++++ 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 8bdd6389b25..65b0ed185ff 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -66,6 +66,9 @@ typedef struct bool processed[MaxHeapTuplesPerPage + 1]; int ndeleted; /* Number of tuples deleted from the page */ + + /* Whether or not the page makes rel truncation unsafe */ + bool hastup; } PruneState; /* Local functions */ @@ -271,6 +274,7 @@ heap_page_prune(Relation relation, Buffer buffer, prstate.ndeleted = 0; prstate.nroot_items = 0; prstate.nheaponly_items = 0; + prstate.hastup = false; /* * If we will prepare to freeze tuples, consider that it might be possible @@ -280,7 +284,7 @@ heap_page_prune(Relation relation, Buffer buffer, presult->all_frozen = true; else presult->all_frozen = false; - + presult->hastup = prstate.hastup; /* * presult->htsv is not initialized here because all ntuple spots in the @@ -819,6 +823,8 @@ heap_prune_record_redirect(PruneState *prstate, */ if (was_normal) prstate->ndeleted++; + + prstate->hastup = true; } /* Record line pointer to be marked dead */ @@ -901,11 +907,15 @@ static void heap_prune_record_unchanged_lp_normal(Page page, int8 *htsv, PruneState *prstate, PruneResult *presult, OffsetNumber offnum) { - HeapTupleHeader htup = (HeapTupleHeader) PageGetItem(page, PageGetItemId(page, offnum)); + HeapTupleHeader htup; Assert(!prstate->processed[offnum]); prstate->processed[offnum] = true; + presult->hastup = true; /* the page is not empty */ + + htup = (HeapTupleHeader) PageGetItem(page, PageGetItemId(page, offnum)); + switch (htsv[offnum]) { case HEAPTUPLE_LIVE: @@ -974,6 +984,16 @@ heap_prune_record_unchanged_lp_dead(Page page, PruneState *prstate, OffsetNumber { Assert(!prstate->processed[offnum]); prstate->processed[offnum] = true; + + /* + * Deliberately don't set hastup for LP_DEAD items. We make the soft + * assumption that any LP_DEAD items encountered here will become + * LP_UNUSED later on, before count_nondeletable_pages is reached. If we + * don't make this assumption then rel truncation will only happen every + * other VACUUM, at most. Besides, VACUUM must treat + * hastup/nonempty_pages as provisional no matter how LP_DEAD items are + * handled (handled here, or handled later on). + */ } static void diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 679c6a866ea..212d76045ef 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -1419,7 +1419,6 @@ lazy_scan_prune(LVRelState *vacrel, int lpdead_items, live_tuples, recently_dead_tuples; - bool hastup = false; bool all_visible; TransactionId visibility_cutoff_xid; uint8 actions = 0; @@ -1500,23 +1499,11 @@ lazy_scan_prune(LVRelState *vacrel, /* Redirect items mustn't be touched */ if (ItemIdIsRedirected(itemid)) - { - /* page makes rel truncation unsafe */ - hastup = true; continue; - } if (ItemIdIsDead(itemid)) { /* - * Deliberately don't set hastup for LP_DEAD items. We make the - * soft assumption that any LP_DEAD items encountered here will - * become LP_UNUSED later on, before count_nondeletable_pages is - * reached. If we don't make this assumption then rel truncation - * will only happen every other VACUUM, at most. Besides, VACUUM - * must treat hastup/nonempty_pages as provisional no matter how - * LP_DEAD items are handled (handled here, or handled later on). - * * Also deliberately delay unsetting all_visible until just before * we return to lazy_scan_heap caller, as explained in full below. * (This is another case where it's useful to anticipate that any @@ -1631,8 +1618,6 @@ lazy_scan_prune(LVRelState *vacrel, elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result"); break; } - - hastup = true; /* page makes rel truncation unsafe */ } /* @@ -1786,7 +1771,7 @@ lazy_scan_prune(LVRelState *vacrel, vacrel->recently_dead_tuples += recently_dead_tuples; /* Can't truncate this page */ - if (hastup) + if (presult.hastup) vacrel->nonempty_pages = blkno + 1; /* Did we find LP_DEAD items? */ diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index ac129692c13..58cfa544ac0 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -231,6 +231,14 @@ typedef struct PruneResult */ int8 htsv[MaxHeapTuplesPerPage + 1]; + /* + * Whether or not the page makes rel truncation unsafe + * + * This is set to 'true', even if the page contains LP_DEAD items. VACUUM + * will remove them before attempting to truncate. + */ + bool hastup; + /* * Prepare to freeze in heap_page_prune(). lazy_scan_prune() will use the * returned freeze plans to execute freezing. -- 2.39.2