]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Improve accounting for PredXactList, RWConflictPool and PGPROC
authorTomas Vondra <tomas.vondra@postgresql.org>
Wed, 2 Apr 2025 15:08:34 +0000 (17:08 +0200)
committerTomas Vondra <tomas.vondra@postgresql.org>
Wed, 2 Apr 2025 15:14:28 +0000 (17:14 +0200)
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

src/backend/storage/lmgr/predicate.c
src/backend/storage/lmgr/proc.c

index 5b21a0539811488acd646755966fd8c9a9a94548..d82114ffca1650a4d3894137cbc06f9b184a510a 100644 (file)
@@ -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,
index 066319afe2b08c46a36a3a205718399dc44d756a..e9ef0fbfe32cb724744e2381fbe9c89561a35dbb 100644 (file)
@@ -91,26 +91,35 @@ static void CheckDeadLock(void);
 
 
 /*
- * Report shared-memory space needed by InitProcGlobal.
+ * Report shared-memory space needed by PGPROC.
  */
-Size
-ProcGlobalShmemSize(void)
+static Size
+PGProcShmemSize(void)
 {
        Size            size = 0;
        Size            TotalProcs =
                add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
-       Size            fpLockBitsSize,
-                               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)));
 
+       return size;
+}
+
+/*
+ * Report shared-memory space needed by Fast-Path locks.
+ */
+static Size
+FastPathLockShmemSize(void)
+{
+       Size            size = 0;
+       Size            TotalProcs =
+               add_size(MaxBackends, add_size(NUM_AUXILIARY_PROCS, max_prepared_xacts));
+       Size            fpLockBitsSize,
+                               fpRelIdSize;
+
        /*
         * Memory needed for PGPROC fast-path lock arrays. Make sure the sizes are
         * nicely aligned in each backend.
@@ -123,6 +132,24 @@ ProcGlobalShmemSize(void)
        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.
  */
@@ -175,6 +202,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,8 +233,17 @@ 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));
-       MemSet(procs, 0, TotalProcs * sizeof(PGPROC));
+       requestSize = PGProcShmemSize();
+
+       ptr = ShmemInitStruct("PGPROC structures",
+                                                 requestSize,
+                                                 &found);
+
+       MemSet(ptr, 0, requestSize);
+
+       procs = (PGPROC *) ptr;
+       ptr = (char *) ptr + TotalProcs * sizeof(PGPROC);
+
        ProcGlobal->allProcs = procs;
        /* XXX allProcCount isn't really all of them; it excludes prepared xacts */
        ProcGlobal->allProcCount = MaxBackends + NUM_AUXILIARY_PROCS;
@@ -217,13 +255,17 @@ InitProcGlobal(void)
         * 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));
-       MemSet(ProcGlobal->xids, 0, TotalProcs * sizeof(*ProcGlobal->xids));
-       ProcGlobal->subxidStates = (XidCacheStatus *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->subxidStates));
-       MemSet(ProcGlobal->subxidStates, 0, TotalProcs * sizeof(*ProcGlobal->subxidStates));
-       ProcGlobal->statusFlags = (uint8 *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->statusFlags));
-       MemSet(ProcGlobal->statusFlags, 0, TotalProcs * sizeof(*ProcGlobal->statusFlags));
+       ProcGlobal->xids = (TransactionId *) ptr;
+       ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->xids));
+
+       ProcGlobal->subxidStates = (XidCacheStatus *) ptr;
+       ptr = (char *) ptr + (TotalProcs * sizeof(*ProcGlobal->subxidStates));
+
+       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
@@ -233,11 +275,16 @@ InitProcGlobal(void)
        fpLockBitsSize = MAXALIGN(FastPathLockGroupsPerBackend * sizeof(uint64));
        fpRelIdSize = MAXALIGN(FastPathLockSlotsPerBackend() * sizeof(Oid));
 
-       fpPtr = ShmemAlloc(TotalProcs * (fpLockBitsSize + fpRelIdSize));
-       MemSet(fpPtr, 0, TotalProcs * (fpLockBitsSize + fpRelIdSize));
+       requestSize = FastPathLockShmemSize();
+
+       fpPtr = ShmemInitStruct("Fast-Path Lock Array",
+                                                       requestSize,
+                                                       &found);
+
+       MemSet(fpPtr, 0, requestSize);
 
        /* For asserts checking we did not overflow. */
-       fpEndPtr = fpPtr + (TotalProcs * (fpLockBitsSize + fpRelIdSize));
+       fpEndPtr = fpPtr + requestSize;
 
        for (i = 0; i < TotalProcs; i++)
        {
@@ -330,7 +377,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);
 }