Index: contrib/userlock/user_locks.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/contrib/userlock/user_locks.c,v retrieving revision 1.16 diff -c -r1.16 user_locks.c *** contrib/userlock/user_locks.c 17 May 2005 21:46:09 -0000 1.16 --- contrib/userlock/user_locks.c 19 May 2005 01:30:55 -0000 *************** *** 44,50 **** SET_LOCKTAG_USERLOCK(tag, id1, id2); ! return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode); } int --- 44,52 ---- SET_LOCKTAG_USERLOCK(tag, id1, id2); ! LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode); ! ! return true; } int *************** *** 75,79 **** int user_unlock_all(void) { ! return LockReleaseAll(USER_LOCKMETHOD, true); } --- 77,83 ---- int user_unlock_all(void) { ! LockReleaseAll(USER_LOCKMETHOD, true); ! ! return true; } Index: src/backend/storage/lmgr/lock.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/storage/lmgr/lock.c,v retrieving revision 1.151 diff -c -r1.151 lock.c *** src/backend/storage/lmgr/lock.c 11 May 2005 01:26:02 -0000 1.151 --- src/backend/storage/lmgr/lock.c 19 May 2005 01:22:46 -0000 *************** *** 166,171 **** --- 166,173 ---- int *myHolding); static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode, PROCLOCK *proclock, LockMethod lockMethodTable); + static void RemoveProcLock(LOCKMETHODID lockmethodid, PROCLOCK *proclock, + LOCK *lock, bool wakeupNeeded); /* *************** *** 792,797 **** --- 794,840 ---- } /* + * Subroutine to unlink and free a proclock entry, and garbage + * collect the lock object. + * + * The locktable's masterLock must be held at entry, and will be + * held at exit. + */ + static void + RemoveProcLock(LOCKMETHODID lockmethodid, PROCLOCK *proclock, LOCK *lock, + bool wakeupNeeded) + { + PROCLOCK_PRINT("RemoveProcLock: deleting", proclock); + SHMQueueDelete(&proclock->lockLink); + SHMQueueDelete(&proclock->procLink); + proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], + (void *) &(proclock->tag), + HASH_REMOVE, NULL); + if (!proclock) + elog(ERROR, "proclock table corrupted"); + + if (lock->nRequested == 0) + { + /* + * The caller just released the last lock, so garbage-collect the + * lock object. + */ + LOCK_PRINT("RemoveProcLock: deleting", lock, 0); + Assert(SHMQueueEmpty(&(lock->procLocks))); + lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], + (void *) &(lock->tag), + HASH_REMOVE, NULL); + if (!lock) + elog(ERROR, "lock table corrupted"); + } + else if (wakeupNeeded) + { + /* There are waiters on this lock, so wake them up. */ + ProcLockWakeup(LockMethods[lockmethodid], lock); + } + } + + /* * LockCheckConflicts -- test whether requested lock conflicts * with those already granted * *************** *** 1196,1202 **** * the waking process and any new process to * come along and request the lock.) */ ! bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode) { --- 1239,1245 ---- * the waking process and any new process to * come along and request the lock.) */ ! void LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode) { *************** *** 1221,1230 **** Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) ! { ! elog(WARNING, "lockMethodTable is null in LockRelease"); ! return FALSE; ! } /* * Find the LOCALLOCK entry for this lock and lockmode --- 1264,1270 ---- Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) ! elog(ERROR, "lockMethodTable is null in LockRelease"); /* * Find the LOCALLOCK entry for this lock and lockmode *************** *** 1237,1253 **** locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid], (void *) &localtag, HASH_FIND, NULL); - /* ! * let the caller print its own error message, too. Do not ! * ereport(ERROR). */ if (!locallock || locallock->nLocks <= 0) ! { ! elog(WARNING, "you don't own a lock of type %s", lock_mode_names[lockmode]); - return FALSE; - } /* * Decrease the count for the resource owner. --- 1277,1289 ---- locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid], (void *) &localtag, HASH_FIND, NULL); /* ! * Double-check that we are actually holding a lock of the type we ! * want to release. */ if (!locallock || locallock->nLocks <= 0) ! elog(ERROR, "you don't own a lock of type %s", lock_mode_names[lockmode]); /* * Decrease the count for the resource owner. *************** *** 1282,1290 **** if (i < 0) { /* don't release a lock belonging to another owner */ ! elog(WARNING, "you don't own a lock of type %s", lock_mode_names[lockmode]); - return FALSE; } } --- 1318,1325 ---- if (i < 0) { /* don't release a lock belonging to another owner */ ! elog(ERROR, "you don't own a lock of type %s", lock_mode_names[lockmode]); } } *************** *** 1295,1301 **** locallock->nLocks--; if (locallock->nLocks > 0) ! return TRUE; /* * Otherwise we've got to mess with the shared lock table. --- 1330,1336 ---- locallock->nLocks--; if (locallock->nLocks > 0) ! return; /* * Otherwise we've got to mess with the shared lock table. *************** *** 1322,1388 **** { PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock); LWLockRelease(masterLock); - elog(WARNING, "you don't own a lock of type %s", - lock_mode_names[lockmode]); RemoveLocalLock(locallock); ! return FALSE; } wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable); /* * If this was my last hold on this lock, delete my entry in the ! * proclock table. */ if (proclock->holdMask == 0) ! { ! PROCLOCK_PRINT("LockRelease: deleting proclock", proclock); ! SHMQueueDelete(&proclock->lockLink); ! SHMQueueDelete(&proclock->procLink); ! proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], ! (void *) &(proclock->tag), ! HASH_REMOVE, NULL); ! if (!proclock) ! { ! LWLockRelease(masterLock); ! elog(WARNING, "proclock table corrupted"); ! RemoveLocalLock(locallock); ! return FALSE; ! } ! } ! ! if (lock->nRequested == 0) ! { ! /* ! * We've just released the last lock, so garbage-collect the lock ! * object. ! */ ! LOCK_PRINT("LockRelease: deleting lock", lock, lockmode); ! Assert(SHMQueueEmpty(&(lock->procLocks))); ! lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], ! (void *) &(lock->tag), ! HASH_REMOVE, NULL); ! if (!lock) ! { ! LWLockRelease(masterLock); ! elog(WARNING, "lock table corrupted"); ! RemoveLocalLock(locallock); ! return FALSE; ! } ! } ! else ! { ! /* ! * Wake up waiters if needed. ! */ ! if (wakeupNeeded) ! ProcLockWakeup(lockMethodTable, lock); ! } LWLockRelease(masterLock); RemoveLocalLock(locallock); - return TRUE; } /* --- 1357,1379 ---- { PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock); LWLockRelease(masterLock); RemoveLocalLock(locallock); ! elog(ERROR, "you don't own a lock of type %s", ! lock_mode_names[lockmode]); } wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable); /* * If this was my last hold on this lock, delete my entry in the ! * proclock table. RemoveProcLock will wake up waiters if needed. */ if (proclock->holdMask == 0) ! RemoveProcLock(lockmethodid, proclock, lock, wakeupNeeded); LWLockRelease(masterLock); RemoveLocalLock(locallock); } /* *************** *** 1397,1403 **** * allxids == false: release all locks with Xid != 0 * (zero is the Xid used for "session" locks). */ ! bool LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids) { HASH_SEQ_STATUS status; --- 1388,1394 ---- * allxids == false: release all locks with Xid != 0 * (zero is the Xid used for "session" locks). */ ! void LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids) { HASH_SEQ_STATUS status; *************** *** 1418,1427 **** Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) ! { ! elog(WARNING, "bad lock method: %d", lockmethodid); ! return FALSE; ! } numLockModes = lockMethodTable->numLockModes; masterLock = lockMethodTable->masterLock; --- 1409,1415 ---- Assert(lockmethodid < NumLockMethods); lockMethodTable = LockMethods[lockmethodid]; if (!lockMethodTable) ! elog(ERROR, "bad lock method: %d", lockmethodid); numLockModes = lockMethodTable->numLockModes; masterLock = lockMethodTable->masterLock; *************** *** 1518,1563 **** PROCLOCK_PRINT("LockReleaseAll: deleting", proclock); ! /* ! * Remove the proclock entry from the linked lists ! */ ! SHMQueueDelete(&proclock->lockLink); ! SHMQueueDelete(&proclock->procLink); ! /* ! * remove the proclock entry from the hashtable ! */ ! proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid], ! (void *) &(proclock->tag), ! HASH_REMOVE, ! NULL); ! if (!proclock) ! { ! LWLockRelease(masterLock); ! elog(WARNING, "proclock table corrupted"); ! return FALSE; ! } ! ! if (lock->nRequested == 0) ! { ! /* ! * We've just released the last lock, so garbage-collect the ! * lock object. ! */ ! LOCK_PRINT("LockReleaseAll: deleting", lock, 0); ! Assert(SHMQueueEmpty(&(lock->procLocks))); ! lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid], ! (void *) &(lock->tag), ! HASH_REMOVE, NULL); ! if (!lock) ! { ! LWLockRelease(masterLock); ! elog(WARNING, "lock table corrupted"); ! return FALSE; ! } ! } ! else if (wakeupNeeded) ! ProcLockWakeup(lockMethodTable, lock); next_item: proclock = nextHolder; --- 1506,1515 ---- PROCLOCK_PRINT("LockReleaseAll: deleting", proclock); ! Assert(proclock->holdMask == 0); ! /* RemoveProcLock will wake up waiters if needed. */ ! RemoveProcLock(lockmethodid, proclock, lock, wakeupNeeded); next_item: proclock = nextHolder; *************** *** 1569,1576 **** if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks) elog(LOG, "LockReleaseAll done"); #endif - - return TRUE; } /* --- 1521,1526 ---- *************** *** 1622,1632 **** /* We want to call LockRelease just once */ lockOwners[i].nLocks = 1; locallock->nLocks = 1; ! if (!LockRelease(DEFAULT_LOCKMETHOD, ! &locallock->tag.lock, ! locallock->tag.xid, ! locallock->tag.mode)) ! elog(WARNING, "LockReleaseCurrentOwner: failed??"); } break; } --- 1572,1581 ---- /* We want to call LockRelease just once */ lockOwners[i].nLocks = 1; locallock->nLocks = 1; ! LockRelease(DEFAULT_LOCKMETHOD, ! &locallock->tag.lock, ! locallock->tag.xid, ! locallock->tag.mode); } break; } Index: src/include/storage/lock.h =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/include/storage/lock.h,v retrieving revision 1.85 diff -c -r1.85 lock.h *** src/include/storage/lock.h 29 Apr 2005 22:28:24 -0000 1.85 --- src/include/storage/lock.h 13 May 2005 01:05:43 -0000 *************** *** 359,367 **** extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid); extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode, bool dontWait); ! extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode); ! extern bool LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids); extern void LockReleaseCurrentOwner(void); extern void LockReassignCurrentOwner(void); extern int LockCheckConflicts(LockMethod lockMethodTable, --- 359,367 ---- extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid); extern bool LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode, bool dontWait); ! extern void LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag, TransactionId xid, LOCKMODE lockmode); ! extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids); extern void LockReleaseCurrentOwner(void); extern void LockReassignCurrentOwner(void); extern int LockCheckConflicts(LockMethod lockMethodTable,