From 6c6178d9c19b51711cf6f3ccd7e18809fb955cce Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Tue, 19 Nov 2024 12:08:38 -0500
Subject: [PATCH v2 06/15] bufmgr: Separate slow/fast path of LockBufHdr

This mainly is beneficial for some upcoming patches that use LockBufHdr() in
reasonably common paths. But I do see a very small improvement when scanning a
large table fully resident in the kernel page cache.

Author:
Reviewed-by:
Discussion: https://postgr.es/m/
Backpatch:
---
 src/include/storage/buf_internals.h | 33 ++++++++++++++++++++++++++++-
 src/backend/storage/buffer/bufmgr.c |  8 ++++---
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index eda6c699212..e2ac85c8d97 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -355,7 +355,38 @@ BufferDescriptorGetContentLock(const BufferDesc *bdesc)
  * Functions for acquiring/releasing a shared buffer header's spinlock.  Do
  * not apply these to local buffers!
  */
-extern uint32 LockBufHdr(BufferDesc *desc);
+extern uint32 LockBufHdrSlow(BufferDesc *desc);
+
+/*
+ * Lock buffer header - set BM_LOCKED in buffer state.
+ *
+ * Implemented as a static inline in the header due to freelist.c using it in
+ * a reasonably common path.
+ */
+static inline uint32
+LockBufHdr(BufferDesc *desc)
+{
+	uint32		old_buf_state;
+
+	Assert(!BufferIsLocal(BufferDescriptorGetBuffer(desc)));
+
+	/* fast path, intended to be inlined into calling functions*/
+
+	/* set BM_LOCKED flag */
+	old_buf_state = pg_atomic_fetch_or_u32(&desc->state, BM_LOCKED);
+	if (likely(!(old_buf_state & BM_LOCKED)))
+		return old_buf_state | BM_LOCKED;
+
+	/*
+	 * The overhead of the spin delay code and the retry loop itself would be
+	 * noticeable due to the buffer header lock being taken very
+	 * frequently. Therefore it is moved into a separate function marked
+	 * pg_noinline.
+	 */
+
+	/* slow path with loop etc, not intended to be inlined */
+	return LockBufHdrSlow(desc);
+}
 
 static inline void
 UnlockBufHdr(BufferDesc *desc, uint32 buf_state)
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index f56f7f9f441..6ad686d9820 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -5796,10 +5796,12 @@ rlocator_comparator(const void *p1, const void *p2)
 }
 
 /*
- * Lock buffer header - set BM_LOCKED in buffer state.
+ * Slow path helper for LockBufHdr().
+ *
+ * See comment in LockBufHdr() for the reason this is moved out of line.
  */
-uint32
-LockBufHdr(BufferDesc *desc)
+pg_noinline uint32
+LockBufHdrSlow(BufferDesc *desc)
 {
 	SpinDelayStatus delayStatus;
 	uint32		old_buf_state;
-- 
2.45.2.746.g06e570c0df.dirty

