From a5dd2a2c09b28c25c3679b27cc0ba5af31f00c45 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 16 Mar 2026 20:35:36 +0200
Subject: [PATCH v6 2/6] Refactor ShmemIndex initialization

Initialize the ShmemIndex hash table in InitShmemAllocator() already,
removing the need for the separate InitShmemIndex() step.
---
 src/backend/storage/ipc/ipci.c  |   8 +-
 src/backend/storage/ipc/shmem.c | 131 ++++++++++++--------------------
 src/include/storage/shmem.h     |   1 -
 3 files changed, 49 insertions(+), 91 deletions(-)

diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index a4785daf1e5..3d3f153809b 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -250,16 +250,10 @@ static void
 CreateOrAttachShmemStructs(void)
 {
 	/*
-	 * Now initialize LWLocks, which do shared memory allocation and are
-	 * needed for InitShmemIndex.
+	 * Now initialize LWLocks, which do shared memory allocation.
 	 */
 	CreateLWLocks();
 
-	/*
-	 * Set up shmem.c index hashtable
-	 */
-	InitShmemIndex();
-
 	dsm_shmem_init();
 	DSMRegistryShmemInit();
 
diff --git a/src/backend/storage/ipc/shmem.c b/src/backend/storage/ipc/shmem.c
index 0424c445723..dce355e6683 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -124,6 +124,12 @@ Datum		pg_numa_available(PG_FUNCTION_ARGS);
 void
 InitShmemAllocator(PGShmemHeader *seghdr)
 {
+	Size		offset;
+	int64		hash_size;
+	HASHCTL		info;
+	int			hash_flags;
+	size_t		size;
+
 	Assert(seghdr != NULL);
 
 	/*
@@ -137,41 +143,54 @@ InitShmemAllocator(PGShmemHeader *seghdr)
 	ShmemBase = seghdr;
 	ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
 
+	/*
+	 * Allocations after this point should go through ShmemAlloc, which
+	 * expects to allocate everything on cache line boundaries.  Make sure the
+	 * first allocation begins on a cache line boundary.
+	 */
+	offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
+	if (offset > seghdr->totalsize)
+		ereport(ERROR,
+				(errcode(ERRCODE_OUT_OF_MEMORY),
+				 errmsg("out of shared memory (%zu bytes requested)",
+						offset)));
+
+	ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
+	ShmemLock = &ShmemAllocator->shmem_lock;
+
 #ifndef EXEC_BACKEND
 	Assert(!IsUnderPostmaster);
 #endif
-	if (IsUnderPostmaster)
+	if (!IsUnderPostmaster)
 	{
-		PGShmemHeader *shmhdr = ShmemSegHdr;
-
-		ShmemAllocator = (ShmemAllocatorData *) ((char *) shmhdr + shmhdr->content_offset);
-		ShmemLock = &ShmemAllocator->shmem_lock;
+		SpinLockInit(&ShmemAllocator->shmem_lock);
+		ShmemAllocator->free_offset = offset;
 	}
-	else
-	{
-		Size		offset;
 
-		/*
-		 * Allocations after this point should go through ShmemAlloc, which
-		 * expects to allocate everything on cache line boundaries.  Make sure
-		 * the first allocation begins on a cache line boundary.
-		 */
-		offset = CACHELINEALIGN(seghdr->content_offset + sizeof(ShmemAllocatorData));
-		if (offset > seghdr->totalsize)
-			ereport(ERROR,
-					(errcode(ERRCODE_OUT_OF_MEMORY),
-					 errmsg("out of shared memory (%zu bytes requested)",
-							offset)));
-
-		ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
+	/*
+	 * Create (or attach to) the shared memory index of shmem areas.
+	 *
+	 * This is the same initialization as ShmemInitHash() does, but we cannot
+	 * use ShmemInitHash() here because it relies on ShmemIndex being already
+	 * initialized.
+	 */
+	hash_size = SHMEM_INDEX_SIZE;
 
-		SpinLockInit(&ShmemAllocator->shmem_lock);
-		ShmemLock = &ShmemAllocator->shmem_lock;
-		ShmemAllocator->free_offset = offset;
-		/* ShmemIndex can't be set up yet (need LWLocks first) */
-		ShmemAllocator->index = NULL;
-		ShmemIndex = (HTAB *) NULL;
+	info.keysize = SHMEM_INDEX_KEYSIZE;
+	info.entrysize = sizeof(ShmemIndexEnt);
+	info.dsize = info.max_dsize = hash_select_dirsize(hash_size);
+	info.alloc = ShmemAllocNoError;
+	hash_flags = HASH_ELEM | HASH_STRINGS | HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
+	if (!IsUnderPostmaster)
+	{
+		size = hash_get_shared_size(&info, hash_flags);
+		ShmemAllocator->index = (HASHHDR *) ShmemAlloc(size);
 	}
+	else
+		hash_flags |= HASH_ATTACH;
+	info.hctl = ShmemAllocator->index;
+	ShmemIndex = hash_create("ShmemIndex", hash_size, &info, hash_flags);
+	Assert(ShmemIndex != NULL);
 }
 
 /*
@@ -270,31 +289,6 @@ ShmemAddrIsValid(const void *addr)
 	return (addr >= ShmemBase) && (addr < ShmemEnd);
 }
 
-/*
- *	InitShmemIndex() --- set up or attach to shmem index table.
- */
-void
-InitShmemIndex(void)
-{
-	HASHCTL		info;
-
-	/*
-	 * Create the shared memory shmem index.
-	 *
-	 * Since ShmemInitHash calls ShmemInitStruct, which expects the ShmemIndex
-	 * hashtable to exist already, we have a bit of a circularity problem in
-	 * initializing the ShmemIndex itself.  The special "ShmemIndex" hash
-	 * table name will tell ShmemInitStruct to fake it.
-	 */
-	info.keysize = SHMEM_INDEX_KEYSIZE;
-	info.entrysize = sizeof(ShmemIndexEnt);
-
-	ShmemIndex = ShmemInitHash("ShmemIndex",
-							   SHMEM_INDEX_SIZE, SHMEM_INDEX_SIZE,
-							   &info,
-							   HASH_ELEM | HASH_STRINGS);
-}
-
 /*
  * ShmemInitHash -- Create and initialize, or attach to, a
  *		shared memory hash table.
@@ -383,38 +377,9 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
 	ShmemIndexEnt *result;
 	void	   *structPtr;
 
-	LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
+	Assert(ShmemIndex != NULL);
 
-	if (!ShmemIndex)
-	{
-		/* Must be trying to create/attach to ShmemIndex itself */
-		Assert(strcmp(name, "ShmemIndex") == 0);
-
-		if (IsUnderPostmaster)
-		{
-			/* Must be initializing a (non-standalone) backend */
-			Assert(ShmemAllocator->index != NULL);
-			structPtr = ShmemAllocator->index;
-			*foundPtr = true;
-		}
-		else
-		{
-			/*
-			 * If the shmem index doesn't exist, we are bootstrapping: we must
-			 * be trying to init the shmem index itself.
-			 *
-			 * Notice that the ShmemIndexLock is released before the shmem
-			 * index has been initialized.  This should be OK because no other
-			 * process can be accessing shared memory yet.
-			 */
-			Assert(ShmemAllocator->index == NULL);
-			structPtr = ShmemAlloc(size);
-			ShmemAllocator->index = structPtr;
-			*foundPtr = false;
-		}
-		LWLockRelease(ShmemIndexLock);
-		return structPtr;
-	}
+	LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
 
 	/* look it up in the shmem index */
 	result = (ShmemIndexEnt *)
diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h
index 89d45287c17..0de8a36429b 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -33,7 +33,6 @@ extern void InitShmemAllocator(PGShmemHeader *seghdr);
 extern void *ShmemAlloc(Size size);
 extern void *ShmemAllocNoError(Size size);
 extern bool ShmemAddrIsValid(const void *addr);
-extern void InitShmemIndex(void);
 extern HTAB *ShmemInitHash(const char *name, int64 init_size, int64 max_size,
 						   HASHCTL *infoP, int hash_flags);
 extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr);
-- 
2.47.3

