From 82d4b262d9614958da38003cdc9d56915d9bcda0 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Mon, 30 Jan 2012 20:56:35 +0200
Subject: [PATCH] Fix bug in the new wait-until-lwlock-is-free mechanism.

If there was a wait-until-free process in the head of the wait queue,
followed by an exclusive locker, the exclusive locker was not be woken up
as it should.
---
 src/backend/storage/lmgr/lwlock.c | 25 ++++++++++++++++---------
 1 file changed, 16 insertions(+), 9 deletions(-)

diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index bee35b8c1cf..6511faf985d 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -754,23 +754,31 @@ LWLockRelease(LWLockId lockid)
 		if (lock->exclusive == 0 && lock->shared == 0 && lock->releaseOK)
 		{
 			/*
-			 * Remove the to-be-awakened PGPROCs from the queue.  If the front
-			 * waiter wants exclusive lock, awaken him only. Otherwise awaken
-			 * as many waiters as want shared access (or just want to be
-			 * woken up when the lock becomes free without acquiring it,
-			 * ie. LWLockWaitUntilFree).
+			 * Remove the to-be-awakened PGPROCs from the queue.
 			 */
 			bool releaseOK = true;
 
 			proc = head;
+
+			/*
+			 * First wake up any backends that want to be woken up without
+			 * acquiring the lock.
+			 */
+			while (proc->lwWaitMode == LW_WAIT_UNTIL_FREE && proc->lwWaitLink)
+				proc = proc->lwWaitLink;
+
+			/*
+			 * If the front waiter wants exclusive lock, awaken him only.
+			 * Otherwise awaken as many waiters as want shared access.
+			 */
 			if (proc->lwWaitMode != LW_EXCLUSIVE)
 			{
 				while (proc->lwWaitLink != NULL &&
 					   proc->lwWaitLink->lwWaitMode != LW_EXCLUSIVE)
 				{
-					proc = proc->lwWaitLink;
 					if (proc->lwWaitMode != LW_WAIT_UNTIL_FREE)
 						releaseOK = false;
+					proc = proc->lwWaitLink;
 				}
 			}
 			/* proc is now the last PGPROC to be released */
@@ -778,9 +786,8 @@ LWLockRelease(LWLockId lockid)
 			proc->lwWaitLink = NULL;
 			/*
 			 * Prevent additional wakeups until retryer gets to run. Backends
-			 * that are just waiting for the lock to become free don't prevent
-			 * wakeups, because they might decide that they don't want the
-			 * lock, after all.
+			 * that are just waiting for the lock to become free don't retry
+			 * automatically.
 			 */
 			if (proc->lwWaitMode != LW_WAIT_UNTIL_FREE)
 				releaseOK = false;
-- 
GitLab