00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "postgres.h"
00027
00028 #include "miscadmin.h"
00029 #include "pg_trace.h"
00030 #include "pgstat.h"
00031 #include "storage/lmgr.h"
00032 #include "storage/proc.h"
00033 #include "utils/memutils.h"
00034
00035
00036
00037 typedef struct
00038 {
00039 PGPROC *waiter;
00040 PGPROC *blocker;
00041 int pred;
00042 int link;
00043 } EDGE;
00044
00045
00046 typedef struct
00047 {
00048 LOCK *lock;
00049 PGPROC **procs;
00050 int nProcs;
00051 } WAIT_ORDER;
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 typedef struct
00062 {
00063 LOCKTAG locktag;
00064 LOCKMODE lockmode;
00065 int pid;
00066 } DEADLOCK_INFO;
00067
00068
00069 static bool DeadLockCheckRecurse(PGPROC *proc);
00070 static int TestConfiguration(PGPROC *startProc);
00071 static bool FindLockCycle(PGPROC *checkProc,
00072 EDGE *softEdges, int *nSoftEdges);
00073 static bool FindLockCycleRecurse(PGPROC *checkProc, int depth,
00074 EDGE *softEdges, int *nSoftEdges);
00075 static bool ExpandConstraints(EDGE *constraints, int nConstraints);
00076 static bool TopoSort(LOCK *lock, EDGE *constraints, int nConstraints,
00077 PGPROC **ordering);
00078
00079 #ifdef DEBUG_DEADLOCK
00080 static void PrintLockQueue(LOCK *lock, const char *info);
00081 #endif
00082
00083
00084
00085
00086
00087
00088
00089 static PGPROC **visitedProcs;
00090 static int nVisitedProcs;
00091
00092
00093 static PGPROC **topoProcs;
00094 static int *beforeConstraints;
00095 static int *afterConstraints;
00096
00097
00098 static WAIT_ORDER *waitOrders;
00099 static int nWaitOrders;
00100 static PGPROC **waitOrderProcs;
00101
00102
00103 static EDGE *curConstraints;
00104 static int nCurConstraints;
00105 static int maxCurConstraints;
00106
00107
00108 static EDGE *possibleConstraints;
00109 static int nPossibleConstraints;
00110 static int maxPossibleConstraints;
00111 static DEADLOCK_INFO *deadlockDetails;
00112 static int nDeadlockDetails;
00113
00114
00115 static PGPROC *blocking_autovacuum_proc = NULL;
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 void
00130 InitDeadLockChecking(void)
00131 {
00132 MemoryContext oldcxt;
00133
00134
00135 oldcxt = MemoryContextSwitchTo(TopMemoryContext);
00136
00137
00138
00139
00140
00141 visitedProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
00142 deadlockDetails = (DEADLOCK_INFO *) palloc(MaxBackends * sizeof(DEADLOCK_INFO));
00143
00144
00145
00146
00147
00148 topoProcs = visitedProcs;
00149 beforeConstraints = (int *) palloc(MaxBackends * sizeof(int));
00150 afterConstraints = (int *) palloc(MaxBackends * sizeof(int));
00151
00152
00153
00154
00155
00156
00157
00158 waitOrders = (WAIT_ORDER *)
00159 palloc((MaxBackends / 2) * sizeof(WAIT_ORDER));
00160 waitOrderProcs = (PGPROC **) palloc(MaxBackends * sizeof(PGPROC *));
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170 maxCurConstraints = MaxBackends;
00171 curConstraints = (EDGE *) palloc(maxCurConstraints * sizeof(EDGE));
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 maxPossibleConstraints = MaxBackends * 4;
00182 possibleConstraints =
00183 (EDGE *) palloc(maxPossibleConstraints * sizeof(EDGE));
00184
00185 MemoryContextSwitchTo(oldcxt);
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 DeadLockState
00204 DeadLockCheck(PGPROC *proc)
00205 {
00206 int i,
00207 j;
00208
00209
00210 nCurConstraints = 0;
00211 nPossibleConstraints = 0;
00212 nWaitOrders = 0;
00213
00214
00215 blocking_autovacuum_proc = NULL;
00216
00217
00218 if (DeadLockCheckRecurse(proc))
00219 {
00220
00221
00222
00223
00224 int nSoftEdges;
00225
00226 TRACE_POSTGRESQL_DEADLOCK_FOUND();
00227
00228 nWaitOrders = 0;
00229 if (!FindLockCycle(proc, possibleConstraints, &nSoftEdges))
00230 elog(FATAL, "deadlock seems to have disappeared");
00231
00232 return DS_HARD_DEADLOCK;
00233 }
00234
00235
00236 for (i = 0; i < nWaitOrders; i++)
00237 {
00238 LOCK *lock = waitOrders[i].lock;
00239 PGPROC **procs = waitOrders[i].procs;
00240 int nProcs = waitOrders[i].nProcs;
00241 PROC_QUEUE *waitQueue = &(lock->waitProcs);
00242
00243 Assert(nProcs == waitQueue->size);
00244
00245 #ifdef DEBUG_DEADLOCK
00246 PrintLockQueue(lock, "DeadLockCheck:");
00247 #endif
00248
00249
00250 ProcQueueInit(waitQueue);
00251 for (j = 0; j < nProcs; j++)
00252 {
00253 SHMQueueInsertBefore(&(waitQueue->links), &(procs[j]->links));
00254 waitQueue->size++;
00255 }
00256
00257 #ifdef DEBUG_DEADLOCK
00258 PrintLockQueue(lock, "rearranged to:");
00259 #endif
00260
00261
00262 ProcLockWakeup(GetLocksMethodTable(lock), lock);
00263 }
00264
00265
00266 if (nWaitOrders > 0)
00267 return DS_SOFT_DEADLOCK;
00268 else if (blocking_autovacuum_proc != NULL)
00269 return DS_BLOCKED_BY_AUTOVACUUM;
00270 else
00271 return DS_NO_DEADLOCK;
00272 }
00273
00274
00275
00276
00277
00278
00279 PGPROC *
00280 GetBlockingAutoVacuumPgproc(void)
00281 {
00282 PGPROC *ptr;
00283
00284 ptr = blocking_autovacuum_proc;
00285 blocking_autovacuum_proc = NULL;
00286
00287 return ptr;
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301 static bool
00302 DeadLockCheckRecurse(PGPROC *proc)
00303 {
00304 int nEdges;
00305 int oldPossibleConstraints;
00306 bool savedList;
00307 int i;
00308
00309 nEdges = TestConfiguration(proc);
00310 if (nEdges < 0)
00311 return true;
00312 if (nEdges == 0)
00313 return false;
00314 if (nCurConstraints >= maxCurConstraints)
00315 return true;
00316 oldPossibleConstraints = nPossibleConstraints;
00317 if (nPossibleConstraints + nEdges + MaxBackends <= maxPossibleConstraints)
00318 {
00319
00320 nPossibleConstraints += nEdges;
00321 savedList = true;
00322 }
00323 else
00324 {
00325
00326 savedList = false;
00327 }
00328
00329
00330
00331
00332 for (i = 0; i < nEdges; i++)
00333 {
00334 if (!savedList && i > 0)
00335 {
00336
00337 if (nEdges != TestConfiguration(proc))
00338 elog(FATAL, "inconsistent results during deadlock check");
00339 }
00340 curConstraints[nCurConstraints] =
00341 possibleConstraints[oldPossibleConstraints + i];
00342 nCurConstraints++;
00343 if (!DeadLockCheckRecurse(proc))
00344 return false;
00345
00346 nCurConstraints--;
00347 }
00348 nPossibleConstraints = oldPossibleConstraints;
00349 return true;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367 static int
00368 TestConfiguration(PGPROC *startProc)
00369 {
00370 int softFound = 0;
00371 EDGE *softEdges = possibleConstraints + nPossibleConstraints;
00372 int nSoftEdges;
00373 int i;
00374
00375
00376
00377
00378 if (nPossibleConstraints + MaxBackends > maxPossibleConstraints)
00379 return -1;
00380
00381
00382
00383
00384
00385 if (!ExpandConstraints(curConstraints, nCurConstraints))
00386 return -1;
00387
00388
00389
00390
00391
00392
00393 for (i = 0; i < nCurConstraints; i++)
00394 {
00395 if (FindLockCycle(curConstraints[i].waiter, softEdges, &nSoftEdges))
00396 {
00397 if (nSoftEdges == 0)
00398 return -1;
00399 softFound = nSoftEdges;
00400 }
00401 if (FindLockCycle(curConstraints[i].blocker, softEdges, &nSoftEdges))
00402 {
00403 if (nSoftEdges == 0)
00404 return -1;
00405 softFound = nSoftEdges;
00406 }
00407 }
00408 if (FindLockCycle(startProc, softEdges, &nSoftEdges))
00409 {
00410 if (nSoftEdges == 0)
00411 return -1;
00412 softFound = nSoftEdges;
00413 }
00414 return softFound;
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 static bool
00436 FindLockCycle(PGPROC *checkProc,
00437 EDGE *softEdges,
00438 int *nSoftEdges)
00439 {
00440 nVisitedProcs = 0;
00441 nDeadlockDetails = 0;
00442 *nSoftEdges = 0;
00443 return FindLockCycleRecurse(checkProc, 0, softEdges, nSoftEdges);
00444 }
00445
00446 static bool
00447 FindLockCycleRecurse(PGPROC *checkProc,
00448 int depth,
00449 EDGE *softEdges,
00450 int *nSoftEdges)
00451 {
00452 PGPROC *proc;
00453 PGXACT *pgxact;
00454 LOCK *lock;
00455 PROCLOCK *proclock;
00456 SHM_QUEUE *procLocks;
00457 LockMethod lockMethodTable;
00458 PROC_QUEUE *waitQueue;
00459 int queue_size;
00460 int conflictMask;
00461 int i;
00462 int numLockModes,
00463 lm;
00464
00465
00466
00467
00468 for (i = 0; i < nVisitedProcs; i++)
00469 {
00470 if (visitedProcs[i] == checkProc)
00471 {
00472
00473 if (i == 0)
00474 {
00475
00476
00477
00478
00479 Assert(depth <= MaxBackends);
00480 nDeadlockDetails = depth;
00481
00482 return true;
00483 }
00484
00485
00486
00487
00488
00489 return false;
00490 }
00491 }
00492
00493 Assert(nVisitedProcs < MaxBackends);
00494 visitedProcs[nVisitedProcs++] = checkProc;
00495
00496
00497
00498
00499 if (checkProc->links.next == NULL)
00500 return false;
00501 lock = checkProc->waitLock;
00502 if (lock == NULL)
00503 return false;
00504 lockMethodTable = GetLocksMethodTable(lock);
00505 numLockModes = lockMethodTable->numLockModes;
00506 conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
00507
00508
00509
00510
00511
00512 procLocks = &(lock->procLocks);
00513
00514 proclock = (PROCLOCK *) SHMQueueNext(procLocks, procLocks,
00515 offsetof(PROCLOCK, lockLink));
00516
00517 while (proclock)
00518 {
00519 proc = proclock->tag.myProc;
00520 pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
00521
00522
00523 if (proc != checkProc)
00524 {
00525 for (lm = 1; lm <= numLockModes; lm++)
00526 {
00527 if ((proclock->holdMask & LOCKBIT_ON(lm)) &&
00528 (conflictMask & LOCKBIT_ON(lm)))
00529 {
00530
00531 if (FindLockCycleRecurse(proc, depth + 1,
00532 softEdges, nSoftEdges))
00533 {
00534
00535 DEADLOCK_INFO *info = &deadlockDetails[depth];
00536
00537 info->locktag = lock->tag;
00538 info->lockmode = checkProc->waitLockMode;
00539 info->pid = checkProc->pid;
00540
00541 return true;
00542 }
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566 if (checkProc == MyProc &&
00567 pgxact->vacuumFlags & PROC_IS_AUTOVACUUM)
00568 blocking_autovacuum_proc = proc;
00569
00570
00571 break;
00572 }
00573 }
00574 }
00575
00576 proclock = (PROCLOCK *) SHMQueueNext(procLocks, &proclock->lockLink,
00577 offsetof(PROCLOCK, lockLink));
00578 }
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 for (i = 0; i < nWaitOrders; i++)
00590 {
00591 if (waitOrders[i].lock == lock)
00592 break;
00593 }
00594
00595 if (i < nWaitOrders)
00596 {
00597
00598 PGPROC **procs = waitOrders[i].procs;
00599
00600 queue_size = waitOrders[i].nProcs;
00601
00602 for (i = 0; i < queue_size; i++)
00603 {
00604 proc = procs[i];
00605
00606
00607 if (proc == checkProc)
00608 break;
00609
00610
00611 if (((1 << proc->waitLockMode) & conflictMask) != 0)
00612 {
00613
00614 if (FindLockCycleRecurse(proc, depth + 1,
00615 softEdges, nSoftEdges))
00616 {
00617
00618 DEADLOCK_INFO *info = &deadlockDetails[depth];
00619
00620 info->locktag = lock->tag;
00621 info->lockmode = checkProc->waitLockMode;
00622 info->pid = checkProc->pid;
00623
00624
00625
00626
00627 Assert(*nSoftEdges < MaxBackends);
00628 softEdges[*nSoftEdges].waiter = checkProc;
00629 softEdges[*nSoftEdges].blocker = proc;
00630 (*nSoftEdges)++;
00631 return true;
00632 }
00633 }
00634 }
00635 }
00636 else
00637 {
00638
00639 waitQueue = &(lock->waitProcs);
00640 queue_size = waitQueue->size;
00641
00642 proc = (PGPROC *) waitQueue->links.next;
00643
00644 while (queue_size-- > 0)
00645 {
00646
00647 if (proc == checkProc)
00648 break;
00649
00650
00651 if (((1 << proc->waitLockMode) & conflictMask) != 0)
00652 {
00653
00654 if (FindLockCycleRecurse(proc, depth + 1,
00655 softEdges, nSoftEdges))
00656 {
00657
00658 DEADLOCK_INFO *info = &deadlockDetails[depth];
00659
00660 info->locktag = lock->tag;
00661 info->lockmode = checkProc->waitLockMode;
00662 info->pid = checkProc->pid;
00663
00664
00665
00666
00667 Assert(*nSoftEdges < MaxBackends);
00668 softEdges[*nSoftEdges].waiter = checkProc;
00669 softEdges[*nSoftEdges].blocker = proc;
00670 (*nSoftEdges)++;
00671 return true;
00672 }
00673 }
00674
00675 proc = (PGPROC *) proc->links.next;
00676 }
00677 }
00678
00679
00680
00681
00682 return false;
00683 }
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697 static bool
00698 ExpandConstraints(EDGE *constraints,
00699 int nConstraints)
00700 {
00701 int nWaitOrderProcs = 0;
00702 int i,
00703 j;
00704
00705 nWaitOrders = 0;
00706
00707
00708
00709
00710
00711
00712 for (i = nConstraints; --i >= 0;)
00713 {
00714 PGPROC *proc = constraints[i].waiter;
00715 LOCK *lock = proc->waitLock;
00716
00717
00718 for (j = nWaitOrders; --j >= 0;)
00719 {
00720 if (waitOrders[j].lock == lock)
00721 break;
00722 }
00723 if (j >= 0)
00724 continue;
00725
00726 waitOrders[nWaitOrders].lock = lock;
00727 waitOrders[nWaitOrders].procs = waitOrderProcs + nWaitOrderProcs;
00728 waitOrders[nWaitOrders].nProcs = lock->waitProcs.size;
00729 nWaitOrderProcs += lock->waitProcs.size;
00730 Assert(nWaitOrderProcs <= MaxBackends);
00731
00732
00733
00734
00735
00736 if (!TopoSort(lock, constraints, i + 1,
00737 waitOrders[nWaitOrders].procs))
00738 return false;
00739 nWaitOrders++;
00740 }
00741 return true;
00742 }
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770 static bool
00771 TopoSort(LOCK *lock,
00772 EDGE *constraints,
00773 int nConstraints,
00774 PGPROC **ordering)
00775 {
00776 PROC_QUEUE *waitQueue = &(lock->waitProcs);
00777 int queue_size = waitQueue->size;
00778 PGPROC *proc;
00779 int i,
00780 j,
00781 k,
00782 last;
00783
00784
00785 proc = (PGPROC *) waitQueue->links.next;
00786 for (i = 0; i < queue_size; i++)
00787 {
00788 topoProcs[i] = proc;
00789 proc = (PGPROC *) proc->links.next;
00790 }
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 MemSet(beforeConstraints, 0, queue_size * sizeof(int));
00803 MemSet(afterConstraints, 0, queue_size * sizeof(int));
00804 for (i = 0; i < nConstraints; i++)
00805 {
00806 proc = constraints[i].waiter;
00807
00808 if (proc->waitLock != lock)
00809 continue;
00810
00811 for (j = queue_size; --j >= 0;)
00812 {
00813 if (topoProcs[j] == proc)
00814 break;
00815 }
00816 Assert(j >= 0);
00817
00818 proc = constraints[i].blocker;
00819 for (k = queue_size; --k >= 0;)
00820 {
00821 if (topoProcs[k] == proc)
00822 break;
00823 }
00824 Assert(k >= 0);
00825 beforeConstraints[j]++;
00826
00827 constraints[i].pred = j;
00828 constraints[i].link = afterConstraints[k];
00829 afterConstraints[k] = i + 1;
00830 }
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 last = queue_size - 1;
00843 for (i = queue_size; --i >= 0;)
00844 {
00845
00846 while (topoProcs[last] == NULL)
00847 last--;
00848 for (j = last; j >= 0; j--)
00849 {
00850 if (topoProcs[j] != NULL && beforeConstraints[j] == 0)
00851 break;
00852 }
00853
00854 if (j < 0)
00855 return false;
00856
00857 ordering[i] = topoProcs[j];
00858 topoProcs[j] = NULL;
00859
00860 for (k = afterConstraints[j]; k > 0; k = constraints[k - 1].link)
00861 beforeConstraints[constraints[k - 1].pred]--;
00862 }
00863
00864
00865 return true;
00866 }
00867
00868 #ifdef DEBUG_DEADLOCK
00869 static void
00870 PrintLockQueue(LOCK *lock, const char *info)
00871 {
00872 PROC_QUEUE *waitQueue = &(lock->waitProcs);
00873 int queue_size = waitQueue->size;
00874 PGPROC *proc;
00875 int i;
00876
00877 printf("%s lock %p queue ", info, lock);
00878 proc = (PGPROC *) waitQueue->links.next;
00879 for (i = 0; i < queue_size; i++)
00880 {
00881 printf(" %d", proc->pid);
00882 proc = (PGPROC *) proc->links.next;
00883 }
00884 printf("\n");
00885 fflush(stdout);
00886 }
00887 #endif
00888
00889
00890
00891
00892 void
00893 DeadLockReport(void)
00894 {
00895 StringInfoData clientbuf;
00896 StringInfoData logbuf;
00897 StringInfoData locktagbuf;
00898 int i;
00899
00900 initStringInfo(&clientbuf);
00901 initStringInfo(&logbuf);
00902 initStringInfo(&locktagbuf);
00903
00904
00905 for (i = 0; i < nDeadlockDetails; i++)
00906 {
00907 DEADLOCK_INFO *info = &deadlockDetails[i];
00908 int nextpid;
00909
00910
00911 if (i < nDeadlockDetails - 1)
00912 nextpid = info[1].pid;
00913 else
00914 nextpid = deadlockDetails[0].pid;
00915
00916
00917 resetStringInfo(&locktagbuf);
00918
00919 DescribeLockTag(&locktagbuf, &info->locktag);
00920
00921 if (i > 0)
00922 appendStringInfoChar(&clientbuf, '\n');
00923
00924 appendStringInfo(&clientbuf,
00925 _("Process %d waits for %s on %s; blocked by process %d."),
00926 info->pid,
00927 GetLockmodeName(info->locktag.locktag_lockmethodid,
00928 info->lockmode),
00929 locktagbuf.data,
00930 nextpid);
00931 }
00932
00933
00934 appendStringInfoString(&logbuf, clientbuf.data);
00935
00936
00937 for (i = 0; i < nDeadlockDetails; i++)
00938 {
00939 DEADLOCK_INFO *info = &deadlockDetails[i];
00940
00941 appendStringInfoChar(&logbuf, '\n');
00942
00943 appendStringInfo(&logbuf,
00944 _("Process %d: %s"),
00945 info->pid,
00946 pgstat_get_backend_current_activity(info->pid, false));
00947 }
00948
00949 pgstat_report_deadlock();
00950
00951 ereport(ERROR,
00952 (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
00953 errmsg("deadlock detected"),
00954 errdetail_internal("%s", clientbuf.data),
00955 errdetail_log("%s", logbuf.data),
00956 errhint("See server log for query details.")));
00957 }
00958
00959
00960
00961
00962
00963
00964 void
00965 RememberSimpleDeadLock(PGPROC *proc1,
00966 LOCKMODE lockmode,
00967 LOCK *lock,
00968 PGPROC *proc2)
00969 {
00970 DEADLOCK_INFO *info = &deadlockDetails[0];
00971
00972 info->locktag = lock->tag;
00973 info->lockmode = lockmode;
00974 info->pid = proc1->pid;
00975 info++;
00976 info->locktag = proc2->waitLock->tag;
00977 info->lockmode = proc2->waitLockMode;
00978 info->pid = proc2->pid;
00979 nDeadlockDetails = 2;
00980 }