Index: lock.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v retrieving revision 1.145 diff -c -r1.145 lock.c *** lock.c 31 Dec 2004 22:01:05 -0000 1.145 --- lock.c 2 Feb 2005 19:40:26 -0000 *************** *** 166,171 **** --- 166,172 ---- ResourceOwner owner); static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding); + static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable); /* *************** *** 958,963 **** --- 959,1020 ---- } /* + * UnGrantLock -- opposite of GrantLock. + * + * Updates the lock and proclock data structures to show that + * the lock is no longer held nor requested by the current holder. + * + * Returns true if there was waiters waiting on the lock + * that should now be woken up with ProcLockWakeup. + */ + static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable) + { + bool wakeupNeeded = false; + Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0)); + Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0)); + Assert(lock->nGranted <= lock->nRequested); + + /* + * fix the general lock stats + */ + lock->nRequested--; + lock->requested[lockmode]--; + lock->nGranted--; + lock->granted[lockmode]--; + + if (lock->granted[lockmode] == 0) + { + /* change the conflict mask. No more of this lock type. */ + lock->grantMask &= LOCKBIT_OFF(lockmode); + } + + LOCK_PRINT("UnGrantLock: updated", lock, lockmode); + Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0)); + Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0)); + Assert(lock->nGranted <= lock->nRequested); + + /* + * We need only run ProcLockWakeup if the released lock conflicts with + * at least one of the lock types requested by waiter(s). Otherwise + * whatever conflict made them wait must still exist. NOTE: before + * MVCC, we could skip wakeup if lock->granted[lockmode] was still + * positive. But that's not true anymore, because the remaining + * granted locks might belong to some waiter, who could now be + * awakened because he doesn't conflict with his own locks. + */ + if (lockMethodTable->conflictTab[lockmode] & lock->waitMask) + wakeupNeeded = true; + + /* + * Now fix the per-proclock state. + */ + proclock->holdMask &= LOCKBIT_OFF(lockmode); + PROCLOCK_PRINT("UnGrantLock: updated", proclock); + + return wakeupNeeded; + } + + /* * GrantLockLocal -- update the locallock data structures to show * the lock request has been granted. * *************** *** 1265,1310 **** RemoveLocalLock(locallock); return FALSE; } - Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0)); - Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0)); - Assert(lock->nGranted <= lock->nRequested); - - /* - * fix the general lock stats - */ - lock->nRequested--; - lock->requested[lockmode]--; - lock->nGranted--; - lock->granted[lockmode]--; ! if (lock->granted[lockmode] == 0) ! { ! /* change the conflict mask. No more of this lock type. */ ! lock->grantMask &= LOCKBIT_OFF(lockmode); ! } ! ! LOCK_PRINT("LockRelease: updated", lock, lockmode); ! Assert((lock->nRequested >= 0) && (lock->requested[lockmode] >= 0)); ! Assert((lock->nGranted >= 0) && (lock->granted[lockmode] >= 0)); ! Assert(lock->nGranted <= lock->nRequested); ! ! /* ! * We need only run ProcLockWakeup if the released lock conflicts with ! * at least one of the lock types requested by waiter(s). Otherwise ! * whatever conflict made them wait must still exist. NOTE: before ! * MVCC, we could skip wakeup if lock->granted[lockmode] was still ! * positive. But that's not true anymore, because the remaining ! * granted locks might belong to some waiter, who could now be ! * awakened because he doesn't conflict with his own locks. ! */ ! if (lockMethodTable->conflictTab[lockmode] & lock->waitMask) ! wakeupNeeded = true; ! ! /* ! * Now fix the per-proclock state. ! */ ! proclock->holdMask &= LOCKBIT_OFF(lockmode); ! PROCLOCK_PRINT("LockRelease: updated", proclock); /* * If this was my last hold on this lock, delete my entry in the --- 1322,1329 ---- RemoveLocalLock(locallock); return FALSE; } ! wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable); /* * If this was my last hold on this lock, delete my entry in the *************** *** 1484,1503 **** { if (proclock->holdMask & LOCKBIT_ON(i)) { ! lock->requested[i]--; ! lock->granted[i]--; ! Assert(lock->requested[i] >= 0 && lock->granted[i] >= 0); ! if (lock->granted[i] == 0) ! lock->grantMask &= LOCKBIT_OFF(i); ! lock->nRequested--; ! lock->nGranted--; ! ! /* ! * Read comments in LockRelease ! */ ! if (!wakeupNeeded && ! lockMethodTable->conflictTab[i] & lock->waitMask) ! wakeupNeeded = true; } } } --- 1503,1509 ---- { if (proclock->holdMask & LOCKBIT_ON(i)) { ! wakeupNeeded |= UnGrantLock(lock, i, proclock, lockMethodTable); } } }