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

Commit f433d0d

Browse files
committed
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.
1 parent c6e6d29 commit f433d0d

File tree

2 files changed

+39
-31
lines changed

2 files changed

+39
-31
lines changed

src/backend/storage/lmgr/README

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.7 2001/01/25 03:31:16 tgl Exp $
1+
$Header: /cvsroot/pgsql/src/backend/storage/lmgr/README,v 1.8 2001/01/26 18:23:12 tgl Exp $
22

33
There are two fundamental lock structures: the per-lockable-object LOCK
44
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
178178
wait queue just ahead of the first such waiter. (If we did not make this
179179
check, the deadlock detection code would adjust the queue order to resolve
180180
the conflict, but it's relatively cheap to make the check in ProcSleep and
181-
avoid a deadlock timeout delay in this case.) Note special case: if the
182-
process holds locks that conflict with the first waiter, so that it would
183-
go at the front of the queue, and its request does not conflict with the
184-
already-granted locks, then the process will be granted the lock without
185-
going to sleep at all.
181+
avoid a deadlock timeout delay in this case.) Note special case when
182+
inserting before the end of the queue: if the process's request does not
183+
conflict with any existing lock nor any waiting request before its insertion
184+
point, then go ahead and grant the lock without waiting.
186185

187186
When a lock is released, the lock release routine (ProcLockWakeup) scans
188187
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.
192191
There are cases where a later waiter must be allowed to go in front of
193192
conflicting earlier waiters to avoid deadlock, but it is not
194193
ProcLockWakeup's responsibility to recognize these cases; instead, the
195-
deadlock detection code re-orders the wait queue when necessary.
194+
deadlock detection code will re-order the wait queue when necessary.
196195

197196
To perform deadlock checking, we use the standard method of viewing the
198197
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.
263262

264263
The easiest way to handle this seems to be to have a lookaside table that
265264
shows the proposed new queue order for each wait queue that we are
266-
considering rearranging. This table is passed to FindLockCycle, and it
267-
believes the given queue order rather than the "real" order for each lock
265+
considering rearranging. This table is checked by FindLockCycle, and it
266+
believes the proposed queue order rather than the real order for each lock
268267
that has an entry in the lookaside table.
269268

270269
We build a proposed new queue order by doing a "topological sort" of the
271270
existing entries. Each soft edge that we are currently considering
272-
reversing is a property of the partial order that the topological sort
271+
reversing creates a property of the partial order that the topological sort
273272
has to enforce. We must use a sort method that preserves the input
274273
ordering as much as possible, so as not to gratuituously break arrival
275274
order for processes not involved in a deadlock. (This is not true of the

src/backend/storage/lmgr/proc.c

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.97 2001/01/25 03:31:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.98 2001/01/26 18:23:12 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -537,13 +537,18 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
537537
* me to before that waiter anyway; but it's relatively cheap to detect
538538
* such a conflict immediately, and avoid delaying till deadlock timeout.
539539
*
540-
* Special case: if I find I should go in front of the first waiter,
541-
* and I do not conflict with already-held locks, then just grant myself
542-
* the requested lock immediately.
540+
* Special case: if I find I should go in front of some waiter, check
541+
* to see if I conflict with already-held locks or the requests before
542+
* that waiter. If not, then just grant myself the requested lock
543+
* immediately. This is the same as the test for immediate grant in
544+
* LockAcquire, except we are only considering the part of the wait queue
545+
* before my insertion point.
543546
* ----------------------
544547
*/
545548
if (myHeldLocks != 0)
546549
{
550+
int aheadRequests = 0;
551+
547552
proc = (PROC *) MAKE_PTR(waitQueue->links.next);
548553
for (i = 0; i < waitQueue->size; i++)
549554
{
@@ -557,26 +562,30 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
557562
MyProc->errType = STATUS_ERROR;
558563
return STATUS_ERROR;
559564
}
560-
if (i == 0)
565+
/* I must go before this waiter. Check special case. */
566+
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
567+
LockCheckConflicts(lockMethodTable,
568+
lockmode,
569+
lock,
570+
holder,
571+
MyProc,
572+
NULL) == STATUS_OK)
561573
{
562-
/* I must go before first waiter. Check special case. */
563-
if (LockCheckConflicts(lockMethodTable,
564-
lockmode,
565-
lock,
566-
holder,
567-
MyProc,
568-
NULL) == STATUS_OK)
569-
{
570-
/* Skip the wait and just grant myself the lock. */
571-
GrantLock(lock, holder, lockmode);
572-
return STATUS_OK;
573-
}
574+
/* Skip the wait and just grant myself the lock. */
575+
GrantLock(lock, holder, lockmode);
576+
return STATUS_OK;
574577
}
575578
/* Break out of loop to put myself before him */
576579
break;
577580
}
581+
/* Nope, so advance to next waiter */
582+
aheadRequests |= (1 << proc->waitLockMode);
578583
proc = (PROC *) MAKE_PTR(proc->links.next);
579584
}
585+
/*
586+
* If we fall out of loop normally, proc points to waitQueue head,
587+
* so we will insert at tail of queue as desired.
588+
*/
580589
}
581590
else
582591
{
@@ -739,7 +748,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
739748
PROC_QUEUE *waitQueue = &(lock->waitProcs);
740749
int queue_size = waitQueue->size;
741750
PROC *proc;
742-
int conflictMask = 0;
751+
int aheadRequests = 0;
743752

744753
Assert(queue_size >= 0);
745754

@@ -756,7 +765,7 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
756765
* Waken if (a) doesn't conflict with requests of earlier waiters,
757766
* and (b) doesn't conflict with already-held locks.
758767
*/
759-
if (((1 << lockmode) & conflictMask) == 0 &&
768+
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
760769
LockCheckConflicts(lockMethodTable,
761770
lockmode,
762771
lock,
@@ -775,8 +784,8 @@ ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
775784
}
776785
else
777786
{
778-
/* Cannot wake this guy. Add his request to conflict mask. */
779-
conflictMask |= lockctl->conflictTab[lockmode];
787+
/* Cannot wake this guy. Remember his request for later checks. */
788+
aheadRequests |= (1 << lockmode);
780789
proc = (PROC *) MAKE_PTR(proc->links.next);
781790
}
782791
}

0 commit comments

Comments
 (0)