提交 f433d0d3 编写于 作者: T Tom Lane

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.
上级 c6e6d292
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.7 2001/01/25 03:31:16 tgl Exp $ $Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.8 2001/01/26 18:23:12 tgl Exp $
There are two fundamental lock structures: the per-lockable-object LOCK There are two fundamental lock structures: the per-lockable-object LOCK
struct, and the per-lock-holder HOLDER struct. A LOCK object exists struct, and the per-lock-holder HOLDER struct. A LOCK object exists
...@@ -178,11 +178,10 @@ request of any pending waiter, then the process will be inserted in the ...@@ -178,11 +178,10 @@ request of any pending waiter, then the process will be inserted in the
wait queue just ahead of the first such waiter. (If we did not make this wait queue just ahead of the first such waiter. (If we did not make this
check, the deadlock detection code would adjust the queue order to resolve check, the deadlock detection code would adjust the queue order to resolve
the conflict, but it's relatively cheap to make the check in ProcSleep and the conflict, but it's relatively cheap to make the check in ProcSleep and
avoid a deadlock timeout delay in this case.) Note special case: if the avoid a deadlock timeout delay in this case.) Note special case when
process holds locks that conflict with the first waiter, so that it would inserting before the end of the queue: if the process's request does not
go at the front of the queue, and its request does not conflict with the conflict with any existing lock nor any waiting request before its insertion
already-granted locks, then the process will be granted the lock without point, then go ahead and grant the lock without waiting.
going to sleep at all.
When a lock is released, the lock release routine (ProcLockWakeup) scans When a lock is released, the lock release routine (ProcLockWakeup) scans
the lock object's wait queue. Each waiter is awoken if (a) its request the lock object's wait queue. Each waiter is awoken if (a) its request
...@@ -192,7 +191,7 @@ ensures that conflicting requests are granted in order of arrival. ...@@ -192,7 +191,7 @@ ensures that conflicting requests are granted in order of arrival.
There are cases where a later waiter must be allowed to go in front of There are cases where a later waiter must be allowed to go in front of
conflicting earlier waiters to avoid deadlock, but it is not conflicting earlier waiters to avoid deadlock, but it is not
ProcLockWakeup's responsibility to recognize these cases; instead, the ProcLockWakeup's responsibility to recognize these cases; instead, the
deadlock detection code re-orders the wait queue when necessary. deadlock detection code will re-order the wait queue when necessary.
To perform deadlock checking, we use the standard method of viewing the To perform deadlock checking, we use the standard method of viewing the
various processes as nodes in a directed graph (the waits-for graph or various processes as nodes in a directed graph (the waits-for graph or
...@@ -263,13 +262,13 @@ orders) as well as the current real order. ...@@ -263,13 +262,13 @@ orders) as well as the current real order.
The easiest way to handle this seems to be to have a lookaside table that The easiest way to handle this seems to be to have a lookaside table that
shows the proposed new queue order for each wait queue that we are shows the proposed new queue order for each wait queue that we are
considering rearranging. This table is passed to FindLockCycle, and it considering rearranging. This table is checked by FindLockCycle, and it
believes the given queue order rather than the "real" order for each lock believes the proposed queue order rather than the real order for each lock
that has an entry in the lookaside table. that has an entry in the lookaside table.
We build a proposed new queue order by doing a "topological sort" of the We build a proposed new queue order by doing a "topological sort" of the
existing entries. Each soft edge that we are currently considering existing entries. Each soft edge that we are currently considering
reversing is a property of the partial order that the topological sort reversing creates a property of the partial order that the topological sort
has to enforce. We must use a sort method that preserves the input has to enforce. We must use a sort method that preserves the input
ordering as much as possible, so as not to gratuituously break arrival ordering as much as possible, so as not to gratuituously break arrival
order for processes not involved in a deadlock. (This is not true of the order for processes not involved in a deadlock. (This is not true of the
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -537,13 +537,18 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
* me to before that waiter anyway; but it's relatively cheap to detect * me to before that waiter anyway; but it's relatively cheap to detect
* such a conflict immediately, and avoid delaying till deadlock timeout. * such a conflict immediately, and avoid delaying till deadlock timeout.
* *
* Special case: if I find I should go in front of the first waiter, * Special case: if I find I should go in front of some waiter, check
* and I do not conflict with already-held locks, then just grant myself * to see if I conflict with already-held locks or the requests before
* the requested lock immediately. * 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) if (myHeldLocks != 0)
{ {
int aheadRequests = 0;
proc = (PROC *) MAKE_PTR(waitQueue->links.next); proc = (PROC *) MAKE_PTR(waitQueue->links.next);
for (i = 0; i < waitQueue->size; i++) for (i = 0; i < waitQueue->size; i++)
{ {
...@@ -557,26 +562,30 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, ...@@ -557,26 +562,30 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
MyProc->errType = STATUS_ERROR; MyProc->errType = STATUS_ERROR;
return 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. */ /* Skip the wait and just grant myself the lock. */
if (LockCheckConflicts(lockMethodTable, GrantLock(lock, holder, lockmode);
lockmode, return STATUS_OK;
lock,
holder,
MyProc,
NULL) == 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 out of loop to put myself before him */
break; break;
} }
/* Nope, so advance to next waiter */
aheadRequests |= (1 << proc->waitLockMode);
proc = (PROC *) MAKE_PTR(proc->links.next); 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 else
{ {
...@@ -739,7 +748,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock) ...@@ -739,7 +748,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
PROC_QUEUE *waitQueue = &(lock->waitProcs); PROC_QUEUE *waitQueue = &(lock->waitProcs);
int queue_size = waitQueue->size; int queue_size = waitQueue->size;
PROC *proc; PROC *proc;
int conflictMask = 0; int aheadRequests = 0;
Assert(queue_size >= 0); Assert(queue_size >= 0);
...@@ -756,7 +765,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock) ...@@ -756,7 +765,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
* Waken if (a) doesn't conflict with requests of earlier waiters, * Waken if (a) doesn't conflict with requests of earlier waiters,
* and (b) doesn't conflict with already-held locks. * and (b) doesn't conflict with already-held locks.
*/ */
if (((1 << lockmode) & conflictMask) == 0 && if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable, LockCheckConflicts(lockMethodTable,
lockmode, lockmode,
lock, lock,
...@@ -775,8 +784,8 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock) ...@@ -775,8 +784,8 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
} }
else else
{ {
/* Cannot wake this guy. Add his request to conflict mask. */ /* Cannot wake this guy. Remember his request for later checks. */
conflictMask |= lockctl->conflictTab[lockmode]; aheadRequests |= (1 << lockmode);
proc = (PROC *) MAKE_PTR(proc->links.next); proc = (PROC *) MAKE_PTR(proc->links.next);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册