From eb9403676d61c32f45139ef6559366182afd608f Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Mon, 13 Apr 2026 11:50:32 -0400 Subject: [PATCH] Update FSM when updating VM even if freespace is zero add323da40a started updating the visibility map in the same WAL record as pruning and freezing. This included updating the freespace map during replay, which we've done since ab7dbd681. add323da40a, however, conditioned doing so on there being > 0 freespace, which differed from the previous state. The FSM is not WAL-logged and is instead updated heuristically on standbys. In rare cases, if the FSM is not updated while replaying inserts, there is 0 freespace, and vacuum replay doesn't update the FSM when setting the page all-visible/all-frozen, after the standby is promoted and runs vacuum, it may skip those pages and then propagate overly optimistic numbers up the FSM, causing slowness when searching for freespace for new tuples. Fix it by always updating the FSM when replaying setting the VM. Author: Melanie Plageman Reported-by: Alexey Makhmutov Discussion: https://postgr.es/m/ead2f110-c736-48f5-99e1-023dc9acbf0b%40postgrespro.ru --- src/backend/access/heap/heapam_xlog.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backend/access/heap/heapam_xlog.c b/src/backend/access/heap/heapam_xlog.c index f3f419d3dc1..9ed7024e814 100644 --- a/src/backend/access/heap/heapam_xlog.c +++ b/src/backend/access/heap/heapam_xlog.c @@ -38,6 +38,7 @@ heap_xlog_prune_freeze(XLogReaderState *record) Buffer vmbuffer = InvalidBuffer; uint8 vmflags = 0; Size freespace = 0; + bool do_update_fsm = false; XLogRecGetBlockTag(record, 0, &rlocator, NULL, &blkno); memcpy(&xlrec, maindataptr, SizeOfHeapPrune); @@ -211,7 +212,10 @@ heap_xlog_prune_freeze(XLogReaderState *record) XLHP_HAS_DEAD_ITEMS | XLHP_HAS_NOW_UNUSED_ITEMS)) || (vmflags & VISIBILITYMAP_VALID_BITS)) + { freespace = PageGetHeapFreeSpace(BufferGetPage(buffer)); + do_update_fsm = true; + } /* * We want to avoid holding an exclusive lock on the heap buffer while @@ -248,7 +252,7 @@ heap_xlog_prune_freeze(XLogReaderState *record) if (BufferIsValid(vmbuffer)) UnlockReleaseBuffer(vmbuffer); - if (freespace > 0) + if (do_update_fsm) XLogRecordPageWithFreeSpace(rlocator, blkno, freespace); } -- 2.43.0