From a00a528be26b06d7de40d59381b7ee864f06f3a9 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Thu, 26 Mar 2020 22:34:29 +1300
Subject: [PATCH v6 6/8] Add ReadBufferPrefetched() (POC only)

Provide a potentially faster version of ReadBuffer(), or cases where you
have a PrefetchBufferResult.  We might be able to avoid an extra buffer
mapping table lookup.

NOT FOR COMMIT -- PROOF OF CONCEPT ONLY
---
 src/backend/storage/buffer/bufmgr.c | 49 +++++++++++++++++++++++++++++
 src/include/storage/bufmgr.h        |  3 ++
 2 files changed, 52 insertions(+)

diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 23f269ae74..f00c837f5a 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -597,6 +597,55 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
 	}
 }
 
+/*
+ * ReadBufferPrefetched -- read a buffer for which a prefetch was issued
+ *
+ * Like ReadBuffer(), but try to use the result of a recent PrefetchBuffer()
+ * call to avoid a buffer mapping table lookup.
+ */
+Buffer
+ReadBufferPrefetched(PrefetchBufferResult *prefetch,
+					 Relation reln,
+					 BlockNumber blockNum)
+{
+	/*
+	 * If PrefetchBuffer() found this block in a buffer recently, try to pin it
+	 * and then double check that it still holds the block we want.
+	 */
+	if (BufferIsValid(prefetch->recent_buffer))
+	{
+		BufferDesc *bufHdr;
+		BufferTag	tag;
+
+		if (BufferIsLocal(prefetch->recent_buffer))
+		{
+			bufHdr = GetBufferDescriptor(-prefetch->recent_buffer - 1);
+		}
+		else
+		{
+			bufHdr = GetBufferDescriptor(prefetch->recent_buffer - 1);
+			ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
+			if (!PinBuffer(bufHdr, NULL))
+			{
+				/* not valid, forget about it */
+				UnpinBuffer(bufHdr, true);
+				bufHdr = NULL;
+			}
+		}
+
+		/* If we managed to pin it or it's local, check tag. */
+		if (bufHdr)
+		{
+			RelationOpenSmgr(reln);
+			INIT_BUFFERTAG(tag, reln->rd_smgr->smgr_rnode.node, MAIN_FORKNUM,
+						   blockNum);
+			if (BUFFERTAGS_EQUAL(tag, bufHdr->tag))
+				return BufferDescriptorGetBuffer(bufHdr);
+		}
+	}
+
+	return ReadBuffer(reln, blockNum);
+}
 
 /*
  * ReadBuffer -- a shorthand for ReadBufferExtended, for reading from main
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index ee91b8fa26..8f6b19e6ac 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -183,6 +183,9 @@ extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
 extern Buffer ReadBufferWithoutRelcache(RelFileNode rnode,
 										ForkNumber forkNum, BlockNumber blockNum,
 										ReadBufferMode mode, BufferAccessStrategy strategy);
+extern Buffer ReadBufferPrefetched(PrefetchBufferResult *prefetch,
+								   Relation reln,
+								   BlockNumber blockNum);
 extern void ReleaseBuffer(Buffer buffer);
 extern void UnlockReleaseBuffer(Buffer buffer);
 extern void MarkBufferDirty(Buffer buffer);
-- 
2.20.1

