1
0
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:
Tom Lane
2013-11-27 18:10:03 -05:00
parent 08302a3974
commit d32e8387ba
2 changed files with 73 additions and 30 deletions

View File

@@ -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;