From 137abc33199e91878b55fa054e0c409074e5856a Mon Sep 17 00:00:00 2001
From: Jingxian Li <aqktjcm@qq.com>
Date: Tue, 28 Nov 2023 16:01:48 +0800
Subject: [PATCH] LockAcquireExtended improvement

---
 src/backend/storage/lmgr/lock.c | 66 +++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 15 deletions(-)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index b8c57b3e16..e0ce691941 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -357,6 +357,8 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 
 static uint32 proclock_hash(const void *key, Size keysize);
 static void RemoveLocalLock(LOCALLOCK *locallock);
+static bool CheckLocalLockConflictTabCover(LockMethod lockMethodTable,
+								  const LOCKTAG *locktag, LOCKMODE lockmode);
 static PROCLOCK *SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
 								  const LOCKTAG *locktag, uint32 hashcode, LOCKMODE lockmode);
 static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
@@ -774,6 +776,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	uint32		hashcode;
 	LWLock	   *partitionLock;
 	bool		found_conflict;
+	bool		found_locallock_cover;
 	bool		log_lock = false;
 
 	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
@@ -938,6 +941,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
 		}
 	}
 
+	found_locallock_cover = CheckLocalLockConflictTabCover(lockMethodTable, locktag, lockmode);
+
 	/*
 	 * If this lock could potentially have been taken via the fast-path by
 	 * some other backend, we must (temporarily) disable further use of the
@@ -949,21 +954,24 @@ LockAcquireExtended(const LOCKTAG *locktag,
 		uint32		fasthashcode = FastPathStrongLockHashPartition(hashcode);
 
 		BeginStrongLockAcquire(locallock, fasthashcode);
-		if (!FastPathTransferRelationLocks(lockMethodTable, locktag,
-										   hashcode))
+		if (!found_locallock_cover)
 		{
-			AbortStrongLockAcquire();
-			if (locallock->nLocks == 0)
-				RemoveLocalLock(locallock);
-			if (locallockp)
-				*locallockp = NULL;
-			if (reportMemoryError)
-				ereport(ERROR,
-						(errcode(ERRCODE_OUT_OF_MEMORY),
-						 errmsg("out of shared memory"),
-						 errhint("You might need to increase %s.", "max_locks_per_transaction")));
-			else
-				return LOCKACQUIRE_NOT_AVAIL;
+			if (!FastPathTransferRelationLocks(lockMethodTable, locktag,
+											   hashcode))
+			{
+				AbortStrongLockAcquire();
+				if (locallock->nLocks == 0)
+					RemoveLocalLock(locallock);
+				if (locallockp)
+					*locallockp = NULL;
+				if (reportMemoryError)
+					ereport(ERROR,
+							(errcode(ERRCODE_OUT_OF_MEMORY),
+							 errmsg("out of shared memory"),
+							 errhint("You might need to increase %s.", "max_locks_per_transaction")));
+				else
+					return LOCKACQUIRE_NOT_AVAIL;
+			}
 		}
 	}
 
@@ -1012,7 +1020,9 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	 * wait queue.  Otherwise, check for conflict with already-held locks.
 	 * (That's last because most complex check.)
 	 */
-	if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
+	if (found_locallock_cover)
+		found_conflict = false;
+	else if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
 		found_conflict = true;
 	else
 		found_conflict = LockCheckConflicts(lockMethodTable, lockmode,
@@ -1137,6 +1147,32 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	return LOCKACQUIRE_OK;
 }
 
+/*
+ *  CheckLocalLockConflictTabCover -- test if there is a local lock
+ *		whose conflictTab covers the requested lock's
+ * 
+ *	Returns true if any such local lock found, false if not.
+ */
+static bool
+CheckLocalLockConflictTabCover(LockMethod lockMethodTable,
+								  const LOCKTAG *locktag, LOCKMODE lockmode)
+{
+	int conflictMask = lockMethodTable->conflictTab[lockmode];
+	
+	for (int i = lockMethodTable->numLockModes; i > lockmode; i--)
+	{
+		if ((lockMethodTable->conflictTab[i] & conflictMask) == conflictMask)
+		{
+			if (LockHeldByMe(locktag, (LOCKMODE) i))
+			{
+				return true;
+			}
+		}
+	}
+
+	return false;
+}
+
 /*
  * Find or create LOCK and PROCLOCK objects as needed for a new lock
  * request.
-- 
2.37.1.windows.1

