|
|
@ -12,7 +12,7 @@ |
|
|
|
* |
|
|
|
* |
|
|
|
* |
|
|
|
* |
|
|
|
* IDENTIFICATION |
|
|
|
* IDENTIFICATION |
|
|
|
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.48 2007/06/19 20:13:21 tgl Exp $ |
|
|
|
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.49 2007/10/26 20:45:10 alvherre Exp $ |
|
|
|
* |
|
|
|
* |
|
|
|
* Interface: |
|
|
|
* Interface: |
|
|
|
* |
|
|
|
* |
|
|
@ -109,6 +109,9 @@ static int maxPossibleConstraints; |
|
|
|
static DEADLOCK_INFO *deadlockDetails; |
|
|
|
static DEADLOCK_INFO *deadlockDetails; |
|
|
|
static int nDeadlockDetails; |
|
|
|
static int nDeadlockDetails; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* PGPROC pointer of any blocking autovacuum worker found */ |
|
|
|
|
|
|
|
static PGPROC *blocking_autovacuum_proc = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* InitDeadLockChecking -- initialize deadlock checker during backend startup |
|
|
|
* InitDeadLockChecking -- initialize deadlock checker during backend startup |
|
|
@ -206,6 +209,9 @@ DeadLockCheck(PGPROC *proc) |
|
|
|
nPossibleConstraints = 0; |
|
|
|
nPossibleConstraints = 0; |
|
|
|
nWaitOrders = 0; |
|
|
|
nWaitOrders = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Initialize to not blocked by an autovacuum worker */ |
|
|
|
|
|
|
|
blocking_autovacuum_proc = NULL; |
|
|
|
|
|
|
|
|
|
|
|
/* Search for deadlocks and possible fixes */ |
|
|
|
/* Search for deadlocks and possible fixes */ |
|
|
|
if (DeadLockCheckRecurse(proc)) |
|
|
|
if (DeadLockCheckRecurse(proc)) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -255,10 +261,28 @@ DeadLockCheck(PGPROC *proc) |
|
|
|
/* Return code tells caller if we had to escape a deadlock or not */ |
|
|
|
/* Return code tells caller if we had to escape a deadlock or not */ |
|
|
|
if (nWaitOrders > 0) |
|
|
|
if (nWaitOrders > 0) |
|
|
|
return DS_SOFT_DEADLOCK; |
|
|
|
return DS_SOFT_DEADLOCK; |
|
|
|
|
|
|
|
else if (blocking_autovacuum_proc != NULL) |
|
|
|
|
|
|
|
return DS_BLOCKED_BY_AUTOVACUUM; |
|
|
|
else |
|
|
|
else |
|
|
|
return DS_NO_DEADLOCK; |
|
|
|
return DS_NO_DEADLOCK; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Return the PGPROC of the autovacuum that's blocking a process. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* We reset the saved pointer as soon as we pass it back. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
PGPROC * |
|
|
|
|
|
|
|
GetBlockingAutoVacuumPgproc(void) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
PGPROC *ptr; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ptr = blocking_autovacuum_proc; |
|
|
|
|
|
|
|
blocking_autovacuum_proc = NULL; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ptr; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
/*
|
|
|
|
* DeadLockCheckRecurse -- recursively search for valid orderings |
|
|
|
* DeadLockCheckRecurse -- recursively search for valid orderings |
|
|
|
* |
|
|
|
* |
|
|
@ -497,6 +521,25 @@ FindLockCycleRecurse(PGPROC *checkProc, |
|
|
|
if ((proclock->holdMask & LOCKBIT_ON(lm)) && |
|
|
|
if ((proclock->holdMask & LOCKBIT_ON(lm)) && |
|
|
|
(conflictMask & LOCKBIT_ON(lm))) |
|
|
|
(conflictMask & LOCKBIT_ON(lm))) |
|
|
|
{ |
|
|
|
{ |
|
|
|
|
|
|
|
/*
|
|
|
|
|
|
|
|
* Look for a blocking autovacuum. There can be more than |
|
|
|
|
|
|
|
* one in the deadlock cycle, in which case we just pick a |
|
|
|
|
|
|
|
* random one. We stash the autovacuum worker's PGPROC so |
|
|
|
|
|
|
|
* that the caller can send a cancel signal to it, if |
|
|
|
|
|
|
|
* appropriate. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Note we read vacuumFlags without any locking. This is |
|
|
|
|
|
|
|
* OK only for checking the PROC_IS_AUTOVACUUM flag, |
|
|
|
|
|
|
|
* because that flag is set at process start and never |
|
|
|
|
|
|
|
* reset; there is logic elsewhere to avoid cancelling an |
|
|
|
|
|
|
|
* autovacuum that is working for preventing Xid wraparound |
|
|
|
|
|
|
|
* problems (which needs to read a different vacuumFlag |
|
|
|
|
|
|
|
* bit), but we don't do that here to avoid grabbing |
|
|
|
|
|
|
|
* ProcArrayLock. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (proc->vacuumFlags & PROC_IS_AUTOVACUUM) |
|
|
|
|
|
|
|
blocking_autovacuum_proc = proc; |
|
|
|
|
|
|
|
|
|
|
|
/* This proc hard-blocks checkProc */ |
|
|
|
/* This proc hard-blocks checkProc */ |
|
|
|
if (FindLockCycleRecurse(proc, depth + 1, |
|
|
|
if (FindLockCycleRecurse(proc, depth + 1, |
|
|
|
softEdges, nSoftEdges)) |
|
|
|
softEdges, nSoftEdges)) |
|
|
|