From 46dc299c2bc878799e2c56ed4c240d5c5284b986 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Mon, 22 Jan 2024 14:53:36 -0500 Subject: [PATCH v3 13/17] 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 | 33 ++++++++++++++++++++++++---- src/backend/access/heap/vacuumlazy.c | 25 ++------------------- src/include/access/heapam.h | 3 +++ 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 994cf75c54e..2fee9aa509c 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -70,7 +70,8 @@ static void prune_prepare_freeze_tuple(Page page, OffsetNumber offnum, PruneFreezeResult *presult); static void heap_prune_record_prunable(PruneState *prstate, TransactionId xid); static void heap_prune_record_redirect(PruneState *prstate, - OffsetNumber offnum, OffsetNumber rdoffnum); + OffsetNumber offnum, OffsetNumber rdoffnum, + PruneFreezeResult *presult); static void heap_prune_record_dead(PruneState *prstate, OffsetNumber offnum, PruneFreezeResult *presult); static void heap_prune_record_dead_or_unused(PruneState *prstate, OffsetNumber offnum, @@ -294,6 +295,8 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, presult->nnewlpdead = 0; presult->nfrozen = 0; + presult->hastup = false; + /* * Keep track of whether or not the page is all_visible in case the caller * wants to use this information to update the VM. @@ -474,18 +477,37 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, prune_prepare_freeze_tuple(page, offnum, pagefrz, frozen, presult); + itemid = PageGetItemId(page, offnum); + + if (ItemIdIsNormal(itemid) && + presult->htsv[offnum] != HEAPTUPLE_DEAD) + { + Assert(presult->htsv[offnum] != -1); + + /* + * 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). + */ + presult->hastup = true; + } + /* Ignore items already processed as part of an earlier chain */ if (prstate.marked[offnum]) continue; /* Nothing to do if slot is empty */ - itemid = PageGetItemId(page, offnum); if (!ItemIdIsUsed(itemid)) continue; /* Process this item or chain of items */ presult->ndeleted += heap_prune_chain(buffer, offnum, &prstate, presult); + } /* Clear the offset information once we have processed the given page. */ @@ -1040,7 +1062,7 @@ heap_prune_chain(Buffer buffer, OffsetNumber rootoffnum, if (i >= nchain) heap_prune_record_dead_or_unused(prstate, rootoffnum, presult); else - heap_prune_record_redirect(prstate, rootoffnum, chainitems[i]); + heap_prune_record_redirect(prstate, rootoffnum, chainitems[i], presult); } else if (nchain < 2 && ItemIdIsRedirected(rootlp)) { @@ -1122,7 +1144,8 @@ heap_prune_record_prunable(PruneState *prstate, TransactionId xid) /* Record line pointer to be redirected */ static void heap_prune_record_redirect(PruneState *prstate, - OffsetNumber offnum, OffsetNumber rdoffnum) + OffsetNumber offnum, OffsetNumber rdoffnum, + PruneFreezeResult *presult) { Assert(prstate->nredirected < MaxHeapTuplesPerPage); prstate->redirected[prstate->nredirected * 2] = offnum; @@ -1132,6 +1155,8 @@ heap_prune_record_redirect(PruneState *prstate, prstate->marked[offnum] = true; Assert(!prstate->marked[rdoffnum]); prstate->marked[rdoffnum] = true; + + presult->hastup = true; } /* Record line pointer to be marked dead */ diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 6dd8d457c9c..aac38f54c0a 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -1447,7 +1447,6 @@ lazy_scan_prune(LVRelState *vacrel, live_tuples, recently_dead_tuples; HeapPageFreeze pagefrz; - bool hastup = false; OffsetNumber deadoffsets[MaxHeapTuplesPerPage]; Assert(BufferGetBlockNumber(buf) == blkno); @@ -1491,7 +1490,6 @@ lazy_scan_prune(LVRelState *vacrel, * the VM after collecting LP_DEAD items and freezing tuples. Pruning will * have determined whether or not the page is all_visible and able to * become all_frozen. - * */ for (offnum = FirstOffsetNumber; offnum <= maxoff; @@ -1504,28 +1502,12 @@ lazy_scan_prune(LVRelState *vacrel, vacrel->offnum = offnum; itemid = PageGetItemId(page, offnum); - if (!ItemIdIsUsed(itemid)) - continue; - /* Redirect items mustn't be touched */ - if (ItemIdIsRedirected(itemid)) - { - /* page makes rel truncation unsafe */ - hastup = true; + if (ItemIdIsRedirected(itemid) || !ItemIdIsUsed(itemid)) 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). - */ deadoffsets[lpdead_items++] = offnum; continue; } @@ -1593,9 +1575,6 @@ lazy_scan_prune(LVRelState *vacrel, elog(ERROR, "unexpected HeapTupleSatisfiesVacuum result"); break; } - - hastup = true; /* page makes rel truncation unsafe */ - } vacrel->offnum = InvalidOffsetNumber; @@ -1677,7 +1656,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 8a6bc071345..7ad46696d66 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -202,11 +202,14 @@ typedef struct PruneFreezeResult int nnewlpdead; /* Number of newly LP_DEAD items */ bool all_visible; /* Whether or not the page is all visible */ bool all_visible_except_removable; + bool hastup; /* Does page make rel truncation unsafe */ + /* Whether or not the page can be set all frozen in the VM */ bool all_frozen; /* Number of newly frozen tuples */ int nfrozen; + TransactionId frz_conflict_horizon; /* Newest xmin on the page */ /* -- 2.40.1