From c65c153a4634ce95a81063dffccbcbde01575532 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Wed, 15 Nov 2017 10:47:01 +0200 Subject: [PATCH 1/2] Skip speculative locks for distributed deadlock detection These locks are held for a very short duration time and cannot contribute to a deadlock. Speculative locks are used by Postgres for internal notification mechanism among transactions. --- src/backend/distributed/transaction/lock_graph.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/backend/distributed/transaction/lock_graph.c b/src/backend/distributed/transaction/lock_graph.c index cc05c72ba..fde08e8ff 100644 --- a/src/backend/distributed/transaction/lock_graph.c +++ b/src/backend/distributed/transaction/lock_graph.c @@ -494,7 +494,7 @@ BuildLocalWaitGraph(void) /* * IsProcessWaitingForSafeOperations returns true if the given PROC - * waiting on relation extension lock or page locks. + * waiting on relation extension locks, page locks or speculative locks. * * In general for the purpose of distributed deadlock detection, we should * skip if the process blocked on the locks that may not be part of deadlocks. @@ -519,7 +519,8 @@ IsProcessWaitingForSafeOperations(PGPROC *proc) waitLock = waitProcLock->tag.myLock; return waitLock->tag.locktag_type == LOCKTAG_RELATION_EXTEND || - waitLock->tag.locktag_type == LOCKTAG_PAGE; + waitLock->tag.locktag_type == LOCKTAG_PAGE || + waitLock->tag.locktag_type == LOCKTAG_SPECULATIVE_TOKEN; } @@ -596,8 +597,7 @@ AddEdgesForLockWaits(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai /* * Skip processes from the same lock group, processes that don't conflict, - * and processes that are waiting on a relation extension lock or page locks, - * which will be released shortly. + * and processes that are waiting on safe operations. */ if (!IsSameLockGroup(waitingProc, currentProc) && IsConflictingLockMask(procLock->holdMask, conflictMask) && @@ -641,8 +641,7 @@ AddEdgesForWaitQueue(WaitGraph *waitGraph, PGPROC *waitingProc, PROCStack *remai /* * Skip processes from the same lock group, processes that don't conflict, - * and processes that are waiting on a relation extension lock or page locks, - * which will be released shortly. + * and processes that are waiting on safe operations. */ if (!IsSameLockGroup(waitingProc, currentProc) && IsConflictingLockMask(awaitMask, conflictMask) && From 5bea95009b3fb6ca47a5bbc3e4fca3c89c696199 Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Wed, 15 Nov 2017 11:17:37 +0200 Subject: [PATCH 2/2] Skip autovacuum processes for distributed deadlock detection Autovacuum process cancels itself if any modification starts on the table in order to avoid blocking your regular Postgres sessions. That's normal and expected. Thus, any locks held by autovacuum process cannot involve in a distributed deadlock since it'll be released if needed. --- src/backend/distributed/transaction/lock_graph.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/backend/distributed/transaction/lock_graph.c b/src/backend/distributed/transaction/lock_graph.c index fde08e8ff..793fa3cca 100644 --- a/src/backend/distributed/transaction/lock_graph.c +++ b/src/backend/distributed/transaction/lock_graph.c @@ -496,6 +496,10 @@ BuildLocalWaitGraph(void) * IsProcessWaitingForSafeOperations returns true if the given PROC * waiting on relation extension locks, page locks or speculative locks. * + * The function also returns true if the waiting process is an autovacuum + * process given that autovacuum cannot contribute to any distributed + * deadlocks. + * * In general for the purpose of distributed deadlock detection, we should * skip if the process blocked on the locks that may not be part of deadlocks. * Those locks are held for a short duration while the relation or the index @@ -509,12 +513,20 @@ IsProcessWaitingForSafeOperations(PGPROC *proc) { PROCLOCK *waitProcLock = NULL; LOCK *waitLock = NULL; + PGXACT *pgxact = NULL; if (proc->waitStatus != STATUS_WAITING) { return false; } + /* get the transaction that the backend associated with */ + pgxact = &ProcGlobal->allPgXact[proc->pgprocno]; + if (pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) + { + return true; + } + waitProcLock = proc->waitProcLock; waitLock = waitProcLock->tag.myLock;