]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Refactor ShmemIndex initialization
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 26 Mar 2026 09:35:55 +0000 (11:35 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 26 Mar 2026 09:35:55 +0000 (11:35 +0200)
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
src/backend/storage/ipc/shmem.c
src/include/storage/shmem.h

index a4785daf1e52f40642ea06066ccb446a4adb6855..3d3f153809b5d1f61ecff62b34d0d0558e95d2ef 100644 (file)
@@ -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();
 
index 0424c44572375b94e21831373bed1b49473588b6..0fb3bc5992930b1378766641f060949ba9aa0eaa 100644 (file)
@@ -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 *)
index 89d45287c1770261411f8d346ef9f7ddcd9ec2dd..0de8a36429b0fbbd7e010cd97030fe34727307da 100644 (file)
@@ -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);