0002-Use-AutoReadStream-for-btree-leaf-page-scans.txt

text/plain

Filename: 0002-Use-AutoReadStream-for-btree-leaf-page-scans.txt
Type: text/plain
Part: 1
Message: Re: index prefetching
From b3dee96bfaf31a4dff31b903ad05a7d5430d23e2 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sat, 12 Oct 2024 09:57:17 +1300
Subject: [PATCH 2/2] Use AutoReadStream for btree leaf page scans.

Leaf pages tend to be sequential on recently built/clustered indexes, so
there is an opportunity to do I/O combining and look-ahead.  It's hard
to do it 'precisely' with a ReadStream because they form a linked list.

XXX POC
---
 src/backend/access/nbtree/nbtpage.c   | 22 ++++++++++++++++++++++
 src/backend/access/nbtree/nbtree.c    |  5 +++++
 src/backend/access/nbtree/nbtsearch.c |  2 +-
 src/include/access/nbtree.h           |  5 +++++
 4 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c
index c79dd38ee18..e617bf108dd 100644
--- a/src/backend/access/nbtree/nbtpage.c
+++ b/src/backend/access/nbtree/nbtpage.c
@@ -856,6 +856,28 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
 	return buf;
 }
 
+/*
+ * Like _bt_getbuf(), but use auto_stream instead of reading directly.  This
+ * allows I/O to be combined if the blocks happen to be sequential on disk.
+ */
+Buffer
+_bt_getbuf_auto(AutoReadStream *auto_stream,
+				Relation rel,
+				BlockNumber blkno,
+				int access)
+{
+	Buffer		buf;
+
+	Assert(BlockNumberIsValid(blkno));
+
+	/* Read an existing block of the relation */
+	buf = auto_read_buffer(auto_stream, blkno);
+	_bt_lockbuf(rel, buf, access);
+	_bt_checkpage(rel, buf);
+
+	return buf;
+}
+
 /*
  *	_bt_allocbuf() -- Allocate a new block/page.
  *
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index fdff960c130..309147bea15 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -364,6 +364,9 @@ btbeginscan(Relation rel, int nkeys, int norderbys)
 	so->killedItems = NULL;		/* until needed */
 	so->numKilled = 0;
 
+	/* XXX defer until it looks like it's worth it? */
+	so->auto_stream = auto_read_stream_begin(NULL, rel, MAIN_FORKNUM);
+
 	/*
 	 * We don't know yet whether the scan will be index-only, so we do not
 	 * allocate the tuple workspace arrays until btrescan.  However, we set up
@@ -483,6 +486,8 @@ btendscan(IndexScanDesc scan)
 	so->markItemIndex = -1;
 	BTScanPosUnpinIfPinned(so->markPos);
 
+	auto_read_stream_end(so->auto_stream);
+
 	/* No need to invalidate positions, the RAM is about to be freed. */
 
 	/* Release storage */
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index d69798795b4..f15e05042b4 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -2408,7 +2408,7 @@ _bt_readnextpage(IndexScanDesc scan, BlockNumber blkno,
 		{
 			/* read blkno, but check for interrupts first */
 			CHECK_FOR_INTERRUPTS();
-			so->currPos.buf = _bt_getbuf(rel, blkno, BT_READ);
+			so->currPos.buf = _bt_getbuf_auto(so->auto_stream, rel, blkno, BT_READ);
 		}
 		else
 		{
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index e709d2e0afe..c4b82cd4466 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -22,6 +22,7 @@
 #include "catalog/pg_am_d.h"
 #include "catalog/pg_index.h"
 #include "lib/stringinfo.h"
+#include "storage/auto_read_stream.h"
 #include "storage/bufmgr.h"
 #include "storage/shm_toc.h"
 #include "utils/skipsupport.h"
@@ -1072,6 +1073,8 @@ typedef struct BTScanOpaqueData
 	int			numKilled;		/* number of currently stored items */
 	bool		dropPin;		/* drop leaf pin before btgettuple returns? */
 
+	AutoReadStream *auto_stream;
+
 	/*
 	 * If we are doing an index-only scan, these are the tuple storage
 	 * workspaces for the currPos and markPos respectively.  Each is of size
@@ -1273,6 +1276,8 @@ extern void _bt_metaversion(Relation rel, bool *heapkeyspace,
 							bool *allequalimage);
 extern void _bt_checkpage(Relation rel, Buffer buf);
 extern Buffer _bt_getbuf(Relation rel, BlockNumber blkno, int access);
+extern Buffer _bt_getbuf_auto(AutoReadStream *auto_stream,
+							  Relation rel, BlockNumber blkno, int access);
 extern Buffer _bt_allocbuf(Relation rel, Relation heaprel);
 extern Buffer _bt_relandgetbuf(Relation rel, Buffer obuf,
 							   BlockNumber blkno, int access);
-- 
2.39.5 (Apple Git-154)