From ff1715e22200f4a6f22486f9ce6b851b94e4899a Mon Sep 17 00:00:00 2001
From: Jingtang Zhang <mrdrivingduck@gmail.com>
Date: Thu, 23 Jul 2026 00:13:23 +0800
Subject: [PATCH] vacuum: stop using stream ring after failsafe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Ensure future heap reads stop using VACUUM’s buffer access strategy
after wraparound failsafe activates, including when it activates during
a round of index vacuuming.
---
 src/backend/access/heap/vacuumlazy.c  |  7 +++++++
 src/backend/storage/aio/read_stream.c | 21 +++++++++++++++++++--
 src/include/storage/read_stream.h     |  2 ++
 3 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 39395aed0d5..9651b19b39a 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -1385,6 +1385,13 @@ lazy_scan_heap(LVRelState *vacrel)
 										 PROGRESS_VACUUM_PHASE_SCAN_HEAP);
 		}
 
+		/*
+		 * Switch the stream's strategy after any check, including one that
+		 * might have happened in lazy_vacuum().
+		 */
+		if (VacuumFailsafeActive)
+			read_stream_set_strategy(stream, NULL);
+
 		buf = read_stream_next_buffer(stream, &per_buffer_data);
 
 		/* The relation is exhausted. */
diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index a318539e56c..93e5227cb70 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -123,6 +123,7 @@ struct ReadStream
 	bool		batch_mode;		/* READ_STREAM_USE_BATCHING */
 	bool		advice_enabled;
 	bool		temporary;
+	BufferAccessStrategy strategy;
 
 	/* scan stats counters */
 	IOStats    *stats;
@@ -441,6 +442,7 @@ read_stream_start_pending_read(ReadStream *stream)
 	while (stream->initialized_buffers < buffer_index + nblocks)
 		stream->buffers[stream->initialized_buffers++] = InvalidBuffer;
 	requested_nblocks = nblocks;
+	stream->ios[io_index].op.strategy = stream->strategy;
 	need_wait = StartReadBuffers(&stream->ios[io_index].op,
 								 &stream->buffers[buffer_index],
 								 stream->pending_read_blocknum,
@@ -931,6 +933,7 @@ read_stream_begin_impl(int flags,
 	stream->seq_blocknum = InvalidBlockNumber;
 	stream->seq_until_processed = InvalidBlockNumber;
 	stream->temporary = SmgrIsTemp(smgr);
+	stream->strategy = strategy;
 	stream->distance_decay_holdoff = 0;
 
 	/*
@@ -962,7 +965,6 @@ read_stream_begin_impl(int flags,
 		stream->ios[i].op.smgr = smgr;
 		stream->ios[i].op.persistence = persistence;
 		stream->ios[i].op.forknum = forknum;
-		stream->ios[i].op.strategy = strategy;
 	}
 
 	return stream;
@@ -1098,6 +1100,7 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
 			 * held at the same time, the model used here is that the stream
 			 * holds only one, and the other now belongs to the caller.
 			 */
+			stream->ios[0].op.strategy = stream->strategy;
 			if (likely(!StartReadBuffer(&stream->ios[0].op,
 										&stream->buffers[oldest_buffer_index],
 										next_blocknum,
@@ -1376,10 +1379,24 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
 BlockNumber
 read_stream_next_block(ReadStream *stream, BufferAccessStrategy *strategy)
 {
-	*strategy = stream->ios[0].op.strategy;
+	*strategy = stream->strategy;
 	return read_stream_get_block(stream, NULL);
 }
 
+/*
+ * Change the buffer access strategy used for future reads.
+ *
+ * I/O operations may be in progress, so their ReadBuffersOperation must not
+ * be modified here.  The new strategy is installed when an idle operation is
+ * reused to start another read.  The pinned-buffer limit and queue capacity
+ * are fixed when the stream is created.
+ */
+void
+read_stream_set_strategy(ReadStream *stream, BufferAccessStrategy strategy)
+{
+	stream->strategy = strategy;
+}
+
 /*
  * Temporarily stop consuming block numbers from the block number callback.
  * If called inside the block number callback, its return value should be
diff --git a/src/include/storage/read_stream.h b/src/include/storage/read_stream.h
index 48995c6d534..6d43bfab3f8 100644
--- a/src/include/storage/read_stream.h
+++ b/src/include/storage/read_stream.h
@@ -100,6 +100,8 @@ extern ReadStream *read_stream_begin_smgr_relation(int flags,
 												   ReadStreamBlockNumberCB callback,
 												   void *callback_private_data,
 												   size_t per_buffer_data_size);
+extern void read_stream_set_strategy(ReadStream *stream,
+									 BufferAccessStrategy strategy);
 extern BlockNumber read_stream_pause(ReadStream *stream);
 extern void read_stream_resume(ReadStream *stream);
 extern void read_stream_reset(ReadStream *stream);
-- 
2.50.1 (Apple Git-155)

