1
0
mirror of https://github.com/postgres/postgres.git synced 2026-10-23 13:29:09 +03:00

Update FSM in COPY FREEZE replay

d96f87332b folded COPY FREEZE visibility map updates into
XLOG_HEAP2_MULTI_INSERT records. Unlike the former XLOG_HEAP2_VISIBLE
redo path, multi-insert redo only updated the FSM when the record did
not contain a heap page FPI and the heap page had less than 20% free
space.

This can leave all-frozen pages with missing or stale FSM entries on a
standby. After promotion, vacuum will skip those pages, preventing
their free space from being discovered.

When a multi-insert record sets the page all-frozen, record the heap
page's free space unconditionally.

Reported-by: Melanie Plageman <melanieplageman@gmail.com>
Discussion: https://postgr.es/m/CAAKRu_bS3nfMJCF2fjE%2Bceb5-t%3D2p_VPMk2PWuVomrOFxg5DGQ%40mail.gmail.com
Backpatch-through: 19
This commit is contained in:
Melanie Plageman
2026-09-14 11:57:08 -04:00
parent d69b06e5ab
commit f4b511ae93

View File

@@ -643,8 +643,6 @@ heap_xlog_multi_insert(XLogReaderState *record)
if (tupdata != endptr)
elog(PANIC, "total tuple length mismatch");
freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */
PageSetLSN(page, lsn);
if (xlrec->flags & XLH_INSERT_ALL_VISIBLE_CLEARED)
@@ -672,9 +670,41 @@ heap_xlog_multi_insert(XLogReaderState *record)
MarkBufferDirty(buffer);
}
if (BufferIsValid(buffer))
{
/*
* If we are marking the page all-frozen or the page is running low on
* free space, update the FSM as well. Arbitrarily, our definition of
* "low" is less than 20%. We can't do much better than that without
* knowing the fill-factor for the table.
*
* XXX: Unless setting the page all-frozen, we don't do this if the
* page was restored from full page image. We don't bother to update
* the FSM in that case, it doesn't need to be totally accurate
* anyway.
*
* If setting the page all-frozen, we update the FSM regardless since,
* once frozen, we lose the chance to update it during vacuum after
* promotion. See comment in heap_xlog_prune_freeze() for details.
*/
bool update_fsm = false;
if (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET ||
action == BLK_NEEDS_REDO)
{
freespace = PageGetHeapFreeSpace(BufferGetPage(buffer));
if (xlrec->flags & XLH_INSERT_ALL_FROZEN_SET ||
freespace < BLCKSZ / 5)
update_fsm = true;
}
UnlockReleaseBuffer(buffer);
if (update_fsm)
XLogRecordPageWithFreeSpace(rlocator, blkno, freespace);
}
buffer = InvalidBuffer;
/*
@@ -717,18 +747,6 @@ heap_xlog_multi_insert(XLogReaderState *record)
if (BufferIsValid(vmbuffer))
UnlockReleaseBuffer(vmbuffer);
/*
* If the page is running low on free space, update the FSM as well.
* Arbitrarily, our definition of "low" is less than 20%. We can't do much
* better than that without knowing the fill-factor for the table.
*
* XXX: Don't do this if the page was restored from full page image. We
* don't bother to update the FSM in that case, it doesn't need to be
* totally accurate anyway.
*/
if (action == BLK_NEEDS_REDO && freespace < BLCKSZ / 5)
XLogRecordPageWithFreeSpace(rlocator, blkno, freespace);
}
/*