88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.151 2005/05/11 01:26:02 neilc Exp $
11+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.152 2005/05/19 23:30:18 tgl Exp $
1212 *
1313 * NOTES
1414 * Outside modules can create a lock table and acquire/release
@@ -166,6 +166,8 @@ static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
166166int * myHolding );
167167static bool UnGrantLock (LOCK * lock ,LOCKMODE lockmode ,
168168PROCLOCK * proclock ,LockMethod lockMethodTable );
169+ static void CleanUpLock (LOCKMETHODID lockmethodid ,LOCK * lock ,
170+ PROCLOCK * proclock ,bool wakeupNeeded );
169171
170172
171173/*
@@ -589,13 +591,12 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
589591 * anyone to release the lock object later.
590592 */
591593Assert (SHMQueueEmpty (& (lock -> procLocks )));
592- lock = (LOCK * )hash_search (LockMethodLockHash [lockmethodid ],
593- (void * )& (lock -> tag ),
594- HASH_REMOVE ,NULL );
594+ if (!hash_search (LockMethodLockHash [lockmethodid ],
595+ (void * )& (lock -> tag ),
596+ HASH_REMOVE ,NULL ))
597+ elog (PANIC ,"lock table corrupted" );
595598}
596599LWLockRelease (masterLock );
597- if (!lock )/* hash remove failed? */
598- elog (WARNING ,"lock table corrupted" );
599600ereport (ERROR ,
600601(errcode (ERRCODE_OUT_OF_MEMORY ),
601602errmsg ("out of shared memory" ),
@@ -708,11 +709,10 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
708709{
709710SHMQueueDelete (& proclock -> lockLink );
710711SHMQueueDelete (& proclock -> procLink );
711- proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash [lockmethodid ],
712- (void * )& (proclock -> tag ),
713- HASH_REMOVE ,NULL );
714- if (!proclock )
715- elog (WARNING ,"proclock table corrupted" );
712+ if (!hash_search (LockMethodProcLockHash [lockmethodid ],
713+ (void * )& (proclock -> tag ),
714+ HASH_REMOVE ,NULL ))
715+ elog (PANIC ,"proclock table corrupted" );
716716}
717717else
718718PROCLOCK_PRINT ("LockAcquire: NOWAIT" ,proclock );
@@ -784,10 +784,9 @@ RemoveLocalLock(LOCALLOCK *locallock)
784784
785785pfree (locallock -> lockOwners );
786786locallock -> lockOwners = NULL ;
787- locallock = (LOCALLOCK * )hash_search (LockMethodLocalHash [lockmethodid ],
788- (void * )& (locallock -> tag ),
789- HASH_REMOVE ,NULL );
790- if (!locallock )
787+ if (!hash_search (LockMethodLocalHash [lockmethodid ],
788+ (void * )& (locallock -> tag ),
789+ HASH_REMOVE ,NULL ))
791790elog (WARNING ,"locallock table corrupted" );
792791}
793792
@@ -993,6 +992,55 @@ UnGrantLock(LOCK *lock, LOCKMODE lockmode,
993992return wakeupNeeded ;
994993}
995994
995+ /*
996+ * CleanUpLock -- clean up after releasing a lock. We garbage-collect the
997+ * proclock and lock objects if possible, and call ProcLockWakeup if there
998+ * are remaining requests and the caller says it's OK. (Normally, this
999+ * should be called after UnGrantLock, and wakeupNeeded is the result from
1000+ * UnGrantLock.)
1001+ *
1002+ * The locktable's masterLock must be held at entry, and will be
1003+ * held at exit.
1004+ */
1005+ static void
1006+ CleanUpLock (LOCKMETHODID lockmethodid ,LOCK * lock ,PROCLOCK * proclock ,
1007+ bool wakeupNeeded )
1008+ {
1009+ /*
1010+ * If this was my last hold on this lock, delete my entry in the
1011+ * proclock table.
1012+ */
1013+ if (proclock -> holdMask == 0 )
1014+ {
1015+ PROCLOCK_PRINT ("CleanUpLock: deleting" ,proclock );
1016+ SHMQueueDelete (& proclock -> lockLink );
1017+ SHMQueueDelete (& proclock -> procLink );
1018+ if (!hash_search (LockMethodProcLockHash [lockmethodid ],
1019+ (void * )& (proclock -> tag ),
1020+ HASH_REMOVE ,NULL ))
1021+ elog (PANIC ,"proclock table corrupted" );
1022+ }
1023+
1024+ if (lock -> nRequested == 0 )
1025+ {
1026+ /*
1027+ * The caller just released the last lock, so garbage-collect the
1028+ * lock object.
1029+ */
1030+ LOCK_PRINT ("CleanUpLock: deleting" ,lock ,0 );
1031+ Assert (SHMQueueEmpty (& (lock -> procLocks )));
1032+ if (!hash_search (LockMethodLockHash [lockmethodid ],
1033+ (void * )& (lock -> tag ),
1034+ HASH_REMOVE ,NULL ))
1035+ elog (PANIC ,"lock table corrupted" );
1036+ }
1037+ else if (wakeupNeeded )
1038+ {
1039+ /* There are waiters on this lock, so wake them up. */
1040+ ProcLockWakeup (LockMethods [lockmethodid ],lock );
1041+ }
1042+ }
1043+
9961044/*
9971045 * GrantLockLocal -- update the locallock data structures to show
9981046 *the lock request has been granted.
@@ -1160,30 +1208,12 @@ RemoveFromWaitQueue(PGPROC *proc)
11601208
11611209/*
11621210 * Delete the proclock immediately if it represents no already-held locks.
1163- * This must happen now because if the owner of the lock decides to release
1164- * it, and the requested/granted counts then go to zero, LockRelease
1165- * expects there to be no remaining proclocks.
1166- */
1167- if (proclock -> holdMask == 0 )
1168- {
1169- PROCLOCK_PRINT ("RemoveFromWaitQueue: deleting proclock" ,proclock );
1170- SHMQueueDelete (& proclock -> lockLink );
1171- SHMQueueDelete (& proclock -> procLink );
1172- proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash [lockmethodid ],
1173- (void * )& (proclock -> tag ),
1174- HASH_REMOVE ,NULL );
1175- if (!proclock )
1176- elog (WARNING ,"proclock table corrupted" );
1177- }
1178-
1179- /*
1180- * There should still be some requests for the lock ... else what were
1181- * we waiting for? Therefore no need to delete the lock object.
1211+ * (This must happen now because if the owner of the lock decides to
1212+ * release it, and the requested/granted counts then go to zero,
1213+ * LockRelease expects there to be no remaining proclocks.)
1214+ * Then see if any other waiters for the lock can be woken up now.
11821215 */
1183- Assert (waitLock -> nRequested > 0 );
1184-
1185- /* See if any other waiters for the lock can be woken up now */
1186- ProcLockWakeup (LockMethods [lockmethodid ],waitLock );
1216+ CleanUpLock (lockmethodid ,waitLock ,proclock , true);
11871217}
11881218
11891219/*
@@ -1221,10 +1251,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
12211251Assert (lockmethodid < NumLockMethods );
12221252lockMethodTable = LockMethods [lockmethodid ];
12231253if (!lockMethodTable )
1224- {
1225- elog (WARNING ,"lockMethodTable is null in LockRelease" );
1226- return FALSE;
1227- }
1254+ elog (ERROR ,"bad lock method: %d" ,lockmethodid );
12281255
12291256/*
12301257 * Find the LOCALLOCK entry for this lock and lockmode
@@ -1328,56 +1355,12 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
13281355return FALSE;
13291356}
13301357
1331- wakeupNeeded = UnGrantLock (lock ,lockmode ,proclock ,lockMethodTable );
1332-
13331358/*
1334- * If this was my last hold on this lock, delete my entry in the
1335- * proclock table.
1359+ * Do the releasing. CleanUpLock will waken any now-wakable waiters.
13361360 */
1337- if (proclock -> holdMask == 0 )
1338- {
1339- PROCLOCK_PRINT ("LockRelease: deleting proclock" ,proclock );
1340- SHMQueueDelete (& proclock -> lockLink );
1341- SHMQueueDelete (& proclock -> procLink );
1342- proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash [lockmethodid ],
1343- (void * )& (proclock -> tag ),
1344- HASH_REMOVE ,NULL );
1345- if (!proclock )
1346- {
1347- LWLockRelease (masterLock );
1348- elog (WARNING ,"proclock table corrupted" );
1349- RemoveLocalLock (locallock );
1350- return FALSE;
1351- }
1352- }
1361+ wakeupNeeded = UnGrantLock (lock ,lockmode ,proclock ,lockMethodTable );
13531362
1354- if (lock -> nRequested == 0 )
1355- {
1356- /*
1357- * We've just released the last lock, so garbage-collect the lock
1358- * object.
1359- */
1360- LOCK_PRINT ("LockRelease: deleting lock" ,lock ,lockmode );
1361- Assert (SHMQueueEmpty (& (lock -> procLocks )));
1362- lock = (LOCK * )hash_search (LockMethodLockHash [lockmethodid ],
1363- (void * )& (lock -> tag ),
1364- HASH_REMOVE ,NULL );
1365- if (!lock )
1366- {
1367- LWLockRelease (masterLock );
1368- elog (WARNING ,"lock table corrupted" );
1369- RemoveLocalLock (locallock );
1370- return FALSE;
1371- }
1372- }
1373- else
1374- {
1375- /*
1376- * Wake up waiters if needed.
1377- */
1378- if (wakeupNeeded )
1379- ProcLockWakeup (lockMethodTable ,lock );
1380- }
1363+ CleanUpLock (lockmethodid ,lock ,proclock ,wakeupNeeded );
13811364
13821365LWLockRelease (masterLock );
13831366
@@ -1397,7 +1380,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
13971380 * allxids == false: release all locks with Xid != 0
13981381 * (zero is the Xid used for "session" locks).
13991382 */
1400- bool
1383+ void
14011384LockReleaseAll (LOCKMETHODID lockmethodid ,bool allxids )
14021385{
14031386HASH_SEQ_STATUS status ;
@@ -1418,10 +1401,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
14181401Assert (lockmethodid < NumLockMethods );
14191402lockMethodTable = LockMethods [lockmethodid ];
14201403if (!lockMethodTable )
1421- {
1422- elog (WARNING ,"bad lock method: %d" ,lockmethodid );
1423- return FALSE;
1424- }
1404+ elog (ERROR ,"bad lock method: %d" ,lockmethodid );
14251405
14261406numLockModes = lockMethodTable -> numLockModes ;
14271407masterLock = lockMethodTable -> masterLock ;
@@ -1516,48 +1496,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
15161496Assert (lock -> nGranted <=lock -> nRequested );
15171497LOCK_PRINT ("LockReleaseAll: updated" ,lock ,0 );
15181498
1519- PROCLOCK_PRINT ("LockReleaseAll: deleting" ,proclock );
1520-
1521- /*
1522- * Remove the proclock entry from the linked lists
1523- */
1524- SHMQueueDelete (& proclock -> lockLink );
1525- SHMQueueDelete (& proclock -> procLink );
1526-
1527- /*
1528- * remove the proclock entry from the hashtable
1529- */
1530- proclock = (PROCLOCK * )hash_search (LockMethodProcLockHash [lockmethodid ],
1531- (void * )& (proclock -> tag ),
1532- HASH_REMOVE ,
1533- NULL );
1534- if (!proclock )
1535- {
1536- LWLockRelease (masterLock );
1537- elog (WARNING ,"proclock table corrupted" );
1538- return FALSE;
1539- }
1499+ Assert (proclock -> holdMask == 0 );
15401500
1541- if (lock -> nRequested == 0 )
1542- {
1543- /*
1544- * We've just released the last lock, so garbage-collect the
1545- * lock object.
1546- */
1547- LOCK_PRINT ("LockReleaseAll: deleting" ,lock ,0 );
1548- Assert (SHMQueueEmpty (& (lock -> procLocks )));
1549- lock = (LOCK * )hash_search (LockMethodLockHash [lockmethodid ],
1550- (void * )& (lock -> tag ),
1551- HASH_REMOVE ,NULL );
1552- if (!lock )
1553- {
1554- LWLockRelease (masterLock );
1555- elog (WARNING ,"lock table corrupted" );
1556- return FALSE;
1557- }
1558- }
1559- else if (wakeupNeeded )
1560- ProcLockWakeup (lockMethodTable ,lock );
1501+ /* CleanUpLock will wake up waiters if needed. */
1502+ CleanUpLock (lockmethodid ,lock ,proclock ,wakeupNeeded );
15611503
15621504next_item :
15631505proclock = nextHolder ;
@@ -1569,8 +1511,6 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
15691511if (lockmethodid == USER_LOCKMETHOD ?Trace_userlocks :Trace_locks )
15701512elog (LOG ,"LockReleaseAll done" );
15711513#endif
1572-
1573- return TRUE;
15741514}
15751515
15761516/*