postgres.git / summary / log / commit / refs
commit 6b8238cb6aa76924fa63640fe421c421d2fa5472
Author: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Thu Mar 26 09:35:55 2026 +0000
Refactor ShmemIndex initialization
Initialize the ShmemIndex hash table in InitShmemAllocator() already,
removing the need for the separate InitShmemIndex() step.
Reviewed-by: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Discussion: https://www.postgresql.org/message-id/CAExHW5vM1bneLYfg0wGeAa=52UiJ3z4vKd3AJ72X8Fw6k3KKrg@mail.gmail.com
src/backend/storage/ipc/ipci.c | 8 +--
src/backend/storage/ipc/shmem.c | 143 ++++++++++++++++------------------------
src/include/storage/shmem.h | 1 -
3 files changed, 56 insertions(+), 96 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..0fb3bc59929 100644
--- a/src/backend/storage/ipc/shmem.c
+++ b/src/backend/storage/ipc/shmem.c
@@ -124,6 +124,14 @@ Datum pg_numa_available(PG_FUNCTION_ARGS);
void
InitShmemAllocator(PGShmemHeader *seghdr)
{
+ Size offset;
+ HASHCTL info;
+ int hash_flags;
+ size_t size;
+
+#ifndef EXEC_BACKEND
+ Assert(!IsUnderPostmaster);
+#endif
Assert(seghdr != NULL);
/*
@@ -133,45 +141,58 @@ InitShmemAllocator(PGShmemHeader *seghdr)
Assert(seghdr == (void *) MAXALIGN(seghdr));
Assert(seghdr->content_offset == MAXALIGN(seghdr->content_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)));
+
+ /*
+ * In postmaster or stand-alone backend, initialize the shared memory
+ * allocator and the spinlock so that we can allocate shared memory for
+ * ShmemIndex using ShmemAlloc(). In a regular backend just set up the
+ * pointers required by ShmemAlloc().
+ */
+ ShmemAllocator = (ShmemAllocatorData *) ((char *) seghdr + seghdr->content_offset);
+ if (!IsUnderPostmaster)
+ {
+ SpinLockInit(&ShmemAllocator->shmem_lock);
+ ShmemAllocator->free_offset = offset;
+ }
+
+ ShmemLock = &ShmemAllocator->shmem_lock;
ShmemSegHdr = seghdr;
ShmemBase = seghdr;
ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
-#ifndef EXEC_BACKEND
- Assert(!IsUnderPostmaster);
-#endif
- if (IsUnderPostmaster)
+ /*
+ * 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.
+ */
+ info.keysize = SHMEM_INDEX_KEYSIZE;
+ info.entrysize = sizeof(ShmemIndexEnt);
+ info.dsize = info.max_dsize = hash_select_dirsize(SHMEM_INDEX_SIZE);
+ info.alloc = ShmemAllocNoError;
+ hash_flags = HASH_ELEM | HASH_STRINGS | HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE;
+ if (!IsUnderPostmaster)
{
- PGShmemHeader *shmhdr = ShmemSegHdr;
-
- ShmemAllocator = (ShmemAllocatorData *) ((char *) shmhdr + shmhdr->content_offset);
- ShmemLock = &ShmemAllocator->shmem_lock;
+ size = hash_get_shared_size(&info, hash_flags);
+ ShmemAllocator->index = (HASHHDR *) ShmemAlloc(size);
}
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);
-
- 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;
- }
+ hash_flags |= HASH_ATTACH;
+ info.hctl = ShmemAllocator->index;
+ ShmemIndex = hash_create("ShmemIndex", SHMEM_INDEX_SIZE, &info, hash_flags);
+ Assert(ShmemIndex != NULL);
}
/*
@@ -270,31 +291,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 +379,9 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
ShmemIndexEnt *result;
void *structPtr;
- LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
-
- if (!ShmemIndex)
- {
- /* Must be trying to create/attach to ShmemIndex itself */
- Assert(strcmp(name, "ShmemIndex") == 0);
+ Assert(ShmemIndex != NULL);
- 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);
[parent: 515b0dc4bc74]