0002-aio-Add-READ_STREAM_RESET_CONTINUE-flag.txt

text/plain

Filename: 0002-aio-Add-READ_STREAM_RESET_CONTINUE-flag.txt
Type: text/plain
Part: 1
Message: Re: index prefetching
From 5c3cf2018845093041dcf23bd6e8ae90b5c5906a Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 21 Jul 2025 14:38:32 +1200
Subject: [PATCH 2/3] aio: Add READ_STREAM_RESET_CONTINUE flag.

For users that sometimes run out of block numbers temporarily but then
later want to continue, provide a way to reset the stream and continue
without forgetting the internal look-ahead distance.

This is done as a bitmask, just in case we think of more reasons for
fine-grained control of what is reset or not in the future.

XXX Name debatable; is it better to use a 'high level' concept like
'continuing an interrupted stream', or a lower level concept explicitly
referring to what is reset or not?

XXX Where existing users pass 0 or the new flag not thought about very
hard

Discussion: https://postgr.es/m/CA%2BhUKG%2BWWr4-8TYemyU%3DucQsNe6bUBN_Sq3mCnBoBtxaJ9w3ug%40mail.gmail.com
---
 src/backend/access/gist/gistvacuum.c  |  2 +-
 src/backend/access/heap/heapam.c      |  4 ++--
 src/backend/access/nbtree/nbtree.c    |  2 +-
 src/backend/access/spgist/spgvacuum.c |  2 +-
 src/backend/storage/aio/read_stream.c | 13 +++++++++----
 src/include/storage/read_stream.h     | 14 +++++++++++++-
 6 files changed, 27 insertions(+), 10 deletions(-)

diff --git a/src/backend/access/gist/gistvacuum.c b/src/backend/access/gist/gistvacuum.c
index dca236b6e57..45044e3cc84 100644
--- a/src/backend/access/gist/gistvacuum.c
+++ b/src/backend/access/gist/gistvacuum.c
@@ -260,7 +260,7 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		 * InvalidBuffer, the read stream API won't invoke our callback again
 		 * until the stream has been reset.
 		 */
-		read_stream_reset(stream);
+		read_stream_reset(stream, READ_STREAM_RESET_CONTINUE);
 	}
 
 	read_stream_end(stream);
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 0dcd6ee817e..1ffc4a872db 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -667,7 +667,7 @@ heap_fetch_next_buffer(HeapScanDesc scan, ScanDirection dir)
 	if (unlikely(scan->rs_dir != dir))
 	{
 		scan->rs_prefetch_block = scan->rs_cblock;
-		read_stream_reset(scan->rs_read_stream);
+		read_stream_reset(scan->rs_read_stream, 0);
 	}
 
 	scan->rs_dir = dir;
@@ -1284,7 +1284,7 @@ heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params,
 	 * in initscan().
 	 */
 	if (scan->rs_read_stream)
-		read_stream_reset(scan->rs_read_stream);
+		read_stream_reset(scan->rs_read_stream, 0);
 
 	/*
 	 * reinitialize scan descriptor
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index fdff960c130..596df227c20 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -1318,7 +1318,7 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
 		 * InvalidBuffer, the read stream API won't invoke our callback again
 		 * until the stream has been reset.
 		 */
-		read_stream_reset(stream);
+		read_stream_reset(stream, READ_STREAM_RESET_CONTINUE);
 	}
 
 	read_stream_end(stream);
diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c
index 2678f7ab782..c4e4a89680e 100644
--- a/src/backend/access/spgist/spgvacuum.c
+++ b/src/backend/access/spgist/spgvacuum.c
@@ -885,7 +885,7 @@ spgvacuumscan(spgBulkDeleteState *bds)
 		 * InvalidBuffer, the read stream API won't invoke our callback again
 		 * until the stream has been reset.
 		 */
-		read_stream_reset(stream);
+		read_stream_reset(stream, READ_STREAM_RESET_CONTINUE);
 	}
 
 	read_stream_end(stream);
diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index 5de6f83c253..f242b373b22 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -1011,9 +1011,13 @@ read_stream_next_block(ReadStream *stream, BufferAccessStrategy *strategy)
  * to be used again for different blocks.  This can be used to clear an
  * end-of-stream condition and start again, or to throw away blocks that were
  * speculatively read and read some different blocks instead.
+ *
+ * READ_STREAM_RESET_CONTINUE can be pass to flags to indicate that a stream
+ * was temporarily interrupted but internal look-ahead distance heuristics
+ * should not be reset, because a similar access pattern is expected.
  */
 void
-read_stream_reset(ReadStream *stream)
+read_stream_reset(ReadStream *stream, int flags)
 {
 	int16		index;
 	Buffer		buffer;
@@ -1050,8 +1054,9 @@ read_stream_reset(ReadStream *stream)
 	Assert(stream->pinned_buffers == 0);
 	Assert(stream->ios_in_progress == 0);
 
-	/* Start off assuming data is cached. */
-	stream->distance = 1;
+	/* Start off like a newly initialized stream, unless asked not to. */
+	if ((flags & READ_STREAM_RESET_CONTINUE) == 0)
+		stream->distance = 1;
 	stream->end_of_stream = false;
 }
 
@@ -1061,6 +1066,6 @@ read_stream_reset(ReadStream *stream)
 void
 read_stream_end(ReadStream *stream)
 {
-	read_stream_reset(stream);
+	read_stream_reset(stream, 0);
 	pfree(stream);
 }
diff --git a/src/include/storage/read_stream.h b/src/include/storage/read_stream.h
index 9b0d65161d0..90ec278117f 100644
--- a/src/include/storage/read_stream.h
+++ b/src/include/storage/read_stream.h
@@ -17,6 +17,8 @@
 #include "storage/bufmgr.h"
 #include "storage/smgr.h"
 
+/* Flags controlling stream initialization. */
+
 /* Default tuning, reasonable for many users. */
 #define READ_STREAM_DEFAULT 0x00
 
@@ -42,6 +44,16 @@
  */
 #define READ_STREAM_FULL 0x04
 
+/* Flags controlling read_stream_reset(). */
+
+/*
+ * If the callback reports end-of-stream or higher levels decide to abandon
+ * blocks that it generated speculatively, the stream can be reset and allowed
+ * to try to fetch blocks again without forgetting internal heuristics by
+ * passing this flag.
+ */
+#define READ_STREAM_RESET_CONTINUE 0x01
+
 /* ---
  * Opt-in to using AIO batchmode.
  *
@@ -99,7 +111,7 @@ 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_reset(ReadStream *stream);
+extern void read_stream_reset(ReadStream *stream, int flags);
 extern void read_stream_end(ReadStream *stream);
 
 #endif							/* READ_STREAM_H */
-- 
2.39.5 (Apple Git-154)