/* *Oneedgeinthewaits-forgraph. * *waiterandblockermayormaynotbemembersofalockgroup,butifeither *is,itwillbetheleaderratherthananyothermemberofthelockgroup. *Thegroupleadersactasrepresentativesofthewholegroupeventhough *thoseparticularprocessesneednotbewaitingatall.Therewillbeat *leastonememberofthewaiter'slockgrouponthewaitqueueforthegiven *lock,maybemore.
*/ typedefstruct
{
PGPROC *waiter; /* the leader of the waiting lock group */
PGPROC *blocker; /* the leader of the group it is waiting for */
LOCK *lock; /* the lock being waited for */ int pred; /* workspace for TopoSort */ int link; /* workspace for TopoSort */
} EDGE;
/* One potential reordering of a lock's wait queue */ typedefstruct
{
LOCK *lock; /* the lock whose wait queue is described */
PGPROC **procs; /* array of PGPROC *'s in new wait order */ int nProcs;
} WAIT_ORDER;
/* *Informationsavedabouteachedgeinadetecteddeadlockcycle.This *isusedtoprintadiagnosticmessageuponfailure. * *Note:becausewewanttoexaminethisinfoafterreleasingthelock *manager'spartitionlocks,wecan'tjuststoreLOCKandPGPROCpointers; *wemustextractoutalltheinfowewanttobeabletoprint.
*/ typedefstruct
{
LOCKTAG locktag; /* ID of awaited lock object */
LOCKMODE lockmode; /* type of lock we're waiting for */ int pid; /* PID of blocked backend */
} DEADLOCK_INFO;
staticbool DeadLockCheckRecurse(PGPROC *proc); staticint TestConfiguration(PGPROC *startProc); staticbool FindLockCycle(PGPROC *checkProc,
EDGE *softEdges, int *nSoftEdges); staticbool FindLockCycleRecurse(PGPROC *checkProc, int depth,
EDGE *softEdges, int *nSoftEdges); staticbool FindLockCycleRecurseMember(PGPROC *checkProc,
PGPROC *checkProcLeader, int depth, EDGE *softEdges, int *nSoftEdges); staticbool ExpandConstraints(EDGE *constraints, int nConstraints); staticbool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,
PGPROC **ordering);
/* Workspace for FindLockCycle */ static PGPROC **visitedProcs; /* Array of visited procs */ staticint nVisitedProcs;
/* Workspace for TopoSort */ static PGPROC **topoProcs; /* Array of not-yet-output procs */ staticint *beforeConstraints; /* Counts of remaining before-constraints */ staticint *afterConstraints; /* List head for after-constraints */
/* Output area for ExpandConstraints */ static WAIT_ORDER *waitOrders; /* Array of proposed queue rearrangements */ staticint nWaitOrders; static PGPROC **waitOrderProcs; /* Space for waitOrders queue contents */
/* Current list of constraints being considered */ static EDGE *curConstraints; staticint nCurConstraints; staticint maxCurConstraints;
/* Storage space for results from FindLockCycle */ static EDGE *possibleConstraints; staticint nPossibleConstraints; staticint maxPossibleConstraints; static DEADLOCK_INFO *deadlockDetails; staticint nDeadlockDetails;
/* PGPROC pointer of any blocking autovacuum worker found */ static PGPROC *blocking_autovacuum_proc = NULL;
/* Initialize to not blocked by an autovacuum worker */
blocking_autovacuum_proc = NULL;
/* Search for deadlocks and possible fixes */ if (DeadLockCheckRecurse(proc))
{ /* *CallFindLockCycleonemoretime,torecordthecorrect *deadlockDetails[]forthebasicstatewithnorearrangements.
*/ int nSoftEdges;
TRACE_POSTGRESQL_DEADLOCK_FOUND();
nWaitOrders = 0; if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
elog(FATAL, "deadlock seems to have disappeared");
return DS_HARD_DEADLOCK; /* cannot find a non-deadlocked state */
}
/* Apply any needed rearrangements of wait queues */ for (int i = 0; i < nWaitOrders; i++)
{
LOCK *lock = waitOrders[i].lock;
PGPROC **procs = waitOrders[i].procs; int nProcs = waitOrders[i].nProcs;
dclist_head *waitQueue = &lock->waitProcs;
/* Reset the queue and re-add procs in the desired order */
dclist_init(waitQueue); for (int j = 0; j < nProcs; j++)
dclist_push_tail(waitQueue, &procs[j]->links);
/* See if any waiters for the lock can be woken up now */
ProcLockWakeup(GetLocksMethodTable(lock), lock);
}
/* Return code tells caller if we had to escape a deadlock or not */ if (nWaitOrders > 0) return DS_SOFT_DEADLOCK; elseif (blocking_autovacuum_proc != NULL) return DS_BLOCKED_BY_AUTOVACUUM; else return DS_NO_DEADLOCK;
}
/* *DeadLockCheckRecurse--recursivelysearchforvalidorderings * *curConstraints[]holdsthecurrentsetofconstraintsbeingconsidered *byanouterlevelofrecursion.Addtothiseachpossiblesolution *constraintforanycycledetectedatthislevel. * *Returnstrueifnosolutionexists.Returnsfalseifadeadlock-free *stateisattainable,inwhichcasewaitOrders[]showstherequired *rearrangementsoflockwaitqueues(ifany).
*/ staticbool
DeadLockCheckRecurse(PGPROC *proc)
{ int nEdges; int oldPossibleConstraints; bool savedList; int i;
nEdges = TestConfiguration(proc); if (nEdges < 0) returntrue; /* hard deadlock --- no solution */ if (nEdges == 0) returnfalse; /* good configuration found */ if (nCurConstraints >= maxCurConstraints) returntrue; /* out of room for active constraints? */
oldPossibleConstraints = nPossibleConstraints; if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
{ /* We can save the edge list in possibleConstraints[] */
nPossibleConstraints += nEdges;
savedList = true;
} else
{ /* Not room; will need to regenerate the edges on-the-fly */
savedList = false;
}
/* *Tryeachavailablesoftedgeasanadditiontotheconfiguration.
*/ for (i = 0; i < nEdges; i++)
{ if (!savedList && i > 0)
{ /* Regenerate the list of possible added constraints */ if (nEdges != TestConfiguration(proc))
elog(FATAL, "inconsistent results during deadlock check");
}
curConstraints[nCurConstraints] =
possibleConstraints[oldPossibleConstraints + i];
nCurConstraints++; if (!DeadLockCheckRecurse(proc)) returnfalse; /* found a valid solution! */ /* give up on that added constraint, try again */
nCurConstraints--;
}
nPossibleConstraints = oldPossibleConstraints; returntrue; /* no solution found */
}
/* *Havewealreadyseenthisproc?
*/ for (i = 0; i < nVisitedProcs; i++)
{ if (visitedProcs[i] == checkProc)
{ /* If we return to starting point, we have a deadlock cycle */ if (i == 0)
{ /* *recordtotallengthofcycle---outerlevelswillnowfill *deadlockDetails[]
*/
Assert(depth <= MaxBackends);
nDeadlockDetails = depth;
returntrue;
}
/* *Otherwise,wehaveacyclebutitdoesnotincludethestart *point,sosay"nodeadlock".
*/ returnfalse;
}
} /* Mark proc as seen */
Assert(nVisitedProcs < MaxBackends);
visitedProcs[nVisitedProcs++] = checkProc;
/* A proc never blocks itself or any other lock group member */ if (leader != checkProcLeader)
{ for (lm = 1; lm <= numLockModes; lm++)
{ if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
(conflictMask & LOCKBIT_ON(lm)))
{ /* This proc hard-blocks checkProc */ if (FindLockCycleRecurse(proc, depth + 1,
softEdges, nSoftEdges))
{ /* fill deadlockDetails[] */
DEADLOCK_INFO *info = &deadlockDetails[depth];
/* Is there a conflict with this guy's request? */ if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0)
{ /* This proc soft-blocks checkProc */ if (FindLockCycleRecurse(proc, depth + 1,
softEdges, nSoftEdges))
{ /* fill deadlockDetails[] */
DEADLOCK_INFO *info = &deadlockDetails[depth];
/* Done when we reach the target proc */ if (proc == lastGroupMember) break;
/* Is there a conflict with this guy's request? */ if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0 &&
leader != checkProcLeader)
{ /* This proc soft-blocks checkProc */ if (FindLockCycleRecurse(proc, depth + 1,
softEdges, nSoftEdges))
{ /* fill deadlockDetails[] */
DEADLOCK_INFO *info = &deadlockDetails[depth];
/* *ExpandConstraints--expandalistofconstraintsintoasetof *specificneworderingsforaffectedwaitqueues * *Inputisalistofsoftedgestobereversed.Theoutputisalist *ofnWaitOrdersWAIT_ORDERstructsinwaitOrders[],withPGPROCarray *workspaceinwaitOrderProcs[]. * *Returnstrueifabletobuildanorderingthatsatisfiesallthe *constraints,falseifnot(therearecontradictoryconstraints).
*/ staticbool
ExpandConstraints(EDGE *constraints, int nConstraints)
{ int nWaitOrderProcs = 0; int i,
j;
nWaitOrders = 0;
/* *Scanconstraintlistbackwards.Thisisbecausethelast-added *constraintistheonlyonethatcouldfail,andsowewanttotestit *forinconsistencyfirst.
*/ for (i = nConstraints; --i >= 0;)
{
LOCK *lock = constraints[i].lock;
/* Did we already make a list for this lock? */ for (j = nWaitOrders; --j >= 0;)
{ if (waitOrders[j].lock == lock) break;
} if (j >= 0) continue; /* No, so allocate a new list */
waitOrders[nWaitOrders].lock = lock;
waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
waitOrders[nWaitOrders].nProcs = dclist_count(&lock->waitProcs);
nWaitOrderProcs += dclist_count(&lock->waitProcs);
Assert(nWaitOrderProcs <= MaxBackends);
/* *Dothetoposort.TopoSortneednotexamineconstraintsafterthis *one,sincetheymustbefordifferentlocks.
*/ if (!TopoSort(lock, constraints, i + 1,
waitOrders[nWaitOrders].procs)) returnfalse;
nWaitOrders++;
} returntrue;
}
/* First, fill topoProcs[] array with the procs in their current order */
i = 0;
dclist_foreach(proc_iter, waitQueue)
{
proc = dlist_container(PGPROC, links, proc_iter.cur);
topoProcs[i++] = proc;
}
Assert(i == queue_size);
if (blocker == proc || blocker->lockGroupLeader == proc)
{
Assert(blocker->waitLock == lock); if (kk == -1)
kk = k; else
{
Assert(beforeConstraints[k] <= 0);
beforeConstraints[k] = -1;
}
}
}
/* If no matching blocker, constraint is not relevant to this lock. */ if (kk < 0) continue;
Assert(beforeConstraints[jj] >= 0);
beforeConstraints[jj]++; /* waiter must come before */ /* add this constraint to list of after-constraints for blocker */
constraints[i].pred = jj;
constraints[i].link = afterConstraints[kk];
afterConstraints[kk] = i + 1;
}
/*-------------------- *NowscanthetopoProcsarraybackwards.Ateachstep,outputthe *lastprocthathasnoremainingbefore-constraintsplusanyother *membersofthesamelockgroup;thendecreasethebeforeConstraints *countofeachoftheprocsitwasconstrainedagainst. *i=indexofordering[]entrywewanttooutputthistime *j=searchindexfortopoProcs[] *k=tempforscanningconstraintlistforprocj *last=lastnon-nullindexintopoProcs(avoidredundantsearches) *--------------------
*/
last = queue_size - 1; for (i = queue_size - 1; i >= 0;)
{ int c; int nmatches = 0;
/* Find next candidate to output */ while (topoProcs[last] == NULL)
last--; for (j = last; j >= 0; j--)
{ if (topoProcs[j] != NULL && beforeConstraints[j] == 0) break;
}
/* If no available candidate, topological sort fails */ if (j < 0) returnfalse;
/* Update beforeConstraints counts of its predecessors */ for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
beforeConstraints[constraints[k - 1].pred]--;
}
/* Generate the "waits for" lines sent to the client */ for (i = 0; i < nDeadlockDetails; i++)
{
DEADLOCK_INFO *info = &deadlockDetails[i]; int nextpid;
/* The last proc waits for the first one... */ if (i < nDeadlockDetails - 1)
nextpid = info[1].pid; else
nextpid = deadlockDetails[0].pid;
/* reset locktagbuf to hold next object description */
resetStringInfo(&locktagbuf);
DescribeLockTag(&locktagbuf, &info->locktag);
if (i > 0)
appendStringInfoChar(&clientbuf, '\n');
appendStringInfo(&clientbuf,
_("Process %d waits for %s on %s; blocked by process %d."),
info->pid,
GetLockmodeName(info->locktag.locktag_lockmethodid,
info->lockmode),
locktagbuf.data,
nextpid);
}
/* Duplicate all the above for the server ... */
appendBinaryStringInfo(&logbuf, clientbuf.data, clientbuf.len);
/* ... and add info about query strings */ for (i = 0; i < nDeadlockDetails; i++)
{
DEADLOCK_INFO *info = &deadlockDetails[i];
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.36Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-27)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.