pg.ddx.io  pgsql-hackers@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Alexey Makhmutov <a.makhmutov@postgrespro.ru>
To: Andrey Borodin <x4mmm@yandex-team.ru>
Cc: pgsql-hackers@postgresql.org
Subject: Re: Two issues leading to discrepancies in FSM data on the standby server
Date: Mon, 6 Apr 2026 17:26:01 +0300
Message-ID: <60b79f39-69e5-4c73-a708-6ef1fd5e7980@postgrespro.ru> (raw)
In-Reply-To: <6A6138F4-8D6F-463D-9ECC-38C0881308FE@yandex-team.ru>
References: <596c4f1c-f966-4512-b9c9-dd8fbcaf0928@postgrespro.ru>
	<6A6138F4-8D6F-463D-9ECC-38C0881308FE@yandex-team.ru>

Hi Andrey!

Thank you for the attention to this patch!

> Originally in e981653 was used MarkBufferDirty() but 96ef3b8 flipped to MarkBufferDirtyHint().
> Neither of these commits provided a comment on why this version was chosen. I think if we fix it we must comment things.

I think that reason of change in 96ef3b8 (changing of 'MarkBufferDirty' 
to 'MarkBufferDirtyHint') may be described in the next commit (9df56f6), 
during the README update:
 > New WAL records cannot be written during recovery, so hint bits set 
during recovery must not dirty the page if the buffer is not already 
dirty, when checksums are enabled.  Systems in Hot-Standby mode may 
benefit from hint bits being set, but with checksums enabled, a page 
cannot be dirtied after setting a hint bit (due to the torn page risk). 
So, it must wait for full-page images containing the hint bit updates to 
arrive from the master.

So, it seems logical, that any changes to the data not protected by the 
WAL (which includes VM and FSM as well) should use MarkBufferDirtyHint, 
which does not set dirty flag during recovery. However, as FSM blocks 
could be just zeroed in case of checksums mismatch, so I think it's 
perfectly fine to use regular MarkBufferDirty here.

I've updated the first patch by adding the comment with explanation of 
the reason for using MarkBufferDirty instead of MarkBufferDirtyHint here.

As for the second issue and the patch - it seems to be resolved in the 
current master by a881cc9, which removed the entire 'heap_xlog_visible' 
method, as all-visibility information is now sent with the 
XLOG_HEAP2_PRUNE_VACUUM_CLEANUP message and its handler already uses 
PageGetHeapFreeSpace. The problem is still relevant for the pre-19 
versions, so I will probably move it to the separate thread in bugs.

Thanks,
Alexey

Attachments:

0001-Mark-modified-FSM-buffer-as-dirty-during-recovery.patch (text/x-patch, 4.0K) download From 205e050b87870450084a55b4f42629ef27668444 Mon Sep 17 00:00:00 2001 From: Alexey Makhmutov <a.makhmutov@postgrespro.ru> Date: Mon, 16 Mar 2026 13:32:45 +0300 Subject: [PATCH] Mark modified FSM buffer as dirty during recovery. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XLogRecordPageWithFreeSpace function updates freespace map (FSM) data while replaying data-level WAL records during the recovery. If FSM block is updated, then it need to be marked as modified and currently this task is performed using MarkBufferDirtyHint call (as in all other cases for modifying of FSM data). However, in recovery context this function will actually do nothing if checksums are enabled. It’s assumed that page should not be dirtied during recovery while modifying hints to protect from torn pages as no new WAL data could be generated at this point to store FPI. Such logic seems to be not fully aligned with the FSM case, as its blocks could be just zeroed if checksum mismatch is detected. Currently changes to a FSM block could be lost if each change to the particular FSM block occurs rarely enough to allow its eviction from the cache. To persist the change the modification need to be performed while FSM block is still kept in buffers and marked as dirty after receiving its FPI. If block was already cleaned, then the change won’t be persisted, so stored FSM blocks may remain in an obsolete state. If large number of discrepancies between the data in leaf FSM blocks and actual data blocks is accumulated on the replica server side, then this could cause significant delays for insert operations after switchover. Such insert operation may need to visit many data blocks marked as having enough space in FSM only to discover that this information is incorrect and FSM records need to be fixed. In a heavily trafficked insert-only table with many concurrent clients performing inserts this has been observed to cause several second stalls, causing visible application malfunction. The desire to avoid such cases was the reason behind the commit ab7dbd681, which introduced an update of FSM data during the heap_xlog_visible invocation. However, an update to the FSM data on the standby side could be lost due to missing 'dirty' flag, so there is still a possibility that a large number of FSM records will contain incorrect data. Note, that having a zeroed FSM page in such case (as result of checksum mismatch) is more preferable, as zero value will be interpreted as indication of full data blocks and inserter will be just routed to the next FSM block or to the end of the table. Given that FSM is ready to handle torn page writes and XLogRecordPageWithFreeSpace is called only during the recovery, there seems to be no reason to use MarkBufferDirtyHint here instead of a regular MarkBufferDirty call. --- src/backend/storage/freespace/freespace.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/storage/freespace/freespace.c b/src/backend/storage/freespace/freespace.c index 40d67a96178..1631bc79872 100644 --- a/src/backend/storage/freespace/freespace.c +++ b/src/backend/storage/freespace/freespace.c @@ -231,8 +231,18 @@ XLogRecordPageWithFreeSpace(RelFileLocator rlocator, BlockNumber heapBlk, if (PageIsNew(page)) PageInit(page, BLCKSZ, 0); + /* + * Changes to FSM are usually marked as changed using MarkBufferDirtyHint, + * however during recovery it does nothing if checksums are enabled. It is + * assumed that page should not be dirtied during recovery while modifying + * hints to protect from torn pages as no new WAL data could be generated + * at this point to store FPI. This is not relevant for the FSM case, as + * its blocks are just zeroed in case of checksum mismatch. So, we need to + * use regular MarkBufferDirty here to actually mark FSM block as modified + * during the recovery, otherwise changes to the FSM may be just lost. + */ if (fsm_set_avail(page, slot, new_cat)) - MarkBufferDirtyHint(buf, false); + MarkBufferDirty(buf); UnlockReleaseBuffer(buf); } -- 2.53.0

view thread (21+ messages)  latest in thread

Message-ID: <60b79f39-69e5-4c73-a708-6ef1fd5e7980@postgrespro.ru>
Permalink:  ../60b79f39-69e5-4c73-a708-6ef1fd5e7980@postgrespro.ru/
Also on:    postgresql.org/message-id/60b79f39-69e5-4c73-a708-6ef1fd5e7980@postgrespro.ru

 ·  · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-hackers@postgresql.org
  Cc: a.makhmutov@postgrespro.ru, x4mmm@yandex-team.ru
  Subject: Re: Two issues leading to discrepancies in FSM data on the standby server
  In-Reply-To: <60b79f39-69e5-4c73-a708-6ef1fd5e7980@postgrespro.ru>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox