From 0d52ad50c8c5d96d87c7e9ee37e9e4122b6196eb Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu, 2 Apr 2026 00:44:02 +0300
Subject: [PATCH v20260405 13/15] Convert buffer manager to the new API

---
 src/backend/storage/buffer/buf_init.c  | 149 ++++++++++---------------
 src/backend/storage/buffer/buf_table.c |  54 +++++----
 src/backend/storage/buffer/freelist.c  |  93 +++++----------
 src/backend/storage/ipc/ipci.c         |   3 -
 src/include/storage/buf_internals.h    |   5 -
 src/include/storage/bufmgr.h           |   4 -
 src/include/storage/subsystemlist.h    |   3 +
 7 files changed, 124 insertions(+), 187 deletions(-)

diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index c0c223b2e32..1407c930c56 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -18,6 +18,8 @@
 #include "storage/buf_internals.h"
 #include "storage/bufmgr.h"
 #include "storage/proclist.h"
+#include "storage/shmem.h"
+#include "storage/subsystems.h"
 
 BufferDescPadded *BufferDescriptors;
 char	   *BufferBlocks;
@@ -25,6 +27,15 @@ ConditionVariableMinimallyPadded *BufferIOCVArray;
 WritebackContext BackendWritebackContext;
 CkptSortItem *CkptBufferIds;
 
+static void BufferManagerShmemRequest(void *arg);
+static void BufferManagerShmemInit(void *arg);
+static void BufferManagerShmemAttach(void *arg);
+
+const ShmemCallbacks BufferManagerShmemCallbacks = {
+	.request_fn = BufferManagerShmemRequest,
+	.init_fn = BufferManagerShmemInit,
+	.attach_fn = BufferManagerShmemAttach,
+};
 
 /*
  * Data Structures:
@@ -60,37 +71,31 @@ CkptSortItem *CkptBufferIds;
 
 
 /*
- * Initialize shared buffer pool
- *
- * This is called once during shared-memory initialization (either in the
- * postmaster, or in a standalone backend).
+ * Register shared memory area for the buffer pool.
  */
-void
-BufferManagerShmemInit(void)
+static void
+BufferManagerShmemRequest(void *arg)
 {
-	bool		foundBufs,
-				foundDescs,
-				foundIOCV,
-				foundBufCkpt;
-
+	ShmemRequestStruct(.name = "Buffer Descriptors",
+					   .size = NBuffers * sizeof(BufferDescPadded),
 	/* Align descriptors to a cacheline boundary. */
-	BufferDescriptors = (BufferDescPadded *)
-		ShmemInitStruct("Buffer Descriptors",
-						NBuffers * sizeof(BufferDescPadded),
-						&foundDescs);
+					   .alignment = PG_CACHE_LINE_SIZE,
+					   .ptr = (void **) &BufferDescriptors,
+		);
 
+	ShmemRequestStruct(.name = "Buffer Blocks",
+					   .size = NBuffers * (Size) BLCKSZ,
 	/* Align buffer pool on IO page size boundary. */
-	BufferBlocks = (char *)
-		TYPEALIGN(PG_IO_ALIGN_SIZE,
-				  ShmemInitStruct("Buffer Blocks",
-								  NBuffers * (Size) BLCKSZ + PG_IO_ALIGN_SIZE,
-								  &foundBufs));
-
-	/* Align condition variables to cacheline boundary. */
-	BufferIOCVArray = (ConditionVariableMinimallyPadded *)
-		ShmemInitStruct("Buffer IO Condition Variables",
-						NBuffers * sizeof(ConditionVariableMinimallyPadded),
-						&foundIOCV);
+					   .alignment = PG_IO_ALIGN_SIZE,
+					   .ptr = (void **) &BufferBlocks,
+		);
+
+	ShmemRequestStruct(.name = "Buffer IO Condition Variables",
+					   .size = NBuffers * sizeof(ConditionVariableMinimallyPadded),
+	/* Align descriptors to a cacheline boundary. */
+					   .alignment = PG_CACHE_LINE_SIZE,
+					   .ptr = (void **) &BufferIOCVArray,
+		);
 
 	/*
 	 * The array used to sort to-be-checkpointed buffer ids is located in
@@ -99,80 +104,50 @@ BufferManagerShmemInit(void)
 	 * the checkpointer is restarted, memory allocation failures would be
 	 * painful.
 	 */
-	CkptBufferIds = (CkptSortItem *)
-		ShmemInitStruct("Checkpoint BufferIds",
-						NBuffers * sizeof(CkptSortItem), &foundBufCkpt);
+	ShmemRequestStruct(.name = "Checkpoint BufferIds",
+					   .size = NBuffers * sizeof(CkptSortItem),
+					   .ptr = (void **) &CkptBufferIds,
+		);
+}
 
-	if (foundDescs || foundBufs || foundIOCV || foundBufCkpt)
-	{
-		/* should find all of these, or none of them */
-		Assert(foundDescs && foundBufs && foundIOCV && foundBufCkpt);
-		/* note: this path is only taken in EXEC_BACKEND case */
-	}
-	else
+/*
+ * Initialize shared buffer pool
+ *
+ * This is called once during shared-memory initialization (either in the
+ * postmaster, or in a standalone backend).
+ */
+static void
+BufferManagerShmemInit(void *arg)
+{
+	/*
+	 * Initialize all the buffer headers.
+	 */
+	for (int i = 0; i < NBuffers; i++)
 	{
-		int			i;
+		BufferDesc *buf = GetBufferDescriptor(i);
 
-		/*
-		 * Initialize all the buffer headers.
-		 */
-		for (i = 0; i < NBuffers; i++)
-		{
-			BufferDesc *buf = GetBufferDescriptor(i);
+		ClearBufferTag(&buf->tag);
 
-			ClearBufferTag(&buf->tag);
+		pg_atomic_init_u64(&buf->state, 0);
+		buf->wait_backend_pgprocno = INVALID_PROC_NUMBER;
 
-			pg_atomic_init_u64(&buf->state, 0);
-			buf->wait_backend_pgprocno = INVALID_PROC_NUMBER;
+		buf->buf_id = i;
 
-			buf->buf_id = i;
+		pgaio_wref_clear(&buf->io_wref);
 
-			pgaio_wref_clear(&buf->io_wref);
-
-			proclist_init(&buf->lock_waiters);
-			ConditionVariableInit(BufferDescriptorGetIOCV(buf));
-		}
+		proclist_init(&buf->lock_waiters);
+		ConditionVariableInit(BufferDescriptorGetIOCV(buf));
 	}
 
-	/* Init other shared buffer-management stuff */
-	StrategyInitialize(!foundDescs);
-
 	/* Initialize per-backend file flush context */
 	WritebackContextInit(&BackendWritebackContext,
 						 &backend_flush_after);
 }
 
-/*
- * BufferManagerShmemSize
- *
- * compute the size of shared memory for the buffer pool including
- * data pages, buffer descriptors, hash tables, etc.
- */
-Size
-BufferManagerShmemSize(void)
+static void
+BufferManagerShmemAttach(void *arg)
 {
-	Size		size = 0;
-
-	/* size of buffer descriptors */
-	size = add_size(size, mul_size(NBuffers, sizeof(BufferDescPadded)));
-	/* to allow aligning buffer descriptors */
-	size = add_size(size, PG_CACHE_LINE_SIZE);
-
-	/* size of data pages, plus alignment padding */
-	size = add_size(size, PG_IO_ALIGN_SIZE);
-	size = add_size(size, mul_size(NBuffers, BLCKSZ));
-
-	/* size of stuff controlled by freelist.c */
-	size = add_size(size, StrategyShmemSize());
-
-	/* size of I/O condition variables */
-	size = add_size(size, mul_size(NBuffers,
-								   sizeof(ConditionVariableMinimallyPadded)));
-	/* to allow aligning the above */
-	size = add_size(size, PG_CACHE_LINE_SIZE);
-
-	/* size of checkpoint sort array in bufmgr.c */
-	size = add_size(size, mul_size(NBuffers, sizeof(CkptSortItem)));
-
-	return size;
+	/* Initialize per-backend file flush context */
+	WritebackContextInit(&BackendWritebackContext,
+						 &backend_flush_after);
 }
diff --git a/src/backend/storage/buffer/buf_table.c b/src/backend/storage/buffer/buf_table.c
index d04ef74b850..347bf267d73 100644
--- a/src/backend/storage/buffer/buf_table.c
+++ b/src/backend/storage/buffer/buf_table.c
@@ -22,6 +22,7 @@
 #include "postgres.h"
 
 #include "storage/buf_internals.h"
+#include "storage/subsystems.h"
 
 /* entry for buffer lookup hashtable */
 typedef struct
@@ -32,37 +33,42 @@ typedef struct
 
 static HTAB *SharedBufHash;
 
+static void BufTableShmemRequest(void *arg);
 
-/*
- * Estimate space needed for mapping hashtable
- *		size is the desired hash table size (possibly more than NBuffers)
- */
-Size
-BufTableShmemSize(int size)
-{
-	return hash_estimate_size(size, sizeof(BufferLookupEnt));
-}
+const ShmemCallbacks BufTableShmemCallbacks = {
+	.request_fn = BufTableShmemRequest,
+	/* no special initialization needed, the hash table will start empty */
+};
 
 /*
- * Initialize shmem hash table for mapping buffers
+ * Register shmem hash table for mapping buffers.
  *		size is the desired hash table size (possibly more than NBuffers)
  */
 void
-InitBufTable(int size)
+BufTableShmemRequest(void *arg)
 {
-	HASHCTL		info;
-
-	/* assume no locking is needed yet */
-
-	/* BufferTag maps to Buffer */
-	info.keysize = sizeof(BufferTag);
-	info.entrysize = sizeof(BufferLookupEnt);
-	info.num_partitions = NUM_BUFFER_PARTITIONS;
-
-	SharedBufHash = ShmemInitHash("Shared Buffer Lookup Table",
-								  size,
-								  &info,
-								  HASH_ELEM | HASH_BLOBS | HASH_PARTITION | HASH_FIXED_SIZE);
+	int			size;
+
+	/*
+	 * Request the shared buffer lookup hashtable.
+	 *
+	 * Since we can't tolerate running out of lookup table entries, we must be
+	 * sure to specify an adequate table size here.  The maximum steady-state
+	 * usage is of course NBuffers entries, but BufferAlloc() tries to insert
+	 * a new entry before deleting the old.  In principle this could be
+	 * happening in each partition concurrently, so we could need as many as
+	 * NBuffers + NUM_BUFFER_PARTITIONS entries.
+	 */
+	size = NBuffers + NUM_BUFFER_PARTITIONS;
+
+	ShmemRequestHash(.name = "Shared Buffer Lookup Table",
+					 .nelems = size,
+					 .ptr = &SharedBufHash,
+					 .hash_info.keysize = sizeof(BufferTag),
+					 .hash_info.entrysize = sizeof(BufferLookupEnt),
+					 .hash_info.num_partitions = NUM_BUFFER_PARTITIONS,
+					 .hash_flags = HASH_ELEM | HASH_BLOBS | HASH_PARTITION | HASH_FIXED_SIZE,
+		);
 }
 
 /*
diff --git a/src/backend/storage/buffer/freelist.c b/src/backend/storage/buffer/freelist.c
index b7687836188..fdb5bad7910 100644
--- a/src/backend/storage/buffer/freelist.c
+++ b/src/backend/storage/buffer/freelist.c
@@ -20,6 +20,8 @@
 #include "storage/buf_internals.h"
 #include "storage/bufmgr.h"
 #include "storage/proc.h"
+#include "storage/shmem.h"
+#include "storage/subsystems.h"
 
 #define INT_ACCESS_ONCE(var)	((int)(*((volatile int *)&(var))))
 
@@ -56,6 +58,14 @@ typedef struct
 /* Pointers to shared state */
 static BufferStrategyControl *StrategyControl = NULL;
 
+static void StrategyCtlShmemRequest(void *arg);
+static void StrategyCtlShmemInit(void *arg);
+
+const ShmemCallbacks StrategyCtlShmemCallbacks = {
+	.request_fn = StrategyCtlShmemRequest,
+	.init_fn = StrategyCtlShmemInit,
+};
+
 /*
  * Private (non-shared) state for managing a ring of shared buffers to re-use.
  * This is currently the only kind of BufferAccessStrategy object, but someday
@@ -369,80 +379,35 @@ StrategyNotifyBgWriter(int bgwprocno)
 
 
 /*
- * StrategyShmemSize
- *
- * estimate the size of shared memory used by the freelist-related structures.
- *
- * Note: for somewhat historical reasons, the buffer lookup hashtable size
- * is also determined here.
+ * StrategyCtlShmemRequest -- request shared memory for the buffer
+ *		cache replacement strategy.
  */
-Size
-StrategyShmemSize(void)
+static void
+StrategyCtlShmemRequest(void *arg)
 {
-	Size		size = 0;
-
-	/* size of lookup hash table ... see comment in StrategyInitialize */
-	size = add_size(size, BufTableShmemSize(NBuffers + NUM_BUFFER_PARTITIONS));
-
-	/* size of the shared replacement strategy control block */
-	size = add_size(size, MAXALIGN(sizeof(BufferStrategyControl)));
-
-	return size;
+	ShmemRequestStruct(.name = "Buffer Strategy Status",
+					   .size = sizeof(BufferStrategyControl),
+					   .ptr = (void **) &StrategyControl
+		);
 }
 
 /*
- * StrategyInitialize -- initialize the buffer cache replacement
- *		strategy.
- *
- * Assumes: All of the buffers are already built into a linked list.
- *		Only called by postmaster and only during initialization.
+ * StrategyCtlShmemInit -- initialize the buffer cache replacement strategy.
  */
-void
-StrategyInitialize(bool init)
+static void
+StrategyCtlShmemInit(void *arg)
 {
-	bool		found;
+	SpinLockInit(&StrategyControl->buffer_strategy_lock);
 
-	/*
-	 * Initialize the shared buffer lookup hashtable.
-	 *
-	 * Since we can't tolerate running out of lookup table entries, we must be
-	 * sure to specify an adequate table size here.  The maximum steady-state
-	 * usage is of course NBuffers entries, but BufferAlloc() tries to insert
-	 * a new entry before deleting the old.  In principle this could be
-	 * happening in each partition concurrently, so we could need as many as
-	 * NBuffers + NUM_BUFFER_PARTITIONS entries.
-	 */
-	InitBufTable(NBuffers + NUM_BUFFER_PARTITIONS);
-
-	/*
-	 * Get or create the shared strategy control block
-	 */
-	StrategyControl = (BufferStrategyControl *)
-		ShmemInitStruct("Buffer Strategy Status",
-						sizeof(BufferStrategyControl),
-						&found);
-
-	if (!found)
-	{
-		/*
-		 * Only done once, usually in postmaster
-		 */
-		Assert(init);
-
-		SpinLockInit(&StrategyControl->buffer_strategy_lock);
+	/* Initialize the clock-sweep pointer */
+	pg_atomic_init_u32(&StrategyControl->nextVictimBuffer, 0);
 
-		/* Initialize the clock-sweep pointer */
-		pg_atomic_init_u32(&StrategyControl->nextVictimBuffer, 0);
+	/* Clear statistics */
+	StrategyControl->completePasses = 0;
+	pg_atomic_init_u32(&StrategyControl->numBufferAllocs, 0);
 
-		/* Clear statistics */
-		StrategyControl->completePasses = 0;
-		pg_atomic_init_u32(&StrategyControl->numBufferAllocs, 0);
-
-		/* No pending notification */
-		StrategyControl->bgwprocno = -1;
-	}
-	else
-		Assert(!init);
+	/* No pending notification */
+	StrategyControl->bgwprocno = -1;
 }
 
 
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index a510c928daa..f64c1d59fa3 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -39,7 +39,6 @@
 #include "replication/walreceiver.h"
 #include "replication/walsender.h"
 #include "storage/aio_subsys.h"
-#include "storage/bufmgr.h"
 #include "storage/dsm.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -99,7 +98,6 @@ CalculateShmemSize(void)
 	size = add_size(size, ShmemGetRequestedSize());
 
 	/* legacy subsystems */
-	size = add_size(size, BufferManagerShmemSize());
 	size = add_size(size, LockManagerShmemSize());
 	size = add_size(size, XLogPrefetchShmemSize());
 	size = add_size(size, XLOGShmemSize());
@@ -263,7 +261,6 @@ CreateOrAttachShmemStructs(void)
 	XLOGShmemInit();
 	XLogPrefetchShmemInit();
 	XLogRecoveryShmemInit();
-	BufferManagerShmemInit();
 
 	/*
 	 * Set up lock manager
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index ad1b7b2216a..89615a254a3 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -587,12 +587,7 @@ extern bool StrategyRejectBuffer(BufferAccessStrategy strategy,
 extern int	StrategySyncStart(uint32 *complete_passes, uint32 *num_buf_alloc);
 extern void StrategyNotifyBgWriter(int bgwprocno);
 
-extern Size StrategyShmemSize(void);
-extern void StrategyInitialize(bool init);
-
 /* buf_table.c */
-extern Size BufTableShmemSize(int size);
-extern void InitBufTable(int size);
 extern uint32 BufTableHashCode(BufferTag *tagPtr);
 extern int	BufTableLookup(BufferTag *tagPtr, uint32 hashcode);
 extern int	BufTableInsert(BufferTag *tagPtr, uint32 hashcode, int buf_id);
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index aa61a39d9e6..6837b35fc6d 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -371,10 +371,6 @@ extern void MarkDirtyAllUnpinnedBuffers(int32 *buffers_dirtied,
 										int32 *buffers_already_dirty,
 										int32 *buffers_skipped);
 
-/* in buf_init.c */
-extern void BufferManagerShmemInit(void);
-extern Size BufferManagerShmemSize(void);
-
 /* in localbuf.c */
 extern void AtProcExit_LocalBuffers(void);
 
diff --git a/src/include/storage/subsystemlist.h b/src/include/storage/subsystemlist.h
index b438794d46d..d8e11756a61 100644
--- a/src/include/storage/subsystemlist.h
+++ b/src/include/storage/subsystemlist.h
@@ -36,6 +36,9 @@ PG_SHMEM_SUBSYSTEM(CLOGShmemCallbacks)
 PG_SHMEM_SUBSYSTEM(CommitTsShmemCallbacks)
 PG_SHMEM_SUBSYSTEM(SUBTRANSShmemCallbacks)
 PG_SHMEM_SUBSYSTEM(MultiXactShmemCallbacks)
+PG_SHMEM_SUBSYSTEM(BufferManagerShmemCallbacks)
+PG_SHMEM_SUBSYSTEM(StrategyCtlShmemCallbacks)
+PG_SHMEM_SUBSYSTEM(BufTableShmemCallbacks)
 
 /* predicate lock manager */
 PG_SHMEM_SUBSYSTEM(PredicateLockShmemCallbacks)
-- 
2.34.1

