Skip to content

Commit 74aaa21

Browse files
committed
Fix race condition in CheckTargetForConflictsIn.
Dan Ports
1 parent 6b449d9 commit 74aaa21

File tree

1 file changed

+79
-128
lines changed

1 file changed

+79
-128
lines changed

src/backend/storage/lmgr/predicate.c

Lines changed: 79 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -3638,6 +3638,8 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
36383638
LWLockId partitionLock;
36393639
PREDICATELOCKTARGET *target;
36403640
PREDICATELOCK *predlock;
3641+
PREDICATELOCK *mypredlock = NULL;
3642+
PREDICATELOCKTAG mypredlocktag;
36413643

36423644
Assert(MySerializableXact != InvalidSerializableXact);
36433645

@@ -3683,139 +3685,21 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
36833685
if (sxact == MySerializableXact)
36843686
{
36853687
/*
3686-
* If we're getting a write lock on the tuple and we're not in a
3687-
* subtransaction, we don't need a predicate (SIREAD) lock. We
3688-
* can't use this optimization within a subtransaction because the
3689-
* subtransaction could be rolled back, and we would be left
3690-
* without any lock at the top level.
3688+
* If we're getting a write lock on a tuple, we don't need
3689+
* a predicate (SIREAD) lock on the same tuple. We can
3690+
* safely remove our SIREAD lock, but we'll defer doing so
3691+
* until after the loop because that requires upgrading to
3692+
* an exclusive partition lock.
36913693
*
3692-
* At this point our transaction already has an ExclusiveRowLock
3693-
* on the relation, so we are OK to drop the predicate lock on the
3694-
* tuple, if found, without fearing that another write against the
3695-
* tuple will occur before the MVCC information makes it to the
3696-
* buffer.
3694+
* We can't use this optimization within a subtransaction
3695+
* because the subtransaction could roll back, and we
3696+
* would be left without any lock at the top level.
36973697
*/
36983698
if (!IsSubTransaction()
36993699
&& GET_PREDICATELOCKTARGETTAG_OFFSET(*targettag))
37003700
{
3701-
uint32 predlockhashcode;
3702-
PREDICATELOCKTARGET *rmtarget = NULL;
3703-
PREDICATELOCK *rmpredlock;
3704-
LOCALPREDICATELOCK *locallock,
3705-
*rmlocallock;
3706-
3707-
/*
3708-
* This is a tuple on which we have a tuple predicate lock. We
3709-
* only have shared LW locks now; release those, and get
3710-
* exclusive locks only while we modify things.
3711-
*/
3712-
LWLockRelease(SerializableXactHashLock);
3713-
LWLockRelease(partitionLock);
3714-
LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3715-
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3716-
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3717-
3718-
/*
3719-
* Remove the predicate lock from shared memory, if it wasn't
3720-
* removed while the locks were released. One way that could
3721-
* happen is from autovacuum cleaning up an index.
3722-
*/
3723-
predlockhashcode = PredicateLockHashCodeFromTargetHashCode
3724-
(&(predlock->tag), targettaghash);
3725-
rmpredlock = (PREDICATELOCK *)
3726-
hash_search_with_hash_value(PredicateLockHash,
3727-
&(predlock->tag),
3728-
predlockhashcode,
3729-
HASH_FIND, NULL);
3730-
if (rmpredlock)
3731-
{
3732-
Assert(rmpredlock == predlock);
3733-
3734-
SHMQueueDelete(predlocktargetlink);
3735-
SHMQueueDelete(&(predlock->xactLink));
3736-
3737-
rmpredlock = (PREDICATELOCK *)
3738-
hash_search_with_hash_value(PredicateLockHash,
3739-
&(predlock->tag),
3740-
predlockhashcode,
3741-
HASH_REMOVE, NULL);
3742-
Assert(rmpredlock == predlock);
3743-
3744-
RemoveTargetIfNoLongerUsed(target, targettaghash);
3745-
3746-
LWLockRelease(SerializableXactHashLock);
3747-
LWLockRelease(partitionLock);
3748-
LWLockRelease(SerializablePredicateLockListLock);
3749-
3750-
locallock = (LOCALPREDICATELOCK *)
3751-
hash_search_with_hash_value(LocalPredicateLockHash,
3752-
targettag, targettaghash,
3753-
HASH_FIND, NULL);
3754-
3755-
/*
3756-
* Remove entry in local lock table if it exists and has
3757-
* no children. It's OK if it doesn't exist; that means
3758-
* the lock was transferred to a new target by a different
3759-
* backend.
3760-
*/
3761-
if (locallock != NULL)
3762-
{
3763-
locallock->held = false;
3764-
3765-
if (locallock->childLocks == 0)
3766-
{
3767-
rmlocallock = (LOCALPREDICATELOCK *)
3768-
hash_search_with_hash_value(LocalPredicateLockHash,
3769-
targettag, targettaghash,
3770-
HASH_REMOVE, NULL);
3771-
Assert(rmlocallock == locallock);
3772-
}
3773-
}
3774-
3775-
DecrementParentLocks(targettag);
3776-
3777-
/*
3778-
* If we've cleaned up the last of the predicate locks for
3779-
* the target, bail out before re-acquiring the locks.
3780-
*/
3781-
if (rmtarget)
3782-
return;
3783-
3784-
/*
3785-
* The list has been altered. Start over at the front.
3786-
*/
3787-
LWLockAcquire(partitionLock, LW_SHARED);
3788-
nextpredlock = (PREDICATELOCK *)
3789-
SHMQueueNext(&(target->predicateLocks),
3790-
&(target->predicateLocks),
3791-
offsetof(PREDICATELOCK, targetLink));
3792-
3793-
LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3794-
}
3795-
else
3796-
{
3797-
/*
3798-
* The predicate lock was cleared while we were attempting
3799-
* to upgrade our lightweight locks. Revert to the shared
3800-
* locks.
3801-
*/
3802-
LWLockRelease(SerializableXactHashLock);
3803-
LWLockRelease(partitionLock);
3804-
LWLockRelease(SerializablePredicateLockListLock);
3805-
LWLockAcquire(partitionLock, LW_SHARED);
3806-
3807-
/*
3808-
* The list may have been altered by another process while
3809-
* we weren't holding the partition lock. Start over at
3810-
* the front.
3811-
*/
3812-
nextpredlock = (PREDICATELOCK *)
3813-
SHMQueueNext(&(target->predicateLocks),
3814-
&(target->predicateLocks),
3815-
offsetof(PREDICATELOCK, targetLink));
3816-
3817-
LWLockAcquire(SerializableXactHashLock, LW_SHARED);
3818-
}
3701+
mypredlock = predlock;
3702+
mypredlocktag = predlock->tag;
38193703
}
38203704
}
38213705
else if (!SxactIsRolledBack(sxact)
@@ -3849,6 +3733,73 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
38493733
}
38503734
LWLockRelease(SerializableXactHashLock);
38513735
LWLockRelease(partitionLock);
3736+
3737+
/*
3738+
* If we found one of our own SIREAD locks to remove, remove it
3739+
* now.
3740+
*
3741+
* At this point our transaction already has an ExclusiveRowLock
3742+
* on the relation, so we are OK to drop the predicate lock on the
3743+
* tuple, if found, without fearing that another write against the
3744+
* tuple will occur before the MVCC information makes it to the
3745+
* buffer.
3746+
*/
3747+
if (mypredlock != NULL)
3748+
{
3749+
uint32 predlockhashcode;
3750+
PREDICATELOCK *rmpredlock;
3751+
3752+
LWLockAcquire(SerializablePredicateLockListLock, LW_SHARED);
3753+
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
3754+
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
3755+
3756+
/*
3757+
* Remove the predicate lock from shared memory, if it wasn't
3758+
* removed while the locks were released. One way that could
3759+
* happen is from autovacuum cleaning up an index.
3760+
*/
3761+
predlockhashcode = PredicateLockHashCodeFromTargetHashCode
3762+
(&mypredlocktag, targettaghash);
3763+
rmpredlock = (PREDICATELOCK *)
3764+
hash_search_with_hash_value(PredicateLockHash,
3765+
&mypredlocktag,
3766+
predlockhashcode,
3767+
HASH_FIND, NULL);
3768+
if (rmpredlock != NULL)
3769+
{
3770+
Assert(rmpredlock == mypredlock);
3771+
3772+
SHMQueueDelete(&(mypredlock->targetLink));
3773+
SHMQueueDelete(&(mypredlock->xactLink));
3774+
3775+
rmpredlock = (PREDICATELOCK *)
3776+
hash_search_with_hash_value(PredicateLockHash,
3777+
&mypredlocktag,
3778+
predlockhashcode,
3779+
HASH_REMOVE, NULL);
3780+
Assert(rmpredlock == mypredlock);
3781+
3782+
RemoveTargetIfNoLongerUsed(target, targettaghash);
3783+
}
3784+
3785+
LWLockRelease(SerializableXactHashLock);
3786+
LWLockRelease(partitionLock);
3787+
LWLockRelease(SerializablePredicateLockListLock);
3788+
3789+
if (rmpredlock != NULL)
3790+
{
3791+
/*
3792+
* Remove entry in local lock table if it exists. It's OK
3793+
* if it doesn't exist; that means the lock was
3794+
* transferred to a new target by a different backend.
3795+
*/
3796+
hash_search_with_hash_value(LocalPredicateLockHash,
3797+
targettag, targettaghash,
3798+
HASH_REMOVE, NULL);
3799+
3800+
DecrementParentLocks(targettag);
3801+
}
3802+
}
38523803
}
38533804

38543805
/*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy