Skip relation extension locks

We should skip if the process blocked on the relation
extension since those locks are hold for a short duration
while the relation is actually extended on the disk and
released as soon as the extension is done. Thus, recording
such waits on our lock graphs could yield detecting wrong
distributed deadlocks.
pull/1670/head
Onder Kalaci 2017-09-27 11:44:46 +03:00
parent 4676c4f7a5
commit 68ca8cb7f0
1 changed files with 60 additions and 5 deletions

View File

@ -49,6 +49,7 @@ static bool ParseBoolField(PGresult *result, int rowIndex, int colIndex);
static TimestampTz ParseTimestampTzField(PGresult *result, int rowIndex, int colIndex);
static void ReturnWaitGraph(WaitGraph *waitGraph, FunctionCallInfo fcinfo);
static WaitGraph * BuildLocalWaitGraph(void);
static bool IsProcessWaitingForRelationExtension(PGPROC *proc);
static void LockLockData(void);
static void UnlockLockData(void);
static void AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc,
@ -447,6 +448,12 @@ BuildLocalWaitGraph(void)
continue;
}
/* skip if the process is blocked for relation extension */
if (IsProcessWaitingForRelationExtension(currentProc))
{
continue;
}
AddProcToVisit(&remaining, currentProc);
}
@ -460,6 +467,12 @@ BuildLocalWaitGraph(void)
continue;
}
/* skip if the process is blocked for relation extension */
if (IsProcessWaitingForRelationExtension(waitingProc))
{
continue;
}
/*
* Record an edge for everyone already holding the lock in a
* conflicting manner ("hard edges" in postgres parlance).
@ -479,6 +492,36 @@ BuildLocalWaitGraph(void)
}
/*
* IsProcessWaitingForRelationExtension returns true if the given PROC
* waiting on relation extension lock.
*
* In general for the purpose of distributed deadlock detection, we should
* skip if the process blocked on the relation extension. Those locks are
* held for a short duration while the relation is actually extended on
* the disk and released as soon as the extension is done, even before the
* execution of the command that triggered the extension finishes. Thus,
* recording such waits on our lock graphs could yield detecting wrong
* distributed deadlocks.
*/
static bool
IsProcessWaitingForRelationExtension(PGPROC *proc)
{
PROCLOCK *waitProcLock = NULL;
LOCK *waitLock = NULL;
if (proc->waitStatus != STATUS_WAITING)
{
return false;
}
waitProcLock = proc->waitProcLock;
waitLock = waitProcLock->tag.myLock;
return waitLock->tag.locktag_type == LOCKTAG_RELATION_EXTEND;
}
/*
* LockLockData takes locks the shared lock data structure, which prevents
* concurrent lock acquisitions/releases.
@ -550,9 +593,14 @@ AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai
{
PGPROC *currentProc = procLock->tag.myProc;
/* skip processes from the same lock group and ones that don't conflict */
/*
* Skip processes from the same lock group, processes that don't conflict,
* and processes that are waiting on a relation extension lock, which
* will be released shortly.
*/
if (!IsSameLockGroup(waitingProc, currentProc) &&
IsConflictingLockMask(procLock->holdMask, conflictMask))
IsConflictingLockMask(procLock->holdMask, conflictMask) &&
!IsProcessWaitingForRelationExtension(currentProc))
{
AddWaitEdge(waitGraph, waitingProc, currentProc, remaining);
}
@ -590,9 +638,14 @@ AddEdgesForWaitQueue(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai
{
int awaitMask = LOCKBIT_ON(currentProc->waitLockMode);
/* skip processes from the same lock group and ones that don't conflict */
/*
* Skip processes from the same lock group, processes that don't conflict,
* and processes that are waiting on a relation extension lock, which
* will be released shortly.
*/
if (!IsSameLockGroup(waitingProc, currentProc) &&
IsConflictingLockMask(awaitMask, conflictMask))
IsConflictingLockMask(awaitMask, conflictMask) &&
!IsProcessWaitingForRelationExtension(currentProc))
{
AddWaitEdge(waitGraph, waitingProc, currentProc, remaining);
}
@ -621,7 +674,9 @@ AddWaitEdge(WaitGraph *waitGraph, PGPROC *waitingProc, PGPROC *blockingProc,
GetBackendDataForProc(waitingProc, &waitingBackendData);
GetBackendDataForProc(blockingProc, &blockingBackendData);
curEdge->isBlockingXactWaiting = IsProcessWaitingForLock(blockingProc);
curEdge->isBlockingXactWaiting =
IsProcessWaitingForLock(blockingProc) &&
!IsProcessWaitingForRelationExtension(blockingProc);
if (curEdge->isBlockingXactWaiting)
{
AddProcToVisit(remaining, blockingProc);