From ad9aaca8aa5d589bed5d8f7238965e212c2872a6 Mon Sep 17 00:00:00 2001 From: Alexandre Felipe Date: Mon, 5 Oct 2026 18:00:17 +0100 Subject: [PATCH-v1 1/2] LWLock struct layout This commit change how the LWLock partitions are declared, without actually changing how they are allocated. The idea is leverage structure fields for the offset calculation instead of writing macros recursively. This will make easier to declare lock groups of different sizes in the next commit. --- src/backend/storage/lmgr/lwlock.c | 62 ++++++++++++++-------------- src/backend/storage/lmgr/predicate.c | 4 +- src/include/storage/buf_internals.h | 5 +-- src/include/storage/lock.h | 5 +-- src/include/storage/lwlock.h | 36 ++++++++++------ src/include/storage/lwlocklist.h | 3 +- 6 files changed, 63 insertions(+), 52 deletions(-) diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 82a1d4d2e26..2abaa81a688 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -147,7 +147,7 @@ StaticAssertDecl(lengthof(BuiltinTrancheNames) == "missing entries in BuiltinTrancheNames[]"); /* Main array of LWLocks in shared memory */ -LWLockPadded *MainLWLockArray = NULL; +MainLWLockStruct *MainLWLocks = NULL; /* * We use this structure to keep track of locked LWLocks for release @@ -180,9 +180,8 @@ typedef struct LWLockTrancheShmemData char name[NAMEDATALEN]; /* - * Index of the tranche's locks in MainLWLockArray if this tranche was - * allocated with RequestNamedLWLockTranche(), or -1 if the tranche - * was allocated with LWLockNewTrancheId() + * Index of this tranche's first lock in MainLWLockStruct.extra, or -1 + * if the tranche was allocated with LWLockNewTrancheId(). */ int main_array_idx; } user_defined[MAX_USER_DEFINED_TRANCHES]; @@ -210,8 +209,8 @@ typedef struct NamedLWLockTrancheRequest static List *NamedLWLockTrancheRequests = NIL; -/* Size of MainLWLockArray. Only valid in postmaster. */ -static int num_main_array_locks; +/* Number of extension LWLocks in MainLWLockStruct.extra[]. Postmaster only. */ +static int num_extra_lwlocks; static void LWLockShmemRequest(void *arg); static void LWLockShmemInit(void *arg); @@ -344,7 +343,7 @@ print_lwlock_stats(int code, Datum arg) hash_seq_init(&scan, lwlock_stats_htab); /* Grab an LWLock to keep different backends from mixing reports */ - LWLockAcquire(&MainLWLockArray[0].lock, LW_EXCLUSIVE); + LWLockAcquire(&MainLWLocks->individual[0].lock, LW_EXCLUSIVE); while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL) { @@ -356,7 +355,7 @@ print_lwlock_stats(int code, Datum arg) lwstats->spin_delay_count, lwstats->dequeue_self_count); } - LWLockRelease(&MainLWLockArray[0].lock); + LWLockRelease(&MainLWLocks->individual[0].lock); } static lwlock_stats * @@ -426,15 +425,16 @@ LWLockShmemRequest(void *arg) /* Space for the LWLock array */ if (!IsUnderPostmaster) { - num_main_array_locks = NUM_FIXED_LWLOCKS + NumLWLocksForNamedTranches(); - size = num_main_array_locks * sizeof(LWLockPadded); + num_extra_lwlocks = NumLWLocksForNamedTranches(); + size = MAIN_LWLOCKS_BUILTIN_SIZE + + ((Size) num_extra_lwlocks) * sizeof(LWLockPadded); } else size = SHMEM_ATTACH_UNKNOWN_SIZE; ShmemRequestStruct(.name = "Main LWLock array", .size = size, - .ptr = (void **) &MainLWLockArray, + .ptr = (void **) &MainLWLocks, ); } @@ -451,37 +451,36 @@ LWLockShmemInit(void *arg) SpinLockInit(&LWLockTranches->lock); + Assert(MainLWLocks != NULL); + /* - * Allocate and initialize all LWLocks in the main array. It includes all - * LWLocks for built-in tranches and those requested with + * Initialize built-in LWLocks and those requested with * RequestNamedLWLockTranche(). */ - pos = 0; - + /* Initialize all individual LWLocks in main array */ for (int id = 0; id < NUM_INDIVIDUAL_LWLOCKS; id++) - LWLockInitialize(&MainLWLockArray[pos++].lock, id); + LWLockInitialize(&MainLWLocks->individual[id].lock, id); /* Initialize buffer mapping LWLocks in main array */ - Assert(pos == BUFFER_MAPPING_LWLOCK_OFFSET); for (int i = 0; i < NUM_BUFFER_PARTITIONS; i++) - LWLockInitialize(&MainLWLockArray[pos++].lock, LWTRANCHE_BUFFER_MAPPING); + LWLockInitialize(&MainLWLocks->buffer_mapping[i].lock, + LWTRANCHE_BUFFER_MAPPING); - /* Initialize lmgrs' LWLocks in main array */ - Assert(pos == LOCK_MANAGER_LWLOCK_OFFSET); for (int i = 0; i < NUM_LOCK_PARTITIONS; i++) - LWLockInitialize(&MainLWLockArray[pos++].lock, LWTRANCHE_LOCK_MANAGER); + LWLockInitialize(&MainLWLocks->lock_manager[i].lock, + LWTRANCHE_LOCK_MANAGER); /* Initialize predicate lmgrs' LWLocks in main array */ - Assert(pos == PREDICATELOCK_MANAGER_LWLOCK_OFFSET); for (int i = 0; i < NUM_PREDICATELOCK_PARTITIONS; i++) - LWLockInitialize(&MainLWLockArray[pos++].lock, LWTRANCHE_PREDICATE_LOCK_MANAGER); + LWLockInitialize(&MainLWLocks->predicate_lock_manager[i].lock, + LWTRANCHE_PREDICATE_LOCK_MANAGER); /* * Copy the info about any user-defined tranches into shared memory (so * that other processes can see it), and initialize the requested LWLocks. */ - Assert(pos == NUM_FIXED_LWLOCKS); + pos = 0; foreach_ptr(NamedLWLockTrancheRequest, request, NamedLWLockTrancheRequests) { int idx = (LWLockTranches->num_user_defined++); @@ -492,11 +491,14 @@ LWLockShmemInit(void *arg) LWLockTranches->user_defined[idx].main_array_idx = pos; for (int i = 0; i < request->num_lwlocks; i++) - LWLockInitialize(&MainLWLockArray[pos++].lock, LWTRANCHE_FIRST_USER_DEFINED + idx); + { + LWLockInitialize(&MainLWLocks->extra[pos++].lock, + LWTRANCHE_FIRST_USER_DEFINED + idx); + } } /* Cross-check that we agree on the total size with LWLockShmemRequest() */ - Assert(pos == num_main_array_locks); + Assert(pos == num_extra_lwlocks); } /* @@ -526,10 +528,8 @@ GetNamedLWLockTranche(const char *tranche_name) SpinLockRelease(&LWLockTranches->lock); /* - * Obtain the position of base address of LWLock belonging to requested - * tranche_name in MainLWLockArray. LWLocks for user-defined tranches - * requested with RequestNamedLWLockTranche() are placed in - * MainLWLockArray after fixed locks. + * Obtain the base address of LWLocks for tranche_name in + * MainLWLockStruct.extra (after the built-in regions). */ for (int i = 0; i < LocalNumUserDefinedTranches; i++) { @@ -545,7 +545,7 @@ GetNamedLWLockTranche(const char *tranche_name) */ if (lock_pos == -1) elog(ERROR, "requested tranche was not registered with RequestNamedLWLockTranche()"); - return &MainLWLockArray[lock_pos]; + return &MainLWLocks->extra[lock_pos]; } } diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index 0ae85b7d5b4..70f7599abd2 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -255,10 +255,10 @@ #define PredicateLockHashPartition(hashcode) \ ((hashcode) % NUM_PREDICATELOCK_PARTITIONS) #define PredicateLockHashPartitionLock(hashcode) \ - (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + \ + (&MainLWLocks->predicate_lock_manager[ \ PredicateLockHashPartition(hashcode)].lock) #define PredicateLockHashPartitionLockByIndex(i) \ - (&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock) + (&MainLWLocks->predicate_lock_manager[(i)].lock) #define NPREDICATELOCKTARGETENTS() \ mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts)) diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h index e4ff5619b79..ec6b3432f22 100644 --- a/src/include/storage/buf_internals.h +++ b/src/include/storage/buf_internals.h @@ -253,14 +253,13 @@ BufTableHashPartition(uint32 hashcode) static inline LWLock * BufMappingPartitionLock(uint32 hashcode) { - return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + - BufTableHashPartition(hashcode)].lock; + return &MainLWLocks->buffer_mapping[BufTableHashPartition(hashcode)].lock; } static inline LWLock * BufMappingPartitionLockByIndex(uint32 index) { - return &MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + index].lock; + return &MainLWLocks->buffer_mapping[index].lock; } /* diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index c63c9075466..d24ff3d0514 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -355,10 +355,9 @@ typedef enum #define LockHashPartition(hashcode) \ ((hashcode) % NUM_LOCK_PARTITIONS) #define LockHashPartitionLock(hashcode) \ - (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + \ - LockHashPartition(hashcode)].lock) + (&MainLWLocks->lock_manager[LockHashPartition(hashcode)].lock) #define LockHashPartitionLockByIndex(i) \ - (&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock) + (&MainLWLocks->lock_manager[(i)].lock) /* * The deadlock detector needs to be able to access lockGroupLeader and diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h index efa5b427e9f..f1afaf894fe 100644 --- a/src/include/storage/lwlock.h +++ b/src/include/storage/lwlock.h @@ -71,16 +71,15 @@ typedef union LWLockPadded char pad[LWLOCK_PADDED_SIZE]; } LWLockPadded; -extern PGDLLIMPORT LWLockPadded *MainLWLockArray; - /* * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS - * here, but we need them to figure out offsets within MainLWLockArray, and + * here, but we need them for the definition of MainLWLockStruct, and * having this file include lock.h or bufmgr.h would be backwards. */ /* Number of partitions of the shared buffer mapping hashtable */ -#define NUM_BUFFER_PARTITIONS 128 +#define LOG2_NUM_BUFFER_PARTITIONS 7 +#define NUM_BUFFER_PARTITIONS (1 << LOG2_NUM_BUFFER_PARTITIONS) /* Number of partitions the shared lock tables are divided into */ #define LOG2_NUM_LOCK_PARTITIONS 4 @@ -90,14 +89,27 @@ extern PGDLLIMPORT LWLockPadded *MainLWLockArray; #define LOG2_NUM_PREDICATELOCK_PARTITIONS 4 #define NUM_PREDICATELOCK_PARTITIONS (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS) -/* Offsets for various chunks of preallocated lwlocks. */ -#define BUFFER_MAPPING_LWLOCK_OFFSET NUM_INDIVIDUAL_LWLOCKS -#define LOCK_MANAGER_LWLOCK_OFFSET \ - (BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS) -#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET \ - (LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS) -#define NUM_FIXED_LWLOCKS \ - (PREDICATELOCK_MANAGER_LWLOCK_OFFSET + NUM_PREDICATELOCK_PARTITIONS) +/* + * Built-in LWLocks in shared memory. Extension locks requested with + * RequestNamedLWLockTranche() are stored in extra[]. + */ +typedef struct MainLWLockStruct +{ + LWLockPadded individual[NUM_INDIVIDUAL_LWLOCKS]; + LWLockPadded buffer_mapping[NUM_BUFFER_PARTITIONS]; + LWLockPadded lock_manager[NUM_LOCK_PARTITIONS]; + LWLockPadded predicate_lock_manager[NUM_PREDICATELOCK_PARTITIONS]; + LWLockPadded extra[FLEXIBLE_ARRAY_MEMBER]; +} MainLWLockStruct; + +extern PGDLLIMPORT MainLWLockStruct *MainLWLocks; + +/* + * Byte size of the built-in portion of MainLWLockStruct (everything before + * extra[]). Used for shared-memory sizing; not a lock count, so member types + * can differ (e.g. mix LWLock and LWLockPadded) without changing this idiom. + */ +#define MAIN_LWLOCKS_BUILTIN_SIZE offsetof(MainLWLockStruct, extra) typedef enum LWLockMode { diff --git a/src/include/storage/lwlocklist.h b/src/include/storage/lwlocklist.h index 8d858be9927..6af5372af55 100644 --- a/src/include/storage/lwlocklist.h +++ b/src/include/storage/lwlocklist.h @@ -20,7 +20,8 @@ */ /* - * Some commonly-used locks have predefined positions within MainLWLockArray; + * Some commonly-used locks have predefined positions within the individual + * locks of MainLWLockStruct.fixed; these are defined here. * these are defined here. If you add a lock, add it to the end to avoid * renumbering the existing locks; if you remove a lock, consider leaving a gap * in the numbering sequence for the benefit of DTrace and other external -- 2.53.0