Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit862927f

Browse files
committed
Real deadlock detection.
1 parent0e91367 commit862927f

File tree

4 files changed

+130
-49
lines changed

4 files changed

+130
-49
lines changed

‎src/backend/storage/lmgr/lock.c

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.21 1998/01/25 05:14:02 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.22 1998/01/27 03:00:28 momjian Exp $
1111
*
1212
* NOTES
1313
* Outside modules can create a lock table and acquire/release
@@ -1201,7 +1201,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
12011201
done= (xidLook->queue.next==end);
12021202
lock= (LOCK*)MAKE_PTR(xidLook->tag.lock);
12031203

1204-
LOCK_PRINT("ReleaseAll", (&lock->tag),0);
1204+
LOCK_PRINT("LockReleaseAll", (&lock->tag),0);
12051205

12061206
#ifdefUSER_LOCKS
12071207

@@ -1307,11 +1307,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
13071307
|| !found)
13081308
{
13091309
SpinRelease(masterLock);
1310-
#ifdefUSER_LOCKS
13111310
elog(NOTICE,"LockReleaseAll: xid table corrupted");
1312-
#else
1313-
elog(NOTICE,"LockReplace: xid table corrupted");
1314-
#endif
13151311
return (FALSE);
13161312
}
13171313

@@ -1329,11 +1325,7 @@ LockReleaseAll(LockTableId tableId, SHM_QUEUE *lockQueue)
13291325
if ((!lock)|| (!found))
13301326
{
13311327
SpinRelease(masterLock);
1332-
#ifdefUSER_LOCKS
13331328
elog(NOTICE,"LockReleaseAll: cannot remove lock from HTAB");
1334-
#else
1335-
elog(NOTICE,"LockReplace: cannot remove lock from HTAB");
1336-
#endif
13371329
return (FALSE);
13381330
}
13391331
}
@@ -1415,6 +1407,86 @@ LockingDisabled()
14151407
returnLockingIsDisabled;
14161408
}
14171409

1410+
/*
1411+
* DeadlockCheck -- Checks for deadlocks for a given process
1412+
*
1413+
* We can't block on user locks, so no sense testing for deadlock
1414+
* because there is no blocking, and no timer for the block.
1415+
*
1416+
* This code takes a list of locks a process holds, and the lock that
1417+
* the process is sleeping on, and tries to find if any of the processes
1418+
* waiting on its locks hold the lock it is waiting for.
1419+
*
1420+
* We have already locked the master lock before being called.
1421+
*/
1422+
bool
1423+
DeadLockCheck(SHM_QUEUE*lockQueue,LOCK*findlock,boolskip_check)
1424+
{
1425+
intdone;
1426+
XIDLookupEnt*xidLook=NULL;
1427+
XIDLookupEnt*tmp=NULL;
1428+
SHMEM_OFFSETend=MAKE_OFFSET(lockQueue);
1429+
LOCK*lock;
1430+
1431+
if (SHMQueueEmpty(lockQueue))
1432+
return false;
1433+
1434+
SHMQueueFirst(lockQueue, (Pointer*)&xidLook,&xidLook->queue);
1435+
1436+
XID_PRINT("DeadLockCheck",xidLook);
1437+
1438+
for (;;)
1439+
{
1440+
/* ---------------------------
1441+
* XXX Here we assume the shared memory queue is circular and
1442+
* that we know its internal structure. Should have some sort of
1443+
* macros to allow one to walk it.mer 20 July 1991
1444+
* ---------------------------
1445+
*/
1446+
done= (xidLook->queue.next==end);
1447+
lock= (LOCK*)MAKE_PTR(xidLook->tag.lock);
1448+
1449+
LOCK_PRINT("DeadLockCheck", (&lock->tag),0);
1450+
1451+
/*
1452+
* This is our only check to see if we found the lock we want.
1453+
*
1454+
* The lock we are waiting for is already in MyProc->lockQueue
1455+
* so we need to skip it here. We are trying to find it in
1456+
* someone else's lockQueue.
1457+
*/
1458+
if (lock==findlock&& !skip_check)
1459+
return true;
1460+
elseif (lock!=findlock|| !skip_check)
1461+
{
1462+
PROC_QUEUE*waitQueue=&(lock->waitProcs);
1463+
PROC*proc;
1464+
inti;
1465+
1466+
proc= (PROC*)MAKE_PTR(waitQueue->links.prev);
1467+
for (i=0;i<waitQueue->size;i++)
1468+
{
1469+
/* prevent endless loops */
1470+
if (proc!=MyProc&&skip_check)
1471+
{
1472+
/* If we found a deadlock, we can stop right now */
1473+
if (DeadLockCheck(&(proc->lockQueue),findlock, false))
1474+
return true;
1475+
}
1476+
proc= (PROC*)MAKE_PTR(proc->links.prev);
1477+
}
1478+
}
1479+
1480+
if (done)
1481+
break;
1482+
SHMQueueFirst(&xidLook->queue, (Pointer*)&tmp,&tmp->queue);
1483+
xidLook=tmp;
1484+
}
1485+
1486+
/* if we got here, no deadlock */
1487+
return false;
1488+
}
1489+
14181490
#ifdefDEADLOCK_DEBUG
14191491
/*
14201492
* Dump all locks. Must have already acquired the masterLock.

‎src/backend/storage/lmgr/proc.c

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.28 1998/01/25 05:14:09 momjian Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.29 1998/01/27 03:00:29 momjian Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -46,7 +46,7 @@
4646
*This is so that we can support more backends. (system-wide semaphore
4747
*sets run out pretty fast.) -ay 4/95
4848
*
49-
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.28 1998/01/25 05:14:09 momjian Exp $
49+
* $Header: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v 1.29 1998/01/27 03:00:29 momjian Exp $
5050
*/
5151
#include<sys/time.h>
5252
#include<unistd.h>
@@ -442,7 +442,7 @@ ProcQueueInit(PROC_QUEUE *queue)
442442
* NOTES: The process queue is now a priority queue for locking.
443443
*/
444444
int
445-
ProcSleep(PROC_QUEUE*queue,
445+
ProcSleep(PROC_QUEUE*waitQueue,
446446
SPINLOCKspinlock,
447447
inttoken,
448448
intprio,
@@ -453,8 +453,8 @@ ProcSleep(PROC_QUEUE *queue,
453453
structitimervaltimeval,
454454
dummy;
455455

456-
proc= (PROC*)MAKE_PTR(queue->links.prev);
457-
for (i=0;i<queue->size;i++)
456+
proc= (PROC*)MAKE_PTR(waitQueue->links.prev);
457+
for (i=0;i<waitQueue->size;i++)
458458
{
459459
if (proc->prio >=prio)
460460
proc= (PROC*)MAKE_PTR(proc->links.prev);
@@ -478,36 +478,38 @@ ProcSleep(PROC_QUEUE *queue,
478478
* -------------------
479479
*/
480480
SHMQueueInsertTL(&(proc->links),&(MyProc->links));
481-
queue->size++;
481+
waitQueue->size++;
482482

483483
SpinRelease(spinlock);
484484

485485
/* --------------
486-
* Postgres does not have any deadlock detection code and for this
487-
* reason we must set a timer to wake up the process in the event of
488-
* a deadlock.For now the timer is set for 1 minute and we assume that
489-
* any process which sleeps for this amount of time is deadlocked and will
490-
* receive a SIGALRM signal. The handler should release the processes
491-
* semaphore and abort the current transaction.
486+
* We set this so we can wake up periodically and check for a deadlock.
487+
* If a deadlock is detected, the handler releases the processes
488+
* semaphore and aborts the current transaction.
492489
*
493490
* Need to zero out struct to set the interval and the micro seconds fields
494491
* to 0.
495492
* --------------
496493
*/
497494
MemSet(&timeval,0,sizeof(structitimerval));
498-
timeval.it_value.tv_sec=DEADLOCK_TIMEOUT;
495+
timeval.it_value.tv_sec=DEADLOCK_CHECK_TIMER;
499496

500-
if (setitimer(ITIMER_REAL,&timeval,&dummy))
501-
elog(FATAL,"ProcSleep: Unable to set timer for process wakeup");
497+
do
498+
{
499+
MyProc->errType=NO_ERROR;/* reset flag after deadlock check */
502500

503-
/* --------------
504-
* if someone wakes us between SpinRelease and IpcSemaphoreLock,
505-
* IpcSemaphoreLock will not block. The wakeup is "saved" by
506-
* the semaphore implementation.
507-
* --------------
508-
*/
509-
IpcSemaphoreLock(MyProc->sem.semId,MyProc->sem.semNum,IpcExclusiveLock);
501+
if (setitimer(ITIMER_REAL,&timeval,&dummy))
502+
elog(FATAL,"ProcSleep: Unable to set timer for process wakeup");
510503

504+
/* --------------
505+
* if someone wakes us between SpinRelease and IpcSemaphoreLock,
506+
* IpcSemaphoreLock will not block. The wakeup is "saved" by
507+
* the semaphore implementation.
508+
* --------------
509+
*/
510+
IpcSemaphoreLock(MyProc->sem.semId,MyProc->sem.semNum,IpcExclusiveLock);
511+
}while (MyProc->errType==STATUS_NOT_FOUND);/* sleep after deadlock check */
512+
511513
/* ---------------
512514
* We were awoken before a timeout - now disable the timer
513515
* ---------------
@@ -615,10 +617,9 @@ ProcAddLock(SHM_QUEUE *elem)
615617
}
616618

617619
/* --------------------
618-
* We only get to this routine if we got SIGALRM after DEADLOCK_TIMEOUT
619-
* while waiting for a lock to be released by some other process. After
620-
* the one minute deadline we assume we have a deadlock and must abort
621-
* this transaction. We must also indicate that I'm no longer waiting
620+
* We only get to this routine if we got SIGALRM after DEADLOCK_CHECK_TIMER
621+
* while waiting for a lock to be released by some other process. If we have
622+
* a real deadlock, we must also indicate that I'm no longer waiting
622623
* on a lock so that other processes don't try to wake me up and screw
623624
* up my semaphore.
624625
* --------------------
@@ -665,12 +666,19 @@ HandleDeadLock(int sig)
665666
return;
666667
}
667668

668-
mywaitlock=MyProc->waitLock;
669-
670669
#ifdefDEADLOCK_DEBUG
671670
DumpLocks();
672671
#endif
673672

673+
if (!DeadLockCheck(&(MyProc->lockQueue),MyProc->waitLock, true))
674+
{
675+
UnlockLockTable();
676+
MyProc->errType=STATUS_NOT_FOUND;
677+
return;
678+
}
679+
680+
mywaitlock=MyProc->waitLock;
681+
674682
/* ------------------------
675683
* Get this process off the lock's wait queue
676684
* ------------------------
@@ -701,8 +709,7 @@ HandleDeadLock(int sig)
701709
*/
702710
UnlockLockTable();
703711

704-
elog(NOTICE,"Timeout interval reached -- possible deadlock.");
705-
elog(NOTICE,"See the lock(l) manual page for a possible cause.");
712+
elog(NOTICE,"Deadlock detected -- See the lock(l) manual page for a possible cause.");
706713
return;
707714
}
708715

‎src/include/config.h.in

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,16 @@ extern void srandom(int seed);
210210
code seems broken without it, Bruce Momjian */
211211
/* #define LOARRAY */
212212

213-
/* This is the time, in seconds, at which a given backend server
214-
* will wait on a lock before deciding to abort the transaction
215-
* (this is what we do in lieu of deadlock detection).
216-
*
217-
* Low numbers are not recommended as they will tend to cause
218-
* false aborts if many transactions are long-lived.
213+
/*
214+
* As soon as the backend blocks on a lock, it waits this number of seconds
215+
* before checking for a deadlock. If not, it keeps checking every this
216+
* number of seconds.
217+
* We don't check for deadlocks just before sleeping because a deadlock is
218+
* a rare event, and checking is an expensive operation.
219+
* We only detect deadlocks between two processes, not three or more, but
220+
* these are the most common.
219221
*/
220-
#defineDEADLOCK_TIMEOUT 60
222+
#defineDEADLOCK_CHECK_TIMER 60
221223

222224
/*
223225
* This flag enables the use of idexes in plans generated for function

‎src/include/storage/lock.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
* Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: lock.h,v 1.9 1998/01/24 22:50:11 momjian Exp $
9+
* $Id: lock.h,v 1.10 1998/01/27 03:00:43 momjian Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -214,7 +214,7 @@ extern void GrantLock(LOCK *lock, LOCKT lockt);
214214
externboolLockReleaseAll(LockTableIdtableId,SHM_QUEUE*lockQueue);
215215
externintLockShmemSize(void);
216216
externboolLockingDisabled(void);
217-
217+
externboolDeadLockCheck(SHM_QUEUE*lockQueue,LOCK*findlock,boolskip_check);
218218
#ifdefDEADLOCK_DEBUG
219219
externvoidDumpLocks(void);
220220

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp