Fix bug in the new wait-until-lwlock-is-free mechanism.
authorHeikki Linnakangas
Mon, 30 Jan 2012 18:56:35 +0000 (20:56 +0200)
committerHeikki Linnakangas
Mon, 30 Jan 2012 22:09:30 +0000 (00:09 +0200)
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

index bee35b8c1cf93c9a5c65ee2d76e05e2fa164e4eb..6511faf985d213c834c341e72d2da7876c1757a6 100644 (file)
@@ -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;