]> granicus.if.org Git - postgresql/commitdiff
Fix bug in the new wait-until-lwlock-is-free mechanism.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Mon, 30 Jan 2012 18:56:35 +0000 (20:56 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
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;