Clean up the lock state properly when aborting because of early deadlock

detection in ProcSleep().  Bug noted by Tomasz Zielonka --- how did this
escape detection for this long??
This commit is contained in:
Tom Lane 2001-09-04 02:26:57 +00:00
parent 3c59a9e3b7
commit b553cba15a
1 changed files with 27 additions and 9 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.104 2001/07/06 21:04:26 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.105 2001/09/04 02:26:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -506,16 +506,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
SPINLOCK spinlock = lockctl->masterLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs);
int myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false;
PROC *proc;
int i;
#ifndef __BEOS__
struct itimerval timeval,
dummy;
#else
bigtime_t time_interval;
#endif
/*
@ -535,7 +533,6 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
* 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)
{
@ -550,9 +547,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
/* Must I wait for him ? */
if (lockctl->conflictTab[lockmode] & proc->heldLocks)
{
/* Yes, can report deadlock failure immediately */
MyProc->errType = STATUS_ERROR;
return STATUS_ERROR;
/*
* Yes, so we have a deadlock. Easiest way to clean up
* correctly is to call RemoveFromWaitQueue(), but we
* can't do that until we are *on* the wait queue.
* So, set a flag to check below, and break out of loop.
*/
early_deadlock = true;
break;
}
/* I must go before this waiter. Check special case. */
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
@ -600,7 +602,19 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
MyProc->waitHolder = holder;
MyProc->waitLockMode = lockmode;
MyProc->errType = STATUS_OK;/* initialize result for success */
MyProc->errType = STATUS_OK; /* initialize result for success */
/*
* If we detected deadlock, give up without waiting. This must agree
* with HandleDeadLock's recovery code, except that we shouldn't release
* the semaphore since we haven't tried to lock it yet.
*/
if (early_deadlock)
{
RemoveFromWaitQueue(MyProc);
MyProc->errType = STATUS_ERROR;
return STATUS_ERROR;
}
/* mark that we are waiting for a lock */
waitingForLock = true;
@ -693,6 +707,10 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
*
* Also remove the process from the wait queue and set its links invalid.
* RETURN: the next process in the wait queue.
*
* XXX: presently, this code is only used for the "success" case, and only
* works correctly for that case. To clean up in failure case, would need
* to twiddle the lock's request counts too --- see RemoveFromWaitQueue.
*/
PROC *
ProcWakeup(PROC *proc, int errType)