1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-06 07:49:08 +03:00

Use dlist/dclist instead of PROC_QUEUE / SHM_QUEUE for heavyweight locks

Part of a series to remove SHM_QUEUE. ilist.h style lists are more widely used
and have an easier to use interface.

As PROC_QUEUE is now unused, remove it.

Reviewed-by: Thomas Munro <thomas.munro@gmail.com> (in an older version)
Discussion: https://postgr.es/m/20221120055930.t6kl3tyivzhlrzu2@awork3.anarazel.de
Discussion: https://postgr.es/m/20200211042229.msv23badgqljrdg2@alap3.anarazel.de
This commit is contained in:
Andres Freund
2023-01-18 11:41:14 -08:00
parent 51384cc40c
commit 5764f611e1
7 changed files with 183 additions and 339 deletions

View File

@@ -345,7 +345,7 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
lock->granted[1], lock->granted[2], lock->granted[3],
lock->granted[4], lock->granted[5], lock->granted[6],
lock->granted[7], lock->nGranted,
lock->waitProcs.size,
dclist_count(&lock->waitProcs),
LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
}
@@ -1058,8 +1058,8 @@ LockAcquireExtended(const LOCKTAG *locktag,
uint32 proclock_hashcode;
proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink);
dlist_delete(&proclock->lockLink);
dlist_delete(&proclock->procLink);
if (!hash_search_with_hash_value(LockMethodProcLockHash,
(void *) &(proclock->tag),
proclock_hashcode,
@@ -1194,8 +1194,8 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
{
lock->grantMask = 0;
lock->waitMask = 0;
SHMQueueInit(&(lock->procLocks));
ProcQueueInit(&(lock->waitProcs));
dlist_init(&lock->procLocks);
dclist_init(&lock->waitProcs);
lock->nRequested = 0;
lock->nGranted = 0;
MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
@@ -1237,7 +1237,7 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
* of shared memory, because there won't be anything to cause
* anyone to release the lock object later.
*/
Assert(SHMQueueEmpty(&(lock->procLocks)));
Assert(dlist_is_empty(&(lock->procLocks)));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
@@ -1270,9 +1270,8 @@ SetupLockInTable(LockMethod lockMethodTable, PGPROC *proc,
proclock->holdMask = 0;
proclock->releaseMask = 0;
/* Add proclock to appropriate lists */
SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
&proclock->procLink);
dlist_push_tail(&lock->procLocks, &proclock->lockLink);
dlist_push_tail(&proc->myProcLocks[partition], &proclock->procLink);
PROCLOCK_PRINT("LockAcquire: new", proclock);
}
else
@@ -1427,9 +1426,8 @@ LockCheckConflicts(LockMethod lockMethodTable,
int conflictMask = lockMethodTable->conflictTab[lockmode];
int conflictsRemaining[MAX_LOCKMODES];
int totalConflictsRemaining = 0;
dlist_iter proclock_iter;
int i;
SHM_QUEUE *procLocks;
PROCLOCK *otherproclock;
/*
* first check for global conflicts: If no locks conflict with my request,
@@ -1501,11 +1499,11 @@ LockCheckConflicts(LockMethod lockMethodTable,
* shared memory state more complex (and larger) but it doesn't seem worth
* it.
*/
procLocks = &(lock->procLocks);
otherproclock = (PROCLOCK *)
SHMQueueNext(procLocks, procLocks, offsetof(PROCLOCK, lockLink));
while (otherproclock != NULL)
dlist_foreach(proclock_iter, &lock->procLocks)
{
PROCLOCK *otherproclock =
dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
if (proclock != otherproclock &&
proclock->groupLeader == otherproclock->groupLeader &&
(otherproclock->holdMask & conflictMask) != 0)
@@ -1530,9 +1528,6 @@ LockCheckConflicts(LockMethod lockMethodTable,
return false;
}
}
otherproclock = (PROCLOCK *)
SHMQueueNext(procLocks, &otherproclock->lockLink,
offsetof(PROCLOCK, lockLink));
}
/* Nope, it's a real conflict. */
@@ -1645,8 +1640,8 @@ CleanUpLock(LOCK *lock, PROCLOCK *proclock,
uint32 proclock_hashcode;
PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
SHMQueueDelete(&proclock->lockLink);
SHMQueueDelete(&proclock->procLink);
dlist_delete(&proclock->lockLink);
dlist_delete(&proclock->procLink);
proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
if (!hash_search_with_hash_value(LockMethodProcLockHash,
(void *) &(proclock->tag),
@@ -1663,7 +1658,7 @@ CleanUpLock(LOCK *lock, PROCLOCK *proclock,
* object.
*/
LOCK_PRINT("CleanUpLock: deleting", lock, 0);
Assert(SHMQueueEmpty(&(lock->procLocks)));
Assert(dlist_is_empty(&lock->procLocks));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
@@ -1926,12 +1921,11 @@ RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
Assert(proc->waitStatus == PROC_WAIT_STATUS_WAITING);
Assert(proc->links.next != NULL);
Assert(waitLock);
Assert(waitLock->waitProcs.size > 0);
Assert(!dclist_is_empty(&waitLock->waitProcs));
Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
/* Remove proc from lock's wait queue */
SHMQueueDelete(&(proc->links));
waitLock->waitProcs.size--;
dclist_delete_from(&waitLock->waitProcs, &proc->links);
/* Undo increments of request counts by waiting process */
Assert(waitLock->nRequested > 0);
@@ -2185,7 +2179,6 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
numLockModes;
LOCALLOCK *locallock;
LOCK *lock;
PROCLOCK *proclock;
int partition;
bool have_fast_path_lwlock = false;
@@ -2342,8 +2335,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
{
LWLock *partitionLock;
SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
PROCLOCK *nextplock;
dlist_head *procLocks = &MyProc->myProcLocks[partition];
dlist_mutable_iter proclock_iter;
partitionLock = LockHashPartitionLockByIndex(partition);
@@ -2366,24 +2359,16 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
* locallock situation, we lose that guarantee for fast-path locks.
* This is not ideal.
*/
if (SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, procLink)) == NULL)
if (dlist_is_empty(procLocks))
continue; /* needn't examine this partition */
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
for (proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, procLink));
proclock;
proclock = nextplock)
dlist_foreach_modify(proclock_iter, procLocks)
{
PROCLOCK *proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
bool wakeupNeeded = false;
/* Get link first, since we may unlink/delete this proclock */
nextplock = (PROCLOCK *)
SHMQueueNext(procLocks, &proclock->procLink,
offsetof(PROCLOCK, procLink));
Assert(proclock->tag.myProc == MyProc);
lock = proclock->tag.myLock;
@@ -2918,7 +2903,7 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LockMethod lockMethodTable;
LOCK *lock;
LOCKMASK conflictMask;
SHM_QUEUE *procLocks;
dlist_iter proclock_iter;
PROCLOCK *proclock;
uint32 hashcode;
LWLock *partitionLock;
@@ -3064,14 +3049,10 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
/*
* Examine each existing holder (or awaiter) of the lock.
*/
procLocks = &(lock->procLocks);
proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, lockLink));
while (proclock)
dlist_foreach(proclock_iter, &lock->procLocks)
{
proclock = dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
if (conflictMask & proclock->holdMask)
{
PGPROC *proc = proclock->tag.myProc;
@@ -3097,9 +3078,6 @@ GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
/* else, xact already committed or aborted */
}
}
proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
offsetof(PROCLOCK, lockLink));
}
LWLockRelease(partitionLock);
@@ -3498,8 +3476,8 @@ PostPrepare_Locks(TransactionId xid)
for (partition = 0; partition < NUM_LOCK_PARTITIONS; partition++)
{
LWLock *partitionLock;
SHM_QUEUE *procLocks = &(MyProc->myProcLocks[partition]);
PROCLOCK *nextplock;
dlist_head *procLocks = &(MyProc->myProcLocks[partition]);
dlist_mutable_iter proclock_iter;
partitionLock = LockHashPartitionLockByIndex(partition);
@@ -3511,21 +3489,14 @@ PostPrepare_Locks(TransactionId xid)
* another backend is adding something to our lists now. For safety,
* though, we code this the same way as in LockReleaseAll.
*/
if (SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, procLink)) == NULL)
if (dlist_is_empty(procLocks))
continue; /* needn't examine this partition */
LWLockAcquire(partitionLock, LW_EXCLUSIVE);
for (proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, procLink));
proclock;
proclock = nextplock)
dlist_foreach_modify(proclock_iter, procLocks)
{
/* Get link first, since we may unlink/relink this proclock */
nextplock = (PROCLOCK *)
SHMQueueNext(procLocks, &proclock->procLink,
offsetof(PROCLOCK, procLink));
proclock = dlist_container(PROCLOCK, procLink, proclock_iter.cur);
Assert(proclock->tag.myProc == MyProc);
@@ -3563,7 +3534,7 @@ PostPrepare_Locks(TransactionId xid)
* same hash partition, cf proclock_hash(). So the partition lock
* we already hold is sufficient for this.
*/
SHMQueueDelete(&proclock->procLink);
dlist_delete(&proclock->procLink);
/*
* Create the new hash key for the proclock.
@@ -3589,8 +3560,7 @@ PostPrepare_Locks(TransactionId xid)
elog(PANIC, "duplicate entry found while reassigning a prepared transaction's locks");
/* Re-link into the new proc's proclock list */
SHMQueueInsertBefore(&(newproc->myProcLocks[partition]),
&proclock->procLink);
dlist_push_tail(&newproc->myProcLocks[partition], &proclock->procLink);
PROCLOCK_PRINT("PostPrepare_Locks: updated", proclock);
} /* loop over PROCLOCKs within this partition */
@@ -3919,12 +3889,10 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
{
LOCK *theLock = blocked_proc->waitLock;
BlockedProcData *bproc;
SHM_QUEUE *procLocks;
PROCLOCK *proclock;
PROC_QUEUE *waitQueue;
PGPROC *queued_proc;
dlist_iter proclock_iter;
dlist_iter proc_iter;
dclist_head *waitQueue;
int queue_size;
int i;
/* Nothing to do if this proc is not blocked */
if (theLock == NULL)
@@ -3942,11 +3910,10 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
*/
/* Collect all PROCLOCKs associated with theLock */
procLocks = &(theLock->procLocks);
proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, lockLink));
while (proclock)
dlist_foreach(proclock_iter, &theLock->procLocks)
{
PROCLOCK *proclock =
dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
PGPROC *proc = proclock->tag.myProc;
LOCK *lock = proclock->tag.myLock;
LockInstanceData *instance;
@@ -3971,14 +3938,11 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
instance->leaderPid = proclock->groupLeader->pid;
instance->fastpath = false;
data->nlocks++;
proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
offsetof(PROCLOCK, lockLink));
}
/* Enlarge waiter_pids[] if it's too small to hold all wait queue PIDs */
waitQueue = &(theLock->waitProcs);
queue_size = waitQueue->size;
queue_size = dclist_count(waitQueue);
if (queue_size > data->maxpids - data->npids)
{
@@ -3989,9 +3953,9 @@ GetSingleProcBlockerStatusData(PGPROC *blocked_proc, BlockedProcsData *data)
}
/* Collect PIDs from the lock's wait queue, stopping at blocked_proc */
queued_proc = (PGPROC *) waitQueue->links.next;
for (i = 0; i < queue_size; i++)
dclist_foreach(proc_iter, waitQueue)
{
PGPROC *queued_proc = dlist_container(PGPROC, links, proc_iter.cur);
if (queued_proc == blocked_proc)
break;
data->waiter_pids[data->npids++] = queued_proc->pid;
@@ -4113,9 +4077,6 @@ GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
void
DumpLocks(PGPROC *proc)
{
SHM_QUEUE *procLocks;
PROCLOCK *proclock;
LOCK *lock;
int i;
if (proc == NULL)
@@ -4126,23 +4087,17 @@ DumpLocks(PGPROC *proc)
for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
{
procLocks = &(proc->myProcLocks[i]);
dlist_head *procLocks = &proc->myProcLocks[i];
dlist_iter iter;
proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
offsetof(PROCLOCK, procLink));
while (proclock)
dlist_foreach(iter, procLocks)
{
PROCLOCK *proclock = dlist_container(PROCLOCK, procLink, iter.cur);
LOCK *lock = proclock->tag.myLock;
Assert(proclock->tag.myProc == proc);
lock = proclock->tag.myLock;
PROCLOCK_PRINT("DumpLocks", proclock);
LOCK_PRINT("DumpLocks", lock, 0);
proclock = (PROCLOCK *)
SHMQueueNext(procLocks, &proclock->procLink,
offsetof(PROCLOCK, procLink));
}
}
}
@@ -4267,8 +4222,8 @@ lock_twophase_recover(TransactionId xid, uint16 info,
{
lock->grantMask = 0;
lock->waitMask = 0;
SHMQueueInit(&(lock->procLocks));
ProcQueueInit(&(lock->waitProcs));
dlist_init(&lock->procLocks);
dclist_init(&lock->waitProcs);
lock->nRequested = 0;
lock->nGranted = 0;
MemSet(lock->requested, 0, sizeof(int) * MAX_LOCKMODES);
@@ -4310,7 +4265,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
* of shared memory, because there won't be anything to cause
* anyone to release the lock object later.
*/
Assert(SHMQueueEmpty(&(lock->procLocks)));
Assert(dlist_is_empty(&lock->procLocks));
if (!hash_search_with_hash_value(LockMethodLockHash,
(void *) &(lock->tag),
hashcode,
@@ -4335,9 +4290,9 @@ lock_twophase_recover(TransactionId xid, uint16 info,
proclock->holdMask = 0;
proclock->releaseMask = 0;
/* Add proclock to appropriate lists */
SHMQueueInsertBefore(&lock->procLocks, &proclock->lockLink);
SHMQueueInsertBefore(&(proc->myProcLocks[partition]),
&proclock->procLink);
dlist_push_tail(&lock->procLocks, &proclock->lockLink);
dlist_push_tail(&proc->myProcLocks[partition],
&proclock->procLink);
PROCLOCK_PRINT("lock_twophase_recover: new", proclock);
}
else