From 52c75faf73cfcef300a2901447b9d45213501a15 Mon Sep 17 00:00:00 2001
From: Mahendra Singh Thalor <mahi6run@gmail.com>
Date: Thu, 5 Mar 2020 10:55:17 -0800
Subject: [PATCH 1/2] Added assert to verify that we never try to take any 
 heavyweight lock after acquiring relation Extension lock.

In LockAcquireExtended, we will call AssertAnyExtentionLockHeadByMe
to check that our backend is not holding any extention lock.
---
 src/backend/storage/lmgr/lock.c | 68 +++++++++++++++++++++++++++++++++
 src/include/storage/lock.h      |  3 ++
 2 files changed, 71 insertions(+)

diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 56dba09299..9ce0a213b0 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -339,6 +339,7 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 #endif							/* not LOCK_DEBUG */
 
 
+static void AssertAnyExtentionLockHeadByMe(const LOCKTAG *locktag);
 static uint32 proclock_hash(const void *key, Size keysize);
 static void RemoveLocalLock(LOCALLOCK *locallock);
 static PROCLOCK *SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
@@ -587,6 +588,66 @@ LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode)
 	return (locallock && locallock->nLocks > 0);
 }
 
+/*
+ * AssertAnyExtentionLockHeadByMe -- test whether any EXTENSION lock held by
+ * this backend.  If any EXTENSION lock is held by this backend, then it should
+ * be same as we are trying to acquire lock now, if not same, then assert will
+ * fail because we expect that after acquiring EXTENSION lock, we will not take
+ * any other heavyweight lock.  To use this function, assert should be enabled.
+ */
+static void
+AssertAnyExtentionLockHeadByMe(const LOCKTAG *locktag)
+{
+#ifdef USE_ASSERT_CHECKING
+	HASH_SEQ_STATUS scan_status;
+	LOCALLOCK  *locallock;
+	bool	need_rel_lock;
+
+	/*
+	 * If we are trying to take relation extension lock, then set need_rel_lock
+	 * flag.
+	 */
+	if (locktag->locktag_type == LOCKTAG_RELATION_EXTEND)
+		need_rel_lock = true;
+	else
+		need_rel_lock = false;
+
+	/* Init the sequence hash search. */
+	hash_seq_init(&scan_status, LockMethodLocalHash);
+
+	/* Do sequence hash search for all the locks. */
+	while ((locallock = (LOCALLOCK *) hash_seq_search(&scan_status)) != NULL)
+	{
+		/*
+		 * If we are trying to acquire relation extension lock, then either this
+		 * lock hash entry should not be relation extension lock or hask lock
+		 * should be same as our required lock(means this backend is already
+		 * holding relation extension lock for same relation) .
+		 */
+		if (need_rel_lock)
+		{
+			/*
+			 * Either this hash entry is not beloging to any relation extension
+			 * lock or required relation extension lock is already hold by this
+			 * backend.
+			 */
+			Assert (LOCALLOCK_LOCKTYPE(locallock) != LOCKTAG_RELATION_EXTEND ||
+					(LOCALLOCK_LOCKDBOID(locallock) == locktag->locktag_field1 &&
+					 LOCALLOCK_LOCKRELOID(locallock) == locktag->locktag_field2));
+		}
+		else
+		{
+			/* This hash entry should not belog to relation extension lock. */
+			Assert (LOCALLOCK_LOCKTYPE(locallock) != LOCKTAG_RELATION_EXTEND);
+		}
+	}
+
+	/* All locks are processed so locallock should be NULL. */
+	Assert (locallock == NULL);
+
+#endif
+}
+
 /*
  * LockHasWaiters -- look up 'locktag' and check if releasing this
  *		lock would wake up other processes waiting for it.
@@ -749,6 +810,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	bool		found_conflict;
 	bool		log_lock = false;
 
+	/*
+	 * Sanity check to verify that after acquiring relation extension lock, we
+	 * never try to take any other heavyweight lock but whle holding relation
+	 * extension lock, backend can ask for same relation extension lock again.
+	 */
+	AssertAnyExtentionLockHeadByMe(locktag);
+
 	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 	lockMethodTable = LockMethods[lockmethodid];
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index bb8e4e6e5b..4593346051 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -301,6 +301,9 @@ typedef struct LOCK
 } LOCK;
 
 #define LOCK_LOCKMETHOD(lock) ((LOCKMETHODID) (lock).tag.locktag_lockmethodid)
+#define LOCALLOCK_LOCKTYPE(locallock) ((locallock)->tag.lock.locktag_type)
+#define LOCALLOCK_LOCKDBOID(locallock) ((locallock)->tag.lock.locktag_field1)
+#define LOCALLOCK_LOCKRELOID(locallock) ((locallock)->tag.lock.locktag_field2)
 
 
 /*
-- 
2.17.1

