1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-20 00:42:27 +03:00

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 Array

The fast-path lock array is allocated separately, not as a part of the
PGPROC structures allocation.

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
This commit is contained in:
Tomas Vondra 2025-04-02 17:08:34 +02:00
parent f5930f9a98
commit 46df9487d9
2 changed files with 94 additions and 35 deletions

View File

@ -1226,14 +1226,21 @@ PredicateLockShmemInit(void)
*/ */
max_table_size *= 10; max_table_size *= 10;
requestSize = add_size(PredXactListDataSize,
(mul_size((Size) max_table_size,
sizeof(SERIALIZABLEXACT))));
PredXact = ShmemInitStruct("PredXactList", PredXact = ShmemInitStruct("PredXactList",
PredXactListDataSize, requestSize,
&found); &found);
Assert(found == IsUnderPostmaster); Assert(found == IsUnderPostmaster);
if (!found) if (!found)
{ {
int i; int i;
/* clean everything, both the header and the element */
memset(PredXact, 0, requestSize);
dlist_init(&PredXact->availableList); dlist_init(&PredXact->availableList);
dlist_init(&PredXact->activeList); dlist_init(&PredXact->activeList);
PredXact->SxactGlobalXmin = InvalidTransactionId; PredXact->SxactGlobalXmin = InvalidTransactionId;
@ -1242,11 +1249,9 @@ PredicateLockShmemInit(void)
PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1; PredXact->LastSxactCommitSeqNo = FirstNormalSerCommitSeqNo - 1;
PredXact->CanPartialClearThrough = 0; PredXact->CanPartialClearThrough = 0;
PredXact->HavePartialClearedThrough = 0; PredXact->HavePartialClearedThrough = 0;
requestSize = mul_size((Size) max_table_size, PredXact->element
sizeof(SERIALIZABLEXACT)); = (SERIALIZABLEXACT *) ((char *) PredXact + PredXactListDataSize);
PredXact->element = ShmemAlloc(requestSize);
/* Add all elements to available list, clean. */ /* Add all elements to available list, clean. */
memset(PredXact->element, 0, requestSize);
for (i = 0; i < max_table_size; i++) for (i = 0; i < max_table_size; i++)
{ {
LWLockInitialize(&PredXact->element[i].perXactPredicateListLock, LWLockInitialize(&PredXact->element[i].perXactPredicateListLock,
@ -1300,20 +1305,25 @@ PredicateLockShmemInit(void)
*/ */
max_table_size *= 5; max_table_size *= 5;
requestSize = RWConflictPoolHeaderDataSize +
mul_size((Size) max_table_size,
RWConflictDataSize);
RWConflictPool = ShmemInitStruct("RWConflictPool", RWConflictPool = ShmemInitStruct("RWConflictPool",
RWConflictPoolHeaderDataSize, requestSize,
&found); &found);
Assert(found == IsUnderPostmaster); Assert(found == IsUnderPostmaster);
if (!found) if (!found)
{ {
int i; int i;
/* clean everything, including the elements */
memset(RWConflictPool, 0, requestSize);
dlist_init(&RWConflictPool->availableList); dlist_init(&RWConflictPool->availableList);
requestSize = mul_size((Size) max_table_size, RWConflictPool->element = (RWConflict) ((char *) RWConflictPool +
RWConflictDataSize); RWConflictPoolHeaderDataSize);
RWConflictPool->element = ShmemAlloc(requestSize);
/* Add all elements to available list, clean. */ /* Add all elements to available list, clean. */
memset(RWConflictPool->element, 0, requestSize);
for (i = 0; i < max_table_size; i++) for (i = 0; i < max_table_size; i++)
{ {
dlist_push_tail(&RWConflictPool->availableList, dlist_push_tail(&RWConflictPool->availableList,

View File

@ -91,10 +91,28 @@ static void CheckDeadLock(void);
/* /*
* Report shared-memory space needed by InitProcGlobal. * Report shared-memory space needed by PGPROC.
*/ */
Size static Size
ProcGlobalShmemSize(void) PGProcShmemSize(void)
{
Size size = 0;
Size TotalProcs =
add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
size = add_size(size, mul_size(TotalProcs, sizeof(PGPROC)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->subxidStates)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->statusFlags)));
return size;
}
/*
* Report shared-memory space needed by Fast-Path locks.
*/
static Size
FastPathLockShmemSize(void)
{ {
Size size = 0; Size size = 0;
Size TotalProcs = Size TotalProcs =
@ -102,15 +120,6 @@ ProcGlobalShmemSize(void)
Size fpLockBitsSize, Size fpLockBitsSize,
fpRelIdSize; fpRelIdSize;
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
size = add_size(size, mul_size(TotalProcs, sizeof(PGPROC)));
size = add_size(size, sizeof(slock_t));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->subxidStates)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->statusFlags)));
/* /*
* Memory needed for PGPROC fast-path lock arrays. Make sure the sizes are * Memory needed for PGPROC fast-path lock arrays. Make sure the sizes are
* nicely aligned in each backend. * nicely aligned in each backend.
@ -123,6 +132,24 @@ ProcGlobalShmemSize(void)
return size; return size;
} }
/*
* Report shared-memory space needed by InitProcGlobal.
*/
Size
ProcGlobalShmemSize(void)
{
Size size = 0;
/* ProcGlobal */
size = add_size(size, sizeof(PROC_HDR));
size = add_size(size, sizeof(slock_t));
size = add_size(size, PGProcShmemSize());
size = add_size(size, FastPathLockShmemSize());
return size;
}
/* /*
* Report number of semaphores needed by InitProcGlobal. * Report number of semaphores needed by InitProcGlobal.
*/ */
@ -175,6 +202,8 @@ InitProcGlobal(void)
*fpEndPtr PG_USED_FOR_ASSERTS_ONLY; *fpEndPtr PG_USED_FOR_ASSERTS_ONLY;
Size fpLockBitsSize, Size fpLockBitsSize,
fpRelIdSize; fpRelIdSize;
Size requestSize;
char *ptr;
/* Create the ProcGlobal shared structure */ /* Create the ProcGlobal shared structure */
ProcGlobal = (PROC_HDR *) ProcGlobal = (PROC_HDR *)
@ -204,8 +233,17 @@ InitProcGlobal(void)
* with a single freelist.) Each PGPROC structure is dedicated to exactly * with a single freelist.) Each PGPROC structure is dedicated to exactly
* one of these purposes, and they do not move between groups. * one of these purposes, and they do not move between groups.
*/ */
procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC)); requestSize = PGProcShmemSize();
MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
ptr = ShmemInitStruct("PGPROC structures",
requestSize,
&found);
MemSet(ptr, 0, requestSize);
procs = (PGPROC *) ptr;
ptr = (char *) ptr + TotalProcs * sizeof(PGPROC);
ProcGlobal->allProcs = procs; ProcGlobal->allProcs = procs;
/* XXX allProcCount isn't really all of them; it excludes prepared xacts */ /* XXX allProcCount isn't really all of them; it excludes prepared xacts */
ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS; ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS;
@ -217,13 +255,17 @@ InitProcGlobal(void)
* XXX: It might make sense to increase padding for these arrays, given * XXX: It might make sense to increase padding for these arrays, given
* how hotly they are accessed. * how hotly they are accessed.
*/ */
ProcGlobal->xids = ProcGlobal->xids = (TransactionId *) ptr;
(TransactionId *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->xids)); ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->xids));
MemSet(ProcGlobal->xids, 0, TotalProcs * sizeof(*ProcGlobal->xids));
ProcGlobal->subxidStates = (XidCacheStatus *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->subxidStates)); ProcGlobal->subxidStates = (XidCacheStatus *) ptr;
MemSet(ProcGlobal->subxidStates, 0, TotalProcs * sizeof(*ProcGlobal->subxidStates)); ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->subxidStates));
ProcGlobal->statusFlags = (uint8 *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->statusFlags));
MemSet(ProcGlobal->statusFlags, 0, TotalProcs * sizeof(*ProcGlobal->statusFlags)); ProcGlobal->statusFlags = (uint8 *) ptr;
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 * Allocate arrays for fast-path locks. Those are variable-length, so
@ -233,11 +275,16 @@ InitProcGlobal(void)
fpLockBitsSize = MAXALIGN(FastPathLockGroupsPerBackend * sizeof(uint64)); fpLockBitsSize = MAXALIGN(FastPathLockGroupsPerBackend * sizeof(uint64));
fpRelIdSize = MAXALIGN(FastPathLockSlotsPerBackend() * sizeof(Oid)); fpRelIdSize = MAXALIGN(FastPathLockSlotsPerBackend() * sizeof(Oid));
fpPtr = ShmemAlloc(TotalProcs * (fpLockBitsSize + fpRelIdSize)); requestSize = FastPathLockShmemSize();
MemSet(fpPtr, 0, TotalProcs * (fpLockBitsSize + fpRelIdSize));
fpPtr = ShmemInitStruct("Fast-Path Lock Array",
requestSize,
&found);
MemSet(fpPtr, 0, requestSize);
/* For asserts checking we did not overflow. */ /* For asserts checking we did not overflow. */
fpEndPtr = fpPtr + (TotalProcs * (fpLockBitsSize + fpRelIdSize)); fpEndPtr = fpPtr + requestSize;
for (i = 0; i < TotalProcs; i++) for (i = 0; i < TotalProcs; i++)
{ {
@ -330,7 +377,9 @@ InitProcGlobal(void)
PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS]; PreparedXactProcs = &procs[MaxBackends + NUM_AUXILIARY_PROCS];
/* Create ProcStructLock spinlock, too */ /* Create ProcStructLock spinlock, too */
ProcStructLock = (slock_t *) ShmemAlloc(sizeof(slock_t)); ProcStructLock = (slock_t *) ShmemInitStruct("ProcStructLock spinlock",
sizeof(slock_t),
&found);
SpinLockInit(ProcStructLock); SpinLockInit(ProcStructLock);
} }