From 131d42809335a51f0ba602a4a45139a6f2d73776 Mon Sep 17 00:00:00 2001
From: Dilip Kumar <dilip.kumar@enterprisedb.com>
Date: Thu, 12 Mar 2020 13:16:45 +0530
Subject: [PATCH v6 1/4] Add assert check for relation extension lock

Add assert to check that we should not acquire any other lock if we are
already holding the relation extension lock.  Only exception is that if
we are trying to acquire the relation extension lock then we can hold the
same lock.
---
 src/backend/storage/lmgr/lock.c | 48 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 56dba09..24ca900 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -170,6 +170,15 @@ typedef struct TwoPhaseLockRecord
  */
 static int	FastPathLocalUseCount = 0;
 
+/*
+ * Flag is set if the relation extension lock is currently held by this backend.
+ * We need this flag so that we can ensure that while holding the relation
+ * extension lock we are not trying to acquire any other heavy weight lock.
+ * Basically, that will ensuring that the proc holding relation extension lock
+ * can not wait for any another lock which can lead to a deadlock.
+ */
+static bool	IsRelationExtensionLockHeld = false;
+
 /* Macros for manipulating proc->fpLockBits */
 #define FAST_PATH_BITS_PER_SLOT			3
 #define FAST_PATH_LOCKNUMBER_OFFSET		1
@@ -208,6 +217,9 @@ static int	FastPathLocalUseCount = 0;
 	(locktag)->locktag_field1 != InvalidOid && \
 	(mode) > ShareUpdateExclusiveLock)
 
+/* Get the lock tag of the local lock. */
+#define LOCALLOCK_LOCKTAG(locallock) ((LockTagType) (locallock).tag.lock.locktag_type)
+
 static bool FastPathGrantRelationLock(Oid relid, LOCKMODE lockmode);
 static bool FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode);
 static bool FastPathTransferRelationLocks(LockMethod lockMethodTable,
@@ -841,6 +853,14 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	}
 
 	/*
+	 * We should not try to acquire any other heavyweight lock if we are already
+	 * holding the relation extension lock.  If we are trying to hold the same
+	 * relation extension lock then it should have been already granted so we
+	 * will not come here.
+	 */
+	Assert(!IsRelationExtensionLockHeld);
+
+	/*
 	 * Prepare to emit a WAL record if acquisition of this lock needs to be
 	 * replayed in a standby server.
 	 *
@@ -1288,6 +1308,28 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
 }
 
 /*
+ * CheckAndSetLockHeld -- check and set the flag that we hold relation extension
+ *						  lock.
+ */
+static inline void
+CheckAndSetLockHeld(LOCALLOCK *locallock)
+{
+	if (LOCALLOCK_LOCKTAG(*locallock) == LOCKTAG_RELATION_EXTEND)
+		IsRelationExtensionLockHeld = true;
+}
+
+/*
+ * CheckAndReSetLockHeld -- check and reset the flag if we have released the
+ *							relation extension lock.
+ */
+static inline void
+CheckAndReSetLockHeld(LOCALLOCK *locallock)
+{
+	if (LOCALLOCK_LOCKTAG(*locallock) == LOCKTAG_RELATION_EXTEND)
+		IsRelationExtensionLockHeld = false;
+}
+
+/*
  * Subroutine to free a locallock entry
  */
 static void
@@ -1322,6 +1364,9 @@ RemoveLocalLock(LOCALLOCK *locallock)
 					 (void *) &(locallock->tag),
 					 HASH_REMOVE, NULL))
 		elog(WARNING, "locallock table corrupted");
+
+	/* Check and reset the lock held flag. */
+	CheckAndReSetLockHeld(locallock);
 }
 
 /*
@@ -1618,6 +1663,9 @@ GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner)
 	locallock->numLockOwners++;
 	if (owner != NULL)
 		ResourceOwnerRememberLock(owner, locallock);
+
+	/* Set the flag if we have acquired relation extension lock. */
+	CheckAndSetLockHeld(locallock);
 }
 
 /*
-- 
1.8.3.1

