]> granicus.if.org Git - postgresql/commitdiff
Release proclock immediately in RemoveFromWaitQueue() if it represents
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Mar 2005 21:15:26 +0000 (21:15 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 1 Mar 2005 21:15:26 +0000 (21:15 +0000)
no held locks.  This maintains the invariant that proclocks are present
only for procs that are holding or awaiting a lock; when this is not
true, LockRelease will fail.  Per report from Stephen Clouse.

src/backend/storage/lmgr/lock.c

index 020c7a5d896c51f6fdb4660b407b72096a28e5c2..a5de178b8e456f9f9238e4398c59a843b71076b7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.128 2003/10/16 20:59:35 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.128.2.1 2005/03/01 21:15:26 tgl Exp $
  *
  * NOTES
  *       Outside modules can create a lock table and acquire/release
@@ -900,8 +900,7 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
        {
                /*
                 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
-                * now.  Removal of the proclock and lock objects, if no longer
-                * needed, will happen in xact cleanup (see above for motivation).
+                * now.
                 */
                LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
                LWLockRelease(lockMethodTable->masterLock);
@@ -927,23 +926,20 @@ WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
  * (caller must know it is on one).
  *
  * Locktable lock must be held by caller.
- *
- * NB: this does not remove the process' proclock object, nor the lock object,
- * even though their counts might now have gone to zero.  That will happen
- * during a subsequent LockReleaseAll call, which we expect will happen
- * during transaction cleanup. (Removal of a proc from its wait queue by
- * this routine can only happen if we are aborting the transaction.)
  */
 void
 RemoveFromWaitQueue(PGPROC *proc)
 {
        LOCK       *waitLock = proc->waitLock;
+       PROCLOCK   *proclock = proc->waitHolder;
        LOCKMODE        lockmode = proc->waitLockMode;
+       LOCKMETHOD      lockmethod = LOCK_LOCKMETHOD(*waitLock);
 
        /* Make sure proc is waiting */
        Assert(proc->links.next != INVALID_OFFSET);
        Assert(waitLock);
        Assert(waitLock->waitProcs.size > 0);
+       Assert(lockmethod > 0 && lockmethod < NumLockMethods);
 
        /* Remove proc from lock's wait queue */
        SHMQueueDelete(&(proc->links));
@@ -963,8 +959,25 @@ RemoveFromWaitQueue(PGPROC *proc)
        proc->waitLock = NULL;
        proc->waitHolder = NULL;
 
+       /*
+        * Delete the proclock immediately if it represents no already-held locks.
+        * This must happen now because if the owner of the lock decides to release
+        * it, and the requested/granted counts then go to zero, LockRelease
+        * expects there to be no remaining proclocks.
+        */
+       if (proclock->nHolding == 0)
+       {
+               SHMQueueDelete(&proclock->lockLink);
+               SHMQueueDelete(&proclock->procLink);
+               proclock = (PROCLOCK *) hash_search(LockMethodTable[lockmethod]->proclockHash,
+                                                                                       (void *) proclock,
+                                                                                       HASH_REMOVE, NULL);
+               if (!proclock)
+                       elog(WARNING, "proclock table corrupted");
+       }
+
        /* See if any other waiters for the lock can be woken up now */
-       ProcLockWakeup(GetLocksMethodTable(waitLock), waitLock);
+       ProcLockWakeup(LockMethodTable[lockmethod], waitLock);
 }
 
 /*