mirror of https://github.com/citusdata/citus.git
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
parent
4676c4f7a5
commit
68ca8cb7f0
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue