Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * deadlock.c
4 : : * POSTGRES deadlock detection code
5 : : *
6 : : * See src/backend/storage/lmgr/README for a description of the deadlock
7 : : * detection and resolution algorithms.
8 : : *
9 : : *
10 : : * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 : : * Portions Copyright (c) 1994, Regents of the University of California
12 : : *
13 : : *
14 : : * IDENTIFICATION
15 : : * src/backend/storage/lmgr/deadlock.c
16 : : *
17 : : * Interface:
18 : : *
19 : : * DeadLockCheck()
20 : : * DeadLockReport()
21 : : * RememberSimpleDeadLock()
22 : : * InitDeadLockChecking()
23 : : *
24 : : *-------------------------------------------------------------------------
25 : : */
26 : : #include "postgres.h"
27 : :
28 : : #include "miscadmin.h"
29 : : #include "pg_trace.h"
30 : : #include "pgstat.h"
31 : : #include "storage/lmgr.h"
32 : : #include "storage/proc.h"
33 : : #include "storage/procnumber.h"
34 : : #include "utils/memutils.h"
35 : :
36 : :
37 : : /*
38 : : * One edge in the waits-for graph.
39 : : *
40 : : * waiter and blocker may or may not be members of a lock group, but if either
41 : : * is, it will be the leader rather than any other member of the lock group.
42 : : * The group leaders act as representatives of the whole group even though
43 : : * those particular processes need not be waiting at all. There will be at
44 : : * least one member of the waiter's lock group on the wait queue for the given
45 : : * lock, maybe more.
46 : : */
47 : : typedef struct
48 : : {
49 : : PGPROC *waiter; /* the leader of the waiting lock group */
50 : : PGPROC *blocker; /* the leader of the group it is waiting for */
51 : : LOCK *lock; /* the lock being waited for */
52 : : int pred; /* workspace for TopoSort */
53 : : int link; /* workspace for TopoSort */
54 : : } EDGE;
55 : :
56 : : /* One potential reordering of a lock's wait queue */
57 : : typedef struct
58 : : {
59 : : LOCK *lock; /* the lock whose wait queue is described */
60 : : PGPROC **procs; /* array of PGPROC *'s in new wait order */
61 : : int nProcs;
62 : : } WAIT_ORDER;
63 : :
64 : : /*
65 : : * Information saved about each edge in a detected deadlock cycle. This
66 : : * is used to print a diagnostic message upon failure.
67 : : *
68 : : * Note: because we want to examine this info after releasing the lock
69 : : * manager's partition locks, we can't just store LOCK and PGPROC pointers;
70 : : * we must extract out all the info we want to be able to print.
71 : : */
72 : : typedef struct
73 : : {
74 : : LOCKTAG locktag; /* ID of awaited lock object */
75 : : LOCKMODE lockmode; /* type of lock we're waiting for */
76 : : int pid; /* PID of blocked backend */
77 : : } DEADLOCK_INFO;
78 : :
79 : :
80 : : static bool DeadLockCheckRecurse(PGPROC *proc);
81 : : static int TestConfiguration(PGPROC *startProc);
82 : : static bool FindLockCycle(PGPROC *checkProc,
83 : : EDGE *softEdges, int *nSoftEdges);
84 : : static bool FindLockCycleRecurse(PGPROC *checkProc, int depth,
85 : : EDGE *softEdges, int *nSoftEdges);
86 : : static bool FindLockCycleRecurseMember(PGPROC *checkProc,
87 : : PGPROC *checkProcLeader,
88 : : int depth, EDGE *softEdges, int *nSoftEdges);
89 : : static bool ExpandConstraints(EDGE *constraints, int nConstraints);
90 : : static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,
91 : : PGPROC **ordering);
92 : :
93 : : #ifdef DEBUG_DEADLOCK
94 : : static void PrintLockQueue(LOCK *lock, const char *info);
95 : : #endif
96 : :
97 : :
98 : : /*
99 : : * Working space for the deadlock detector
100 : : */
101 : :
102 : : /* Workspace for FindLockCycle */
103 : : static PGPROC **visitedProcs; /* Array of visited procs */
104 : : static int nVisitedProcs;
105 : :
106 : : /* Workspace for TopoSort */
107 : : static PGPROC **topoProcs; /* Array of not-yet-output procs */
108 : : static int *beforeConstraints; /* Counts of remaining before-constraints */
109 : : static int *afterConstraints; /* List head for after-constraints */
110 : :
111 : : /* Output area for ExpandConstraints */
112 : : static WAIT_ORDER *waitOrders; /* Array of proposed queue rearrangements */
113 : : static int nWaitOrders;
114 : : static PGPROC **waitOrderProcs; /* Space for waitOrders queue contents */
115 : :
116 : : /* Current list of constraints being considered */
117 : : static EDGE *curConstraints;
118 : : static int nCurConstraints;
119 : : static int maxCurConstraints;
120 : :
121 : : /* Storage space for results from FindLockCycle */
122 : : static EDGE *possibleConstraints;
123 : : static int nPossibleConstraints;
124 : : static int maxPossibleConstraints;
125 : : static DEADLOCK_INFO *deadlockDetails;
126 : : static int nDeadlockDetails;
127 : :
128 : : /* PGPROC pointer of any blocking autovacuum worker found */
129 : : static PGPROC *blocking_autovacuum_proc = NULL;
130 : :
131 : :
132 : : /*
133 : : * InitDeadLockChecking -- initialize deadlock checker during backend startup
134 : : *
135 : : * This does per-backend initialization of the deadlock checker; primarily,
136 : : * allocation of working memory for DeadLockCheck. We do this per-backend
137 : : * since there's no percentage in making the kernel do copy-on-write
138 : : * inheritance of workspace from the postmaster. We want to allocate the
139 : : * space at startup because (a) the deadlock checker might be invoked when
140 : : * there's no free memory left, and (b) the checker is normally run inside a
141 : : * signal handler, which is a very dangerous place to invoke palloc from.
142 : : */
143 : : void
8990 tgl@sss.pgh.pa.us 144 :CBC 14847 : InitDeadLockChecking(void)
145 : : {
146 : : MemoryContext oldcxt;
147 : :
148 : : /* Make sure allocations are permanent */
149 : 14847 : oldcxt = MemoryContextSwitchTo(TopMemoryContext);
150 : :
151 : : /*
152 : : * FindLockCycle needs at most MaxBackends entries in visitedProcs[] and
153 : : * deadlockDetails[].
154 : : */
1243 rhaas@postgresql.org 155 : 14847 : visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
156 : 14847 : deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));
157 : :
158 : : /*
159 : : * TopoSort needs to consider at most MaxBackends wait-queue entries, and
160 : : * it needn't run concurrently with FindLockCycle.
161 : : */
8990 tgl@sss.pgh.pa.us 162 : 14847 : topoProcs = visitedProcs; /* re-use this space */
1243 rhaas@postgresql.org 163 : 14847 : beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
164 : 14847 : afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
165 : :
166 : : /*
167 : : * We need to consider rearranging at most MaxBackends/2 wait queues
168 : : * (since it takes at least two waiters in a queue to create a soft edge),
169 : : * and the expanded form of the wait queues can't involve more than
170 : : * MaxBackends total waiters.
171 : : */
8374 tgl@sss.pgh.pa.us 172 : 14847 : waitOrders = (WAIT_ORDER *)
1243 rhaas@postgresql.org 173 : 14847 : palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
174 : 14847 : waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
175 : :
176 : : /*
177 : : * Allow at most MaxBackends distinct constraints in a configuration. (Is
178 : : * this enough? In practice it seems it should be, but I don't quite see
179 : : * how to prove it. If we run out, we might fail to find a workable wait
180 : : * queue rearrangement even though one exists.) NOTE that this number
181 : : * limits the maximum recursion depth of DeadLockCheckRecurse. Making it
182 : : * really big might potentially allow a stack-overflow problem.
183 : : */
184 : 14847 : maxCurConstraints = MaxBackends;
8990 tgl@sss.pgh.pa.us 185 : 14847 : curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
186 : :
187 : : /*
188 : : * Allow up to 3*MaxBackends constraints to be saved without having to
189 : : * re-run TestConfiguration. (This is probably more than enough, but we
190 : : * can survive if we run low on space by doing excess runs of
191 : : * TestConfiguration to re-compute constraint lists each time needed.) The
192 : : * last MaxBackends entries in possibleConstraints[] are reserved as
193 : : * output workspace for FindLockCycle.
194 : : */
195 : : StaticAssertStmt(MAX_BACKENDS_BITS <= (32 - 3),
196 : : "MAX_BACKENDS_BITS too big for * 4");
1243 rhaas@postgresql.org 197 : 14847 : maxPossibleConstraints = MaxBackends * 4;
8990 tgl@sss.pgh.pa.us 198 : 14847 : possibleConstraints =
199 : 14847 : (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
200 : :
201 : 14847 : MemoryContextSwitchTo(oldcxt);
202 : 14847 : }
203 : :
204 : : /*
205 : : * DeadLockCheck -- Checks for deadlocks for a given process
206 : : *
207 : : * This code looks for deadlocks involving the given process. If any
208 : : * are found, it tries to rearrange lock wait queues to resolve the
209 : : * deadlock. If resolution is impossible, return DS_HARD_DEADLOCK ---
210 : : * the caller is then expected to abort the given proc's transaction.
211 : : *
212 : : * Caller must already have locked all partitions of the lock tables.
213 : : *
214 : : * On failure, deadlock details are recorded in deadlockDetails[] for
215 : : * subsequent printing by DeadLockReport(). That activity is separate
216 : : * because (a) we don't want to do it while holding all those LWLocks,
217 : : * and (b) we are typically invoked inside a signal handler.
218 : : */
219 : : DeadLockState
8488 JanWieck@Yahoo.com 220 : 30 : DeadLockCheck(PGPROC *proc)
221 : : {
222 : : /* Initialize to "no constraints" */
8990 tgl@sss.pgh.pa.us 223 : 30 : nCurConstraints = 0;
224 : 30 : nPossibleConstraints = 0;
225 : 30 : nWaitOrders = 0;
226 : :
227 : : /* Initialize to not blocked by an autovacuum worker */
6525 alvherre@alvh.no-ip. 228 : 30 : blocking_autovacuum_proc = NULL;
229 : :
230 : : /* Search for deadlocks and possible fixes */
8990 tgl@sss.pgh.pa.us 231 [ + + ]: 30 : 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 : :
8269 241 : 5 : nWaitOrders = 0;
242 [ - + ]: 5 : if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
8080 tgl@sss.pgh.pa.us 243 [ # # ]:UBC 0 : elog(FATAL, "deadlock seems to have disappeared");
244 : :
6762 bruce@momjian.us 245 :CBC 5 : return DS_HARD_DEADLOCK; /* cannot find a non-deadlocked state */
246 : : }
247 : :
248 : : /* Apply any needed rearrangements of wait queues */
962 andres@anarazel.de 249 [ + + ]: 28 : for (int i = 0; i < nWaitOrders; i++)
250 : : {
8934 bruce@momjian.us 251 : 3 : LOCK *lock = waitOrders[i].lock;
8488 JanWieck@Yahoo.com 252 : 3 : PGPROC **procs = waitOrders[i].procs;
8934 bruce@momjian.us 253 : 3 : int nProcs = waitOrders[i].nProcs;
962 andres@anarazel.de 254 : 3 : dclist_head *waitQueue = &lock->waitProcs;
255 : :
256 [ - + ]: 3 : Assert(nProcs == dclist_count(waitQueue));
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 : 3 : dclist_init(waitQueue);
264 [ + + ]: 12 : for (int j = 0; j < nProcs; j++)
265 : 9 : dclist_push_tail(waitQueue, &procs[j]->links);
266 : :
267 : : #ifdef DEBUG_DEADLOCK
268 : : PrintLockQueue(lock, "rearranged to:");
269 : : #endif
270 : :
271 : : /* See if any waiters for the lock can be woken up now */
8990 tgl@sss.pgh.pa.us 272 : 3 : ProcLockWakeup(GetLocksMethodTable(lock), lock);
273 : : }
274 : :
275 : : /* Return code tells caller if we had to escape a deadlock or not */
6762 bruce@momjian.us 276 [ + + ]: 25 : if (nWaitOrders > 0)
277 : 3 : return DS_SOFT_DEADLOCK;
6525 alvherre@alvh.no-ip. 278 [ - + ]: 22 : else if (blocking_autovacuum_proc != NULL)
6525 alvherre@alvh.no-ip. 279 :UBC 0 : return DS_BLOCKED_BY_AUTOVACUUM;
280 : : else
6654 tgl@sss.pgh.pa.us 281 :CBC 22 : return DS_NO_DEADLOCK;
282 : : }
283 : :
284 : : /*
285 : : * Return the PGPROC of the autovacuum that's blocking a process.
286 : : *
287 : : * We reset the saved pointer as soon as we pass it back.
288 : : */
289 : : PGPROC *
6525 alvherre@alvh.no-ip. 290 :UBC 0 : GetBlockingAutoVacuumPgproc(void)
291 : : {
292 : : PGPROC *ptr;
293 : :
294 : 0 : ptr = blocking_autovacuum_proc;
295 : 0 : blocking_autovacuum_proc = NULL;
296 : :
297 : 0 : return ptr;
298 : : }
299 : :
300 : : /*
301 : : * DeadLockCheckRecurse -- recursively search for valid orderings
302 : : *
303 : : * curConstraints[] holds the current set of constraints being considered
304 : : * by an outer level of recursion. Add to this each possible solution
305 : : * constraint for any cycle detected at this level.
306 : : *
307 : : * Returns true if no solution exists. Returns false if a deadlock-free
308 : : * state is attainable, in which case waitOrders[] shows the required
309 : : * rearrangements of lock wait queues (if any).
310 : : */
311 : : static bool
8488 JanWieck@Yahoo.com 312 :CBC 33 : DeadLockCheckRecurse(PGPROC *proc)
313 : : {
314 : : int nEdges;
315 : : int oldPossibleConstraints;
316 : : bool savedList;
317 : : int i;
318 : :
8990 tgl@sss.pgh.pa.us 319 : 33 : nEdges = TestConfiguration(proc);
320 [ + + ]: 33 : if (nEdges < 0)
321 : 5 : return true; /* hard deadlock --- no solution */
322 [ + + ]: 28 : if (nEdges == 0)
323 : 25 : return false; /* good configuration found */
324 [ - + ]: 3 : if (nCurConstraints >= maxCurConstraints)
8990 tgl@sss.pgh.pa.us 325 :UBC 0 : return true; /* out of room for active constraints? */
8990 tgl@sss.pgh.pa.us 326 :CBC 3 : oldPossibleConstraints = nPossibleConstraints;
1243 rhaas@postgresql.org 327 [ + - ]: 3 : if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
328 : : {
329 : : /* We can save the edge list in possibleConstraints[] */
8990 tgl@sss.pgh.pa.us 330 : 3 : nPossibleConstraints += nEdges;
331 : 3 : savedList = true;
332 : : }
333 : : else
334 : : {
335 : : /* Not room; will need to regenerate the edges on-the-fly */
8990 tgl@sss.pgh.pa.us 336 :UBC 0 : savedList = false;
337 : : }
338 : :
339 : : /*
340 : : * Try each available soft edge as an addition to the configuration.
341 : : */
8990 tgl@sss.pgh.pa.us 342 [ + - ]:CBC 3 : for (i = 0; i < nEdges; i++)
343 : : {
344 [ - + - - ]: 3 : if (!savedList && i > 0)
345 : : {
346 : : /* Regenerate the list of possible added constraints */
8990 tgl@sss.pgh.pa.us 347 [ # # ]:UBC 0 : if (nEdges != TestConfiguration(proc))
8080 348 [ # # ]: 0 : elog(FATAL, "inconsistent results during deadlock check");
349 : : }
8990 tgl@sss.pgh.pa.us 350 :CBC 3 : curConstraints[nCurConstraints] =
8934 bruce@momjian.us 351 : 3 : possibleConstraints[oldPossibleConstraints + i];
8990 tgl@sss.pgh.pa.us 352 : 3 : nCurConstraints++;
353 [ + - ]: 3 : if (!DeadLockCheckRecurse(proc))
354 : 3 : return false; /* found a valid solution! */
355 : : /* give up on that added constraint, try again */
8990 tgl@sss.pgh.pa.us 356 :UBC 0 : nCurConstraints--;
357 : : }
358 : 0 : nPossibleConstraints = oldPossibleConstraints;
359 : 0 : return true; /* no solution found */
360 : : }
361 : :
362 : :
363 : : /*--------------------
364 : : * Test a configuration (current set of constraints) for validity.
365 : : *
366 : : * Returns:
367 : : * 0: the configuration is good (no deadlocks)
368 : : * -1: the configuration has a hard deadlock or is not self-consistent
369 : : * >0: the configuration has one or more soft deadlocks
370 : : *
371 : : * In the soft-deadlock case, one of the soft cycles is chosen arbitrarily
372 : : * and a list of its soft edges is returned beginning at
373 : : * possibleConstraints+nPossibleConstraints. The return value is the
374 : : * number of soft edges.
375 : : *--------------------
376 : : */
377 : : static int
8488 JanWieck@Yahoo.com 378 :CBC 33 : TestConfiguration(PGPROC *startProc)
379 : : {
8934 bruce@momjian.us 380 : 33 : int softFound = 0;
381 : 33 : EDGE *softEdges = possibleConstraints + nPossibleConstraints;
382 : : int nSoftEdges;
383 : : int i;
384 : :
385 : : /*
386 : : * Make sure we have room for FindLockCycle's output.
387 : : */
1243 rhaas@postgresql.org 388 [ - + ]: 33 : if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
8990 tgl@sss.pgh.pa.us 389 :UBC 0 : return -1;
390 : :
391 : : /*
392 : : * Expand current constraint set into wait orderings. Fail if the
393 : : * constraint set is not self-consistent.
394 : : */
8990 tgl@sss.pgh.pa.us 395 [ - + ]:CBC 33 : if (!ExpandConstraints(curConstraints, nCurConstraints))
8990 tgl@sss.pgh.pa.us 396 :UBC 0 : return -1;
397 : :
398 : : /*
399 : : * Check for cycles involving startProc or any of the procs mentioned in
400 : : * constraints. We check startProc last because if it has a soft cycle
401 : : * still to be dealt with, we want to deal with that first.
402 : : */
8990 tgl@sss.pgh.pa.us 403 [ + + ]:CBC 36 : for (i = 0; i < nCurConstraints; i++)
404 : : {
405 [ - + ]: 3 : if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))
406 : : {
8990 tgl@sss.pgh.pa.us 407 [ # # ]:UBC 0 : if (nSoftEdges == 0)
408 : 0 : return -1; /* hard deadlock detected */
409 : 0 : softFound = nSoftEdges;
410 : : }
8990 tgl@sss.pgh.pa.us 411 [ - + ]:CBC 3 : if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))
412 : : {
8990 tgl@sss.pgh.pa.us 413 [ # # ]:UBC 0 : if (nSoftEdges == 0)
414 : 0 : return -1; /* hard deadlock detected */
415 : 0 : softFound = nSoftEdges;
416 : : }
417 : : }
8990 tgl@sss.pgh.pa.us 418 [ + + ]:CBC 33 : if (FindLockCycle(startProc, softEdges, &nSoftEdges))
419 : : {
420 [ + + ]: 8 : if (nSoftEdges == 0)
421 : 5 : return -1; /* hard deadlock detected */
422 : 3 : softFound = nSoftEdges;
423 : : }
424 : 28 : return softFound;
425 : : }
426 : :
427 : :
428 : : /*
429 : : * FindLockCycle -- basic check for deadlock cycles
430 : : *
431 : : * Scan outward from the given proc to see if there is a cycle in the
432 : : * waits-for graph that includes this proc. Return true if a cycle
433 : : * is found, else false. If a cycle is found, we return a list of
434 : : * the "soft edges", if any, included in the cycle. These edges could
435 : : * potentially be eliminated by rearranging wait queues. We also fill
436 : : * deadlockDetails[] with information about the detected cycle; this info
437 : : * is not used by the deadlock algorithm itself, only to print a useful
438 : : * message after failing.
439 : : *
440 : : * Since we need to be able to check hypothetical configurations that would
441 : : * exist after wait queue rearrangement, the routine pays attention to the
442 : : * table of hypothetical queue orders in waitOrders[]. These orders will
443 : : * be believed in preference to the actual ordering seen in the locktable.
444 : : */
445 : : static bool
8488 JanWieck@Yahoo.com 446 : 44 : FindLockCycle(PGPROC *checkProc,
447 : : EDGE *softEdges, /* output argument */
448 : : int *nSoftEdges) /* output argument */
449 : : {
8990 tgl@sss.pgh.pa.us 450 : 44 : nVisitedProcs = 0;
8269 451 : 44 : nDeadlockDetails = 0;
8990 452 : 44 : *nSoftEdges = 0;
8269 453 : 44 : return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);
454 : : }
455 : :
456 : : static bool
8488 JanWieck@Yahoo.com 457 : 134 : FindLockCycleRecurse(PGPROC *checkProc,
458 : : int depth,
459 : : EDGE *softEdges, /* output argument */
460 : : int *nSoftEdges) /* output argument */
461 : : {
462 : : int i;
463 : : dlist_iter iter;
464 : :
465 : : /*
466 : : * If this process is a lock group member, check the leader instead. (Note
467 : : * that we might be the leader, in which case this is a no-op.)
468 : : */
3499 rhaas@postgresql.org 469 [ + + ]: 134 : if (checkProc->lockGroupLeader != NULL)
470 : 29 : checkProc = checkProc->lockGroupLeader;
471 : :
472 : : /*
473 : : * Have we already seen this proc?
474 : : */
8990 tgl@sss.pgh.pa.us 475 [ + + ]: 284 : for (i = 0; i < nVisitedProcs; i++)
476 : : {
477 [ + + ]: 171 : if (visitedProcs[i] == checkProc)
478 : : {
479 : : /* If we return to starting point, we have a deadlock cycle */
480 [ + + ]: 21 : if (i == 0)
481 : : {
482 : : /*
483 : : * record total length of cycle --- outer levels will now fill
484 : : * deadlockDetails[]
485 : : */
1243 rhaas@postgresql.org 486 [ - + ]: 13 : Assert(depth <= MaxBackends);
8269 tgl@sss.pgh.pa.us 487 : 13 : nDeadlockDetails = depth;
488 : :
8990 489 : 13 : return true;
490 : : }
491 : :
492 : : /*
493 : : * Otherwise, we have a cycle but it does not include the start
494 : : * point, so say "no deadlock".
495 : : */
496 : 8 : return false;
497 : : }
498 : : }
499 : : /* Mark proc as seen */
1243 rhaas@postgresql.org 500 [ - + ]: 113 : Assert(nVisitedProcs < MaxBackends);
8990 tgl@sss.pgh.pa.us 501 : 113 : visitedProcs[nVisitedProcs++] = checkProc;
502 : :
503 : : /*
504 : : * If the process is waiting, there is an outgoing waits-for edge to each
505 : : * process that blocks it.
506 : : */
3499 rhaas@postgresql.org 507 [ + + + - : 190 : if (checkProc->links.next != NULL && checkProc->waitLock != NULL &&
+ + ]
508 : 77 : FindLockCycleRecurseMember(checkProc, checkProc, depth, softEdges,
509 : : nSoftEdges))
510 : 41 : return true;
511 : :
512 : : /*
513 : : * If the process is not waiting, there could still be outgoing waits-for
514 : : * edges if it is part of a lock group, because other members of the lock
515 : : * group might be waiting even though this process is not. (Given lock
516 : : * groups {A1, A2} and {B1, B2}, if A1 waits for B1 and B2 waits for A2,
517 : : * that is a deadlock even neither of B1 and A2 are waiting for anything.)
518 : : */
519 [ + - + + ]: 122 : dlist_foreach(iter, &checkProc->lockGroupMembers)
520 : : {
521 : : PGPROC *memberProc;
522 : :
523 : 54 : memberProc = dlist_container(PGPROC, lockGroupLink, iter.cur);
524 : :
525 [ + + + - : 54 : if (memberProc->links.next != NULL && memberProc->waitLock != NULL &&
+ + ]
526 [ + + ]: 23 : memberProc != checkProc &&
2999 tgl@sss.pgh.pa.us 527 : 23 : FindLockCycleRecurseMember(memberProc, checkProc, depth, softEdges,
528 : : nSoftEdges))
3499 rhaas@postgresql.org 529 : 4 : return true;
530 : : }
531 : :
532 : 68 : return false;
533 : : }
534 : :
535 : : static bool
536 : 100 : FindLockCycleRecurseMember(PGPROC *checkProc,
537 : : PGPROC *checkProcLeader,
538 : : int depth,
539 : : EDGE *softEdges, /* output argument */
540 : : int *nSoftEdges) /* output argument */
541 : : {
542 : : PGPROC *proc;
543 : 100 : LOCK *lock = checkProc->waitLock;
544 : : dlist_iter proclock_iter;
545 : : LockMethod lockMethodTable;
546 : : int conflictMask;
547 : : int i;
548 : : int numLockModes,
549 : : lm;
550 : :
551 : : /*
552 : : * The relation extension lock can never participate in actual deadlock
553 : : * cycle. See Assert in LockAcquireExtended. So, there is no advantage
554 : : * in checking wait edges from it.
555 : : */
793 akapila@postgresql.o 556 [ - + ]: 100 : if (LOCK_LOCKTAG(*lock) == LOCKTAG_RELATION_EXTEND)
1996 akapila@postgresql.o 557 :UBC 0 : return false;
558 : :
8990 tgl@sss.pgh.pa.us 559 :CBC 100 : lockMethodTable = GetLocksMethodTable(lock);
8451 bruce@momjian.us 560 : 100 : numLockModes = lockMethodTable->numLockModes;
561 : 100 : conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
562 : :
563 : : /*
564 : : * Scan for procs that already hold conflicting locks. These are "hard"
565 : : * edges in the waits-for graph.
566 : : */
962 andres@anarazel.de 567 [ + - + + ]: 296 : dlist_foreach(proclock_iter, &lock->procLocks)
568 : : {
569 : 236 : PROCLOCK *proclock = dlist_container(PROCLOCK, lockLink, proclock_iter.cur);
570 : : PGPROC *leader;
571 : :
6985 tgl@sss.pgh.pa.us 572 : 236 : proc = proclock->tag.myProc;
3499 rhaas@postgresql.org 573 [ + + ]: 236 : leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
574 : :
575 : : /* A proc never blocks itself or any other lock group member */
576 [ + + ]: 236 : if (leader != checkProcLeader)
577 : : {
8990 tgl@sss.pgh.pa.us 578 [ + + ]: 1147 : for (lm = 1; lm <= numLockModes; lm++)
579 : : {
7680 580 [ + + + + ]: 1070 : if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
581 : : (conflictMask & LOCKBIT_ON(lm)))
582 : : {
583 : : /* This proc hard-blocks checkProc */
8069 bruce@momjian.us 584 [ + + ]: 72 : if (FindLockCycleRecurse(proc, depth + 1,
585 : : softEdges, nSoftEdges))
586 : : {
587 : : /* fill deadlockDetails[] */
588 : 40 : DEADLOCK_INFO *info = &deadlockDetails[depth];
589 : :
8269 tgl@sss.pgh.pa.us 590 : 40 : info->locktag = lock->tag;
591 : 40 : info->lockmode = checkProc->waitLockMode;
592 : 40 : info->pid = checkProc->pid;
593 : :
8990 594 : 40 : return true;
595 : : }
596 : :
597 : : /*
598 : : * No deadlock here, but see if this proc is an autovacuum
599 : : * that is directly hard-blocking our own proc. If so,
600 : : * report it so that the caller can send a cancel signal
601 : : * to it, if appropriate. If there's more than one such
602 : : * proc, it's indeterminate which one will be reported.
603 : : *
604 : : * We don't touch autovacuums that are indirectly blocking
605 : : * us; it's up to the direct blockee to take action. This
606 : : * rule simplifies understanding the behavior and ensures
607 : : * that an autovacuum won't be canceled with less than
608 : : * deadlock_timeout grace period.
609 : : *
610 : : * Note we read statusFlags without any locking. This is
611 : : * OK only for checking the PROC_IS_AUTOVACUUM flag,
612 : : * because that flag is set at process start and never
613 : : * reset. There is logic elsewhere to avoid canceling an
614 : : * autovacuum that is working to prevent XID wraparound
615 : : * problems (which needs to read a different statusFlags
616 : : * bit), but we don't do that here to avoid grabbing
617 : : * ProcArrayLock.
618 : : */
4790 619 [ + + ]: 32 : if (checkProc == MyProc &&
1755 alvherre@alvh.no-ip. 620 [ - + ]: 21 : proc->statusFlags & PROC_IS_AUTOVACUUM)
4790 tgl@sss.pgh.pa.us 621 :UBC 0 : blocking_autovacuum_proc = proc;
622 : :
623 : : /* We're done looking at this proclock */
8990 tgl@sss.pgh.pa.us 624 :CBC 32 : break;
625 : : }
626 : : }
627 : : }
628 : : }
629 : :
630 : : /*
631 : : * Scan for procs that are ahead of this one in the lock's wait queue.
632 : : * Those that have conflicting requests soft-block this one. This must be
633 : : * done after the hard-block search, since if another proc both hard- and
634 : : * soft-blocks this one, we want to call it a hard edge.
635 : : *
636 : : * If there is a proposed re-ordering of the lock's wait order, use that
637 : : * rather than the current wait order.
638 : : */
639 [ + + ]: 71 : for (i = 0; i < nWaitOrders; i++)
640 : : {
641 [ + + ]: 29 : if (waitOrders[i].lock == lock)
642 : 18 : break;
643 : : }
644 : :
645 [ + + ]: 60 : if (i < nWaitOrders)
646 : : {
647 : : /* Use the given hypothetical wait queue order */
8488 JanWieck@Yahoo.com 648 : 18 : PGPROC **procs = waitOrders[i].procs;
962 andres@anarazel.de 649 : 18 : int queue_size = waitOrders[i].nProcs;
650 : :
8990 tgl@sss.pgh.pa.us 651 [ + - ]: 23 : for (i = 0; i < queue_size; i++)
652 : : {
653 : : PGPROC *leader;
654 : :
655 : 23 : proc = procs[i];
3499 rhaas@postgresql.org 656 [ + + ]: 23 : leader = proc->lockGroupLeader == NULL ? proc :
657 : : proc->lockGroupLeader;
658 : :
659 : : /*
660 : : * TopoSort will always return an ordering with group members
661 : : * adjacent to each other in the wait queue (see comments
662 : : * therein). So, as soon as we reach a process in the same lock
663 : : * group as checkProc, we know we've found all the conflicts that
664 : : * precede any member of the lock group lead by checkProcLeader.
665 : : */
666 [ + + ]: 23 : if (leader == checkProcLeader)
8990 tgl@sss.pgh.pa.us 667 : 18 : break;
668 : :
669 : : /* Is there a conflict with this guy's request? */
3631 rhaas@postgresql.org 670 [ + - ]: 5 : if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0)
671 : : {
672 : : /* This proc soft-blocks checkProc */
8069 bruce@momjian.us 673 [ - + ]: 5 : if (FindLockCycleRecurse(proc, depth + 1,
674 : : softEdges, nSoftEdges))
675 : : {
676 : : /* fill deadlockDetails[] */
8069 bruce@momjian.us 677 :UBC 0 : DEADLOCK_INFO *info = &deadlockDetails[depth];
678 : :
8269 tgl@sss.pgh.pa.us 679 : 0 : info->locktag = lock->tag;
680 : 0 : info->lockmode = checkProc->waitLockMode;
681 : 0 : info->pid = checkProc->pid;
682 : :
683 : : /*
684 : : * Add this edge to the list of soft edges in the cycle
685 : : */
1243 rhaas@postgresql.org 686 [ # # ]: 0 : Assert(*nSoftEdges < MaxBackends);
3499 687 : 0 : softEdges[*nSoftEdges].waiter = checkProcLeader;
688 : 0 : softEdges[*nSoftEdges].blocker = leader;
689 : 0 : softEdges[*nSoftEdges].lock = lock;
8990 tgl@sss.pgh.pa.us 690 : 0 : (*nSoftEdges)++;
691 : 0 : return true;
692 : : }
693 : : }
694 : : }
695 : : }
696 : : else
697 : : {
3499 rhaas@postgresql.org 698 :CBC 42 : PGPROC *lastGroupMember = NULL;
699 : : dlist_iter proc_iter;
700 : : dclist_head *waitQueue;
701 : :
702 : : /* Use the true lock wait queue order */
962 andres@anarazel.de 703 : 42 : waitQueue = &lock->waitProcs;
704 : :
705 : : /*
706 : : * Find the last member of the lock group that is present in the wait
707 : : * queue. Anything after this is not a soft lock conflict. If group
708 : : * locking is not in use, then we know immediately which process we're
709 : : * looking for, but otherwise we've got to search the wait queue to
710 : : * find the last process actually present.
711 : : */
3499 rhaas@postgresql.org 712 [ + + ]: 42 : if (checkProc->lockGroupLeader == NULL)
713 : 30 : lastGroupMember = checkProc;
714 : : else
715 : : {
962 andres@anarazel.de 716 [ + - + + ]: 48 : dclist_foreach(proc_iter, waitQueue)
717 : : {
718 : 36 : proc = dlist_container(PGPROC, links, proc_iter.cur);
719 : :
3499 rhaas@postgresql.org 720 [ + + ]: 36 : if (proc->lockGroupLeader == checkProcLeader)
721 : 21 : lastGroupMember = proc;
722 : : }
723 [ - + ]: 12 : Assert(lastGroupMember != NULL);
724 : : }
725 : :
726 : : /*
727 : : * OK, now rescan (or scan) the queue to identify the soft conflicts.
728 : : */
962 andres@anarazel.de 729 [ + - + - ]: 59 : dclist_foreach(proc_iter, waitQueue)
730 : : {
731 : : PGPROC *leader;
732 : :
733 : 59 : proc = dlist_container(PGPROC, links, proc_iter.cur);
734 : :
3499 rhaas@postgresql.org 735 [ + + ]: 59 : leader = proc->lockGroupLeader == NULL ? proc :
736 : : proc->lockGroupLeader;
737 : :
738 : : /* Done when we reach the target proc */
739 [ + + ]: 59 : if (proc == lastGroupMember)
8990 tgl@sss.pgh.pa.us 740 : 37 : break;
741 : :
742 : : /* Is there a conflict with this guy's request? */
3499 rhaas@postgresql.org 743 [ + + + - ]: 22 : if ((LOCKBIT_ON(proc->waitLockMode) & conflictMask) != 0 &&
744 : : leader != checkProcLeader)
745 : : {
746 : : /* This proc soft-blocks checkProc */
8069 bruce@momjian.us 747 [ + + ]: 13 : if (FindLockCycleRecurse(proc, depth + 1,
748 : : softEdges, nSoftEdges))
749 : : {
750 : : /* fill deadlockDetails[] */
751 : 5 : DEADLOCK_INFO *info = &deadlockDetails[depth];
752 : :
8269 tgl@sss.pgh.pa.us 753 : 5 : info->locktag = lock->tag;
754 : 5 : info->lockmode = checkProc->waitLockMode;
755 : 5 : info->pid = checkProc->pid;
756 : :
757 : : /*
758 : : * Add this edge to the list of soft edges in the cycle
759 : : */
1243 rhaas@postgresql.org 760 [ - + ]: 5 : Assert(*nSoftEdges < MaxBackends);
3499 761 : 5 : softEdges[*nSoftEdges].waiter = checkProcLeader;
762 : 5 : softEdges[*nSoftEdges].blocker = leader;
763 : 5 : softEdges[*nSoftEdges].lock = lock;
8990 tgl@sss.pgh.pa.us 764 : 5 : (*nSoftEdges)++;
765 : 5 : return true;
766 : : }
767 : : }
768 : : }
769 : : }
770 : :
771 : : /*
772 : : * No conflict detected here.
773 : : */
774 : 55 : return false;
775 : : }
776 : :
777 : :
778 : : /*
779 : : * ExpandConstraints -- expand a list of constraints into a set of
780 : : * specific new orderings for affected wait queues
781 : : *
782 : : * Input is a list of soft edges to be reversed. The output is a list
783 : : * of nWaitOrders WAIT_ORDER structs in waitOrders[], with PGPROC array
784 : : * workspace in waitOrderProcs[].
785 : : *
786 : : * Returns true if able to build an ordering that satisfies all the
787 : : * constraints, false if not (there are contradictory constraints).
788 : : */
789 : : static bool
790 : 33 : ExpandConstraints(EDGE *constraints,
791 : : int nConstraints)
792 : : {
793 : 33 : int nWaitOrderProcs = 0;
794 : : int i,
795 : : j;
796 : :
797 : 33 : nWaitOrders = 0;
798 : :
799 : : /*
800 : : * Scan constraint list backwards. This is because the last-added
801 : : * constraint is the only one that could fail, and so we want to test it
802 : : * for inconsistency first.
803 : : */
8934 bruce@momjian.us 804 [ + + ]: 36 : for (i = nConstraints; --i >= 0;)
805 : : {
3499 rhaas@postgresql.org 806 : 3 : LOCK *lock = constraints[i].lock;
807 : :
808 : : /* Did we already make a list for this lock? */
8934 bruce@momjian.us 809 [ - + ]: 3 : for (j = nWaitOrders; --j >= 0;)
810 : : {
8990 tgl@sss.pgh.pa.us 811 [ # # ]:UBC 0 : if (waitOrders[j].lock == lock)
812 : 0 : break;
813 : : }
8990 tgl@sss.pgh.pa.us 814 [ - + ]:CBC 3 : if (j >= 0)
8990 tgl@sss.pgh.pa.us 815 :UBC 0 : continue;
816 : : /* No, so allocate a new list */
8990 tgl@sss.pgh.pa.us 817 :CBC 3 : waitOrders[nWaitOrders].lock = lock;
818 : 3 : waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
962 andres@anarazel.de 819 : 3 : waitOrders[nWaitOrders].nProcs = dclist_count(&lock->waitProcs);
820 : 3 : nWaitOrderProcs += dclist_count(&lock->waitProcs);
1243 rhaas@postgresql.org 821 [ - + ]: 3 : Assert(nWaitOrderProcs <= MaxBackends);
822 : :
823 : : /*
824 : : * Do the topo sort. TopoSort need not examine constraints after this
825 : : * one, since they must be for different locks.
826 : : */
8934 bruce@momjian.us 827 [ - + ]: 3 : if (!TopoSort(lock, constraints, i + 1,
8990 tgl@sss.pgh.pa.us 828 : 3 : waitOrders[nWaitOrders].procs))
8990 tgl@sss.pgh.pa.us 829 :UBC 0 : return false;
8990 tgl@sss.pgh.pa.us 830 :CBC 3 : nWaitOrders++;
831 : : }
832 : 33 : return true;
833 : : }
834 : :
835 : :
836 : : /*
837 : : * TopoSort -- topological sort of a wait queue
838 : : *
839 : : * Generate a re-ordering of a lock's wait queue that satisfies given
840 : : * constraints about certain procs preceding others. (Each such constraint
841 : : * is a fact of a partial ordering.) Minimize rearrangement of the queue
842 : : * not needed to achieve the partial ordering.
843 : : *
844 : : * This is a lot simpler and slower than, for example, the topological sort
845 : : * algorithm shown in Knuth's Volume 1. However, Knuth's method doesn't
846 : : * try to minimize the damage to the existing order. In practice we are
847 : : * not likely to be working with more than a few constraints, so the apparent
848 : : * slowness of the algorithm won't really matter.
849 : : *
850 : : * The initial queue ordering is taken directly from the lock's wait queue.
851 : : * The output is an array of PGPROC pointers, of length equal to the lock's
852 : : * wait queue length (the caller is responsible for providing this space).
853 : : * The partial order is specified by an array of EDGE structs. Each EDGE
854 : : * is one that we need to reverse, therefore the "waiter" must appear before
855 : : * the "blocker" in the output array. The EDGE array may well contain
856 : : * edges associated with other locks; these should be ignored.
857 : : *
858 : : * Returns true if able to build an ordering that satisfies all the
859 : : * constraints, false if not (there are contradictory constraints).
860 : : */
861 : : static bool
862 : 3 : TopoSort(LOCK *lock,
863 : : EDGE *constraints,
864 : : int nConstraints,
865 : : PGPROC **ordering) /* output argument */
866 : : {
962 andres@anarazel.de 867 : 3 : dclist_head *waitQueue = &lock->waitProcs;
868 : 3 : int queue_size = dclist_count(waitQueue);
869 : : PGPROC *proc;
870 : : int i,
871 : : j,
872 : : jj,
873 : : k,
874 : : kk,
875 : : last;
876 : : dlist_iter proc_iter;
877 : :
878 : : /* First, fill topoProcs[] array with the procs in their current order */
879 : 3 : i = 0;
880 [ + - + + ]: 12 : dclist_foreach(proc_iter, waitQueue)
881 : : {
882 : 9 : proc = dlist_container(PGPROC, links, proc_iter.cur);
883 : 9 : topoProcs[i++] = proc;
884 : : }
885 [ - + ]: 3 : Assert(i == queue_size);
886 : :
887 : : /*
888 : : * Scan the constraints, and for each proc in the array, generate a count
889 : : * of the number of constraints that say it must be before something else,
890 : : * plus a list of the constraints that say it must be after something
891 : : * else. The count for the j'th proc is stored in beforeConstraints[j],
892 : : * and the head of its list in afterConstraints[j]. Each constraint
893 : : * stores its list link in constraints[i].link (note any constraint will
894 : : * be in just one list). The array index for the before-proc of the i'th
895 : : * constraint is remembered in constraints[i].pred.
896 : : *
897 : : * Note that it's not necessarily the case that every constraint affects
898 : : * this particular wait queue. Prior to group locking, a process could be
899 : : * waiting for at most one lock. But a lock group can be waiting for
900 : : * zero, one, or multiple locks. Since topoProcs[] is an array of the
901 : : * processes actually waiting, while constraints[] is an array of group
902 : : * leaders, we've got to scan through topoProcs[] for each constraint,
903 : : * checking whether both a waiter and a blocker for that group are
904 : : * present. If so, the constraint is relevant to this wait queue; if not,
905 : : * it isn't.
906 : : */
8990 tgl@sss.pgh.pa.us 907 [ + - + + : 6 : MemSet(beforeConstraints, 0, queue_size * sizeof(int));
+ - + - +
+ ]
908 [ + - + + : 6 : MemSet(afterConstraints, 0, queue_size * sizeof(int));
+ - + - +
+ ]
909 [ + + ]: 6 : for (i = 0; i < nConstraints; i++)
910 : : {
911 : : /*
912 : : * Find a representative process that is on the lock queue and part of
913 : : * the waiting lock group. This may or may not be the leader, which
914 : : * may or may not be waiting at all. If there are any other processes
915 : : * in the same lock group on the queue, set their number of
916 : : * beforeConstraints to -1 to indicate that they should be emitted
917 : : * with their groupmates rather than considered separately.
918 : : *
919 : : * In this loop and the similar one just below, it's critical that we
920 : : * consistently select the same representative member of any one lock
921 : : * group, so that all the constraints are associated with the same
922 : : * proc, and the -1's are only associated with not-representative
923 : : * members. We select the last one in the topoProcs array.
924 : : */
925 : 3 : proc = constraints[i].waiter;
3499 rhaas@postgresql.org 926 [ - + ]: 3 : Assert(proc != NULL);
927 : 3 : jj = -1;
8934 bruce@momjian.us 928 [ + + ]: 12 : for (j = queue_size; --j >= 0;)
929 : : {
3499 rhaas@postgresql.org 930 : 9 : PGPROC *waiter = topoProcs[j];
931 : :
932 [ + + + + ]: 9 : if (waiter == proc || waiter->lockGroupLeader == proc)
933 : : {
934 [ - + ]: 5 : Assert(waiter->waitLock == lock);
935 [ + + ]: 5 : if (jj == -1)
936 : 3 : jj = j;
937 : : else
938 : : {
939 [ - + ]: 2 : Assert(beforeConstraints[j] <= 0);
940 : 2 : beforeConstraints[j] = -1;
941 : : }
942 : : }
943 : : }
944 : :
945 : : /* If no matching waiter, constraint is not relevant to this lock. */
946 [ - + ]: 3 : if (jj < 0)
3499 rhaas@postgresql.org 947 :UBC 0 : continue;
948 : :
949 : : /*
950 : : * Similarly, find a representative process that is on the lock queue
951 : : * and waiting for the blocking lock group. Again, this could be the
952 : : * leader but does not need to be.
953 : : */
8990 tgl@sss.pgh.pa.us 954 :CBC 3 : proc = constraints[i].blocker;
3499 rhaas@postgresql.org 955 [ - + ]: 3 : Assert(proc != NULL);
956 : 3 : kk = -1;
8934 bruce@momjian.us 957 [ + + ]: 12 : for (k = queue_size; --k >= 0;)
958 : : {
3499 rhaas@postgresql.org 959 : 9 : PGPROC *blocker = topoProcs[k];
960 : :
961 [ + + + + ]: 9 : if (blocker == proc || blocker->lockGroupLeader == proc)
962 : : {
963 [ - + ]: 3 : Assert(blocker->waitLock == lock);
964 [ + - ]: 3 : if (kk == -1)
965 : 3 : kk = k;
966 : : else
967 : : {
3499 rhaas@postgresql.org 968 [ # # ]:UBC 0 : Assert(beforeConstraints[k] <= 0);
969 : 0 : beforeConstraints[k] = -1;
970 : : }
971 : : }
972 : : }
973 : :
974 : : /* If no matching blocker, constraint is not relevant to this lock. */
3499 rhaas@postgresql.org 975 [ - + ]:CBC 3 : if (kk < 0)
3499 rhaas@postgresql.org 976 :UBC 0 : continue;
977 : :
2231 tgl@sss.pgh.pa.us 978 [ - + ]:CBC 3 : Assert(beforeConstraints[jj] >= 0);
3499 rhaas@postgresql.org 979 : 3 : beforeConstraints[jj]++; /* waiter must come before */
980 : : /* add this constraint to list of after-constraints for blocker */
981 : 3 : constraints[i].pred = jj;
982 : 3 : constraints[i].link = afterConstraints[kk];
983 : 3 : afterConstraints[kk] = i + 1;
984 : : }
985 : :
986 : : /*--------------------
987 : : * Now scan the topoProcs array backwards. At each step, output the
988 : : * last proc that has no remaining before-constraints plus any other
989 : : * members of the same lock group; then decrease the beforeConstraints
990 : : * count of each of the procs it was constrained against.
991 : : * i = index of ordering[] entry we want to output this time
992 : : * j = search index for topoProcs[]
993 : : * k = temp for scanning constraint list for proc j
994 : : * last = last non-null index in topoProcs (avoid redundant searches)
995 : : *--------------------
996 : : */
8934 bruce@momjian.us 997 : 3 : last = queue_size - 1;
3499 rhaas@postgresql.org 998 [ + + ]: 10 : for (i = queue_size - 1; i >= 0;)
999 : : {
1000 : : int c;
1001 : 7 : int nmatches = 0;
1002 : :
1003 : : /* Find next candidate to output */
8990 tgl@sss.pgh.pa.us 1004 [ - + ]: 7 : while (topoProcs[last] == NULL)
8990 tgl@sss.pgh.pa.us 1005 :UBC 0 : last--;
8990 tgl@sss.pgh.pa.us 1006 [ + - ]:CBC 14 : for (j = last; j >= 0; j--)
1007 : : {
1008 [ + + + + ]: 14 : if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
1009 : 7 : break;
1010 : : }
1011 : :
1012 : : /* If no available candidate, topological sort fails */
1013 [ - + ]: 7 : if (j < 0)
8990 tgl@sss.pgh.pa.us 1014 :UBC 0 : return false;
1015 : :
1016 : : /*
1017 : : * Output everything in the lock group. There's no point in
1018 : : * outputting an ordering where members of the same lock group are not
1019 : : * consecutive on the wait queue: if some other waiter is between two
1020 : : * requests that belong to the same group, then either it conflicts
1021 : : * with both of them and is certainly not a solution; or it conflicts
1022 : : * with at most one of them and is thus isomorphic to an ordering
1023 : : * where the group members are consecutive.
1024 : : */
3499 rhaas@postgresql.org 1025 :CBC 7 : proc = topoProcs[j];
1026 [ + + ]: 7 : if (proc->lockGroupLeader != NULL)
1027 : 2 : proc = proc->lockGroupLeader;
1028 [ - + ]: 7 : Assert(proc != NULL);
1029 [ + + ]: 28 : for (c = 0; c <= last; ++c)
1030 : : {
1031 [ + + + + ]: 21 : if (topoProcs[c] == proc || (topoProcs[c] != NULL &&
2999 tgl@sss.pgh.pa.us 1032 [ + + ]: 11 : topoProcs[c]->lockGroupLeader == proc))
1033 : : {
3499 rhaas@postgresql.org 1034 : 9 : ordering[i - nmatches] = topoProcs[c];
1035 : 9 : topoProcs[c] = NULL;
1036 : 9 : ++nmatches;
1037 : : }
1038 : : }
1039 [ - + ]: 7 : Assert(nmatches > 0);
1040 : 7 : i -= nmatches;
1041 : :
1042 : : /* Update beforeConstraints counts of its predecessors */
8934 bruce@momjian.us 1043 [ + + ]: 10 : for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
1044 : 3 : beforeConstraints[constraints[k - 1].pred]--;
1045 : : }
1046 : :
1047 : : /* Done */
8990 tgl@sss.pgh.pa.us 1048 : 3 : return true;
1049 : : }
1050 : :
1051 : : #ifdef DEBUG_DEADLOCK
1052 : : static void
1053 : : PrintLockQueue(LOCK *lock, const char *info)
1054 : : {
1055 : : dclist_head *waitQueue = &lock->waitProcs;
1056 : : dlist_iter proc_iter;
1057 : :
1058 : : printf("%s lock %p queue ", info, lock);
1059 : :
1060 : : dclist_foreach(proc_iter, waitQueue)
1061 : : {
1062 : : PGPROC *proc = dlist_container(PGPROC, links, proc_iter.cur);
1063 : :
1064 : : printf(" %d", proc->pid);
1065 : : }
1066 : : printf("\n");
1067 : : fflush(stdout);
1068 : : }
1069 : : #endif
1070 : :
1071 : : /*
1072 : : * Report a detected deadlock, with available details.
1073 : : */
1074 : : void
8269 1075 : 6 : DeadLockReport(void)
1076 : : {
1077 : : StringInfoData clientbuf; /* errdetail for client */
1078 : : StringInfoData logbuf; /* errdetail for server log */
1079 : : StringInfoData locktagbuf;
1080 : : int i;
1081 : :
6375 1082 : 6 : initStringInfo(&clientbuf);
1083 : 6 : initStringInfo(&logbuf);
6378 1084 : 6 : initStringInfo(&locktagbuf);
1085 : :
1086 : : /* Generate the "waits for" lines sent to the client */
8269 1087 [ + + ]: 25 : for (i = 0; i < nDeadlockDetails; i++)
1088 : : {
8069 bruce@momjian.us 1089 : 19 : DEADLOCK_INFO *info = &deadlockDetails[i];
1090 : : int nextpid;
1091 : :
1092 : : /* The last proc waits for the first one... */
1093 [ + + ]: 19 : if (i < nDeadlockDetails - 1)
8269 tgl@sss.pgh.pa.us 1094 : 13 : nextpid = info[1].pid;
1095 : : else
1096 : 6 : nextpid = deadlockDetails[0].pid;
1097 : :
1098 : : /* reset locktagbuf to hold next object description */
6378 1099 : 19 : resetStringInfo(&locktagbuf);
1100 : :
1101 : 19 : DescribeLockTag(&locktagbuf, &info->locktag);
1102 : :
1103 [ + + ]: 19 : if (i > 0)
6375 1104 : 13 : appendStringInfoChar(&clientbuf, '\n');
1105 : :
1106 : 38 : appendStringInfo(&clientbuf,
2999 1107 : 19 : _("Process %d waits for %s on %s; blocked by process %d."),
1108 : : info->pid,
7211 1109 : 19 : GetLockmodeName(info->locktag.locktag_lockmethodid,
1110 : : info->lockmode),
1111 : : locktagbuf.data,
1112 : : nextpid);
1113 : : }
1114 : :
1115 : : /* Duplicate all the above for the server ... */
2237 drowley@postgresql.o 1116 : 6 : appendBinaryStringInfo(&logbuf, clientbuf.data, clientbuf.len);
1117 : :
1118 : : /* ... and add info about query strings */
6375 tgl@sss.pgh.pa.us 1119 [ + + ]: 25 : for (i = 0; i < nDeadlockDetails; i++)
1120 : : {
1121 : 19 : DEADLOCK_INFO *info = &deadlockDetails[i];
1122 : :
1123 : 19 : appendStringInfoChar(&logbuf, '\n');
1124 : :
1125 : 19 : appendStringInfo(&logbuf,
6378 1126 : 19 : _("Process %d: %s"),
1127 : : info->pid,
1128 : : pgstat_get_backend_current_activity(info->pid, false));
1129 : : }
1130 : :
4972 magnus@hagander.net 1131 : 6 : pgstat_report_deadlock();
1132 : :
8080 tgl@sss.pgh.pa.us 1133 [ + - ]: 6 : ereport(ERROR,
1134 : : (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
1135 : : errmsg("deadlock detected"),
1136 : : errdetail_internal("%s", clientbuf.data),
1137 : : errdetail_log("%s", logbuf.data),
1138 : : errhint("See server log for query details.")));
1139 : : }
1140 : :
1141 : : /*
1142 : : * RememberSimpleDeadLock: set up info for DeadLockReport when ProcSleep
1143 : : * detects a trivial (two-way) deadlock. proc1 wants to block for lockmode
1144 : : * on lock, but proc2 is already waiting and would be blocked by proc1.
1145 : : */
1146 : : void
8269 1147 : 1 : RememberSimpleDeadLock(PGPROC *proc1,
1148 : : LOCKMODE lockmode,
1149 : : LOCK *lock,
1150 : : PGPROC *proc2)
1151 : : {
8069 bruce@momjian.us 1152 : 1 : DEADLOCK_INFO *info = &deadlockDetails[0];
1153 : :
8269 tgl@sss.pgh.pa.us 1154 : 1 : info->locktag = lock->tag;
1155 : 1 : info->lockmode = lockmode;
1156 : 1 : info->pid = proc1->pid;
1157 : 1 : info++;
1158 : 1 : info->locktag = proc2->waitLock->tag;
1159 : 1 : info->lockmode = proc2->waitLockMode;
1160 : 1 : info->pid = proc2->pid;
1161 : 1 : nDeadlockDetails = 2;
1162 : 1 : }
|