PostgreSQL Source Code  git master
deadlock.c File Reference
#include "postgres.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
Include dependency graph for deadlock.c:

Go to the source code of this file.

Data Structures

struct  EDGE
 
struct  WAIT_ORDER
 
struct  DEADLOCK_INFO
 

Functions

static bool DeadLockCheckRecurse (PGPROC *proc)
 
static int TestConfiguration (PGPROC *startProc)
 
static bool FindLockCycle (PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
 
static bool FindLockCycleRecurse (PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
 
static bool FindLockCycleRecurseMember (PGPROC *checkProc, PGPROC *checkProcLeader, int depth, EDGE *softEdges, int *nSoftEdges)
 
static bool ExpandConstraints (EDGE *constraints, int nConstraints)
 
static bool TopoSort (LOCK *lock, EDGE *constraints, int nConstraints, PGPROC **ordering)
 
void InitDeadLockChecking (void)
 
DeadLockState DeadLockCheck (PGPROC *proc)
 
PGPROCGetBlockingAutoVacuumPgproc (void)
 
void DeadLockReport (void)
 
void RememberSimpleDeadLock (PGPROC *proc1, LOCKMODE lockmode, LOCK *lock, PGPROC *proc2)
 

Variables

static PGPROC ** visitedProcs
 
static int nVisitedProcs
 
static PGPROC ** topoProcs
 
static int * beforeConstraints
 
static int * afterConstraints
 
static WAIT_ORDERwaitOrders
 
static int nWaitOrders
 
static PGPROC ** waitOrderProcs
 
static EDGEcurConstraints
 
static int nCurConstraints
 
static int maxCurConstraints
 
static EDGEpossibleConstraints
 
static int nPossibleConstraints
 
static int maxPossibleConstraints
 
static DEADLOCK_INFOdeadlockDetails
 
static int nDeadlockDetails
 
static PGPROCblocking_autovacuum_proc = NULL
 

Function Documentation

◆ DeadLockCheck()

DeadLockState DeadLockCheck ( PGPROC proc)

Definition at line 217 of file deadlock.c.

References Assert, DeadLockCheckRecurse(), DS_BLOCKED_BY_AUTOVACUUM, DS_HARD_DEADLOCK, DS_NO_DEADLOCK, DS_SOFT_DEADLOCK, elog, FATAL, FindLockCycle(), GetLocksMethodTable(), i, PROC_QUEUE::links, PGPROC::links, WAIT_ORDER::lock, nCurConstraints, nPossibleConstraints, WAIT_ORDER::nProcs, nWaitOrders, ProcLockWakeup(), ProcQueueInit(), WAIT_ORDER::procs, SHMQueueInsertBefore(), PROC_QUEUE::size, and LOCK::waitProcs.

Referenced by CheckDeadLock().

218 {
219  int i,
220  j;
221 
222  /* Initialize to "no constraints" */
223  nCurConstraints = 0;
225  nWaitOrders = 0;
226 
227  /* Initialize to not blocked by an autovacuum worker */
229 
230  /* Search for deadlocks and possible fixes */
231  if (DeadLockCheckRecurse(proc))
232  {
233  /*
234  * Call FindLockCycle one more time, to record the correct
235  * deadlockDetails[] for the basic state with no rearrangements.
236  */
237  int nSoftEdges;
238 
239  TRACE_POSTGRESQL_DEADLOCK_FOUND();
240 
241  nWaitOrders = 0;
242  if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
243  elog(FATAL, "deadlock seems to have disappeared");
244 
245  return DS_HARD_DEADLOCK; /* cannot find a non-deadlocked state */
246  }
247 
248  /* Apply any needed rearrangements of wait queues */
249  for (i = 0; i < nWaitOrders; i++)
250  {
251  LOCK *lock = waitOrders[i].lock;
252  PGPROC **procs = waitOrders[i].procs;
253  int nProcs = waitOrders[i].nProcs;
254  PROC_QUEUE *waitQueue = &(lock->waitProcs);
255 
256  Assert(nProcs == waitQueue->size);
257 
258 #ifdef DEBUG_DEADLOCK
259  PrintLockQueue(lock, "DeadLockCheck:");
260 #endif
261 
262  /* Reset the queue and re-add procs in the desired order */
263  ProcQueueInit(waitQueue);
264  for (j = 0; j < nProcs; j++)
265  {
266  SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));
267  waitQueue->size++;
268  }
269 
270 #ifdef DEBUG_DEADLOCK
271  PrintLockQueue(lock, "rearranged to:");
272 #endif
273 
274  /* See if any waiters for the lock can be woken up now */
275  ProcLockWakeup(GetLocksMethodTable(lock), lock);
276  }
277 
278  /* Return code tells caller if we had to escape a deadlock or not */
279  if (nWaitOrders > 0)
280  return DS_SOFT_DEADLOCK;
281  else if (blocking_autovacuum_proc != NULL)
283  else
284  return DS_NO_DEADLOCK;
285 }
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
SHM_QUEUE links
Definition: lock.h:31
SHM_QUEUE links
Definition: proc.h:104
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
void SHMQueueInsertBefore(SHM_QUEUE *queue, SHM_QUEUE *elem)
Definition: shmqueue.c:89
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
int nProcs
Definition: deadlock.c:60
PROC_QUEUE waitProcs
Definition: lock.h:296
LOCK * lock
Definition: deadlock.c:58
static bool FindLockCycle(PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:449
PGPROC ** procs
Definition: deadlock.c:59
#define FATAL
Definition: elog.h:52
void ProcQueueInit(PROC_QUEUE *queue)
Definition: proc.c:1038
Definition: lock.h:287
void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock)
Definition: proc.c:1632
#define Assert(condition)
Definition: c.h:745
static EDGE * possibleConstraints
Definition: deadlock.c:121
static bool DeadLockCheckRecurse(PGPROC *proc)
Definition: deadlock.c:315
#define elog(elevel,...)
Definition: elog.h:214
int i
int size
Definition: lock.h:32
static int nWaitOrders
Definition: deadlock.c:112
Definition: proc.h:101
LockMethod GetLocksMethodTable(const LOCK *lock)
Definition: lock.c:487

◆ DeadLockCheckRecurse()

static bool DeadLockCheckRecurse ( PGPROC proc)
static

Definition at line 315 of file deadlock.c.

References elog, FATAL, i, MaxBackends, maxCurConstraints, maxPossibleConstraints, nCurConstraints, nPossibleConstraints, and TestConfiguration().

Referenced by DeadLockCheck().

316 {
317  int nEdges;
318  int oldPossibleConstraints;
319  bool savedList;
320  int i;
321 
322  nEdges = TestConfiguration(proc);
323  if (nEdges < 0)
324  return true; /* hard deadlock --- no solution */
325  if (nEdges == 0)
326  return false; /* good configuration found */
328  return true; /* out of room for active constraints? */
329  oldPossibleConstraints = nPossibleConstraints;
331  {
332  /* We can save the edge list in possibleConstraints[] */
333  nPossibleConstraints += nEdges;
334  savedList = true;
335  }
336  else
337  {
338  /* Not room; will need to regenerate the edges on-the-fly */
339  savedList = false;
340  }
341 
342  /*
343  * Try each available soft edge as an addition to the configuration.
344  */
345  for (i = 0; i < nEdges; i++)
346  {
347  if (!savedList && i > 0)
348  {
349  /* Regenerate the list of possible added constraints */
350  if (nEdges != TestConfiguration(proc))
351  elog(FATAL, "inconsistent results during deadlock check");
352  }
354  possibleConstraints[oldPossibleConstraints + i];
355  nCurConstraints++;
356  if (!DeadLockCheckRecurse(proc))
357  return false; /* found a valid solution! */
358  /* give up on that added constraint, try again */
359  nCurConstraints--;
360  }
361  nPossibleConstraints = oldPossibleConstraints;
362  return true; /* no solution found */
363 }
static int maxCurConstraints
Definition: deadlock.c:118
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
#define FATAL
Definition: elog.h:52
int MaxBackends
Definition: globals.c:136
static int TestConfiguration(PGPROC *startProc)
Definition: deadlock.c:381
static EDGE * curConstraints
Definition: deadlock.c:116
static EDGE * possibleConstraints
Definition: deadlock.c:121
static bool DeadLockCheckRecurse(PGPROC *proc)
Definition: deadlock.c:315
#define elog(elevel,...)
Definition: elog.h:214
int i
static int maxPossibleConstraints
Definition: deadlock.c:123

◆ DeadLockReport()

void DeadLockReport ( void  )

Definition at line 1092 of file deadlock.c.

References _, appendBinaryStringInfo(), appendStringInfo(), appendStringInfoChar(), StringInfoData::data, DescribeLockTag(), ereport, errcode(), errdetail_internal(), errdetail_log(), errhint(), errmsg(), ERROR, GetLockmodeName(), i, initStringInfo(), StringInfoData::len, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, LOCKTAG::locktag_lockmethodid, nDeadlockDetails, pgstat_get_backend_current_activity(), pgstat_report_deadlock(), DEADLOCK_INFO::pid, and resetStringInfo().

Referenced by WaitOnLock().

1093 {
1094  StringInfoData clientbuf; /* errdetail for client */
1095  StringInfoData logbuf; /* errdetail for server log */
1096  StringInfoData locktagbuf;
1097  int i;
1098 
1099  initStringInfo(&clientbuf);
1100  initStringInfo(&logbuf);
1101  initStringInfo(&locktagbuf);
1102 
1103  /* Generate the "waits for" lines sent to the client */
1104  for (i = 0; i < nDeadlockDetails; i++)
1105  {
1106  DEADLOCK_INFO *info = &deadlockDetails[i];
1107  int nextpid;
1108 
1109  /* The last proc waits for the first one... */
1110  if (i < nDeadlockDetails - 1)
1111  nextpid = info[1].pid;
1112  else
1113  nextpid = deadlockDetails[0].pid;
1114 
1115  /* reset locktagbuf to hold next object description */
1116  resetStringInfo(&locktagbuf);
1117 
1118  DescribeLockTag(&locktagbuf, &info->locktag);
1119 
1120  if (i > 0)
1121  appendStringInfoChar(&clientbuf, '\n');
1122 
1123  appendStringInfo(&clientbuf,
1124  _("Process %d waits for %s on %s; blocked by process %d."),
1125  info->pid,
1127  info->lockmode),
1128  locktagbuf.data,
1129  nextpid);
1130  }
1131 
1132  /* Duplicate all the above for the server ... */
1133  appendBinaryStringInfo(&logbuf, clientbuf.data, clientbuf.len);
1134 
1135  /* ... and add info about query strings */
1136  for (i = 0; i < nDeadlockDetails; i++)
1137  {
1138  DEADLOCK_INFO *info = &deadlockDetails[i];
1139 
1140  appendStringInfoChar(&logbuf, '\n');
1141 
1142  appendStringInfo(&logbuf,
1143  _("Process %d: %s"),
1144  info->pid,
1146  }
1147 
1149 
1150  ereport(ERROR,
1151  (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
1152  errmsg("deadlock detected"),
1153  errdetail_internal("%s", clientbuf.data),
1154  errdetail_log("%s", logbuf.data),
1155  errhint("See server log for query details.")));
1156 }
void pgstat_report_deadlock(void)
Definition: pgstat.c:1564
int errhint(const char *fmt,...)
Definition: elog.c:1071
const char * GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
Definition: lock.c:4016
LOCKMODE lockmode
Definition: deadlock.c:74
int errcode(int sqlerrcode)
Definition: elog.c:610
int errdetail_internal(const char *fmt,...)
Definition: elog.c:984
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define ERROR
Definition: elog.h:43
void DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
Definition: lmgr.c:1085
static int nDeadlockDetails
Definition: deadlock.c:125
void resetStringInfo(StringInfo str)
Definition: stringinfo.c:75
int errdetail_log(const char *fmt,...)
Definition: elog.c:1005
const char * pgstat_get_backend_current_activity(int pid, bool checkUser)
Definition: pgstat.c:4169
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
#define ereport(elevel,...)
Definition: elog.h:144
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
uint8 locktag_lockmethodid
Definition: lock.h:170
int errmsg(const char *fmt,...)
Definition: elog.c:824
int i
LOCKTAG locktag
Definition: deadlock.c:73
#define _(x)
Definition: elog.c:88
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227

◆ ExpandConstraints()

static bool ExpandConstraints ( EDGE constraints,
int  nConstraints 
)
static

Definition at line 808 of file deadlock.c.

References Assert, i, EDGE::lock, WAIT_ORDER::lock, MaxBackends, WAIT_ORDER::nProcs, nWaitOrders, WAIT_ORDER::procs, PROC_QUEUE::size, TopoSort(), and LOCK::waitProcs.

Referenced by TestConfiguration().

810 {
811  int nWaitOrderProcs = 0;
812  int i,
813  j;
814 
815  nWaitOrders = 0;
816 
817  /*
818  * Scan constraint list backwards. This is because the last-added
819  * constraint is the only one that could fail, and so we want to test it
820  * for inconsistency first.
821  */
822  for (i = nConstraints; --i >= 0;)
823  {
824  LOCK *lock = constraints[i].lock;
825 
826  /* Did we already make a list for this lock? */
827  for (j = nWaitOrders; --j >= 0;)
828  {
829  if (waitOrders[j].lock == lock)
830  break;
831  }
832  if (j >= 0)
833  continue;
834  /* No, so allocate a new list */
835  waitOrders[nWaitOrders].lock = lock;
836  waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
838  nWaitOrderProcs += lock->waitProcs.size;
839  Assert(nWaitOrderProcs <= MaxBackends);
840 
841  /*
842  * Do the topo sort. TopoSort need not examine constraints after this
843  * one, since they must be for different locks.
844  */
845  if (!TopoSort(lock, constraints, i + 1,
846  waitOrders[nWaitOrders].procs))
847  return false;
848  nWaitOrders++;
849  }
850  return true;
851 }
LOCK * lock
Definition: deadlock.c:50
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
int nProcs
Definition: deadlock.c:60
static PGPROC ** waitOrderProcs
Definition: deadlock.c:113
PROC_QUEUE waitProcs
Definition: lock.h:296
LOCK * lock
Definition: deadlock.c:58
PGPROC ** procs
Definition: deadlock.c:59
int MaxBackends
Definition: globals.c:136
Definition: lock.h:287
static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints, PGPROC **ordering)
Definition: deadlock.c:880
#define Assert(condition)
Definition: c.h:745
int i
int size
Definition: lock.h:32
static int nWaitOrders
Definition: deadlock.c:112

◆ FindLockCycle()

static bool FindLockCycle ( PGPROC checkProc,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 449 of file deadlock.c.

References FindLockCycleRecurse(), nDeadlockDetails, and nVisitedProcs.

Referenced by DeadLockCheck(), and TestConfiguration().

452 {
453  nVisitedProcs = 0;
454  nDeadlockDetails = 0;
455  *nSoftEdges = 0;
456  return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);
457 }
static int nDeadlockDetails
Definition: deadlock.c:125
static bool FindLockCycleRecurse(PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:460
static int nVisitedProcs
Definition: deadlock.c:103

◆ FindLockCycleRecurse()

static bool FindLockCycleRecurse ( PGPROC checkProc,
int  depth,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 460 of file deadlock.c.

References Assert, dlist_iter::cur, dlist_container, dlist_foreach, FindLockCycleRecurseMember(), i, PGPROC::links, PGPROC::lockGroupLeader, PGPROC::lockGroupMembers, MaxBackends, nDeadlockDetails, SHM_QUEUE::next, nVisitedProcs, and PGPROC::waitLock.

Referenced by FindLockCycle(), and FindLockCycleRecurseMember().

464 {
465  int i;
466  dlist_iter iter;
467 
468  /*
469  * If this process is a lock group member, check the leader instead. (Note
470  * that we might be the leader, in which case this is a no-op.)
471  */
472  if (checkProc->lockGroupLeader != NULL)
473  checkProc = checkProc->lockGroupLeader;
474 
475  /*
476  * Have we already seen this proc?
477  */
478  for (i = 0; i < nVisitedProcs; i++)
479  {
480  if (visitedProcs[i] == checkProc)
481  {
482  /* If we return to starting point, we have a deadlock cycle */
483  if (i == 0)
484  {
485  /*
486  * record total length of cycle --- outer levels will now fill
487  * deadlockDetails[]
488  */
489  Assert(depth <= MaxBackends);
490  nDeadlockDetails = depth;
491 
492  return true;
493  }
494 
495  /*
496  * Otherwise, we have a cycle but it does not include the start
497  * point, so say "no deadlock".
498  */
499  return false;
500  }
501  }
502  /* Mark proc as seen */
503  Assert(nVisitedProcs < MaxBackends);
504  visitedProcs[nVisitedProcs++] = checkProc;
505 
506  /*
507  * If the process is waiting, there is an outgoing waits-for edge to each
508  * process that blocks it.
509  */
510  if (checkProc->links.next != NULL && checkProc->waitLock != NULL &&
511  FindLockCycleRecurseMember(checkProc, checkProc, depth, softEdges,
512  nSoftEdges))
513  return true;
514 
515  /*
516  * If the process is not waiting, there could still be outgoing waits-for
517  * edges if it is part of a lock group, because other members of the lock
518  * group might be waiting even though this process is not. (Given lock
519  * groups {A1, A2} and {B1, B2}, if A1 waits for B1 and B2 waits for A2,
520  * that is a deadlock even neither of B1 and A2 are waiting for anything.)
521  */
522  dlist_foreach(iter, &checkProc->lockGroupMembers)
523  {
524  PGPROC *memberProc;
525 
526  memberProc = dlist_container(PGPROC, lockGroupLink, iter.cur);
527 
528  if (memberProc->links.next != NULL && memberProc->waitLock != NULL &&
529  memberProc != checkProc &&
530  FindLockCycleRecurseMember(memberProc, checkProc, depth, softEdges,
531  nSoftEdges))
532  return true;
533  }
534 
535  return false;
536 }
dlist_head lockGroupMembers
Definition: proc.h:210
SHM_QUEUE links
Definition: proc.h:104
#define dlist_foreach(iter, lhead)
Definition: ilist.h:507
struct SHM_QUEUE * next
Definition: shmem.h:31
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
int MaxBackends
Definition: globals.c:136
static int nDeadlockDetails
Definition: deadlock.c:125
LOCK * waitLock
Definition: proc.h:145
static bool FindLockCycleRecurseMember(PGPROC *checkProc, PGPROC *checkProcLeader, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:539
dlist_node * cur
Definition: ilist.h:161
#define Assert(condition)
Definition: c.h:745
static PGPROC ** visitedProcs
Definition: deadlock.c:102
int i
static int nVisitedProcs
Definition: deadlock.c:103
Definition: proc.h:101
PGPROC * lockGroupLeader
Definition: proc.h:209

◆ FindLockCycleRecurseMember()

static bool FindLockCycleRecurseMember ( PGPROC checkProc,
PGPROC checkProcLeader,
int  depth,
EDGE softEdges,
int *  nSoftEdges 
)
static

Definition at line 539 of file deadlock.c.

References PROC_HDR::allPgXact, Assert, EDGE::blocker, LockMethodData::conflictTab, FindLockCycleRecurse(), GetLocksMethodTable(), PROCLOCK::holdMask, i, PROC_QUEUE::links, PGPROC::links, EDGE::lock, LOCK_LOCKTAG, LOCKBIT_ON, PGPROC::lockGroupLeader, PROCLOCK::lockLink, DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, LOCKTAG_PAGE, LOCKTAG_RELATION_EXTEND, MaxBackends, MyProc, PROCLOCKTAG::myProc, SHM_QUEUE::next, WAIT_ORDER::nProcs, LockMethodData::numLockModes, nWaitOrders, offsetof, PGPROC::pgprocno, DEADLOCK_INFO::pid, PGPROC::pid, PROC_IS_AUTOVACUUM, ProcGlobal, LOCK::procLocks, WAIT_ORDER::procs, SHMQueueNext(), PROC_QUEUE::size, LOCK::tag, PROCLOCK::tag, PGXACT::vacuumFlags, EDGE::waiter, PGPROC::waitLock, PGPROC::waitLockMode, and LOCK::waitProcs.

Referenced by FindLockCycleRecurse().

544 {
545  PGPROC *proc;
546  LOCK *lock = checkProc->waitLock;
547  PGXACT *pgxact;
548  PROCLOCK *proclock;
549  SHM_QUEUE *procLocks;
550  LockMethod lockMethodTable;
551  PROC_QUEUE *waitQueue;
552  int queue_size;
553  int conflictMask;
554  int i;
555  int numLockModes,
556  lm;
557 
558  /*
559  * The relation extension or page lock can never participate in actual
560  * deadlock cycle. See Asserts in LockAcquireExtended. So, there is no
561  * advantage in checking wait edges from them.
562  */
563  if (LOCK_LOCKTAG(*lock) == LOCKTAG_RELATION_EXTEND ||
564  (LOCK_LOCKTAG(*lock) == LOCKTAG_PAGE))
565  return false;
566 
567  lockMethodTable = GetLocksMethodTable(lock);
568  numLockModes = lockMethodTable->numLockModes;
569  conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
570 
571  /*
572  * Scan for procs that already hold conflicting locks. These are "hard"
573  * edges in the waits-for graph.
574  */
575  procLocks = &(lock->procLocks);
576 
577  proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
578  offsetof(PROCLOCK, lockLink));
579 
580  while (proclock)
581  {
582  PGPROC *leader;
583 
584  proc = proclock->tag.myProc;
585  pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
586  leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
587 
588  /* A proc never blocks itself or any other lock group member */
589  if (leader != checkProcLeader)
590  {
591  for (lm = 1; lm <= numLockModes; lm++)
592  {
593  if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
594  (conflictMask & LOCKBIT_ON(lm)))
595  {
596  /* This proc hard-blocks checkProc */
597  if (FindLockCycleRecurse(proc, depth + 1,
598  softEdges, nSoftEdges))
599  {
600  /* fill deadlockDetails[] */
601  DEADLOCK_INFO *info = &deadlockDetails[depth];
602 
603  info->locktag = lock->tag;
604  info->lockmode = checkProc->waitLockMode;
605  info->pid = checkProc->pid;
606 
607  return true;
608  }
609 
610  /*
611  * No deadlock here, but see if this proc is an autovacuum
612  * that is directly hard-blocking our own proc. If so,
613  * report it so that the caller can send a cancel signal
614  * to it, if appropriate. If there's more than one such
615  * proc, it's indeterminate which one will be reported.
616  *
617  * We don't touch autovacuums that are indirectly blocking
618  * us; it's up to the direct blockee to take action. This
619  * rule simplifies understanding the behavior and ensures
620  * that an autovacuum won't be canceled with less than
621  * deadlock_timeout grace period.
622  *
623  * Note we read vacuumFlags without any locking. This is
624  * OK only for checking the PROC_IS_AUTOVACUUM flag,
625  * because that flag is set at process start and never
626  * reset. There is logic elsewhere to avoid canceling an
627  * autovacuum that is working to prevent XID wraparound
628  * problems (which needs to read a different vacuumFlag
629  * bit), but we don't do that here to avoid grabbing
630  * ProcArrayLock.
631  */
632  if (checkProc == MyProc &&
635 
636  /* We're done looking at this proclock */
637  break;
638  }
639  }
640  }
641 
642  proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
643  offsetof(PROCLOCK, lockLink));
644  }
645 
646  /*
647  * Scan for procs that are ahead of this one in the lock's wait queue.
648  * Those that have conflicting requests soft-block this one. This must be
649  * done after the hard-block search, since if another proc both hard- and
650  * soft-blocks this one, we want to call it a hard edge.
651  *
652  * If there is a proposed re-ordering of the lock's wait order, use that
653  * rather than the current wait order.
654  */
655  for (i = 0; i < nWaitOrders; i++)
656  {
657  if (waitOrders[i].lock == lock)
658  break;
659  }
660 
661  if (i < nWaitOrders)
662  {
663  /* Use the given hypothetical wait queue order */
664  PGPROC **procs = waitOrders[i].procs;
665 
666  queue_size = waitOrders[i].nProcs;
667 
668  for (i = 0; i < queue_size; i++)
669  {
670  PGPROC *leader;
671 
672  proc = procs[i];
673  leader = proc->lockGroupLeader == NULL ? proc :
674  proc->lockGroupLeader;
675 
676  /*
677  * TopoSort will always return an ordering with group members
678  * adjacent to each other in the wait queue (see comments
679  * therein). So, as soon as we reach a process in the same lock
680  * group as checkProc, we know we've found all the conflicts that
681  * precede any member of the lock group lead by checkProcLeader.
682  */
683  if (leader == checkProcLeader)
684  break;
685 
686  /* Is there a conflict with this guy's request? */
687  if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0)
688  {
689  /* This proc soft-blocks checkProc */
690  if (FindLockCycleRecurse(proc, depth + 1,
691  softEdges, nSoftEdges))
692  {
693  /* fill deadlockDetails[] */
694  DEADLOCK_INFO *info = &deadlockDetails[depth];
695 
696  info->locktag = lock->tag;
697  info->lockmode = checkProc->waitLockMode;
698  info->pid = checkProc->pid;
699 
700  /*
701  * Add this edge to the list of soft edges in the cycle
702  */
703  Assert(*nSoftEdges < MaxBackends);
704  softEdges[*nSoftEdges].waiter = checkProcLeader;
705  softEdges[*nSoftEdges].blocker = leader;
706  softEdges[*nSoftEdges].lock = lock;
707  (*nSoftEdges)++;
708  return true;
709  }
710  }
711  }
712  }
713  else
714  {
715  PGPROC *lastGroupMember = NULL;
716 
717  /* Use the true lock wait queue order */
718  waitQueue = &(lock->waitProcs);
719 
720  /*
721  * Find the last member of the lock group that is present in the wait
722  * queue. Anything after this is not a soft lock conflict. If group
723  * locking is not in use, then we know immediately which process we're
724  * looking for, but otherwise we've got to search the wait queue to
725  * find the last process actually present.
726  */
727  if (checkProc->lockGroupLeader == NULL)
728  lastGroupMember = checkProc;
729  else
730  {
731  proc = (PGPROC *) waitQueue->links.next;
732  queue_size = waitQueue->size;
733  while (queue_size-- > 0)
734  {
735  if (proc->lockGroupLeader == checkProcLeader)
736  lastGroupMember = proc;
737  proc = (PGPROC *) proc->links.next;
738  }
739  Assert(lastGroupMember != NULL);
740  }
741 
742  /*
743  * OK, now rescan (or scan) the queue to identify the soft conflicts.
744  */
745  queue_size = waitQueue->size;
746  proc = (PGPROC *) waitQueue->links.next;
747  while (queue_size-- > 0)
748  {
749  PGPROC *leader;
750 
751  leader = proc->lockGroupLeader == NULL ? proc :
752  proc->lockGroupLeader;
753 
754  /* Done when we reach the target proc */
755  if (proc == lastGroupMember)
756  break;
757 
758  /* Is there a conflict with this guy's request? */
759  if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0 &&
760  leader != checkProcLeader)
761  {
762  /* This proc soft-blocks checkProc */
763  if (FindLockCycleRecurse(proc, depth + 1,
764  softEdges, nSoftEdges))
765  {
766  /* fill deadlockDetails[] */
767  DEADLOCK_INFO *info = &deadlockDetails[depth];
768 
769  info->locktag = lock->tag;
770  info->lockmode = checkProc->waitLockMode;
771  info->pid = checkProc->pid;
772 
773  /*
774  * Add this edge to the list of soft edges in the cycle
775  */
776  Assert(*nSoftEdges < MaxBackends);
777  softEdges[*nSoftEdges].waiter = checkProcLeader;
778  softEdges[*nSoftEdges].blocker = leader;
779  softEdges[*nSoftEdges].lock = lock;
780  (*nSoftEdges)++;
781  return true;
782  }
783  }
784 
785  proc = (PGPROC *) proc->links.next;
786  }
787  }
788 
789  /*
790  * No conflict detected here.
791  */
792  return false;
793 }
PROCLOCKTAG tag
Definition: lock.h:351
LOCK * lock
Definition: deadlock.c:50
LOCKMODE lockmode
Definition: deadlock.c:74
Definition: proc.h:228
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
SHM_QUEUE links
Definition: lock.h:31
PGXACT * allPgXact
Definition: proc.h:253
PGPROC * MyProc
Definition: proc.c:67
LOCKMASK holdMask
Definition: lock.h:355
SHM_QUEUE links
Definition: proc.h:104
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
struct SHM_QUEUE * next
Definition: shmem.h:31
PGPROC * waiter
Definition: deadlock.c:48
LOCKMODE waitLockMode
Definition: proc.h:147
LOCKTAG tag
Definition: lock.h:290
const LOCKMASK * conflictTab
Definition: lock.h:113
SHM_QUEUE lockLink
Definition: lock.h:357
PROC_HDR * ProcGlobal
Definition: proc.c:80
int nProcs
Definition: deadlock.c:60
PROC_QUEUE waitProcs
Definition: lock.h:296
uint8 vacuumFlags
Definition: proc.h:239
PGPROC * blocker
Definition: deadlock.c:49
#define LOCK_LOCKTAG(lock)
Definition: lock.h:304
PGPROC ** procs
Definition: deadlock.c:59
int MaxBackends
Definition: globals.c:136
Definition: lock.h:287
LOCK * waitLock
Definition: proc.h:145
SHM_QUEUE procLocks
Definition: lock.h:295
Pointer SHMQueueNext(const SHM_QUEUE *queue, const SHM_QUEUE *curElem, Size linkOffset)
Definition: shmqueue.c:145
#define Assert(condition)
Definition: c.h:745
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
static bool FindLockCycleRecurse(PGPROC *checkProc, int depth, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:460
PGPROC * myProc
Definition: lock.h:345
#define LOCKBIT_ON(lockmode)
Definition: lock.h:86
Definition: lock.h:348
int pgprocno
Definition: proc.h:116
int i
int size
Definition: lock.h:32
static int nWaitOrders
Definition: deadlock.c:112
LOCKTAG locktag
Definition: deadlock.c:73
Definition: proc.h:101
int pid
Definition: proc.h:115
LockMethod GetLocksMethodTable(const LOCK *lock)
Definition: lock.c:487
PGPROC * lockGroupLeader
Definition: proc.h:209
#define PROC_IS_AUTOVACUUM
Definition: proc.h:53
#define offsetof(type, field)
Definition: c.h:668
int numLockModes
Definition: lock.h:112

◆ GetBlockingAutoVacuumPgproc()

PGPROC* GetBlockingAutoVacuumPgproc ( void  )

Definition at line 293 of file deadlock.c.

References blocking_autovacuum_proc.

Referenced by ProcSleep().

294 {
295  PGPROC *ptr;
296 
299 
300  return ptr;
301 }
static PGPROC * blocking_autovacuum_proc
Definition: deadlock.c:128
Definition: proc.h:101

◆ InitDeadLockChecking()

void InitDeadLockChecking ( void  )

Definition at line 143 of file deadlock.c.

References afterConstraints, beforeConstraints, MaxBackends, maxCurConstraints, maxPossibleConstraints, MemoryContextSwitchTo(), palloc(), TopMemoryContext, and visitedProcs.

Referenced by InitProcess().

144 {
145  MemoryContext oldcxt;
146 
147  /* Make sure allocations are permanent */
149 
150  /*
151  * FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
152  * deadlockDetails[].
153  */
154  visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
156 
157  /*
158  * TopoSort needs to consider at most MaxBackends wait-queue entries, and
159  * it needn't run concurrently with FindLockCycle.
160  */
161  topoProcs = visitedProcs; /* re-use this space */
162  beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
163  afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
164 
165  /*
166  * We need to consider rearranging at most MaxBackends/2 wait queues
167  * (since it takes at least two waiters in a queue to create a soft edge),
168  * and the expanded form of the wait queues can't involve more than
169  * MaxBackends total waiters.
170  */
171  waitOrders = (WAIT_ORDER *)
172  palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
173  waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
174 
175  /*
176  * Allow at most MaxBackends distinct constraints in a configuration. (Is
177  * this enough? In practice it seems it should be, but I don't quite see
178  * how to prove it. If we run out, we might fail to find a workable wait
179  * queue rearrangement even though one exists.) NOTE that this number
180  * limits the maximum recursion depth of DeadLockCheckRecurse. Making it
181  * really big might potentially allow a stack-overflow problem.
182  */
185 
186  /*
187  * Allow up to 3*MaxBackends constraints to be saved without having to
188  * re-run TestConfiguration. (This is probably more than enough, but we
189  * can survive if we run low on space by doing excess runs of
190  * TestConfiguration to re-compute constraint lists each time needed.) The
191  * last MaxBackends entries in possibleConstraints[] are reserved as
192  * output workspace for FindLockCycle.
193  */
196  (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
197 
198  MemoryContextSwitchTo(oldcxt);
199 }
static int maxCurConstraints
Definition: deadlock.c:118
static WAIT_ORDER * waitOrders
Definition: deadlock.c:111
Definition: deadlock.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static PGPROC ** waitOrderProcs
Definition: deadlock.c:113
static PGPROC ** topoProcs
Definition: deadlock.c:106
int MaxBackends
Definition: globals.c:136
static EDGE * curConstraints
Definition: deadlock.c:116
MemoryContext TopMemoryContext
Definition: mcxt.c:44
static int * afterConstraints
Definition: deadlock.c:108
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
static PGPROC ** visitedProcs
Definition: deadlock.c:102
static EDGE * possibleConstraints
Definition: deadlock.c:121
void * palloc(Size size)
Definition: mcxt.c:949
static int maxPossibleConstraints
Definition: deadlock.c:123
static int * beforeConstraints
Definition: deadlock.c:107
Definition: proc.h:101

◆ RememberSimpleDeadLock()

void RememberSimpleDeadLock ( PGPROC proc1,
LOCKMODE  lockmode,
LOCK lock,
PGPROC proc2 
)

Definition at line 1164 of file deadlock.c.

References DEADLOCK_INFO::lockmode, DEADLOCK_INFO::locktag, nDeadlockDetails, DEADLOCK_INFO::pid, PGPROC::pid, LOCK::tag, PGPROC::waitLock, and PGPROC::waitLockMode.

Referenced by ProcSleep().

1168 {
1169  DEADLOCK_INFO *info = &deadlockDetails[0];
1170 
1171  info->locktag = lock->tag;
1172  info->lockmode = lockmode;
1173  info->pid = proc1->pid;
1174  info++;
1175  info->locktag = proc2->waitLock->tag;
1176  info->lockmode = proc2->waitLockMode;
1177  info->pid = proc2->pid;
1178  nDeadlockDetails = 2;
1179 }
LOCKMODE lockmode
Definition: deadlock.c:74
LOCKMODE waitLockMode
Definition: proc.h:147
LOCKTAG tag
Definition: lock.h:290
static int nDeadlockDetails
Definition: deadlock.c:125
LOCK * waitLock
Definition: proc.h:145
static DEADLOCK_INFO * deadlockDetails
Definition: deadlock.c:124
LOCKTAG locktag
Definition: deadlock.c:73
int pid
Definition: proc.h:115

◆ TestConfiguration()

static int TestConfiguration ( PGPROC startProc)
static

Definition at line 381 of file deadlock.c.

References ExpandConstraints(), FindLockCycle(), i, MaxBackends, maxPossibleConstraints, nCurConstraints, and nPossibleConstraints.

Referenced by DeadLockCheckRecurse().

382 {
383  int softFound = 0;
385  int nSoftEdges;
386  int i;
387 
388  /*
389  * Make sure we have room for FindLockCycle's output.
390  */
391  if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
392  return -1;
393 
394  /*
395  * Expand current constraint set into wait orderings. Fail if the
396  * constraint set is not self-consistent.
397  */
399  return -1;
400 
401  /*
402  * Check for cycles involving startProc or any of the procs mentioned in
403  * constraints. We check startProc last because if it has a soft cycle
404  * still to be dealt with, we want to deal with that first.
405  */
406  for (i = 0; i < nCurConstraints; i++)
407  {
408  if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))
409  {
410  if (nSoftEdges == 0)
411  return -1; /* hard deadlock detected */
412  softFound = nSoftEdges;
413  }
414  if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))
415  {
416  if (nSoftEdges == 0)
417  return -1; /* hard deadlock detected */
418  softFound = nSoftEdges;
419  }
420  }
421  if (FindLockCycle(startProc, softEdges, &nSoftEdges))
422  {
423  if (nSoftEdges == 0)
424  return -1; /* hard deadlock detected */
425  softFound = nSoftEdges;
426  }
427  return softFound;
428 }
Definition: deadlock.c:46
static int nCurConstraints
Definition: deadlock.c:117
static int nPossibleConstraints
Definition: deadlock.c:122
static bool ExpandConstraints(EDGE *constraints, int nConstraints)
Definition: deadlock.c:808
static bool FindLockCycle(PGPROC *checkProc, EDGE *softEdges, int *nSoftEdges)
Definition: deadlock.c:449
int MaxBackends
Definition: globals.c:136
static EDGE * curConstraints
Definition: deadlock.c:116
static EDGE * possibleConstraints
Definition: deadlock.c:121
int i
static int maxPossibleConstraints
Definition: deadlock.c:123

◆ TopoSort()

static bool TopoSort ( LOCK lock,
EDGE constraints,
int  nConstraints,
PGPROC **  ordering 
)
static

Definition at line 880 of file deadlock.c.

References afterConstraints, Assert, beforeConstraints, EDGE::blocker, i, EDGE::link, PROC_QUEUE::links, PGPROC::links, PGPROC::lockGroupLeader, MemSet, SHM_QUEUE::next, PGPROC::pid, EDGE::pred, printf, PROC_QUEUE::size, generate_unaccent_rules::stdout, EDGE::waiter, PGPROC::waitLock, and LOCK::waitProcs.

Referenced by ExpandConstraints().

884 {
885  PROC_QUEUE *waitQueue = &(lock->waitProcs);
886  int queue_size = waitQueue->size;
887  PGPROC *proc;
888  int i,
889  j,
890  jj,
891  k,
892  kk,
893  last;
894 
895  /* First, fill topoProcs[] array with the procs in their current order */
896  proc = (PGPROC *) waitQueue->links.next;
897  for (i = 0; i < queue_size; i++)
898  {
899  topoProcs[i] = proc;
900  proc = (PGPROC *) proc->links.next;
901  }
902 
903  /*
904  * Scan the constraints, and for each proc in the array, generate a count
905  * of the number of constraints that say it must be before something else,
906  * plus a list of the constraints that say it must be after something
907  * else. The count for the j'th proc is stored in beforeConstraints[j],
908  * and the head of its list in afterConstraints[j]. Each constraint
909  * stores its list link in constraints[i].link (note any constraint will
910  * be in just one list). The array index for the before-proc of the i'th
911  * constraint is remembered in constraints[i].pred.
912  *
913  * Note that it's not necessarily the case that every constraint affects
914  * this particular wait queue. Prior to group locking, a process could be
915  * waiting for at most one lock. But a lock group can be waiting for
916  * zero, one, or multiple locks. Since topoProcs[] is an array of the
917  * processes actually waiting, while constraints[] is an array of group
918  * leaders, we've got to scan through topoProcs[] for each constraint,
919  * checking whether both a waiter and a blocker for that group are
920  * present. If so, the constraint is relevant to this wait queue; if not,
921  * it isn't.
922  */
923  MemSet(beforeConstraints, 0, queue_size * sizeof(int));
924  MemSet(afterConstraints, 0, queue_size * sizeof(int));
925  for (i = 0; i < nConstraints; i++)
926  {
927  /*
928  * Find a representative process that is on the lock queue and part of
929  * the waiting lock group. This may or may not be the leader, which
930  * may or may not be waiting at all. If there are any other processes
931  * in the same lock group on the queue, set their number of
932  * beforeConstraints to -1 to indicate that they should be emitted
933  * with their groupmates rather than considered separately.
934  *
935  * In this loop and the similar one just below, it's critical that we
936  * consistently select the same representative member of any one lock
937  * group, so that all the constraints are associated with the same
938  * proc, and the -1's are only associated with not-representative
939  * members. We select the last one in the topoProcs array.
940  */
941  proc = constraints[i].waiter;
942  Assert(proc != NULL);
943  jj = -1;
944  for (j = queue_size; --j >= 0;)
945  {
946  PGPROC *waiter = topoProcs[j];
947 
948  if (waiter == proc || waiter->lockGroupLeader == proc)
949  {
950  Assert(waiter->waitLock == lock);
951  if (jj == -1)
952  jj = j;
953  else
954  {
955  Assert(beforeConstraints[j] <= 0);
956  beforeConstraints[j] = -1;
957  }
958  }
959  }
960 
961  /* If no matching waiter, constraint is not relevant to this lock. */
962  if (jj < 0)
963  continue;
964 
965  /*
966  * Similarly, find a representative process that is on the lock queue
967  * and waiting for the blocking lock group. Again, this could be the
968  * leader but does not need to be.
969  */
970  proc = constraints[i].blocker;
971  Assert(proc != NULL);
972  kk = -1;
973  for (k = queue_size; --k >= 0;)
974  {
975  PGPROC *blocker = topoProcs[k];
976 
977  if (blocker == proc || blocker->lockGroupLeader == proc)
978  {
979  Assert(blocker->waitLock == lock);
980  if (kk == -1)
981  kk = k;
982  else
983  {
984  Assert(beforeConstraints[k] <= 0);
985  beforeConstraints[k] = -1;
986  }
987  }
988  }
989 
990  /* If no matching blocker, constraint is not relevant to this lock. */
991  if (kk < 0)
992  continue;
993 
994  Assert(beforeConstraints[jj] >= 0);
995  beforeConstraints[jj]++; /* waiter must come before */
996  /* add this constraint to list of after-constraints for blocker */
997  constraints[i].pred = jj;
998  constraints[i].link = afterConstraints[kk];
999  afterConstraints[kk] = i + 1;
1000  }
1001 
1002  /*--------------------
1003  * Now scan the topoProcs array backwards. At each step, output the
1004  * last proc that has no remaining before-constraints plus any other
1005  * members of the same lock group; then decrease the beforeConstraints
1006  * count of each of the procs it was constrained against.
1007  * i = index of ordering[] entry we want to output this time
1008  * j = search index for topoProcs[]
1009  * k = temp for scanning constraint list for proc j
1010  * last = last non-null index in topoProcs (avoid redundant searches)
1011  *--------------------
1012  */
1013  last = queue_size - 1;
1014  for (i = queue_size - 1; i >= 0;)
1015  {
1016  int c;
1017  int nmatches = 0;
1018 
1019  /* Find next candidate to output */
1020  while (topoProcs[last] == NULL)
1021  last--;
1022  for (j = last; j >= 0; j--)
1023  {
1024  if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
1025  break;
1026  }
1027 
1028  /* If no available candidate, topological sort fails */
1029  if (j < 0)
1030  return false;
1031 
1032  /*
1033  * Output everything in the lock group. There's no point in
1034  * outputting an ordering where members of the same lock group are not
1035  * consecutive on the wait queue: if some other waiter is between two
1036  * requests that belong to the same group, then either it conflicts
1037  * with both of them and is certainly not a solution; or it conflicts
1038  * with at most one of them and is thus isomorphic to an ordering
1039  * where the group members are consecutive.
1040  */
1041  proc = topoProcs[j];
1042  if (proc->lockGroupLeader != NULL)
1043  proc = proc->lockGroupLeader;
1044  Assert(proc != NULL);
1045  for (c = 0; c <= last; ++c)
1046  {
1047  if (topoProcs[c] == proc || (topoProcs[c] != NULL &&
1048  topoProcs[c]->lockGroupLeader == proc))
1049  {
1050  ordering[i - nmatches] = topoProcs[c];
1051  topoProcs[c] = NULL;
1052  ++nmatches;
1053  }
1054  }
1055  Assert(nmatches > 0);
1056  i -= nmatches;
1057 
1058  /* Update beforeConstraints counts of its predecessors */
1059  for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
1060  beforeConstraints[constraints[k - 1].pred]--;
1061  }
1062 
1063  /* Done */
1064  return true;
1065 }
int link
Definition: deadlock.c:52
SHM_QUEUE links
Definition: lock.h:31
SHM_QUEUE links
Definition: proc.h:104
struct SHM_QUEUE * next
Definition: shmem.h:31
PGPROC * waiter
Definition: deadlock.c:48
#define MemSet(start, val, len)
Definition: c.h:978
PROC_QUEUE waitProcs
Definition: lock.h:296
int pred
Definition: deadlock.c:51
PGPROC * blocker
Definition: deadlock.c:49
static PGPROC ** topoProcs
Definition: deadlock.c:106
char * c
LOCK * waitLock
Definition: proc.h:145
static int * afterConstraints
Definition: deadlock.c:108
#define Assert(condition)
Definition: c.h:745
int i
int size
Definition: lock.h:32
static int * beforeConstraints
Definition: deadlock.c:107
Definition: proc.h:101
PGPROC * lockGroupLeader
Definition: proc.h:209

Variable Documentation

◆ afterConstraints

int* afterConstraints
static

Definition at line 108 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

◆ beforeConstraints

int* beforeConstraints
static

Definition at line 107 of file deadlock.c.

Referenced by InitDeadLockChecking(), and TopoSort().

◆ blocking_autovacuum_proc

PGPROC* blocking_autovacuum_proc = NULL
static

Definition at line 128 of file deadlock.c.

Referenced by GetBlockingAutoVacuumPgproc().

◆ curConstraints

EDGE* curConstraints
static

Definition at line 116 of file deadlock.c.

◆ deadlockDetails

DEADLOCK_INFO* deadlockDetails
static

Definition at line 124 of file deadlock.c.

◆ maxCurConstraints

int maxCurConstraints
static

Definition at line 118 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), and InitDeadLockChecking().

◆ maxPossibleConstraints

int maxPossibleConstraints
static

Definition at line 123 of file deadlock.c.

Referenced by DeadLockCheckRecurse(), InitDeadLockChecking(), and TestConfiguration().

◆ nCurConstraints

int nCurConstraints
static

Definition at line 117 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

◆ nDeadlockDetails

int nDeadlockDetails
static

◆ nPossibleConstraints

int nPossibleConstraints
static

Definition at line 122 of file deadlock.c.

Referenced by DeadLockCheck(), DeadLockCheckRecurse(), and TestConfiguration().

◆ nVisitedProcs

int nVisitedProcs
static

Definition at line 103 of file deadlock.c.

Referenced by FindLockCycle(), and FindLockCycleRecurse().

◆ nWaitOrders

int nWaitOrders
static

Definition at line 112 of file deadlock.c.

Referenced by DeadLockCheck(), ExpandConstraints(), and FindLockCycleRecurseMember().

◆ possibleConstraints

EDGE* possibleConstraints
static

Definition at line 121 of file deadlock.c.

◆ topoProcs

PGPROC** topoProcs
static

Definition at line 106 of file deadlock.c.

◆ visitedProcs

PGPROC** visitedProcs
static

Definition at line 102 of file deadlock.c.

Referenced by InitDeadLockChecking().

◆ waitOrderProcs

PGPROC** waitOrderProcs
static

Definition at line 113 of file deadlock.c.

◆ waitOrders

WAIT_ORDER* waitOrders
static

Definition at line 111 of file deadlock.c.