From 5eba2b8514f1436d129d8ac6bbe3c84c1344c03b 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 v20261030] 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 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.

Note: It might be worth considering adding a separate state SRS_SIZING
after SRS_REQUESTING and SRS_INITIALIZING to make sure that no new
requests are added between calculating the total amount of memory
required and allocating the shared memory. But it's not done in this
commit.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reviewed-by: TBD
Discussion: https://postgr.es/m/<message-id-TBD>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---
 src/backend/bootstrap/bootstrap.c   |  4 +++-
 src/backend/postmaster/postmaster.c | 11 ++++++++---
 src/backend/storage/ipc/ipci.c      | 21 +++++++++++----------
 src/backend/storage/ipc/shmem.c     | 10 ++++++----
 src/backend/tcop/postgres.c         |  6 ++++--
 src/include/storage/ipc.h           |  4 ++--
 6 files changed, 34 insertions(+), 22 deletions(-)

diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 63e4d71b96b..4baf15e1e9e 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -243,6 +243,7 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	char	   *userDoption = NULL;
 	uint32		bootstrap_data_checksum_version = PG_DATA_CHECKSUM_OFF;
 	yyscan_t	scanner;
+	Size		shmem_size;
 
 	Assert(!IsUnderPostmaster);
 
@@ -377,7 +378,8 @@ BootstrapModeMain(int argc, char *argv[], bool check_only)
 	InitializeFastPathLocks();
 
 	ShmemCallRequestCallbacks();
-	CreateSharedMemoryAndSemaphores();
+	shmem_size = CalculateShmemSize();
+	CreateSharedMemoryAndSemaphores(shmem_size);
 
 	/*
 	 * 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..240a6048cf4 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
@@ -3257,6 +3259,8 @@ PostmasterStateMachine(void)
 	 */
 	if (FatalError && pmState == PM_NO_CHILDREN)
 	{
+		Size		shmem_size;
+
 		ereport(LOG,
 				(errmsg("all server processes terminated; reinitializing")));
 
@@ -3280,7 +3284,8 @@ PostmasterStateMachine(void)
 		 */
 		ResetShmemAllocator();
 		ShmemCallRequestCallbacks();
-		CreateSharedMemoryAndSemaphores();
+		shmem_size = CalculateShmemSize();
+		CreateSharedMemoryAndSemaphores(shmem_size);
 
 		UpdatePMState(PM_STARTUP);
 
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index e149a738c8d..90536f887f1 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -52,6 +52,10 @@ RequestAddinShmemSpace(Size size)
 /*
  * CalculateShmemSize
  *		Calculates the amount of shared memory needed.
+ *
+ * Expected to be called only once after collecting all shared memory requests
+ * but before allocating the shared memory segment at the startup or server
+ * restart.
  */
 Size
 CalculateShmemSize(void)
@@ -114,19 +118,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 +184,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 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..497c0189cf0 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -389,17 +389,19 @@ ShmemRequestInternal(ShmemStructOpts *options, ShmemRequestKind kind)
 }
 
 /*
- *	ShmemGetRequestedSize() --- estimate the total size of all registered shared
- *                              memory structures.
+ * ShmemGetRequestedSize() --- estimate the total size of all registered shared
+ * memory structures.
  *
- * This is called at postmaster startup, before the shared memory segment has
- * been created.
+ * This is called at postmaster startup or server restart, before the shared
+ * memory segment has been created.
  */
 size_t
 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));
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: 4f89416c9dbc78da5679d32072315af56fbeb8ed
-- 
2.34.1

