mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Fix stale-pointer problem in fast-path locking logic.
When acquiring a lock in fast-path mode, we must reset the locallock object's lock and proclock fields to NULL. They are not necessarily that way to start with, because the locallock could be left over from a failed lock acquisition attempt earlier in the transaction. Failure to do this led to all sorts of interesting misbehaviors when LockRelease tried to clean up no-longer-related lock and proclock objects in shared memory. Per report from Dan Wood. In passing, modify LockRelease to elog not just Assert if it doesn't find lock and proclock objects for a formerly fast-path lock, matching the code in FastPathGetRelationLockEntry and LockRefindAndRelease. This isn't a bug but it will help in diagnosing any future bugs in this area. Also, modify FastPathTransferRelationLocks and FastPathGetRelationLockEntry to break out of their loops over the fastpath array once they've found the sole matching entry. This was inconsistently done in some search loops and not others. Improve assorted related comments, too. Back-patch to 9.2 where the fast-path mechanism was introduced.
This commit is contained in:
@@ -379,6 +379,20 @@ typedef struct PROCLOCK
|
||||
* shared memory. We also track the number of lock acquisitions per
|
||||
* ResourceOwner, so that we can release just those locks belonging to a
|
||||
* particular ResourceOwner.
|
||||
*
|
||||
* When holding a lock taken "normally", the lock and proclock fields always
|
||||
* point to the associated objects in shared memory. However, if we acquired
|
||||
* the lock via the fast-path mechanism, the lock and proclock fields are set
|
||||
* to NULL, since there probably aren't any such objects in shared memory.
|
||||
* (If the lock later gets promoted to normal representation, we may eventually
|
||||
* update our locallock's lock/proclock fields after finding the shared
|
||||
* objects.)
|
||||
*
|
||||
* Caution: a locallock object can be left over from a failed lock acquisition
|
||||
* attempt. In this case its lock/proclock fields are untrustworthy, since
|
||||
* the shared lock object is neither held nor awaited, and hence is available
|
||||
* to be reclaimed. If nLocks > 0 then these pointers must either be valid or
|
||||
* NULL, but when nLocks == 0 they should be considered garbage.
|
||||
*/
|
||||
typedef struct LOCALLOCKTAG
|
||||
{
|
||||
@@ -404,13 +418,13 @@ typedef struct LOCALLOCK
|
||||
LOCALLOCKTAG tag; /* unique identifier of locallock entry */
|
||||
|
||||
/* data */
|
||||
LOCK *lock; /* associated LOCK object in shared mem */
|
||||
PROCLOCK *proclock; /* associated PROCLOCK object in shmem */
|
||||
LOCK *lock; /* associated LOCK object, if any */
|
||||
PROCLOCK *proclock; /* associated PROCLOCK object, if any */
|
||||
uint32 hashcode; /* copy of LOCKTAG's hash value */
|
||||
int64 nLocks; /* total number of times lock is held */
|
||||
int numLockOwners; /* # of relevant ResourceOwners */
|
||||
int maxLockOwners; /* allocated size of array */
|
||||
bool holdsStrongLockCount; /* bumped FastPathStrongRelatonLocks? */
|
||||
bool holdsStrongLockCount; /* bumped FastPathStrongRelationLocks */
|
||||
LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */
|
||||
} LOCALLOCK;
|
||||
|
||||
|
Reference in New Issue
Block a user