v8-0003-Improve-accounting-for-PredXactList-RWConflictPoo.patch
text/x-patch
Filename: v8-0003-Improve-accounting-for-PredXactList-RWConflictPoo.patch
Type: text/x-patch
Part: 2
Patch
Format: format-patch
Series: patch v8-0003
Subject: Improve accounting for PredXactList, RWConflictPool and PGPROC
| File | + | − |
|---|---|---|
| src/backend/storage/lmgr/predicate.c | 20 | 10 |
| src/backend/storage/lmgr/proc.c | 47 | 10 |
From 609404c682e28a59f80ac7630e4be8e46d12566e Mon Sep 17 00:00:00 2001
From: Rahila Syed <rahilasyed.90@gmail.com>
Date: Mon, 31 Mar 2025 03:45:50 +0530
Subject: [PATCH v8 3/5] Improve accounting for PredXactList, RWConflictPool
and PGPROC
Various places allocated shared memory by first allocating a small chunk
using ShmemInitStruct(), followed by ShmemAlloc() calls to allocate more
memory. Unfortunately, ShmemAlloc() does not update ShmemIndex, so this
affected pg_shmem_allocations - it only shown the initial chunk.
This commit modifies the following allocations, to allocate everything
as a single chunk, and then split it internally.
- PredXactList
- RWConflictPool
- PGPROC structures
- Fast-Path lock arrays
Author: Rahila Syed <rahilasyed90@gmail.com>
Reviewed-by: Andres Freund <andres@anarazel.de>
Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Reviewed-by: Tomas Vondra <tomas@vondra.me>
Discussion: https://postgr.es/m/CAH2L28vHzRankszhqz7deXURxKncxfirnuW68zD7+hVAqaS5GQ@mail.gmail.com
---
src/backend/storage/lmgr/predicate.c | 30 ++++++++++-----
src/backend/storage/lmgr/proc.c | 57 +++++++++++++++++++++++-----
2 files changed, 67 insertions(+), 20 deletions(-)
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 5b21a053981..d82114ffca1 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1226,14 +1226,21 @@ PredicateLockShmemInit(void)
*/
max_table_size *= 10;
+ requestSize = add_size(PredXactListDataSize,
+ (mul_size((Size) max_table_size,
+ sizeof(SERIALIZABLEXACT))));
+
PredXact = ShmemInitStruct("PredXactList",
- PredXactListDataSize,
+ requestSize,
&found);
Assert(found == IsUnderPostmaster);
if (!found)
{
int i;
+ /* clean everything, both the header and the element */
+ memset(PredXact, 0, requestSize);
+
dlist_init(&PredXact->availableList);
dlist_init(&PredXact->activeList);
PredXact->SxactGlobalXmin = InvalidTransactionId;
@@ -1242,11 +1249,9 @@ PredicateLockShmemInit(void)
PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1;
PredXact->CanPartialClearThrough = 0;
PredXact->HavePartialClearedThrough = 0;
- requestSize = mul_size((Size) max_table_size,
- sizeof(SERIALIZABLEXACT));
- PredXact->element = ShmemAlloc(requestSize);
+ PredXact->element
+ = (SERIALIZABLEXACT *) ((char *) PredXact + PredXactListDataSize);
/* Add all elements to available list, clean. */
- memset(PredXact->element, 0, requestSize);
for (i = 0; i < max_table_size; i++)
{
LWLockInitialize(&PredXact->element[i].perXactPredicateListLock,
@@ -1300,20 +1305,25 @@ PredicateLockShmemInit(void)
*/
max_table_size *= 5;
+ requestSize = RWConflictPoolHeaderDataSize +
+ mul_size((Size) max_table_size,
+ RWConflictDataSize);
+
RWConflictPool = ShmemInitStruct("RWConflictPool",
- RWConflictPoolHeaderDataSize,
+ requestSize,
&found);
Assert(found == IsUnderPostmaster);
if (!found)
{
int i;
+ /* clean everything, including the elements */
+ memset(RWConflictPool, 0, requestSize);
+
dlist_init(&RWConflictPool->availableList);
- requestSize = mul_size((Size) max_table_size,
- RWConflictDataSize);
- RWConflictPool->element = ShmemAlloc(requestSize);
+ RWConflictPool->element = (RWConflict) ((char *) RWConflictPool +
+ RWConflictPoolHeaderDataSize);
/* Add all elements to available list, clean. */
- memset(RWConflictPool->element, 0, requestSize);
for (i = 0; i < max_table_size; i++)
{
dlist_push_tail(&RWConflictPool->availableList,
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 066319afe2b..4e23c793f7f 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -123,6 +123,25 @@ ProcGlobalShmemSize(void)
return size;
}
+/*
+ * Report shared-memory space needed by PGPROC.
+ */
+static Size
+PGProcShmemSize(void)
+{
+ Size size;
+ uint32 TotalProcs;
+
+ TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+
+ size = TotalProcs * sizeof(PGPROC);
+ size = add_size(size, TotalProcs * sizeof(*ProcGlobal->xids));
+ size = add_size(size, TotalProcs * sizeof(*ProcGlobal->subxidStates));
+ size = add_size(size, TotalProcs * sizeof(*ProcGlobal->statusFlags));
+
+ return size;
+}
+
/*
* Report number of semaphores needed by InitProcGlobal.
*/
@@ -175,6 +194,8 @@ InitProcGlobal(void)
*fpEndPtr PG_USED_FOR_ASSERTS_ONLY;
Size fpLockBitsSize,
fpRelIdSize;
+ Size requestSize;
+ char *ptr;
/* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *)
@@ -204,7 +225,15 @@ InitProcGlobal(void)
* with a single freelist.) Each PGPROC structure is dedicated to exactly
* one of these purposes, and they do not move between groups.
*/
- procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC));
+ requestSize = PGProcShmemSize();
+
+ ptr = ShmemInitStruct("PGPROC structures",
+ requestSize,
+ &found);
+
+ procs = (PGPROC *) ptr;
+ ptr = (char *) ptr + TotalProcs * sizeof(PGPROC);
+
MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
ProcGlobal->allProcs = procs;
/* XXX allProcCount isn't really all of them; it excludes prepared xacts */
@@ -213,17 +242,21 @@ InitProcGlobal(void)
/*
* Allocate arrays mirroring PGPROC fields in a dense manner. See
* PROC_HDR.
- *
- * XXX: It might make sense to increase padding for these arrays, given
- * how hotly they are accessed.
*/
- ProcGlobal->xids =
- (TransactionId *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->xids));
+ ProcGlobal->xids = (TransactionId *) ptr;
MemSet(ProcGlobal->xids, 0, TotalProcs * sizeof(*ProcGlobal->xids));
- ProcGlobal->subxidStates = (XidCacheStatus *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->subxidStates));
+ ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->xids));
+
+ ProcGlobal->subxidStates = (XidCacheStatus *) ptr;
MemSet(ProcGlobal->subxidStates, 0, TotalProcs * sizeof(*ProcGlobal->subxidStates));
- ProcGlobal->statusFlags = (uint8 *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->statusFlags));
+ ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->subxidStates));
+
+ ProcGlobal->statusFlags = (uint8 *) ptr;
MemSet(ProcGlobal->statusFlags, 0, TotalProcs * sizeof(*ProcGlobal->statusFlags));
+ ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->statusFlags));
+
+ /* make sure wer didn't overflow */
+ Assert((ptr > (char *) procs) && (ptr <= (char *) procs + requestSize));
/*
* Allocate arrays for fast-path locks. Those are variable-length, so
@@ -233,7 +266,9 @@ InitProcGlobal(void)
fpLockBitsSize = MAXALIGN(FastPathLockGroupsPerBackend * sizeof(uint64));
fpRelIdSize = MAXALIGN(FastPathLockSlotsPerBackend() * sizeof(Oid));
- fpPtr = ShmemAlloc(TotalProcs * (fpLockBitsSize + fpRelIdSize));
+ fpPtr = ShmemInitStruct("Fast path lock arrays",
+ TotalProcs * (fpLockBitsSize + fpRelIdSize),
+ &found);
MemSet(fpPtr, 0, TotalProcs * (fpLockBitsSize + fpRelIdSize));
/* For asserts checking we did not overflow. */
@@ -330,7 +365,9 @@ InitProcGlobal(void)
PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];
/* Create ProcStructLock spinlock, too */
- ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t));
+ ProcStructLock = (slock_t *) ShmemInitStruct("ProcStructLock spinlock",
+ sizeof(slock_t),
+ &found);
SpinLockInit(ProcStructLock);
}
--
2.49.0