From 5ea46be733a1f48804abc09e985f98c40496e0a7 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Thu, 31 Oct 2024 18:19:18 -0400 Subject: [PATCH v2 3/3] Count pages set all-visible and all-frozen in VM during vacuum Vacuum already counts and logs pages with newly frozen tuples. Count and log pages set all-frozen in the VM too. This includes pages that are empty before or after vacuuming. While we are at it, count and log the number of pages vacuum set all-visible. Pages that are all-visible but not all-frozen are debt for future aggressive vacuums. The newly all-visible and all-frozen counts give us visiblity into the rate at which this debt is being accrued and paid down. --- src/backend/access/heap/vacuumlazy.c | 88 ++++++++++++++++++++++++---- 1 file changed, 76 insertions(+), 12 deletions(-) diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index a74ba75dde1..d80231fc727 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -189,6 +189,8 @@ typedef struct LVRelState BlockNumber scanned_pages; /* # pages examined (not skipped via VM) */ BlockNumber removed_pages; /* # pages removed by relation truncation */ BlockNumber tuple_freeze_pages; /* # pages with newly frozen tuples */ + BlockNumber vm_page_freezes; /* # pages newly set all-frozen in VM */ + BlockNumber vm_page_visibles; /* # pages newly set all-visible in the VM */ BlockNumber lpdead_item_pages; /* # pages with LP_DEAD items */ BlockNumber missed_dead_pages; /* # pages with missed dead tuples */ BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */ @@ -702,6 +704,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params, 100.0 * vacrel->tuple_freeze_pages / orig_rel_pages, (long long) vacrel->tuples_frozen); + appendStringInfo(&buf, _("visibility map: %u pages set all-visible, %u pages set all-frozen.\n"), + vacrel->vm_page_visibles, + vacrel->vm_page_freezes); if (vacrel->do_index_vacuuming) { if (vacrel->nindexes == 0 || vacrel->num_index_scans == 0) @@ -1357,6 +1362,8 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno, */ if (!PageIsAllVisible(page)) { + uint8 old_vmbits; + START_CRIT_SECTION(); /* mark buffer dirty before writing a WAL record */ @@ -1376,10 +1383,22 @@ lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf, BlockNumber blkno, log_newpage_buffer(buf, true); PageSetAllVisible(page); - visibilitymap_set(vacrel->rel, blkno, buf, InvalidXLogRecPtr, - vmbuffer, InvalidTransactionId, - VISIBILITYMAP_ALL_VISIBLE | VISIBILITYMAP_ALL_FROZEN); + old_vmbits = visibilitymap_set(vacrel->rel, blkno, buf, + InvalidXLogRecPtr, + vmbuffer, InvalidTransactionId, + VISIBILITYMAP_ALL_VISIBLE | + VISIBILITYMAP_ALL_FROZEN); END_CRIT_SECTION(); + + /* + * If the page wasn't already set all-visible and all-frozen in + * the VM, count it as newly set for logging. + */ + if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0) + vacrel->vm_page_visibles++; + + if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0) + vacrel->vm_page_freezes++; } freespace = PageGetHeapFreeSpace(page); @@ -1533,6 +1552,7 @@ lazy_scan_prune(LVRelState *vacrel, */ if (!all_visible_according_to_vm && presult.all_visible) { + uint8 old_vmbits; uint8 flags = VISIBILITYMAP_ALL_VISIBLE; if (presult.all_frozen) @@ -1556,9 +1576,21 @@ lazy_scan_prune(LVRelState *vacrel, */ PageSetAllVisible(page); MarkBufferDirty(buf); - visibilitymap_set(vacrel->rel, blkno, buf, InvalidXLogRecPtr, - vmbuffer, presult.vm_conflict_horizon, - flags); + old_vmbits = visibilitymap_set(vacrel->rel, blkno, buf, InvalidXLogRecPtr, + vmbuffer, + presult.vm_conflict_horizon, + flags); + + /* + * If the page wasn't already set all-visible and all-frozen in the + * VM, count it as newly set for logging. + */ + if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0) + vacrel->vm_page_visibles++; + + if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0 + && presult.all_frozen) + vacrel->vm_page_freezes++; } /* @@ -1608,6 +1640,8 @@ lazy_scan_prune(LVRelState *vacrel, else if (all_visible_according_to_vm && presult.all_visible && presult.all_frozen && !VM_ALL_FROZEN(vacrel->rel, blkno, &vmbuffer)) { + uint8 old_vmbits; + /* * Avoid relying on all_visible_according_to_vm as a proxy for the * page-level PD_ALL_VISIBLE bit being set, since it might have become @@ -1627,10 +1661,26 @@ lazy_scan_prune(LVRelState *vacrel, * was logged when the page's tuples were frozen. */ Assert(!TransactionIdIsValid(presult.vm_conflict_horizon)); - visibilitymap_set(vacrel->rel, blkno, buf, InvalidXLogRecPtr, - vmbuffer, InvalidTransactionId, - VISIBILITYMAP_ALL_VISIBLE | - VISIBILITYMAP_ALL_FROZEN); + old_vmbits = visibilitymap_set(vacrel->rel, blkno, buf, InvalidXLogRecPtr, + vmbuffer, InvalidTransactionId, + VISIBILITYMAP_ALL_VISIBLE | + VISIBILITYMAP_ALL_FROZEN); + + /* + * The page was likely already set all-visible in the VM. However, + * there is a small chance that it was modified sometime between + * setting all_visible_according_to_vm and checking the visibility + * during pruning. Check old_vmbits anyway to ensure the value of + * vm_page_visibles is accurate. + */ + if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0) + vacrel->vm_page_visibles++; + + /* + * We already checked that the page was not set all-frozen in the VM + * above, so we don't need to test old_vmbits. + */ + vacrel->vm_page_freezes++; } } @@ -2276,6 +2326,7 @@ lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, Buffer buffer, if (heap_page_is_all_visible(vacrel, buffer, &visibility_cutoff_xid, &all_frozen)) { + uint8 old_vmbits; uint8 flags = VISIBILITYMAP_ALL_VISIBLE; if (all_frozen) @@ -2285,8 +2336,21 @@ lazy_vacuum_heap_page(LVRelState *vacrel, BlockNumber blkno, Buffer buffer, } PageSetAllVisible(page); - visibilitymap_set(vacrel->rel, blkno, buffer, InvalidXLogRecPtr, - vmbuffer, visibility_cutoff_xid, flags); + old_vmbits = visibilitymap_set(vacrel->rel, blkno, buffer, + InvalidXLogRecPtr, + vmbuffer, visibility_cutoff_xid, + flags); + + /* + * If the page wasn't already set all-visible and all-frozen in the + * VM, count it as newly set for logging. + */ + if ((old_vmbits & VISIBILITYMAP_ALL_VISIBLE) == 0) + vacrel->vm_page_visibles++; + + if ((old_vmbits & VISIBILITYMAP_ALL_FROZEN) == 0 + && all_frozen) + vacrel->vm_page_freezes++; } /* Revert to the previous phase information for error traceback */ -- 2.45.2