From 9cf7db1410ce3ea6014296bdb304d2781a50b0e8 Mon Sep 17 00:00:00 2001
From: Yuhang Qiu <iamqyh@gmail.com>
Date: Wed, 26 Aug 2026 11:57:21 +0000
Subject: [PATCH v2 1/4] read_stream: Allow changing the buffer access strategy

Heap scans can replace their buffer access strategy during a rescan.
A read stream retained across such a rescan would keep references to
the old strategy, which may then be freed.

Add read_stream_set_strategy() to update an idle stream. It changes the
strategy used by subsequent reads and recomputes the limit on pinned
buffers.

Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/D1F99EB2-5A03-465F-A210-98F7DF256168@gmail.com
---
 src/backend/storage/aio/read_stream.c | 23 +++++++++++++++++++++++
 src/include/storage/read_stream.h     |  2 ++
 2 files changed, 25 insertions(+)

diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index e7dbbe03326..5b0b065be62 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -1428,6 +1428,29 @@ read_stream_clear_strategy(ReadStream *stream)
 		stream->ios[i].op.strategy = NULL;
 }
 
+/*
+ * Change the buffer access strategy used by an idle stream.
+ *
+ * The stream must first be reset so that no reads still refer to the old
+ * strategy.  The allocation made when the stream was created cannot grow, so
+ * the new limit remains capped by the existing queue capacity.  The caller
+ * must create a new stream to exceed that capacity.
+ */
+void
+read_stream_set_strategy(ReadStream *stream, BufferAccessStrategy strategy)
+{
+	Assert(stream->pinned_buffers == 0);
+	Assert(stream->ios_in_progress == 0);
+	Assert(stream->pending_read_nblocks == 0);
+
+	stream->max_pinned_buffers = Max(1,
+									 Min(stream->queue_size - 1,
+										 GetAccessStrategyPinLimit(strategy)));
+
+	for (int i = 0; i < stream->max_ios; ++i)
+		stream->ios[i].op.strategy = strategy;
+}
+
 /*
  * Reset a read stream by releasing any queued up buffers, allowing the stream
  * to be used again for different blocks.  This can be used to clear an
diff --git a/src/include/storage/read_stream.h b/src/include/storage/read_stream.h
index e2dcf1be50a..38a455bba12 100644
--- a/src/include/storage/read_stream.h
+++ b/src/include/storage/read_stream.h
@@ -103,6 +103,8 @@ extern ReadStream *read_stream_begin_smgr_relation(int flags,
 extern BlockNumber read_stream_pause(ReadStream *stream);
 extern void read_stream_resume(ReadStream *stream);
 extern void read_stream_clear_strategy(ReadStream *stream);
+extern void read_stream_set_strategy(ReadStream *stream,
+									 BufferAccessStrategy strategy);
 extern void read_stream_reset(ReadStream *stream);
 extern void read_stream_end(ReadStream *stream);
 extern void read_stream_enable_stats(ReadStream *stream, struct IOStats *stats);
-- 
2.43.7

