0001-Allow-to-use-multiple-shared-memory-mapping-20250113.patch
text/x-patch
Filename: 0001-Allow-to-use-multiple-shared-memory-mapping-20250113.patch
Type: text/x-patch
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0001
Subject: Allow to use multiple shared memory mappings
| File | + | − |
|---|---|---|
| src/backend/port/posix_sema.c | 2 | 2 |
| src/backend/port/sysv_sema.c | 2 | 2 |
| src/backend/port/sysv_shmem.c | 95 | 43 |
| src/backend/port/win32_sema.c | 1 | 1 |
| src/backend/storage/ipc/ipc.c | 1 | 1 |
| src/backend/storage/ipc/ipci.c | 32 | 29 |
| src/backend/storage/ipc/shmem.c | 94 | 41 |
| src/backend/storage/lmgr/lwlock.c | 3 | 2 |
| src/include/storage/buf_internals.h | 1 | 0 |
| src/include/storage/ipc.h | 1 | 1 |
| src/include/storage/pg_sema.h | 1 | 1 |
| src/include/storage/pg_shmem.h | 18 | 0 |
| src/include/storage/shmem.h | 10 | 0 |
From e7b3e3690a9b9575394cffbde2f7c5e674d28ed9 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Wed, 9 Oct 2024 15:41:32 +0200
Subject: [PATCH 1/7] 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 | 135 ++++++++++++++++++---------
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, 261 insertions(+), 123 deletions(-)
diff --git a/src/backend/port/posix_sema.c b/src/backend/port/posix_sema.c
index 64186ec0a7e..b97723d2ede 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 68835723b90..e6720a6a077 100644
--- a/src/backend/port/sysv_sema.c
+++ b/src/backend/port/sysv_sema.c
@@ -313,7 +313,7 @@ PGSemaphoreShmemSize(int maxSemas)
* have clobbered.)
*/
void
-PGReserveSemaphores(int maxSemas)
+PGReserveSemaphores(int maxSemas, int shmem_slot)
{
struct stat statbuf;
@@ -334,7 +334,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 a5a4511f66d..475c9c8f1a1 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 f2b54bdfda0..d62084cc0d9 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 b06e4b84528..2aabd4a77f3 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 7783ba854fc..c0e1d94d1f7 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -85,7 +85,7 @@ RequestAddinShmemSpace(Size size)
* required.
*/
Size
-CalculateShmemSize(int *num_semaphores)
+CalculateShmemSize(int *num_semaphores, int shmem_slot)
{
Size size;
int numSemas;
@@ -204,33 +204,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();
@@ -360,7 +363,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 6d3074594a6..89d8c7baf16 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 */
@@ -96,9 +91,17 @@ static HTAB *ShmemIndex = NULL; /* primary index hashtable for shmem */
void
InitShmemAccess(PGShmemHeader *seghdr)
{
- ShmemSegHdr = seghdr;
- ShmemBase = seghdr;
- ShmemEnd = (char *) ShmemBase + seghdr->totalsize;
+ InitShmemAccessInSlot(seghdr, MAIN_SHMEM_SLOT);
+}
+
+void
+InitShmemAccessInSlot(PGShmemHeader *seghdr, int shmem_slot)
+{
+ ShmemSegment *seg = &Segments[shmem_slot];
+
+ seg->ShmemSegHdr = seghdr;
+ seg->ShmemBase = (void *) seghdr;
+ seg->ShmemEnd = (char *) seg->ShmemBase + seghdr->totalsize;
}
/*
@@ -109,7 +112,13 @@ InitShmemAccess(PGShmemHeader *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);
@@ -118,9 +127,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
@@ -145,11 +154,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),
@@ -179,10 +194,17 @@ 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;
void *newSpace;
+ ShmemSegment *seg = &Segments[shmem_slot];
/*
* Ensure all space is adequately aligned. We used to only MAXALIGN this
@@ -198,22 +220,22 @@ ShmemAllocRaw(Size size, Size *allocated_size)
size = CACHELINEALIGN(size);
*allocated_size = size;
- Assert(ShmemSegHdr != NULL);
+ Assert(seg->ShmemSegHdr != NULL);
- SpinLockAcquire(ShmemLock);
+ SpinLockAcquire(seg->ShmemLock);
- newStart = ShmemSegHdr->freeoffset;
+ newStart = seg->ShmemSegHdr->freeoffset;
newFree = newStart + size;
- if (newFree <= ShmemSegHdr->totalsize)
+ if (newFree <= seg->ShmemSegHdr->totalsize)
{
- newSpace = (char *) ShmemBase + newStart;
- ShmemSegHdr->freeoffset = newFree;
+ newSpace = (char *) seg->ShmemBase + newStart;
+ seg->ShmemSegHdr->freeoffset = newFree;
}
else
newSpace = NULL;
- SpinLockRelease(ShmemLock);
+ SpinLockRelease(seg->ShmemLock);
/* note this assert is okay with newSpace == NULL */
Assert(newSpace == (void *) CACHELINEALIGN(newSpace));
@@ -231,29 +253,36 @@ 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;
void *newSpace;
+ ShmemSegment *seg = &Segments[shmem_slot];
/*
* Ensure allocated space is adequately aligned.
*/
size = MAXALIGN(size);
- Assert(ShmemSegHdr != NULL);
+ Assert(seg->ShmemSegHdr != NULL);
- newStart = ShmemSegHdr->freeoffset;
+ newStart = seg->ShmemSegHdr->freeoffset;
newFree = newStart + size;
- if (newFree > ShmemSegHdr->totalsize)
+ if (newFree > seg->ShmemSegHdr->totalsize)
ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of shared memory (%zu bytes requested)",
size)));
- ShmemSegHdr->freeoffset = newFree;
+ seg->ShmemSegHdr->freeoffset = newFree;
- newSpace = (char *) ShmemBase + newStart;
+ newSpace = (char *) seg->ShmemBase + newStart;
Assert(newSpace == (void *) MAXALIGN(newSpace));
@@ -268,7 +297,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);
}
/*
@@ -329,6 +364,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;
@@ -345,9 +392,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
@@ -380,6 +427,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;
@@ -388,7 +442,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);
@@ -411,7 +465,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;
}
@@ -428,8 +482,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)
@@ -454,7 +508,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 */
@@ -473,14 +527,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
*/
@@ -540,7 +593,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;
@@ -552,15 +605,15 @@ pg_get_shmem_allocations(PG_FUNCTION_ARGS)
/* output shared memory allocated but not counted via the shmem index */
values[0] = CStringGetTextDatum("<anonymous>");
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 9cf3e4f4f3a..cd3237b3736 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 eda6c699212..b25dc0199b8 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -22,6 +22,7 @@
#include "storage/condition_variable.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 b2d062781ec..be4b1312888 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 dfef79ac963..081fffaf165 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 3065ff5be71..e968deeef7f 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 8cdbe7a89c8..4261b4039b9 100644
--- a/src/include/storage/shmem.h
+++ b/src/include/storage/shmem.h
@@ -29,15 +29,25 @@
extern PGDLLIMPORT slock_t *ShmemLock;
struct PGShmemHeader; /* avoid including storage/pg_shmem.h here */
extern void InitShmemAccess(struct PGShmemHeader *seghdr);
+extern void InitShmemAccessInSlot(struct PGShmemHeader *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);
--
2.34.1