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
This commit is contained in:
Heikki Linnakangas 2026-03-26 11:35:55 +02:00
parent 515b0dc4bc
commit 6b8238cb6a
3 changed files with 56 additions and 96 deletions

View file

@ -250,16 +250,10 @@ static void
CreateOrAttachShmemStructs(void) CreateOrAttachShmemStructs(void)
{ {
/* /*
* Now initialize LWLocks, which do shared memory allocation and are * Now initialize LWLocks, which do shared memory allocation.
* needed for InitShmemIndex.
*/ */
CreateLWLocks(); CreateLWLocks();
/*
* Set up shmem.c index hashtable
*/
InitShmemIndex();
dsm_shmem_init(); dsm_shmem_init();
DSMRegistryShmemInit(); DSMRegistryShmemInit();

View file

@ -124,6 +124,14 @@ Datum pg_numa_available(PG_FUNCTION_ARGS);
void void
InitShmemAllocator(PGShmemHeader *seghdr) InitShmemAllocator(PGShmemHeader *seghdr)
{ {
Size offset;
HASHCTL info;
int hash_flags;
size_t size;
#ifndef EXEC_BACKEND
Assert(!IsUnderPostmaster);
#endif
Assert(seghdr != NULL); Assert(seghdr != NULL);
/* /*
@ -133,45 +141,58 @@ InitShmemAllocator(PGShmemHeader *seghdr)
Assert(seghdr == (void *) MAXALIGN(seghdr)); Assert(seghdr == (void *) MAXALIGN(seghdr));
Assert(seghdr->content_offset == MAXALIGN(seghdr->content_offset)); 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; ShmemSegHdr = seghdr;
ShmemBase = seghdr; ShmemBase = seghdr;
ShmemEnd = (char *) ShmemBase + seghdr->totalsize; ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
#ifndef EXEC_BACKEND /*
Assert(!IsUnderPostmaster); * Create (or attach to) the shared memory index of shmem areas.
#endif *
if (IsUnderPostmaster) * 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; size = hash_get_shared_size(&info, hash_flags);
ShmemAllocator->index = (HASHHDR *) ShmemAlloc(size);
ShmemAllocator = (ShmemAllocatorData *) ((char *) shmhdr + shmhdr->content_offset);
ShmemLock = &ShmemAllocator->shmem_lock;
} }
else else
{ hash_flags |= HASH_ATTACH;
Size offset; info.hctl = ShmemAllocator->index;
ShmemIndex = hash_create("ShmemIndex", SHMEM_INDEX_SIZE, &info, hash_flags);
/* Assert(ShmemIndex != NULL);
* 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;
}
} }
/* /*
@ -270,31 +291,6 @@ ShmemAddrIsValid(const void *addr)
return (addr >= ShmemBase) && (addr < ShmemEnd); 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 * ShmemInitHash -- Create and initialize, or attach to, a
* shared memory hash table. * shared memory hash table.
@ -383,39 +379,10 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr)
ShmemIndexEnt *result; ShmemIndexEnt *result;
void *structPtr; void *structPtr;
Assert(ShmemIndex != NULL);
LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE); LWLockAcquire(ShmemIndexLock, LW_EXCLUSIVE);
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;
}
/* look it up in the shmem index */ /* look it up in the shmem index */
result = (ShmemIndexEnt *) result = (ShmemIndexEnt *)
hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr); hash_search(ShmemIndex, name, HASH_ENTER_NULL, foundPtr);

View file

@ -33,7 +33,6 @@ extern void InitShmemAllocator(PGShmemHeader *seghdr);
extern void *ShmemAlloc(Size size); extern void *ShmemAlloc(Size size);
extern void *ShmemAllocNoError(Size size); extern void *ShmemAllocNoError(Size size);
extern bool ShmemAddrIsValid(const void *addr); extern bool ShmemAddrIsValid(const void *addr);
extern void InitShmemIndex(void);
extern HTAB *ShmemInitHash(const char *name, int64 init_size, int64 max_size, extern HTAB *ShmemInitHash(const char *name, int64 init_size, int64 max_size,
HASHCTL *infoP, int hash_flags); HASHCTL *infoP, int hash_flags);
extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr); extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr);