Skip to content
Snippets Groups Projects
Commit b553cba1 authored by Tom Lane's avatar Tom Lane
Browse files

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??
parent 3c59a9e3
No related branches found
No related tags found
No related merge requests found
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -506,16 +506,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
SPINLOCK spinlock = lockctl->masterLock; SPINLOCK spinlock = lockctl->masterLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs); PROC_QUEUE *waitQueue = &(lock->waitProcs);
int myHeldLocks = MyProc->heldLocks; int myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false;
PROC *proc; PROC *proc;
int i; int i;
#ifndef __BEOS__ #ifndef __BEOS__
struct itimerval timeval, struct itimerval timeval,
dummy; dummy;
#else #else
bigtime_t time_interval; bigtime_t time_interval;
#endif #endif
/* /*
...@@ -535,7 +533,6 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, ...@@ -535,7 +533,6 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
* immediately. This is the same as the test for immediate grant in * immediately. This is the same as the test for immediate grant in
* LockAcquire, except we are only considering the part of the wait * LockAcquire, except we are only considering the part of the wait
* queue before my insertion point. * queue before my insertion point.
*
*/ */
if (myHeldLocks != 0) if (myHeldLocks != 0)
{ {
...@@ -550,9 +547,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, ...@@ -550,9 +547,14 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
/* Must I wait for him ? */ /* Must I wait for him ? */
if (lockctl->conflictTab[lockmode] & proc->heldLocks) if (lockctl->conflictTab[lockmode] & proc->heldLocks)
{ {
/* Yes, can report deadlock failure immediately */ /*
MyProc->errType = STATUS_ERROR; * Yes, so we have a deadlock. Easiest way to clean up
return STATUS_ERROR; * 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. */ /* I must go before this waiter. Check special case. */
if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 && if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
...@@ -600,7 +602,19 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, ...@@ -600,7 +602,19 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
MyProc->waitHolder = holder; MyProc->waitHolder = holder;
MyProc->waitLockMode = lockmode; 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 */ /* mark that we are waiting for a lock */
waitingForLock = true; waitingForLock = true;
...@@ -693,6 +707,10 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable, ...@@ -693,6 +707,10 @@ ProcSleep(LOCKMETHODTABLE *lockMethodTable,
* *
* Also remove the process from the wait queue and set its links invalid. * Also remove the process from the wait queue and set its links invalid.
* RETURN: the next process in the wait queue. * 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 * PROC *
ProcWakeup(PROC *proc, int errType) ProcWakeup(PROC *proc, int errType)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment