1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Special case in ProcSleep() wasn't sufficiently general: must check to

see if we shouldn't block whenever we insert ourselves anywhere before
the end of the queue, not only at the front.
This commit is contained in:
Tom Lane
2001-01-26 18:23:12 +00:00
parent c6e6d292bc
commit f433d0d3cd
2 changed files with 39 additions and 31 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.97 2001/01/25 03:31:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.98 2001/01/26 18:23:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -537,13 +537,18 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
* me to before that waiter anyway; but it's relatively cheap to detect
* such a conflict immediately, and avoid delaying till deadlock timeout.
*
* Special case: if I find I should go in front of the first waiter,
* and I do not conflict with already-held locks, then just grant myself
* the requested lock immediately.
* Special case: if I find I should go in front of some waiter, check
* to see if I conflict with already-held locks or the requests before
* that waiter. If not, then just grant myself the requested lock
* immediately. This is the same as the test for immediate grant in
* LockAcquire, except we are only considering the part of the wait queue
* before my insertion point.
* ----------------------
*/
if (myHeldLocks != 0)
{
int aheadRequests = 0;
proc = (PROC *) MAKE_PTR(waitQueue->links.next);
for (i = 0; i < waitQueue->size; i++)
{
@ -557,26 +562,30 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
MyProc->errType = STATUS_ERROR;
return STATUS_ERROR;
}
if (i == 0)
/* I must go before this waiter. Check special case. */
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
holder,
MyProc,
NULL) == STATUS_OK)
{
/* I must go before first waiter. Check special case. */
if (LockCheckConflicts(lockMethodTable,
lockmode,
lock,
holder,
MyProc,
NULL) == STATUS_OK)
{
/* Skip the wait and just grant myself the lock. */
GrantLock(lock, holder, lockmode);
return STATUS_OK;
}
/* Skip the wait and just grant myself the lock. */
GrantLock(lock, holder, lockmode);
return STATUS_OK;
}
/* Break out of loop to put myself before him */
break;
}
/* Nope, so advance to next waiter */
aheadRequests |= (1 << proc->waitLockMode);
proc = (PROC *) MAKE_PTR(proc->links.next);
}
/*
* If we fall out of loop normally, proc points to waitQueue head,
* so we will insert at tail of queue as desired.
*/
}
else
{
@ -739,7 +748,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
PROC_QUEUE *waitQueue = &(lock->waitProcs);
int queue_size = waitQueue->size;
PROC *proc;
int conflictMask = 0;
int aheadRequests = 0;
Assert(queue_size >= 0);
@ -756,7 +765,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
* Waken if (a) doesn't conflict with requests of earlier waiters,
* and (b) doesn't conflict with already-held locks.
*/
if (((1 << lockmode) & conflictMask) == 0 &&
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
@ -775,8 +784,8 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
}
else
{
/* Cannot wake this guy. Add his request to conflict mask. */
conflictMask |= lockctl->conflictTab[lockmode];
/* Cannot wake this guy. Remember his request for later checks. */
aheadRequests |= (1 << lockmode);
proc = (PROC *) MAKE_PTR(proc->links.next);
}
}