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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user