From 6904df93e445c0eada8ef2e2f326bbd6f41e810d Mon Sep 17 00:00:00 2001
From: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Date: Thu, 29 Oct 2026 15:12:37 +0530
Subject: [PATCH v20261106] Call CalculateShmemSize() only once when creating
 shared memory

During normal startup, CalculateShmemSize() is called twice: first in
InitializeShmemGUCs() and then in CreateSharedMemoryAndSemaphores().
When the server is invoked only to report a runtime-computed GUC, the
second call is not reached.

Calculate the size by calling CalculateShmemSize() only once after
collecting shared memory requests and pass it to both functions. Besides
avoiding duplicate calculation, this ensures that GUC reporting and
shared memory creation use the same calculated size.

Also add a separate shmem_request_state SRS_SIZING which is reached once
we calculate the shared memory size after collecting requests in state
SRS_REQUESTING. This state is retained till the shared memory is
allocated. Once we start allocating shared areas, state SRS_INITIALIZING
is reached. No new requests are added in state SRS_SIZING, so that all
the shared areas allocated initially are exactly the ones which decided
the size of the shared memory.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: Nathan Bossart <nathandbossart@gmail.com>
Discussion: https://postgr.es/m/CAExHW5ttQauXiYCM4OKL8xKHZrndTN2jMN4WQjm1PkPNuqX_bg@mail.gmail.com
---
 src/backend/bootstrap/bootstrap.c   |  2 +-
 src/backend/postmaster/postmaster.c |  8 +++++---
 src/backend/storage/ipc/ipci.c      | 17 +++++++----------
 src/backend/storage/ipc/shmem.c     | 15 +++++++++++++--
 src/backend/tcop/postgres.c         |  6 ++++--
 src/include/storage/ipc.h           |  4 ++--
 6 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 63e4d71b96b..063666a8424 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -377,7 +377,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	InitializeFastPathLocks();
 
 	ShmemCallRequestCallbacks();
-	CreateSharedMemoryAndSemaphores();
+	CreateSharedMemoryAndSemaphores(CalculateShmemSize());
 
 	/*
 	 * Estimate number of openable files.  This is essential too in --check
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index f53aa9c404d..2b6e5f9fc6c 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -501,6 +501,7 @@ PostmasterMain(int argc, char *argv[])
 	char	   *userDoption = NULL;
 	bool		listen_addr_saved = false;
 	char	   *output_config_variable = NULL;
+	Size		shmem_size;
 
 	InitProcessGlobals();
 
@@ -973,13 +974,14 @@ PostmasterMain(int argc, char *argv[])
 	 * shared memory needs.
 	 */
 	ShmemCallRequestCallbacks();
+	shmem_size = CalculateShmemSize();
 
 	/*
 	 * Now that loadable modules have had their chance to request additional
 	 * shared memory, determine the value of any runtime-computed GUCs that
 	 * depend on the amount of shared memory required.
 	 */
-	InitializeShmemGUCs();
+	InitializeShmemGUCs(shmem_size);
 
 	/*
 	 * Now that modules have been loaded, we can process any custom resource
@@ -1014,7 +1016,7 @@ PostmasterMain(int argc, char *argv[])
 	 * normally choose the same IPC keys.  This helps ensure that we will
 	 * clean up dead IPC objects if the postmaster crashes and is restarted.
 	 */
-	CreateSharedMemoryAndSemaphores();
+	CreateSharedMemoryAndSemaphores(shmem_size);
 
 	/*
 	 * Estimate number of openable files.  This must happen after setting up
@@ -3280,7 +3282,7 @@ PostmasterStateMachine(void)
 		 */
 		ResetShmemAllocator();
 		ShmemCallRequestCallbacks();
-		CreateSharedMemoryAndSemaphores();
+		CreateSharedMemoryAndSemaphores(CalculateShmemSize());
 
 		UpdatePMState(PM_STARTUP);
 
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index e149a738c8d..1c4cd27d2be 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -114,19 +114,16 @@ AttachSharedMemoryStructs(void)
 
 /*
  * CreateSharedMemoryAndSemaphores
- *		Creates and initializes shared memory and semaphores.
+ *		Creates and initializes shared memory of given size and semaphores.
  */
 void
-CreateSharedMemoryAndSemaphores(void)
+CreateSharedMemoryAndSemaphores(Size size)
 {
 	PGShmemHeader *shim;
 	PGShmemHeader *seghdr;
-	Size		size;
 
 	Assert(!IsUnderPostmaster);
 
-	/* Compute the size of the shared-memory block */
-	size = CalculateShmemSize();
 	elog(DEBUG3, "invoking IpcMemoryCreate(size=%zu)", size);
 
 	/*
@@ -183,20 +180,20 @@ RegisterBuiltinShmemCallbacks(void)
  * InitializeShmemGUCs
  *
  * This function initializes runtime-computed GUCs related to the amount of
- * shared memory required for the current configuration.
+ * shared memory required for the current configuration.  The input size is
+ * expected to be the total shared memory size (in bytes) computed for the
+ * current configuration.
  */
 void
-InitializeShmemGUCs(void)
+InitializeShmemGUCs(Size size_b)
 {
 	char		buf[64];
-	Size		size_b;
 	Size		size_mb;
 	Size		hp_size;
 
 	/*
-	 * Calculate the shared memory size and round up to the nearest megabyte.
+	 * Round the shared memory size up to the nearest megabyte.
 	 */
-	size_b = CalculateShmemSize();
 	size_mb = add_size(size_b, (1024 * 1024) - 1) / (1024 * 1024);
 	sprintf(buf, "%zu", size_mb);
 	SetConfigOption("shared_memory_size", buf,
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 8d81893b470..e6658631a45 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -181,7 +181,7 @@ static List *pending_shmem_requests;	/* List of ShmemRequests */
  * right order.
  *
  * Postmaster:
- *   INITIAL -> REQUESTING -> INITIALIZING -> DONE
+ *   INITIAL -> REQUESTING -> SIZED -> INITIALIZING -> DONE
  *
  * Backends in EXEC_BACKEND mode:
  *   INITIAL -> REQUESTING -> ATTACHING -> DONE
@@ -201,6 +201,13 @@ enum shmem_request_state
 	 */
 	SRS_REQUESTING,
 
+	/*
+	 * The required size of the shared memory segment has been calculated. No
+	 * further requests shall be registered before creating the shared memory
+	 * segment.
+	 */
+	SRS_SIZED,
+
 	/*
 	 * Postmaster has finished all shmem requests, and is now initializing the
 	 * shared memory segment.  init_fn callbacks are called in this state.
@@ -400,6 +407,8 @@ ShmemGetRequestedSize(void)
 {
 	size_t		size;
 
+	Assert(shmem_request_state == SRS_REQUESTING);
+
 	/* memory needed for the ShmemIndex */
 	size = hash_estimate_size(list_length(pending_shmem_requests) + SHMEM_INDEX_ADDITIONAL_SIZE,
 							  sizeof(ShmemIndexEnt));
@@ -418,6 +427,8 @@ ShmemGetRequestedSize(void)
 		size = add_size(size, request->options->size);
 	}
 
+	shmem_request_state = SRS_SIZED;
+
 	return size;
 }
 
@@ -693,7 +704,7 @@ InitShmemAllocator(PGShmemHeader *seghdr)
 	}
 	else
 	{
-		Assert(shmem_request_state == SRS_REQUESTING);
+		Assert(shmem_request_state == SRS_SIZED);
 		shmem_request_state = SRS_INITIALIZING;
 	}
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b6bdfe213fe..944aefe3699 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -4222,6 +4222,7 @@ PostgresSingleUserMain(int argc, char *argv[],
 					   const char *username)
 {
 	const char *dbname = NULL;
+	Size		shmem_size;
 
 	Assert(!IsUnderPostmaster);
 
@@ -4303,13 +4304,14 @@ PostgresSingleUserMain(int argc, char *argv[],
 	 * add-ins, a chance to chance to adjust their requested shmem sizes.
 	 */
 	ShmemCallRequestCallbacks();
+	shmem_size = CalculateShmemSize();
 
 	/*
 	 * Now that loadable modules have had their chance to request additional
 	 * shared memory, determine the value of any runtime-computed GUCs that
 	 * depend on the amount of shared memory required.
 	 */
-	InitializeShmemGUCs();
+	InitializeShmemGUCs(shmem_size);
 
 	/*
 	 * Now that modules have been loaded, we can process any custom resource
@@ -4321,7 +4323,7 @@ PostgresSingleUserMain(int argc, char *argv[],
 	 * Create shared memory etc.  (Nothing's really "shared" in single-user
 	 * mode, but we must have these data structures anyway.)
 	 */
-	CreateSharedMemoryAndSemaphores();
+	CreateSharedMemoryAndSemaphores(shmem_size);
 
 	/*
 	 * Estimate number of openable files.  This must happen after setting up
diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h
index b205b00e7a1..db5c69a08db 100644
--- a/src/include/storage/ipc.h
+++ b/src/include/storage/ipc.h
@@ -79,10 +79,10 @@ extern PGDLLIMPORT shmem_startup_hook_type shmem_startup_hook;
 
 extern void RegisterBuiltinShmemCallbacks(void);
 extern Size CalculateShmemSize(void);
-extern void CreateSharedMemoryAndSemaphores(void);
+extern void CreateSharedMemoryAndSemaphores(Size size);
 #ifdef EXEC_BACKEND
 extern void AttachSharedMemoryStructs(void);
 #endif
-extern void InitializeShmemGUCs(void);
+extern void InitializeShmemGUCs(Size size_b);
 
 #endif							/* IPC_H */

base-commit: edbe7ffdc8afe7f3c12675df6ef614bcd5017b3f
-- 
2.34.1

