0001-Add-AutoReadStream.txt

text/plain

Filename: 0001-Add-AutoReadStream.txt
Type: text/plain
Part: 0
Message: Re: index prefetching
From 2eeec2f0488a74fa1f3cfdaeef36c5f9926d417c Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sat, 12 Oct 2024 09:57:01 +1300
Subject: [PATCH 1/2] Add AutoReadStream.

Provide auto_read_buffer() as a drop-in replacement for ReadBuffer().
As long as the caller requests sequential pages, they come from a
ReadStream that predicts that it'll keep doing that.  Otherwise it falls
back to regular ReadBuffer().

XXX experimental
---
 src/backend/storage/aio/Makefile           |  1 +
 src/backend/storage/aio/auto_read_stream.c | 92 ++++++++++++++++++++++
 src/backend/storage/aio/meson.build        |  1 +
 src/include/storage/auto_read_stream.h     | 16 ++++
 src/tools/pgindent/typedefs.list           |  1 +
 5 files changed, 111 insertions(+)
 create mode 100644 src/backend/storage/aio/auto_read_stream.c
 create mode 100644 src/include/storage/auto_read_stream.h

diff --git a/src/backend/storage/aio/Makefile b/src/backend/storage/aio/Makefile
index 3f2469cc399..7270f486109 100644
--- a/src/backend/storage/aio/Makefile
+++ b/src/backend/storage/aio/Makefile
@@ -15,6 +15,7 @@ OBJS = \
 	aio_init.o \
 	aio_io.o \
 	aio_target.o \
+	auto_read_stream.o \
 	method_io_uring.o \
 	method_sync.o \
 	method_worker.o \
diff --git a/src/backend/storage/aio/auto_read_stream.c b/src/backend/storage/aio/auto_read_stream.c
new file mode 100644
index 00000000000..a8dac066bd6
--- /dev/null
+++ b/src/backend/storage/aio/auto_read_stream.c
@@ -0,0 +1,92 @@
+#include "postgres.h"
+#include "storage/auto_read_stream.h"
+#include "storage/bufmgr.h"
+#include "storage/read_stream.h"
+
+struct AutoReadStream
+{
+	ReadStream *stream;
+	Relation	rel;
+	BlockNumber next;
+	BlockNumber last;
+};
+
+static BlockNumber
+auto_read_stream_cb(ReadStream *stream,
+					void *callback_private_data,
+					void *per_buffer_data)
+{
+	AutoReadStream *auto_stream = callback_private_data;
+	BlockNumber next = auto_stream->next;
+
+	if (next == InvalidBlockNumber)
+		return InvalidBuffer;
+	auto_stream->next = Min(auto_stream->next + 1, auto_stream->last);
+
+	return next;
+}
+
+AutoReadStream *
+auto_read_stream_begin(BufferAccessStrategy strategy,
+					   Relation rel,
+					   ForkNumber forknum)
+{
+	AutoReadStream *auto_stream;
+
+	auto_stream = palloc(sizeof(*auto_stream));
+	auto_stream->rel = rel;
+	auto_stream->next = InvalidBlockNumber;
+	auto_stream->last = InvalidBlockNumber;
+	auto_stream->stream = read_stream_begin_relation(0,
+													 strategy,
+													 rel,
+													 forknum,
+													 auto_read_stream_cb,
+													 auto_stream,
+													 0);
+
+	return auto_stream;
+}
+
+void
+auto_read_stream_end(AutoReadStream *auto_stream)
+{
+	read_stream_end(auto_stream->stream);
+	pfree(auto_stream);
+}
+
+Buffer
+auto_read_buffer(AutoReadStream *auto_stream, BlockNumber blocknum)
+{
+
+	if (auto_stream->last != InvalidBlockNumber)
+	{
+		Buffer		buffer = read_stream_next_buffer(auto_stream->stream, NULL);
+
+		/* Did the stream guess right? */
+		if (buffer != InvalidBlockNumber)
+		{
+			if (BufferGetBlockNumber(buffer) == blocknum)
+				return buffer;
+			ReleaseBuffer(buffer);
+		}
+	}
+
+	/* Figure out the highest block number if we haven't already. */
+	if (auto_stream->last == InvalidBlockNumber)
+	{
+		BlockNumber nblocks;
+
+		nblocks = RelationGetNumberOfBlocks(auto_stream->rel);
+		if (nblocks > 0)
+			auto_stream->last = nblocks - 1;
+	}
+
+	/* Take a guess at the next block. */
+	if (auto_stream->last != InvalidBlockNumber &&
+		auto_stream->last >= blocknum + 1)
+		auto_stream->next = blocknum + 1;
+	read_stream_reset(auto_stream->stream);
+
+	return ReadBuffer(auto_stream->rel, blocknum);
+}
diff --git a/src/backend/storage/aio/meson.build b/src/backend/storage/aio/meson.build
index da6df2d3654..07c2fb2e42c 100644
--- a/src/backend/storage/aio/meson.build
+++ b/src/backend/storage/aio/meson.build
@@ -7,6 +7,7 @@ backend_sources += files(
   'aio_init.c',
   'aio_io.c',
   'aio_target.c',
+  'auto_read_stream.c',
   'method_io_uring.c',
   'method_sync.c',
   'method_worker.c',
diff --git a/src/include/storage/auto_read_stream.h b/src/include/storage/auto_read_stream.h
new file mode 100644
index 00000000000..96d4a9ac726
--- /dev/null
+++ b/src/include/storage/auto_read_stream.h
@@ -0,0 +1,16 @@
+#ifndef AUTO_READ_STREAM_H
+#define AUTO_READ_STREAM_H
+
+#include "storage/bufmgr.h"
+
+struct AutoReadStream;
+typedef struct AutoReadStream AutoReadStream;
+
+extern AutoReadStream *auto_read_stream_begin(BufferAccessStrategy strategy,
+											  Relation rel,
+											  ForkNumber forknum);
+extern void auto_read_stream_end(AutoReadStream *auto_stream);
+extern Buffer auto_read_buffer(AutoReadStream *auto_stream,
+							   BlockNumber blocknum);
+
+#endif
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index e6f2e93b2d6..43f206e30ed 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -173,6 +173,7 @@ AuthRequest
 AuthToken
 AutoPrewarmReadStreamData
 AutoPrewarmSharedState
+AutoReadStream
 AutoVacOpts
 AutoVacuumShmemStruct
 AutoVacuumWorkItem
-- 
2.39.5 (Apple Git-154)