From 118cb90d4273f6cf84b98a4f9c9f66325bd827e2 Mon Sep 17 00:00:00 2001
From: Matthias van de Meent <boekewurm+postgres@gmail.com>
Date: Wed, 20 Nov 2024 17:31:26 +0100
Subject: [PATCH v0 4/4] Reduce PROCLOCK hash table size

This reduces the memory usage of the heavyweight lock mechanism by 25%.

Because the main LOCK table is already sized for max_locks_per_transaction
for every backend, further allocation of more PROCLOCK entries doesn't make
sense, as those would let the average number of locked objects per backend
to increase past max_locks_per_transaction.
---
 src/backend/storage/lmgr/lock.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 15e1512e75..bd3e4d0f20 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -438,16 +438,18 @@ void
 LockManagerShmemInit(void)
 {
 	HASHCTL		info;
-	long		init_table_size,
-				max_table_size;
+	long		max_table_size;
 	bool		found;
+	Size		allocated;
+	char	   *start;
+	char	   *end;
 
+	start = ShmemAllocNoError(0);
 	/*
 	 * Compute init/max size to request for lock hashtables.  Note these
 	 * calculations must agree with LockManagerShmemSize!
 	 */
 	max_table_size = NLOCKENTS();
-	init_table_size = max_table_size / 2;
 
 	/*
 	 * Allocate hash table for LOCK structs.  This stores per-locked-object
@@ -458,14 +460,17 @@ LockManagerShmemInit(void)
 	info.num_partitions = NUM_LOCK_PARTITIONS;
 
 	LockMethodLockHash = ShmemInitHash("LOCK hash",
-									   init_table_size,
+									   max_table_size,
 									   max_table_size,
 									   &info,
 									   HASH_ELEM | HASH_BLOBS | HASH_PARTITION);
 
-	/* Assume an average of 2 holders per lock */
-	max_table_size *= 2;
-	init_table_size *= 2;
+	/*
+	 * Assume every proc has max_locks_per_transaction locks. We don't
+	 * need more PROCLOCK entries after that, because we can't acquire more
+	 * locks after that. This is also more consistent with the advertised
+	 * behaviour of max_locks_per_transaction.
+	 */
 
 	/*
 	 * Allocate hash table for PROCLOCK structs.  This stores
@@ -477,7 +482,7 @@ LockManagerShmemInit(void)
 	info.num_partitions = NUM_LOCK_PARTITIONS;
 
 	LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
-										   init_table_size,
+										   max_table_size,
 										   max_table_size,
 										   &info,
 										   HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
@@ -490,6 +495,13 @@ LockManagerShmemInit(void)
 						sizeof(FastPathStrongRelationLockData), &found);
 	if (!found)
 		SpinLockInit(&FastPathStrongRelationLocks->mutex);
+	end = ShmemAllocNoError(0);
+
+	allocated = end - start;
+	elog(LOG, "Lock ShMem: Allocated %lu for NLOCKENTS=%ld (= %d mlpxid * (%d m_c + %d m_p_xids))",
+		 (unsigned long) allocated, max_table_size,
+		 max_locks_per_xact, MaxBackends, max_prepared_xacts
+	);
 }
 
 /*
@@ -3682,7 +3694,6 @@ LockManagerShmemSize(void)
 	size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
 
 	/* proclock hash table */
-	max_table_size *= 2;
 	size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
 
 	/*
-- 
2.45.2

