From 8875d0987d767f0ea14bffd636841e003d41eca8 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 30 Mar 2007 00:12:59 +0000
Subject: [PATCH] Fix oversight in coding of _bt_start_vacuum: we can't assume
 that the LWLock will be released by transaction abort before _bt_end_vacuum
 gets called. If either of these "can't happen" errors actually happened, we'd
 freeze up trying to acquire an already-held lock.  Latest word is that this
 does not explain Martin Pitt's trouble report, but it still looks like a bug.

---
 src/backend/access/nbtree/nbtutils.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index d453a93cafa..9c227d7f6c6 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.82 2007/01/09 02:14:10 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.83 2007/03/30 00:12:59 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1214,13 +1214,25 @@ _bt_start_vacuum(Relation rel)
 		vac = &btvacinfo->vacuums[i];
 		if (vac->relid.relId == rel->rd_lockInfo.lockRelId.relId &&
 			vac->relid.dbId == rel->rd_lockInfo.lockRelId.dbId)
+		{
+			/*
+			 * Unlike most places in the backend, we have to explicitly
+			 * release our LWLock before throwing an error.  This is because
+			 * we expect _bt_end_vacuum() to be called before transaction
+			 * abort cleanup can run to release LWLocks.
+			 */
+			LWLockRelease(BtreeVacuumLock);
 			elog(ERROR, "multiple active vacuums for index \"%s\"",
 				 RelationGetRelationName(rel));
+		}
 	}
 
 	/* OK, add an entry */
 	if (btvacinfo->num_vacuums >= btvacinfo->max_vacuums)
+	{
+		LWLockRelease(BtreeVacuumLock);
 		elog(ERROR, "out of btvacinfo slots");
+	}
 	vac = &btvacinfo->vacuums[btvacinfo->num_vacuums];
 	vac->relid = rel->rd_lockInfo.lockRelId;
 	vac->cycleid = result;
-- 
GitLab