0003-aio-Improve-read_stream.c-look-ahead-heuristics-A.txt

text/plain

Filename: 0003-aio-Improve-read_stream.c-look-ahead-heuristics-A.txt
Type: text/plain
Part: 2
Message: Re: index prefetching
From 7e862c651a9b023bc9b3363f59d17b8bc6a22089 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 21 Jul 2025 16:34:59 +1200
Subject: [PATCH 3/3] aio: Improve read_stream.c look-ahead heuristics A.

Previously we would reduce the look-ahead distance by one every time we
got a cache hit, which sometimes performed poorly with mixed hit/miss
patterns, especially if it was trapped at one.

The new rule prevents distance reduction while any IO is still running,
which allows for more concurrent I/O with some mixed hit/miss patterns
that the old algorithm didn't handle well.

XXX But you can always adjust
your test patterns with more hit between the misses to make it give up
I/O concurrency that you could have benefited from....
XXX But it also finds it way back to the fast path sooner...
XXX Highly experimental!

Suggested-by: AF
---
 src/backend/storage/aio/read_stream.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index f242b373b22..8961fad463f 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -343,22 +343,25 @@ read_stream_start_pending_read(ReadStream *stream)
 	/* Remember whether we need to wait before returning this buffer. */
 	if (!need_wait)
 	{
-		/* Look-ahead distance decays, no I/O necessary. */
-		if (stream->distance > 1)
+		/* Look-ahead distance decays when there is no I/O activity. */
+		if (stream->distance > 1 && stream->ios_in_progress == 0)
 			stream->distance--;
 	}
 	else
 	{
-		/*
-		 * Remember to call WaitReadBuffers() before returning head buffer.
-		 * Look-ahead distance will be adjusted after waiting.
-		 */
+		/* Remember to call WaitReadBuffers() before returning head buffer. */
 		stream->ios[io_index].buffer_index = buffer_index;
 		if (++stream->next_io_index == stream->max_ios)
 			stream->next_io_index = 0;
 		Assert(stream->ios_in_progress < stream->max_ios);
 		stream->ios_in_progress++;
 		stream->seq_blocknum = stream->pending_read_blocknum + nblocks;
+
+		/* Look-ahead distance grows by twice this read size. */
+		if (stream->max_pinned_buffers - stream->distance < nblocks * 2)
+			stream->distance = stream->max_pinned_buffers;
+		else
+			stream->distance += nblocks * 2;
 	}
 
 	/*
@@ -897,7 +900,6 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
 		stream->ios[stream->oldest_io_index].buffer_index == oldest_buffer_index)
 	{
 		int16		io_index = stream->oldest_io_index;
-		int32		distance;	/* wider temporary value, clamped below */
 
 		/* Sanity check that we still agree on the buffers. */
 		Assert(stream->ios[io_index].op.buffers ==
@@ -910,11 +912,6 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
 		if (++stream->oldest_io_index == stream->max_ios)
 			stream->oldest_io_index = 0;
 
-		/* Look-ahead distance ramps up rapidly after we do I/O. */
-		distance = stream->distance * 2;
-		distance = Min(distance, stream->max_pinned_buffers);
-		stream->distance = distance;
-
 		/*
 		 * If we've reached the first block of a sequential region we're
 		 * issuing advice for, cancel that until the next jump.  The kernel
-- 
2.39.5 (Apple Git-154)