From 954613a63cb1102d7eb88f92e7ff561828bbb5c9 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Wed, 9 Oct 2024 15:41:32 +0200 Subject: [PATCH v1 1/5] Allow to use multiple shared memory mappings Currently all the work with shared memory is done via a single anonymous memory mapping, which limits ways how the shared memory could be organized. Introduce possibility to allocate multiple shared memory mappings, where a single mapping is associated with a specified shared memory slot. There is only fixed amount of available slots, currently only one main shared memory slot is allocated. A new shared memory API is introduces, extended with a slot as a new parameter. As a path of least resistance, the original API is kept in place, utilizing the main shared memory slot. --- src/backend/port/posix_sema.c | 4 +- src/backend/port/sysv_sema.c | 4 +- src/backend/port/sysv_shmem.c | 138 +++++++++++++++++++--------- src/backend/port/win32_sema.c | 2 +- src/backend/storage/ipc/ipc.c | 2 +- src/backend/storage/ipc/ipci.c | 61 ++++++------ src/backend/storage/ipc/shmem.c | 133 ++++++++++++++++++--------- src/backend/storage/lmgr/lwlock.c | 5 +- src/include/storage/buf_internals.h | 1 + src/include/storage/ipc.h | 2 +- src/include/storage/pg_sema.h | 2 +- src/include/storage/pg_shmem.h | 18 ++++ src/include/storage/shmem.h | 10 ++ 13 files changed, 258 insertions(+), 124 deletions(-) diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c index 64186ec0a7..b97723d2ed 100644 --- a/src/backend/port/posix_sema.c +++ b/src/backend/port/posix_sema.c @@ -193,7 +193,7 @@ PGSemaphoreShmemSize(int maxSemas) * we don't have to expose the counters to other processes.) */ void -PGReserveSemaphores(int maxSemas) +PGReserveSemaphores(int maxSemas, int shmem_slot) { struct stat statbuf; @@ -220,7 +220,7 @@ PGReserveSemaphores(int maxSemas) * ShmemAlloc() won't be ready yet. */ sharedSemas = (PGSemaphore) - ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas)); + ShmemAllocUnlockedInSlot(PGSemaphoreShmemSize(maxSemas), shmem_slot); #endif numSems = 0; diff --git a/src/backend/port/sysv_sema.c b/src/backend/port/sysv_sema.c index 5b88a92bc9..8ef95b12c9 100644 --- a/src/backend/port/sysv_sema.c +++ b/src/backend/port/sysv_sema.c @@ -307,7 +307,7 @@ PGSemaphoreShmemSize(int maxSemas) * have clobbered.) */ void -PGReserveSemaphores(int maxSemas) +PGReserveSemaphores(int maxSemas, int shmem_slot) { struct stat statbuf; @@ -328,7 +328,7 @@ PGReserveSemaphores(int maxSemas) * ShmemAlloc() won't be ready yet. */ sharedSemas = (PGSemaphore) - ShmemAllocUnlocked(PGSemaphoreShmemSize(maxSemas)); + ShmemAllocUnlockedInSlot(PGSemaphoreShmemSize(maxSemas), shmem_slot); numSharedSemas = 0; maxSharedSemas = maxSemas; diff --git a/src/backend/port/sysv_shmem.c b/src/backend/port/sysv_shmem.c index 362a37d3b3..065a5b63ac 100644 --- a/src/backend/port/sysv_shmem.c +++ b/src/backend/port/sysv_shmem.c @@ -94,8 +94,19 @@ typedef enum unsigned long UsedShmemSegID = 0; void *UsedShmemSegAddr = NULL; -static Size AnonymousShmemSize; -static void *AnonymousShmem = NULL; +typedef struct AnonymousMapping +{ + int shmem_slot; + Size shmem_size; /* Size of the mapping */ + void *shmem; /* Pointer to the start of the mapped memory */ + void *seg_addr; /* SysV shared memory for the header */ + unsigned long seg_id; /* IPC key */ +} AnonymousMapping; + +static AnonymousMapping Mappings[ANON_MAPPINGS]; + +/* Keeps track of used mapping slots */ +static int next_free_slot = 0; static void *InternalIpcMemoryCreate(IpcMemoryKey memKey, Size size); static void IpcMemoryDetach(int status, Datum shmaddr); @@ -104,6 +115,28 @@ static IpcMemoryState PGSharedMemoryAttach(IpcMemoryId shmId, void *attachAt, PGShmemHeader **addr); +static const char* +MappingName(int shmem_slot) +{ + switch (shmem_slot) + { + case MAIN_SHMEM_SLOT: + return "main"; + default: + return "unknown"; + } +} + +static void +DebugMappings() +{ + for(int i = 0; i < next_free_slot; i++) + { + AnonymousMapping m = Mappings[i]; + elog(DEBUG1, "Mapping[%s]: addr %p, size %zu", + MappingName(i), m.shmem, m.shmem_size); + } +} /* * InternalIpcMemoryCreate(memKey, size) @@ -591,14 +624,13 @@ check_huge_page_size(int *newval, void **extra, GucSource source) /* * Creates an anonymous mmap()ed shared memory segment. * - * Pass the requested size in *size. This function will modify *size to the - * actual size of the allocation, if it ends up allocating a segment that is - * larger than requested. + * This function will modify mapping size to the actual size of the allocation, + * if it ends up allocating a segment that is larger than requested. */ -static void * -CreateAnonymousSegment(Size *size) +static void +CreateAnonymousSegment(AnonymousMapping *mapping) { - Size allocsize = *size; + Size allocsize = mapping->shmem_size; void *ptr = MAP_FAILED; int mmap_errno = 0; @@ -623,8 +655,11 @@ CreateAnonymousSegment(Size *size) PG_MMAP_FLAGS | mmap_flags, -1, 0); mmap_errno = errno; if (huge_pages == HUGE_PAGES_TRY && ptr == MAP_FAILED) - elog(DEBUG1, "mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m", - allocsize); + { + DebugMappings(); + elog(DEBUG1, "slot[%s]: mmap(%zu) with MAP_HUGETLB failed, huge pages disabled: %m", + MappingName(mapping->shmem_slot), allocsize); + } } #endif @@ -642,7 +677,7 @@ CreateAnonymousSegment(Size *size) * Use the original size, not the rounded-up value, when falling back * to non-huge pages. */ - allocsize = *size; + allocsize = mapping->shmem_size; ptr = mmap(NULL, allocsize, PROT_READ | PROT_WRITE, PG_MMAP_FLAGS, -1, 0); mmap_errno = errno; @@ -651,8 +686,10 @@ CreateAnonymousSegment(Size *size) if (ptr == MAP_FAILED) { errno = mmap_errno; + DebugMappings(); ereport(FATAL, - (errmsg("could not map anonymous shared memory: %m"), + (errmsg("slot[%s]: could not map anonymous shared memory: %m", + MappingName(mapping->shmem_slot)), (mmap_errno == ENOMEM) ? errhint("This error usually means that PostgreSQL's request " "for a shared memory segment exceeded available memory, " @@ -663,8 +700,8 @@ CreateAnonymousSegment(Size *size) allocsize) : 0)); } - *size = allocsize; - return ptr; + mapping->shmem = ptr; + mapping->shmem_size = allocsize; } /* @@ -674,13 +711,18 @@ CreateAnonymousSegment(Size *size) static void AnonymousShmemDetach(int status, Datum arg) { - /* Release anonymous shared memory block, if any. */ - if (AnonymousShmem != NULL) + for(int i = 0; i < next_free_slot; i++) { - if (munmap(AnonymousShmem, AnonymousShmemSize) < 0) - elog(LOG, "munmap(%p, %zu) failed: %m", - AnonymousShmem, AnonymousShmemSize); - AnonymousShmem = NULL; + AnonymousMapping m = Mappings[i]; + + /* Release anonymous shared memory block, if any. */ + if (m.shmem != NULL) + { + if (munmap(m.shmem, m.shmem_size) < 0) + elog(LOG, "munmap(%p, %zu) failed: %m", + m.shmem, m.shmem_size); + m.shmem = NULL; + } } } @@ -705,6 +747,7 @@ PGSharedMemoryCreate(Size size, PGShmemHeader *hdr; struct stat statbuf; Size sysvsize; + AnonymousMapping *mapping = &Mappings[next_free_slot]; /* * We use the data directory's ID info (inode and device numbers) to @@ -733,11 +776,15 @@ PGSharedMemoryCreate(Size size, /* Room for a header? */ Assert(size > MAXALIGN(sizeof(PGShmemHeader))); + mapping->shmem_size = size; + mapping->shmem_slot = next_free_slot; if (shared_memory_type == SHMEM_TYPE_MMAP) { - AnonymousShmem = CreateAnonymousSegment(&size); - AnonymousShmemSize = size; + /* On success, mapping data will be modified. */ + CreateAnonymousSegment(mapping); + + next_free_slot++; /* Register on-exit routine to unmap the anonymous segment */ on_shmem_exit(AnonymousShmemDetach, (Datum) 0); @@ -760,7 +807,7 @@ PGSharedMemoryCreate(Size size, * loop simultaneously. (CreateDataDirLockFile() does not entirely ensure * that, but prefer fixing it over coping here.) */ - NextShmemSegID = statbuf.st_ino; + NextShmemSegID = statbuf.st_ino + next_free_slot; for (;;) { @@ -852,13 +899,13 @@ PGSharedMemoryCreate(Size size, /* * Initialize space allocation status for segment. */ - hdr->totalsize = size; + hdr->totalsize = mapping->shmem_size; hdr->freeoffset = MAXALIGN(sizeof(PGShmemHeader)); *shim = hdr; /* Save info for possible future use */ - UsedShmemSegAddr = memAddress; - UsedShmemSegID = (unsigned long) NextShmemSegID; + mapping->seg_addr = memAddress; + mapping->seg_id = (unsigned long) NextShmemSegID; /* * If AnonymousShmem is NULL here, then we're not using anonymous shared @@ -866,10 +913,10 @@ PGSharedMemoryCreate(Size size, * block. Otherwise, the System V shared memory block is only a shim, and * we must return a pointer to the real block. */ - if (AnonymousShmem == NULL) + if (mapping->shmem == NULL) return hdr; - memcpy(AnonymousShmem, hdr, sizeof(PGShmemHeader)); - return (PGShmemHeader *) AnonymousShmem; + memcpy(mapping->shmem, hdr, sizeof(PGShmemHeader)); + return (PGShmemHeader *) mapping->shmem; } #ifdef EXEC_BACKEND @@ -969,23 +1016,28 @@ PGSharedMemoryNoReAttach(void) void PGSharedMemoryDetach(void) { - if (UsedShmemSegAddr != NULL) + for(int i = 0; i < next_free_slot; i++) { - if ((shmdt(UsedShmemSegAddr) < 0) + AnonymousMapping m = Mappings[i]; + + if (m.seg_addr != NULL) + { + if ((shmdt(m.seg_addr) < 0) #if defined(EXEC_BACKEND) && defined(__CYGWIN__) - /* Work-around for cygipc exec bug */ - && shmdt(NULL) < 0 + /* Work-around for cygipc exec bug */ + && shmdt(NULL) < 0 #endif - ) - elog(LOG, "shmdt(%p) failed: %m", UsedShmemSegAddr); - UsedShmemSegAddr = NULL; - } + ) + elog(LOG, "shmdt(%p) failed: %m", m.seg_addr); + m.seg_addr = NULL; + } - if (AnonymousShmem != NULL) - { - if (munmap(AnonymousShmem, AnonymousShmemSize) < 0) - elog(LOG, "munmap(%p, %zu) failed: %m", - AnonymousShmem, AnonymousShmemSize); - AnonymousShmem = NULL; + if (m.shmem != NULL) + { + if (munmap(m.shmem, m.shmem_size) < 0) + elog(LOG, "munmap(%p, %zu) failed: %m", + m.shmem, m.shmem_size); + m.shmem = NULL; + } } } diff --git a/src/backend/port/win32_sema.c b/src/backend/port/win32_sema.c index f2b54bdfda..d62084cc0d 100644 --- a/src/backend/port/win32_sema.c +++ b/src/backend/port/win32_sema.c @@ -44,7 +44,7 @@ PGSemaphoreShmemSize(int maxSemas) * process exits. */ void -PGReserveSemaphores(int maxSemas) +PGReserveSemaphores(int maxSemas, int shmem_slot) { mySemSet = (HANDLE *) malloc(maxSemas * sizeof(HANDLE)); if (mySemSet == NULL) diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c index b06e4b8452..2aabd4a77f 100644 --- a/src/backend/storage/ipc/ipc.c +++ b/src/backend/storage/ipc/ipc.c @@ -68,7 +68,7 @@ static void proc_exit_prepare(int code); * ---------------------------------------------------------------- */ -#define MAX_ON_EXITS 20 +#define MAX_ON_EXITS 40 struct ONEXIT { diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c index 35fa2e1dda..8224015b53 100644 --- a/src/backend/storage/ipc/ipci.c +++ b/src/backend/storage/ipc/ipci.c @@ -88,7 +88,7 @@ RequestAddinShmemSpace(Size size) * required. */ Size -CalculateShmemSize(int *num_semaphores) +CalculateShmemSize(int *num_semaphores, int shmem_slot) { Size size; int numSemas; @@ -202,33 +202,36 @@ CreateSharedMemoryAndSemaphores(void) Assert(!IsUnderPostmaster); - /* Compute the size of the shared-memory block */ - size = CalculateShmemSize(&numSemas); - elog(DEBUG3, "invoking IpcMemoryCreate(size=%zu)", size); - - /* - * Create the shmem segment - */ - seghdr = PGSharedMemoryCreate(size, &shim); - - /* - * Make sure that huge pages are never reported as "unknown" while the - * server is running. - */ - Assert(strcmp("unknown", - GetConfigOption("huge_pages_status", false, false)) != 0); - - InitShmemAccess(seghdr); - - /* - * Create semaphores - */ - PGReserveSemaphores(numSemas); - - /* - * Set up shared memory allocation mechanism - */ - InitShmemAllocation(); + for(int slot = 0; slot < ANON_MAPPINGS; slot++) + { + /* Compute the size of the shared-memory block */ + size = CalculateShmemSize(&numSemas, slot); + elog(DEBUG3, "invoking IpcMemoryCreate(size=%zu)", size); + + /* + * Create the shmem segment + */ + seghdr = PGSharedMemoryCreate(size, &shim); + + /* + * Make sure that huge pages are never reported as "unknown" while the + * server is running. + */ + Assert(strcmp("unknown", + GetConfigOption("huge_pages_status", false, false)) != 0); + + InitShmemAccessInSlot(seghdr, slot); + + /* + * Create semaphores + */ + PGReserveSemaphores(numSemas, slot); + + /* + * Set up shared memory allocation mechanism + */ + InitShmemAllocationInSlot(slot); + } /* Initialize subsystems */ CreateOrAttachShmemStructs(); @@ -359,7 +362,7 @@ InitializeShmemGUCs(void) /* * Calculate the shared memory size and round up to the nearest megabyte. */ - size_b = CalculateShmemSize(&num_semas); + size_b = CalculateShmemSize(&num_semas, MAIN_SHMEM_SLOT); 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 6d5f083986..c670b9cf43 100644 --- a/src/backend/storage/ipc/shmem.c +++ b/src/backend/storage/ipc/shmem.c @@ -75,17 +75,12 @@ #include "utils/builtins.h" static void *ShmemAllocRaw(Size size, Size *allocated_size); +static void *ShmemAllocRawInSlot(Size size, Size *allocated_size, + int shmem_slot); /* shared memory global variables */ -static PGShmemHeader *ShmemSegHdr; /* shared mem segment header */ - -static void *ShmemBase; /* start address of shared memory */ - -static void *ShmemEnd; /* end+1 address of shared memory */ - -slock_t *ShmemLock; /* spinlock for shared memory and LWLock - * allocation */ +ShmemSegment Segments[ANON_MAPPINGS]; static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */ @@ -99,11 +94,17 @@ static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */ void InitShmemAccess(void *seghdr) { - PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr; + InitShmemAccessInSlot(seghdr, MAIN_SHMEM_SLOT); +} - ShmemSegHdr = shmhdr; - ShmemBase = (void *) shmhdr; - ShmemEnd = (char *) ShmemBase + shmhdr->totalsize; +void +InitShmemAccessInSlot(void *seghdr, int shmem_slot) +{ + PGShmemHeader *shmhdr = (PGShmemHeader *) seghdr; + ShmemSegment *seg = &Segments[shmem_slot]; + seg->ShmemSegHdr = shmhdr; + seg->ShmemBase = (void *) shmhdr; + seg->ShmemEnd = (char *) seg->ShmemBase + shmhdr->totalsize; } /* @@ -114,7 +115,13 @@ InitShmemAccess(void *seghdr) void InitShmemAllocation(void) { - PGShmemHeader *shmhdr = ShmemSegHdr; + InitShmemAllocationInSlot(MAIN_SHMEM_SLOT); +} + +void +InitShmemAllocationInSlot(int shmem_slot) +{ + PGShmemHeader *shmhdr = Segments[shmem_slot].ShmemSegHdr; char *aligned; Assert(shmhdr != NULL); @@ -123,9 +130,9 @@ InitShmemAllocation(void) * Initialize the spinlock used by ShmemAlloc. We must use * ShmemAllocUnlocked, since obviously ShmemAlloc can't be called yet. */ - ShmemLock = (slock_t *) ShmemAllocUnlocked(sizeof(slock_t)); + Segments[shmem_slot].ShmemLock = (slock_t *) ShmemAllocUnlockedInSlot(sizeof(slock_t), shmem_slot); - SpinLockInit(ShmemLock); + SpinLockInit(Segments[shmem_slot].ShmemLock); /* * Allocations after this point should go through ShmemAlloc, which @@ -150,11 +157,17 @@ InitShmemAllocation(void) */ void * ShmemAlloc(Size size) +{ + return ShmemAllocInSlot(size, MAIN_SHMEM_SLOT); +} + +void * +ShmemAllocInSlot(Size size, int shmem_slot) { void *newSpace; Size allocated_size; - newSpace = ShmemAllocRaw(size, &allocated_size); + newSpace = ShmemAllocRawInSlot(size, &allocated_size, shmem_slot); if (!newSpace) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), @@ -184,6 +197,12 @@ ShmemAllocNoError(Size size) */ static void * ShmemAllocRaw(Size size, Size *allocated_size) +{ + return ShmemAllocRawInSlot(size, allocated_size, MAIN_SHMEM_SLOT); +} + +static void * +ShmemAllocRawInSlot(Size size, Size *allocated_size, int shmem_slot) { Size newStart; Size newFree; @@ -203,22 +222,22 @@ ShmemAllocRaw(Size size, Size *allocated_size) size = CACHELINEALIGN(size); *allocated_size = size; - Assert(ShmemSegHdr != NULL); + Assert(Segments[shmem_slot].ShmemSegHdr != NULL); - SpinLockAcquire(ShmemLock); + SpinLockAcquire(Segments[shmem_slot].ShmemLock); - newStart = ShmemSegHdr->freeoffset; + newStart = Segments[shmem_slot].ShmemSegHdr->freeoffset; newFree = newStart + size; - if (newFree <= ShmemSegHdr->totalsize) + if (newFree <= Segments[shmem_slot].ShmemSegHdr->totalsize) { - newSpace = (void *) ((char *) ShmemBase + newStart); - ShmemSegHdr->freeoffset = newFree; + newSpace = (void *) ((char *) Segments[shmem_slot].ShmemBase + newStart); + Segments[shmem_slot].ShmemSegHdr->freeoffset = newFree; } else newSpace = NULL; - SpinLockRelease(ShmemLock); + SpinLockRelease(Segments[shmem_slot].ShmemLock); /* note this assert is okay with newSpace == NULL */ Assert(newSpace == (void *) CACHELINEALIGN(newSpace)); @@ -236,6 +255,12 @@ ShmemAllocRaw(Size size, Size *allocated_size) */ void * ShmemAllocUnlocked(Size size) +{ + return ShmemAllocUnlockedInSlot(size, MAIN_SHMEM_SLOT); +} + +void * +ShmemAllocUnlockedInSlot(Size size, int shmem_slot) { Size newStart; Size newFree; @@ -246,19 +271,19 @@ ShmemAllocUnlocked(Size size) */ size = MAXALIGN(size); - Assert(ShmemSegHdr != NULL); + Assert(Segments[shmem_slot].ShmemSegHdr != NULL); - newStart = ShmemSegHdr->freeoffset; + newStart = Segments[shmem_slot].ShmemSegHdr->freeoffset; newFree = newStart + size; - if (newFree > ShmemSegHdr->totalsize) + if (newFree > Segments[shmem_slot].ShmemSegHdr->totalsize) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of shared memory (%zu bytes requested)", size))); - ShmemSegHdr->freeoffset = newFree; + Segments[shmem_slot].ShmemSegHdr->freeoffset = newFree; - newSpace = (void *) ((char *) ShmemBase + newStart); + newSpace = (void *) ((char *) Segments[shmem_slot].ShmemBase + newStart); Assert(newSpace == (void *) MAXALIGN(newSpace)); @@ -273,7 +298,13 @@ ShmemAllocUnlocked(Size size) bool ShmemAddrIsValid(const void *addr) { - return (addr >= ShmemBase) && (addr < ShmemEnd); + return ShmemAddrIsValidInSlot(addr, MAIN_SHMEM_SLOT); +} + +bool +ShmemAddrIsValidInSlot(const void *addr, int shmem_slot) +{ + return (addr >= Segments[shmem_slot].ShmemBase) && (addr < Segments[shmem_slot].ShmemEnd); } /* @@ -334,6 +365,18 @@ ShmemInitHash(const char *name, /* table string name for shmem index */ long max_size, /* max size of the table */ HASHCTL *infoP, /* info about key and bucket size */ int hash_flags) /* info about infoP */ +{ + return ShmemInitHashInSlot(name, init_size, max_size, infoP, hash_flags, + MAIN_SHMEM_SLOT); +} + +HTAB * +ShmemInitHashInSlot(const char *name, /* table string name for shmem index */ + long init_size, /* initial table size */ + long max_size, /* max size of the table */ + HASHCTL *infoP, /* info about key and bucket size */ + int hash_flags, /* info about infoP */ + int shmem_slot) /* in which slot to keep the table */ { bool found; void *location; @@ -350,9 +393,9 @@ ShmemInitHash(const char *name, /* table string name for shmem index */ hash_flags |= HASH_SHARED_MEM | HASH_ALLOC | HASH_DIRSIZE; /* look it up in the shmem index */ - location = ShmemInitStruct(name, + location = ShmemInitStructInSlot(name, hash_get_shared_size(infoP, hash_flags), - &found); + &found, shmem_slot); /* * if it already exists, attach to it rather than allocate and initialize @@ -385,6 +428,13 @@ ShmemInitHash(const char *name, /* table string name for shmem index */ */ void * ShmemInitStruct(const char *name, Size size, bool *foundPtr) +{ + return ShmemInitStructInSlot(name, size, foundPtr, MAIN_SHMEM_SLOT); +} + +void * +ShmemInitStructInSlot(const char *name, Size size, bool *foundPtr, + int shmem_slot) { ShmemIndexEnt *result; void *structPtr; @@ -393,7 +443,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) if (!ShmemIndex) { - PGShmemHeader *shmemseghdr = ShmemSegHdr; + PGShmemHeader *shmemseghdr = Segments[shmem_slot].ShmemSegHdr; /* Must be trying to create/attach to ShmemIndex itself */ Assert(strcmp(name, "ShmemIndex") == 0); @@ -416,7 +466,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) * process can be accessing shared memory yet. */ Assert(shmemseghdr->index == NULL); - structPtr = ShmemAlloc(size); + structPtr = ShmemAllocInSlot(size, shmem_slot); shmemseghdr->index = structPtr; *foundPtr = false; } @@ -433,8 +483,8 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) LWLockRelease(ShmemIndexLock); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("could not create ShmemIndex entry for data structure \"%s\"", - name))); + errmsg("could not create ShmemIndex entry for data structure \"%s\" in slot %d", + name, shmem_slot))); } if (*foundPtr) @@ -459,7 +509,7 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) Size allocated_size; /* It isn't in the table yet. allocate and initialize it */ - structPtr = ShmemAllocRaw(size, &allocated_size); + structPtr = ShmemAllocRawInSlot(size, &allocated_size, shmem_slot); if (structPtr == NULL) { /* out of memory; remove the failed ShmemIndex entry */ @@ -478,14 +528,13 @@ ShmemInitStruct(const char *name, Size size, bool *foundPtr) LWLockRelease(ShmemIndexLock); - Assert(ShmemAddrIsValid(structPtr)); + Assert(ShmemAddrIsValidInSlot(structPtr, shmem_slot)); Assert(structPtr == (void *) CACHELINEALIGN(structPtr)); return structPtr; } - /* * Add two Size values, checking for overflow */ @@ -545,7 +594,7 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) while ((ent = (ShmemIndexEnt *) hash_seq_search(&hstat)) != NULL) { values[0] = CStringGetTextDatum(ent->key); - values[1] = Int64GetDatum((char *) ent->location - (char *) ShmemSegHdr); + values[1] = Int64GetDatum((char *) ent->location - (char *) Segments[MAIN_SHMEM_SLOT].ShmemSegHdr); values[2] = Int64GetDatum(ent->size); values[3] = Int64GetDatum(ent->allocated_size); named_allocated += ent->allocated_size; @@ -557,15 +606,15 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS) /* output shared memory allocated but not counted via the shmem index */ values[0] = CStringGetTextDatum(""); nulls[1] = true; - values[2] = Int64GetDatum(ShmemSegHdr->freeoffset - named_allocated); + values[2] = Int64GetDatum(Segments[MAIN_SHMEM_SLOT].ShmemSegHdr->freeoffset - named_allocated); values[3] = values[2]; tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); /* output as-of-yet unused shared memory */ nulls[0] = true; - values[1] = Int64GetDatum(ShmemSegHdr->freeoffset); + values[1] = Int64GetDatum(Segments[MAIN_SHMEM_SLOT].ShmemSegHdr->freeoffset); nulls[1] = false; - values[2] = Int64GetDatum(ShmemSegHdr->totalsize - ShmemSegHdr->freeoffset); + values[2] = Int64GetDatum(Segments[MAIN_SHMEM_SLOT].ShmemSegHdr->totalsize - Segments[MAIN_SHMEM_SLOT].ShmemSegHdr->freeoffset); values[3] = values[2]; tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index e765754d80..fb0c33bf17 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -81,6 +81,7 @@ #include "pgstat.h" #include "port/pg_bitutils.h" #include "postmaster/postmaster.h" +#include "storage/pg_shmem.h" #include "storage/proc.h" #include "storage/proclist.h" #include "storage/spin.h" @@ -607,9 +608,9 @@ LWLockNewTrancheId(void) LWLockCounter = (int *) ((char *) MainLWLockArray - sizeof(int)); /* We use the ShmemLock spinlock to protect LWLockCounter */ - SpinLockAcquire(ShmemLock); + SpinLockAcquire(Segments[MAIN_SHMEM_SLOT].ShmemLock); result = (*LWLockCounter)++; - SpinLockRelease(ShmemLock); + SpinLockRelease(Segments[MAIN_SHMEM_SLOT].ShmemLock); return result; } diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index f190e6e5e4..aef80e049b 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -23,6 +23,7 @@ #include "storage/latch.h" #include "storage/lwlock.h" #include "storage/shmem.h" +#include "storage/pg_shmem.h" #include "storage/smgr.h" #include "storage/spin.h" #include "utils/relcache.h" diff --git a/src/include/storage/ipc.h b/src/include/storage/ipc.h index b2d062781e..be4b131288 100644 --- a/src/include/storage/ipc.h +++ b/src/include/storage/ipc.h @@ -77,7 +77,7 @@ extern void check_on_shmem_exit_lists_are_empty(void); /* ipci.c */ extern PGDLLIMPORT shmem_startup_hook_type shmem_startup_hook; -extern Size CalculateShmemSize(int *num_semaphores); +extern Size CalculateShmemSize(int *num_semaphores, int shmem_slot); extern void CreateSharedMemoryAndSemaphores(void); #ifdef EXEC_BACKEND extern void AttachSharedMemoryStructs(void); diff --git a/src/include/storage/pg_sema.h b/src/include/storage/pg_sema.h index dfef79ac96..081fffaf16 100644 --- a/src/include/storage/pg_sema.h +++ b/src/include/storage/pg_sema.h @@ -41,7 +41,7 @@ typedef HANDLE PGSemaphore; extern Size PGSemaphoreShmemSize(int maxSemas); /* Module initialization (called during postmaster start or shmem reinit) */ -extern void PGReserveSemaphores(int maxSemas); +extern void PGReserveSemaphores(int maxSemas, int shmem_slot); /* Allocate a PGSemaphore structure with initial count 1 */ extern PGSemaphore PGSemaphoreCreate(void); diff --git a/src/include/storage/pg_shmem.h b/src/include/storage/pg_shmem.h index 3065ff5be7..e968deeef7 100644 --- a/src/include/storage/pg_shmem.h +++ b/src/include/storage/pg_shmem.h @@ -25,6 +25,7 @@ #define PG_SHMEM_H #include "storage/dsm_impl.h" +#include "storage/spin.h" typedef struct PGShmemHeader /* standard header for all Postgres shmem */ { @@ -41,6 +42,20 @@ typedef struct PGShmemHeader /* standard header for all Postgres shmem */ #endif } PGShmemHeader; +typedef struct ShmemSegment +{ + PGShmemHeader *ShmemSegHdr; /* shared mem segment header */ + void *ShmemBase; /* start address of shared memory */ + void *ShmemEnd; /* end+1 address of shared memory */ + slock_t *ShmemLock; /* spinlock for shared memory and LWLock + * allocation */ +} ShmemSegment; + +// Number of available slots for anonymous memory mappings +#define ANON_MAPPINGS 1 + +extern PGDLLIMPORT ShmemSegment Segments[ANON_MAPPINGS]; + /* GUC variables */ extern PGDLLIMPORT int shared_memory_type; extern PGDLLIMPORT int huge_pages; @@ -90,4 +105,7 @@ extern bool PGSharedMemoryIsInUse(unsigned long id1, unsigned long id2); extern void PGSharedMemoryDetach(void); extern void GetHugePageSize(Size *hugepagesize, int *mmap_flags); +/* The main slot, contains everything except buffer blocks and related data. */ +#define MAIN_SHMEM_SLOT 0 + #endif /* PG_SHMEM_H */ diff --git a/src/include/storage/shmem.h b/src/include/storage/shmem.h index 842989111c..d3e9cc721d 100644 --- a/src/include/storage/shmem.h +++ b/src/include/storage/shmem.h @@ -28,15 +28,25 @@ /* shmem.c */ extern PGDLLIMPORT slock_t *ShmemLock; extern void InitShmemAccess(void *seghdr); +extern void InitShmemAccessInSlot(void *seghdr, int shmem_slot); extern void InitShmemAllocation(void); +extern void InitShmemAllocationInSlot(int shmem_slot); extern void *ShmemAlloc(Size size); +extern void *ShmemAllocInSlot(Size size, int shmem_slot); extern void *ShmemAllocNoError(Size size); extern void *ShmemAllocUnlocked(Size size); +extern void *ShmemAllocUnlockedInSlot(Size size, int shmem_slot); extern bool ShmemAddrIsValid(const void *addr); +extern bool ShmemAddrIsValidInSlot(const void *addr, int shmem_slot); extern void InitShmemIndex(void); +extern void InitVariableShmemIndex(void); extern HTAB *ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags); +extern HTAB *ShmemInitHashInSlot(const char *name, long init_size, long max_size, + HASHCTL *infoP, int hash_flags, int shmem_slot); extern void *ShmemInitStruct(const char *name, Size size, bool *foundPtr); +extern void *ShmemInitStructInSlot(const char *name, Size size, bool *foundPtr, + int shmem_slot); extern Size add_size(Size s1, Size s2); extern Size mul_size(Size s1, Size s2); base-commit: 2488058dc356a43455b21a099ea879fff9266634 -- 2.45.1