From 6f2bd62a520dbf9249879afa174faf4ae063818d Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 14 Sep 2020 23:20:55 +1200
Subject: [PATCH v17 09/10] Provide ReadRecentBuffer() to re-pin buffers by ID.

If you know the buffer ID that recently held a given block you would
like to pin, this function will check if it's still there and pin it if
the tag hasn't changed.  Otherwise, you'll need to use the regular
ReadBuffer() function.  This will be used by later patches to avoid
double lookup in some cases where it's very likely not to have moved.

Discussion: https://postgr.es/m/CA+hUKGJ4VJN8ttxScUFM8dOKX0BrBiboo5uz1cq=AovOddfHpA@mail.gmail.com
---
 src/backend/storage/buffer/bufmgr.c | 43 +++++++++++++++++++++++++++++
 src/include/storage/bufmgr.h        |  2 ++
 2 files changed, 45 insertions(+)

diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 852138f9c9..0e5f92d92b 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -610,6 +610,49 @@ PrefetchBuffer(Relation reln, ForkNumber forkNum, BlockNumber blockNum)
 	}
 }
 
+/*
+ * ReadRecentBuffer -- try to refind a buffer that we suspect holds a given
+ *		block
+ *
+ * Return true if the buffer is valid, has the correct tag, and we managed
+ * to pin it.
+ */
+bool
+ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum, BlockNumber blockNum,
+				 Buffer recent_buffer)
+{
+	BufferDesc *bufHdr;
+	BufferTag	tag;
+
+	Assert(BufferIsValid(recent_buffer));
+
+	/* Look up the header by index, and try to pin if shared. */
+	if (BufferIsLocal(recent_buffer))
+		bufHdr = GetBufferDescriptor(-recent_buffer - 1);
+	else
+	{
+		bufHdr = GetBufferDescriptor(recent_buffer - 1);
+		ResourceOwnerEnlargeBuffers(CurrentResourceOwner);
+		if (!PinBuffer(bufHdr, NULL))
+		{
+			/* Not valid, couldn't pin it. */
+			UnpinBuffer(bufHdr, true);
+
+			return false;
+		}
+	}
+
+	/* Does the tag still match? */
+	INIT_BUFFERTAG(tag, rnode, forkNum, blockNum);
+	if (BUFFERTAGS_EQUAL(tag, bufHdr->tag))
+		return true;
+
+	/* Too late!  Unpin if shared. */
+	if (!BufferIsLocal(recent_buffer))
+		UnpinBuffer(bufHdr, true);
+
+	return false;
+}
 
 /*
  * ReadBuffer -- a shorthand for ReadBufferExtended, for reading from main
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index fb00fda6a7..aa64fb42ec 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -176,6 +176,8 @@ extern PrefetchBufferResult PrefetchSharedBuffer(struct SMgrRelationData *smgr_r
 												 BlockNumber blockNum);
 extern PrefetchBufferResult PrefetchBuffer(Relation reln, ForkNumber forkNum,
 										   BlockNumber blockNum);
+extern bool ReadRecentBuffer(RelFileNode rnode, ForkNumber forkNum,
+							 BlockNumber blockNum, Buffer recent_buffer);
 extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
 extern Buffer ReadBufferExtended(Relation reln, ForkNumber forkNum,
 								 BlockNumber blockNum, ReadBufferMode mode,
-- 
2.30.1

