Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c00dc33

Browse files
committed
Fix potential corruption of lock table in CREATE/DROP INDEX CONCURRENTLY.
If VirtualXactLock() has to wait for a transaction that holds its VXID lock as a fast-path lock, it must first convert the fast-path lock to a regular lock. It failed to take the required "partition" lock on the main shared-memory lock table while doing so. This is the direct cause of the assert failure in GetLockStatusData() recently observed in the buildfarm, but more worryingly it could result in arbitrary corruption of the shared lock table if some other process were concurrently engaged in modifying the same partition of the lock table. Fortunately, VirtualXactLock() is only used by CREATE INDEX CONCURRENTLY and DROP INDEX CONCURRENTLY, so the opportunities for failure are fewer than they might have been. In passing, improve some comments and be a bit more consistent about order of operations.
1 parent f31d5ba commit c00dc33

File tree

1 file changed

+25
-4
lines changed
  • src/backend/storage/lmgr

1 file changed

+25
-4
lines changed

src/backend/storage/lmgr/lock.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,12 @@ LockAcquireExtended(const LOCKTAG *locktag,
10171017
/*
10181018
* Find or create LOCK and PROCLOCK objects as needed for a new lock
10191019
* request.
1020+
*
1021+
* Returns the PROCLOCK object, or NULL if we failed to create the objects
1022+
* for lack of shared memory.
1023+
*
1024+
* The appropriate partition lock must be held at entry, and will be
1025+
* held at exit.
10201026
*/
10211027
static PROCLOCK *
10221028
SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
@@ -2414,6 +2420,8 @@ FastPathUnGrantRelationLock(Oid relid, LOCKMODE lockmode)
24142420
* FastPathTransferRelationLocks
24152421
* Transfer locks matching the given lock tag from per-backend fast-path
24162422
* arrays to the shared hash table.
2423+
*
2424+
* Returns true if successful, false if ran out of shared memory.
24172425
*/
24182426
static bool
24192427
FastPathTransferRelationLocks(LockMethod lockMethodTable, const LOCKTAG *locktag,
@@ -2529,6 +2537,7 @@ FastPathGetRelationLockEntry(LOCALLOCK *locallock)
25292537
locallock->hashcode, lockmode);
25302538
if (!proclock)
25312539
{
2540+
LWLockRelease(partitionLock);
25322541
ereport(ERROR,
25332542
(errcode(ERRCODE_OUT_OF_MEMORY),
25342543
errmsg("out of shared memory"),
@@ -3422,9 +3431,6 @@ GetRunningTransactionLocks(int *nlocks)
34223431
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
34233432
LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
34243433

3425-
/* Now scan the tables to copy the data */
3426-
hash_seq_init(&seqstat, LockMethodProcLockHash);
3427-
34283434
/* Now we can safely count the number of proclocks */
34293435
els = hash_get_num_entries(LockMethodProcLockHash);
34303436

@@ -3434,6 +3440,9 @@ GetRunningTransactionLocks(int *nlocks)
34343440
*/
34353441
accessExclusiveLocks = palloc(els * sizeof(xl_standby_lock));
34363442

3443+
/* Now scan the tables to copy the data */
3444+
hash_seq_init(&seqstat, LockMethodProcLockHash);
3445+
34373446
/*
34383447
* If lock is a currently granted AccessExclusiveLock then it will have
34393448
* just one proclock holder, so locks are never accessed twice in this
@@ -3978,22 +3987,34 @@ VirtualXactLock(VirtualTransactionId vxid, bool wait)
39783987

39793988
/*
39803989
* OK, we're going to need to sleep on the VXID. But first, we must set
3981-
* up the primary lock table entry, if needed.
3990+
* up the primary lock table entry, if needed (ie, convert the proc's
3991+
* fast-path lock on its VXID to a regular lock).
39823992
*/
39833993
if (proc->fpVXIDLock)
39843994
{
39853995
PROCLOCK *proclock;
39863996
uint32 hashcode;
3997+
LWLockId partitionLock;
39873998

39883999
hashcode = LockTagHashCode(&tag);
4000+
4001+
partitionLock = LockHashPartitionLock(hashcode);
4002+
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
4003+
39894004
proclock = SetupLockInTable(LockMethods[DEFAULT_LOCKMETHOD], proc,
39904005
&tag, hashcode, ExclusiveLock);
39914006
if (!proclock)
4007+
{
4008+
LWLockRelease(partitionLock);
39924009
ereport(ERROR,
39934010
(errcode(ERRCODE_OUT_OF_MEMORY),
39944011
errmsg("out of shared memory"),
39954012
errhint("You might need to increase max_locks_per_transaction.")));
4013+
}
39964014
GrantLock(proclock->tag.myLock, proclock, ExclusiveLock);
4015+
4016+
LWLockRelease(partitionLock);
4017+
39974018
proc->fpVXIDLock = false;
39984019
}
39994020

0 commit comments

Comments
 (0)