From a4f18fd8f2800084304844060fe5564136e6b3e5 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Wed, 16 Sep 2026 13:49:59 +0300 Subject: [PATCH] Say in the FSM README why its hint writes still need full page images The Recovery section said we would "operate correctly without the full page images that MarkBufferDirtyHint() provides", offering them only as a way to lose less slot knowledge to RBM_ZERO_ON_ERROR. That is true of freespace.c, which passes RBM_ZERO_ON_ERROR on every read, and false of the system around it, which reads the same files and does verify checksums. Reading it as a licence to dirty FSM pages without a full page image is what led to c06d1a4ba6b, since reverted. Say instead that RBM_ZERO_ON_ERROR is a property of this directory rather than of the fork, and name the readers that do not share it: RelationCopyStorage(), RelationCopyStorageUsingBuffer(), base backups and pg_checksums. Rather than presenting today's behavior as the only one possible, note that the alternative is for all of that code to skip checksum validation of the FSM. Reported-by: Noah Misch Reviewed-by: Noah Misch Reviewed-by: Andrey Borodin Discussion: https://postgr.es/m/20260901211837.f6.noahmisch%40microsoft.com --- src/backend/storage/freespace/README | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/backend/storage/freespace/README b/src/backend/storage/freespace/README index dc2a63a137b..d68bd4c2aab 100644 --- a/src/backend/storage/freespace/README +++ b/src/backend/storage/freespace/README @@ -189,9 +189,25 @@ to propagate the new free-space info into the upper pages of the FSM tree. As a result when we write to the FSM we treat that as a hint and thus use MarkBufferDirtyHint() rather than MarkBufferDirty(). Every read here uses RBM_ZERO_ON_ERROR to bypass checksum mismatches and other verification -failures. We'd operate correctly without the full page images that -MarkBufferDirtyHint() provides, but they do decrease the chance of losing slot -knowledge to RBM_ZERO_ON_ERROR. +failures. + +That RBM_ZERO_ON_ERROR is a property of this directory, not of the FSM fork +itself. The files themselves are ordinary relation files, and plenty of code +outside freespace.c reads them and does verify checksums: +RelationCopyStorage(), which ALTER TABLE ... SET TABLESPACE runs over every +fork; the read stream in RelationCopyStorageUsingBuffer(), used by +CREATE DATABASE ... STRATEGY = wal_log; and the checksum verification in base +backups and in pg_checksums. The alternative would be all such code skipping +checksum validation of *_fsm files, and that may be the right call someday. +Today they do verify, so what we write here has to be valid. + +So the full page images MarkBufferDirtyHint() writes are not just an +optimization that reduces how often RBM_ZERO_ON_ERROR loses knowledge. +When checksums or wal_log_hints are enabled they are what keeps an FSM page +that reaches disk either checksum-valid or repairable by a later FPI. Do not +replace MarkBufferDirtyHint() with MarkBufferDirty() here on the grounds that +the FSM survives torn pages; it does, but the rest of the system is not +promised the same. Relation extension is not WAL-logged. Hence, after WAL replay, an on-disk FSM slot may indicate free space in PageIsNew() blocks that never reached disk.