Merge pull request #1670 from citusdata/remove_unnecessary_locks_in_graph

Skip relation extension locks on distributed deadlock detection
pull/1667/head
Önder Kalacı 2017-09-28 10:30:49 +03:00 committed by GitHub
commit b2d42a0595
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 TimestampTz ParseTimestampTzField(PGresult *result, int rowIndex, int colIndex);
static void ReturnWaitGraph(WaitGraph *waitGraph, FunctionCallInfo fcinfo); static void ReturnWaitGraph(WaitGraph *waitGraph, FunctionCallInfo fcinfo);
static WaitGraph * BuildLocalWaitGraph(void); static WaitGraph * BuildLocalWaitGraph(void);
static bool IsProcessWaitingForRelationExtension(PGPROC *proc);
static void LockLockData(void); static void LockLockData(void);
static void UnlockLockData(void); static void UnlockLockData(void);
static void AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc, static void AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc,
@ -447,6 +448,12 @@ BuildLocalWaitGraph(void)
continue; continue;
} }
/* skip if the process is blocked for relation extension */
if (IsProcessWaitingForRelationExtension(currentProc))
{
continue;
}
AddProcToVisit(&remaining, currentProc); AddProcToVisit(&remaining, currentProc);
} }
@ -460,6 +467,12 @@ BuildLocalWaitGraph(void)
continue; 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 * Record an edge for everyone already holding the lock in a
* conflicting manner ("hard edges" in postgres parlance). * 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 * LockLockData takes locks the shared lock data structure, which prevents
* concurrent lock acquisitions/releases. * concurrent lock acquisitions/releases.
@ -550,9 +593,14 @@ AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai
{ {
PGPROC *currentProc = procLock->tag.myProc; 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) && if (!IsSameLockGroup(waitingProc, currentProc) &&
IsConflictingLockMask(procLock->holdMask, conflictMask)) IsConflictingLockMask(procLock->holdMask, conflictMask) &&
!IsProcessWaitingForRelationExtension(currentProc))
{ {
AddWaitEdge(waitGraph, waitingProc, currentProc, remaining); AddWaitEdge(waitGraph, waitingProc, currentProc, remaining);
} }
@ -590,9 +638,14 @@ AddEdgesForWaitQueue(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai
{ {
int awaitMask = LOCKBIT_ON(currentProc->waitLockMode); 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) && if (!IsSameLockGroup(waitingProc, currentProc) &&
IsConflictingLockMask(awaitMask, conflictMask)) IsConflictingLockMask(awaitMask, conflictMask) &&
!IsProcessWaitingForRelationExtension(currentProc))
{ {
AddWaitEdge(waitGraph, waitingProc, currentProc, remaining); AddWaitEdge(waitGraph, waitingProc, currentProc, remaining);
} }
@ -621,7 +674,9 @@ AddWaitEdge(WaitGraph *waitGraph, PGPROC *waitingProc, PGPROC *blockingProc,
GetBackendDataForProc(waitingProc, &waitingBackendData); GetBackendDataForProc(waitingProc, &waitingBackendData);
GetBackendDataForProc(blockingProc, &blockingBackendData); GetBackendDataForProc(blockingProc, &blockingBackendData);
curEdge->isBlockingXactWaiting = IsProcessWaitingForLock(blockingProc); curEdge->isBlockingXactWaiting =
IsProcessWaitingForLock(blockingProc) &&
!IsProcessWaitingForRelationExtension(blockingProc);
if (curEdge->isBlockingXactWaiting) if (curEdge->isBlockingXactWaiting)
{ {
AddProcToVisit(remaining, blockingProc); AddProcToVisit(remaining, blockingProc);