From ffe876140536c89e2d80df1b9711e0970472b3d8 Mon Sep 17 00:00:00 2001
From: Nazir Bilal Yavuz <byavuz81@gmail.com>
Date: Wed, 27 Nov 2024 16:53:58 +0300
Subject: [PATCH v5 2/2] Count free buffers at the start of the autoprewarm

Streamified version of the autoprewarm code may do unnecessary I/O and
buffer evicting. To prevent it at least a little bit, count the number
of free buffers in the buffer pool and queue buffers up to that number
in the callback function of the autoprewarm.
---
 contrib/pg_prewarm/autoprewarm.c      |  4 ++--
 src/backend/storage/buffer/freelist.c | 17 +++++++++++++++++
 src/include/storage/buf_internals.h   |  1 +
 3 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/contrib/pg_prewarm/autoprewarm.c b/contrib/pg_prewarm/autoprewarm.c
index 71c4f8a5920..42f2bc88fa9 100644
--- a/contrib/pg_prewarm/autoprewarm.c
+++ b/contrib/pg_prewarm/autoprewarm.c
@@ -516,13 +516,13 @@ autoprewarm_database_main(Datum main_arg)
 	pos = apw_state->prewarm_start_idx;
 
 	p.block_info = block_info;
-	p.max_pos = apw_state->prewarm_stop_idx;
+	p.max_pos = Min(apw_state->prewarm_stop_idx, pos + get_number_of_free_buffers());
 
 	/*
 	 * Loop until we run out of blocks to prewarm or until we run out of free
 	 * buffers.
 	 */
-	for (; pos < apw_state->prewarm_stop_idx; pos++)
+	for (; pos < p.max_pos; pos++)
 	{
 		BlockInfoRecord *blk = &block_info[pos];
 		Buffer		buf;
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index 336715b6c63..9f26e940426 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -180,6 +180,23 @@ have_free_buffer(void)
 		return false;
 }
 
+/*
+ * get_number_of_free_buffers -- a lockless way to get the number of free
+ *								 buffers in buffer pool.
+ *
+ * Note that result continuously changes as free buffers are moved out by other
+ * operations.
+ */
+int
+get_number_of_free_buffers(void)
+{
+	/* All the buffers are free. */
+	if (StrategyControl->firstFreeBuffer < 0)
+		return NBuffers;
+	else
+		return StrategyControl->lastFreeBuffer - StrategyControl->firstFreeBuffer;
+}
+
 /*
  * StrategyGetBuffer
  *
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 9327f60c44c..197d2db49f5 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -445,6 +445,7 @@ extern void StrategyNotifyBgWriter(int bgwprocno);
 extern Size StrategyShmemSize(void);
 extern void StrategyInitialize(bool init);
 extern bool have_free_buffer(void);
+extern int	get_number_of_free_buffers(void);
 
 /* buf_table.c */
 extern Size BufTableShmemSize(int size);
-- 
2.43.0

