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,
166166 int * myHolding );
167167static bool UnGrantLock (LOCK * lock , LOCKMODE lockmode ,
168168 PROCLOCK * 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 */
591593 Assert (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 }
596599 LWLockRelease (masterLock );
597- if (!lock ) /* hash remove failed? */
598- elog (WARNING , "lock table corrupted" );
599600 ereport (ERROR ,
600601 (errcode (ERRCODE_OUT_OF_MEMORY ),
601602 errmsg ("out of shared memory" ),
@@ -708,11 +709,10 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
708709 {
709710 SHMQueueDelete (& proclock -> lockLink );
710711 SHMQueueDelete (& 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 }
717717 else
718718 PROCLOCK_PRINT ("LockAcquire: NOWAIT" , proclock );
@@ -784,10 +784,9 @@ RemoveLocalLock(LOCALLOCK *locallock)
784784
785785 pfree (locallock -> lockOwners );
786786 locallock -> 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 ))
791790 elog (WARNING , "locallock table corrupted" );
792791}
793792
@@ -993,6 +992,55 @@ UnGrantLock(LOCK *lock, LOCKMODE lockmode,
993992 return 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,
12211251 Assert (lockmethodid < NumLockMethods );
12221252 lockMethodTable = LockMethods [lockmethodid ];
12231253 if (!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,
13281355 return 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
13821365 LWLockRelease (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{
14031386 HASH_SEQ_STATUS status ;
@@ -1418,10 +1401,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
14181401 Assert (lockmethodid < NumLockMethods );
14191402 lockMethodTable = LockMethods [lockmethodid ];
14201403 if (!lockMethodTable )
1421- {
1422- elog (WARNING , "bad lock method: %d" , lockmethodid );
1423- return FALSE;
1424- }
1404+ elog (ERROR , "bad lock method: %d" , lockmethodid );
14251405
14261406 numLockModes = lockMethodTable -> numLockModes ;
14271407 masterLock = lockMethodTable -> masterLock ;
@@ -1516,48 +1496,10 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
15161496 Assert (lock -> nGranted <= lock -> nRequested );
15171497 LOCK_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 :
15631505 proclock = nextHolder ;
@@ -1569,8 +1511,6 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allxids)
15691511 if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks )
15701512 elog (LOG , "LockReleaseAll done" );
15711513#endif
1572-
1573- return TRUE;
15741514}
15751515
15761516/*
0 commit comments