>From bf329af4eb6d839ae2a75c4f8a2d6867877510f4 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 23 Oct 2013 02:34:51 +0200
Subject: [PATCH 1/4] debug-lock-on-index-without-heap-lock

---
 src/backend/access/heap/heapam.c   | 10 ++++++++++
 src/backend/access/index/indexam.c | 14 ++++++++++++++
 src/backend/storage/lmgr/lmgr.c    |  9 +++++++++
 src/backend/storage/lmgr/lock.c    | 16 ++++++++++++++++
 src/backend/utils/cache/relcache.c | 10 ++++++++++
 src/include/storage/lmgr.h         |  2 ++
 src/include/storage/lock.h         |  2 ++
 7 files changed, 63 insertions(+)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index a21f31b..3eecd5f 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1203,6 +1203,16 @@ heap_open(Oid relationId, LOCKMODE lockmode)
 				 errmsg("\"%s\" is a composite type",
 						RelationGetRelationName(r))));
 
+	if (IsNormalProcessingMode() && lockmode == NoLock)
+	{
+		LOCKMODE	mode;
+
+		mode = StrongestLocalRelationLock(relationId);
+		if (mode == NoLock)
+			elog(WARNING, "no relation lock on rel %s",
+				 RelationGetRelationName(r));
+	}
+
 	return r;
 }
 
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index b878155..10c3991 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -65,6 +65,8 @@
 
 #include "postgres.h"
 
+#include "miscadmin.h"
+
 #include "access/relscan.h"
 #include "access/transam.h"
 #include "catalog/index.h"
@@ -142,6 +144,8 @@ static IndexScanDesc index_beginscan_internal(Relation indexRelation,
  * ----------------------------------------------------------------
  */
 
+#include "catalog/catalog.h"
+
 /* ----------------
  *		index_open - open an index relation by relation OID
  *
@@ -169,6 +173,16 @@ index_open(Oid relationId, LOCKMODE lockmode)
 				 errmsg("\"%s\" is not an index",
 						RelationGetRelationName(r))));
 
+	if (IsNormalProcessingMode())
+	{
+		LOCKMODE	mode;
+
+		mode = StrongestLocalRelationLock(r->rd_index->indrelid);
+		if (mode == NoLock)
+			elog(WARNING, "no relation lock on rel %u held while opening index %s",
+				 r->rd_index->indrelid,
+				 RelationGetRelationName(r));
+	}
 	return r;
 }
 
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index a978172..32d7bba 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -232,6 +232,15 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
 	LockRelease(&tag, lockmode, false);
 }
 
+LOCKMODE
+StrongestLocalRelationLock(Oid relid)
+{
+	LOCKTAG		tag;
+	SetLocktagRelationOid(&tag, relid);
+	return StrongestLocalLock(&tag);
+}
+
+
 /*
  *		LockHasWaitersRelation
  *
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index f4f32e9..2f068be 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -2365,6 +2365,22 @@ LockReassignOwner(LOCALLOCK *locallock, ResourceOwner parent)
 	ResourceOwnerForgetLock(CurrentResourceOwner, locallock);
 }
 
+LOCKMODE
+StrongestLocalLock(const LOCKTAG* locktag)
+{
+	HASH_SEQ_STATUS status;
+	LOCALLOCK  *locallock;
+	LOCKMODE	strongest = NoLock;
+	hash_seq_init(&status, LockMethodLocalHash);
+
+	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
+	{
+		if (memcmp(&locallock->tag.lock, locktag, sizeof(LOCKTAG)) == 0)
+			strongest = Max(strongest, locallock->tag.mode);
+	}
+	return strongest;
+}
+
 /*
  * FastPathGrantRelationLock
  *		Grant lock using per-backend fast-path array, if there is space.
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index b4cc6ad..f74c6af 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1577,6 +1577,16 @@ RelationIdGetRelation(Oid relationId)
 {
 	Relation	rd;
 
+	if (IsNormalProcessingMode())
+	{
+		LOCKMODE	mode;
+
+		mode = StrongestLocalRelationLock(relationId);
+		if (mode == NoLock)
+			elog(WARNING, "no relation lock for descriptor of oid %u",
+				 relationId);
+	}
+
 	/*
 	 * first try to find reldesc in the cache
 	 */
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 1a8c018..c2c6026 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -40,6 +40,8 @@ extern void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode);
 extern void LockRelationForExtension(Relation relation, LOCKMODE lockmode);
 extern void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode);
 
+extern LOCKMODE StrongestLocalRelationLock(Oid relid);
+
 /* Lock a page (currently only used within indexes) */
 extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
 extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 7bcaf7c..ea915c8 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -495,6 +495,8 @@ extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
 extern void LockReleaseSession(LOCKMETHODID lockmethodid);
 extern void LockReleaseCurrentOwner(LOCALLOCK **locallocks, int nlocks);
 extern void LockReassignCurrentOwner(LOCALLOCK **locallocks, int nlocks);
+extern LOCKMODE StrongestLocalLock(const LOCKTAG* locktag);
+
 extern bool LockHasWaiters(const LOCKTAG *locktag,
 			   LOCKMODE lockmode, bool sessionLock);
 extern VirtualTransactionId *GetLockConflicts(const LOCKTAG *locktag,
-- 
1.8.3.251.g1462b67

