From 132e1155b6b2ad1522087a11deb1029fa0dcdb4b Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Mon, 1 Sep 2025 15:40:41 +0530
Subject: [PATCH 12/19] Initial value of shared_buffers (or NBuffers)

The assign_hook for shared_buffers (assign_shared_buffers()) is called twice
during server startup. First time it sets the default value of shared_buffers,
followed by a second time when it sets the value specified in the configuration
file or on the command line.  At those times the shared buffer pool is yet to be
initialized. Hence there is no need to keep the GUC change pending or going
through the entire process of resizing memory maps, reinitializing the shared memory
and process synchronization. Instead the given value should be assigned directly to
NBuffers, which will be used when creating the shared
memory and also when initializing the buffer pool the first time.  Any changes
to shared_buffer after that will need remapping the shared memory segment and
synchronize buffer pool reinitialization across the backends.

If BufferBlocks is not initilized assign_shared_buffers() sets the given
value to NBuffers directly. Otherwise it marks the change as pending and
sets the flag pending_pm_shmem_resize so that Postmaster can start the
buffer pool reinitialization.

TODO:

1. The change depends upon the C convention that the global pointer variables
being initialized to NULL. May be initialize BufferBlocks to NULL explicitly.

2. We might think of a better way to check whether buffer pool has been
initialized or not. See comment in assign_shared_buffers().

Author: Ashutosh Bapat
---
 src/backend/port/sysv_shmem.c | 42 ++++++++++++++++++++++++++---------
 1 file changed, 32 insertions(+), 10 deletions(-)

diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c
index dc4eeeee56a..ba8613678f6 100644
--- a/src/backend/port/sysv_shmem.c
+++ b/src/backend/port/sysv_shmem.c
@@ -1168,20 +1168,42 @@ ProcessBarrierShmemResize(Barrier *barrier)
 }
 
 /*
- * GUC assign hook for shared_buffers. It's recommended for an assign hook to
- * be as minimal as possible, thus we just request shared memory resize and
- * remember the previous value.
+ * GUC assign hook for shared_buffers.
+ *
+ * When setting the GUC first time after starting the server, the GUC value is
+ * changed immediately since there is not shared memory setup yet.
+ *
+ * After the shared memory is setup, changing the GUC value requires resizing and
+ * reiniatializing (at least parts of) the shared memory structures related to
+ * shared buffers. That's a long and complicated process.  It's recommended for
+ * an assign hook to be as minimal as possible, thus we just request shared
+ * memory resize and remember the previous value.
  */
 void
 assign_shared_buffers(int newval, void *extra, bool *pending)
 {
-	elog(DEBUG1, "Received SIGHUP for shmem resizing");
-
-	pending_pm_shmem_resize = true;
-	*pending = true;
-	NBuffersPending = newval;
-
-	NBuffersOld = NBuffers;
+	/*
+	 * TODO: If a backend joins while the buffer resizing is in progress or it
+	 * reads a value of shared_buffers from configuration which is different from
+	 * the value being used by existing backends, this method may not work. Need
+	 * to think of a better solution. 
+	 */
+	if (BufferBlocks)
+	{
+		elog(DEBUG1, "bufferpool is already initialized with size = %d, reinitializing it with size = %d",
+			NBuffers, newval);
+		pending_pm_shmem_resize = true;
+		*pending = true;
+		NBuffersPending = newval;
+		NBuffersOld = NBuffers;
+	}
+	else
+	{
+		elog(DEBUG1, "initializing buffer pool with size = %d", newval);
+		NBuffers = newval;
+		*pending = false;
+		pending_pm_shmem_resize = false;
+	}
 }
 
 /*
-- 
2.34.1

