From 65dde757ee4845747644221b9ce25273a82666b1 Mon Sep 17 00:00:00 2001
From: Michael Zhilin <mizhka@FreeBSD.org>
Date: Sun, 30 Mar 2025 01:30:37 +0300
Subject: [PATCH v1 1/9] Avoid useless prefetches in case of recent FPI WAL
 records

If block is logged into WAL with full page, then the startup process reads
full page image from WAL stream and load them into shared buffer by
XLogReadBufferForRedoExtended. Every further WAL records related to
particular blocks should be skipped by XLogPrefetcher.

Author: Michael Zhilin <mizhka@FreeBSD.org>
Discussion: https://www.postgresql.org/message-id/9bdb428a-fc8e-4801-8fff-1ad0bc6fa76b%40postgrespro.ru
---
 src/backend/access/transam/xlogprefetcher.c | 22 ++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index 288cdbd34c4..41c1caf45e1 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -54,7 +54,7 @@
 
 /*
  * To detect repeated access to the same block and skip useless extra system
- * calls, we remember a small window of recently prefetched blocks.
+ * calls, we remember a small window of recently prefetched / FPW blocks.
  */
 #define XLOGPREFETCHER_SEQ_WINDOW_SIZE 4
 
@@ -679,6 +679,26 @@ XLogPrefetcherNextBlock(uintptr_t pgsr_private, XLogRecPtr *lsn)
 			if (block->has_image)
 			{
 				XLogPrefetchIncrement(&SharedStats->skip_fpw);
+
+				/*
+				 * A full page image is copied to shared buffer during replay.
+				 * Every next WAL records related to particular block doesn't
+				 * require prefetching of shared buffer.
+				 */
+				for (int i = 0; i < XLOGPREFETCHER_SEQ_WINDOW_SIZE; ++i)
+				{
+					if (block->blkno == prefetcher->recent_block[i] &&
+						RelFileLocatorEquals(block->rlocator, prefetcher->recent_rlocator[i]))
+					{
+						return LRQ_NEXT_NO_IO;
+					}
+				}
+
+				prefetcher->recent_rlocator[prefetcher->recent_idx] = block->rlocator;
+				prefetcher->recent_block[prefetcher->recent_idx] = block->blkno;
+				prefetcher->recent_idx =
+					(prefetcher->recent_idx + 1) % XLOGPREFETCHER_SEQ_WINDOW_SIZE;
+
 				return LRQ_NEXT_NO_IO;
 			}
 
-- 
2.55.0

