From ee48966af6dcf6e2d18279faab17bbf8944f903e Mon Sep 17 00:00:00 2001
From: ChangAo Chen <cca5507@qq.com>
Date: Wed, 3 Jun 2026 19:01:17 +0800
Subject: [PATCH v1] Use streaming read I/O when enabling data checksums online

---
 src/backend/postmaster/datachecksum_state.c | 35 +++++++++++++++++++--
 1 file changed, 32 insertions(+), 3 deletions(-)

diff --git a/src/backend/postmaster/datachecksum_state.c b/src/backend/postmaster/datachecksum_state.c
index a49a31d1281..2b793b082d8 100644
--- a/src/backend/postmaster/datachecksum_state.c
+++ b/src/backend/postmaster/datachecksum_state.c
@@ -210,6 +210,7 @@
 #include "storage/lmgr.h"
 #include "storage/lwlock.h"
 #include "storage/procarray.h"
+#include "storage/read_stream.h"
 #include "storage/smgr.h"
 #include "storage/subsystems.h"
 #include "tcop/tcopprot.h"
@@ -654,6 +655,9 @@ ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrateg
 	BlockNumber numblocks = RelationGetNumberOfBlocksInFork(reln, forkNum);
 	char		activity[NAMEDATALEN * 2 + 128];
 	char	   *relns;
+	bool		success = true;
+	BlockRangeReadStreamPrivate	p;
+	ReadStream *stream;
 
 	relns = get_namespace_name(RelationGetNamespace(reln));
 
@@ -670,9 +674,26 @@ ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrateg
 	 * start, which is safe since new blocks are created with checksums set
 	 * already due to the state being "inprogress-on".
 	 */
+	p.current_blocknum = 0;
+	p.last_exclusive = numblocks;
+
+	/*
+	 * It is safe to use batchmode as block_range_read_stream_cb takes no
+	 * locks.
+	 */
+	stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE |
+										READ_STREAM_FULL |
+										READ_STREAM_USE_BATCHING,
+										strategy,
+										reln,
+										forkNum,
+										block_range_read_stream_cb,
+										&p,
+										0);
+
 	for (BlockNumber blknum = 0; blknum < numblocks; blknum++)
 	{
-		Buffer		buf = ReadBufferExtended(reln, forkNum, blknum, RBM_NORMAL, strategy);
+		Buffer		buf = read_stream_next_buffer(stream, NULL);
 
 		/* Need to get an exclusive lock to mark the buffer as dirty */
 		LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
@@ -715,7 +736,10 @@ ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrateg
 		LWLockRelease(DataChecksumsWorkerLock);
 
 		if (abort_requested)
-			return false;
+		{
+			success = false;
+			break;
+		}
 
 		/* update the block counter */
 		pgstat_progress_update_param(PROGRESS_DATACHECKSUMS_BLOCKS_DONE,
@@ -728,7 +752,12 @@ ProcessSingleRelationFork(Relation reln, ForkNumber forkNum, BufferAccessStrateg
 		vacuum_delay_point(false);
 	}
 
-	return true;
+	if (success)
+		Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
+
+	read_stream_end(stream);
+
+	return success;
 }
 
 /*
-- 
2.34.1

