Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4b7ae4a

Browse files
committed
Report the current queries of all backends involved in a deadlock
(if they'd be visible to the current user in pg_stat_activity). This might look like it's subject to race conditions, but it's actually pretty safe because at the time DeadLockReport() is constructing the report, we haven't yet aborted our transaction and so we can expect that everyone else involved in the deadlock is still blocked on some lock. (There are corner cases where that might not be true, such as a statement timeout triggering in another backend before we finish reporting; but at worst we'd report a misleading activity string, so it seems acceptable considering the usefulness of reporting the queries.) Original patch by Itagaki Takahiro, heavily modified by me.
1 parent df812e9 commit 4b7ae4a

File tree

3 files changed

+103
-15
lines changed

3 files changed

+103
-15
lines changed

src/backend/postmaster/pgstat.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
1515
*
16-
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.169 2008/01/01 19:45:51 momjian Exp $
16+
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.170 2008/03/21 21:08:31 tgl Exp $
1717
* ----------
1818
*/
1919
#include "postgres.h"
@@ -2036,6 +2036,80 @@ pgstat_read_current_status(void)
20362036
}
20372037

20382038

2039+
/* ----------
2040+
* pgstat_get_backend_current_activity() -
2041+
*
2042+
* Return a string representing the current activity of the backend with
2043+
* the specified PID. This looks directly at the BackendStatusArray,
2044+
* and so will provide current information regardless of the age of our
2045+
* transaction's snapshot of the status array.
2046+
*
2047+
* It is the caller's responsibility to invoke this only for backends whose
2048+
* state is expected to remain stable while the result is in use. The
2049+
* only current use is in deadlock reporting, where we can expect that
2050+
* the target backend is blocked on a lock. (There are corner cases
2051+
* where the target's wait could get aborted while we are looking at it,
2052+
* but the very worst consequence is to return a pointer to a string
2053+
* that's been changed, so we won't worry too much.)
2054+
*
2055+
* Note: return strings for special cases match pg_stat_get_backend_activity.
2056+
* ----------
2057+
*/
2058+
const char *
2059+
pgstat_get_backend_current_activity(int pid)
2060+
{
2061+
PgBackendStatus *beentry;
2062+
int i;
2063+
2064+
beentry = BackendStatusArray;
2065+
for (i = 1; i <= MaxBackends; i++)
2066+
{
2067+
/*
2068+
* Although we expect the target backend's entry to be stable, that
2069+
* doesn't imply that anyone else's is. To avoid identifying the
2070+
* wrong backend, while we check for a match to the desired PID we
2071+
* must follow the protocol of retrying if st_changecount changes
2072+
* while we examine the entry, or if it's odd. (This might be
2073+
* unnecessary, since fetching or storing an int is almost certainly
2074+
* atomic, but let's play it safe.) We use a volatile pointer here
2075+
* to ensure the compiler doesn't try to get cute.
2076+
*/
2077+
volatile PgBackendStatus *vbeentry = beentry;
2078+
bool found;
2079+
2080+
for (;;)
2081+
{
2082+
int save_changecount = vbeentry->st_changecount;
2083+
2084+
found = (vbeentry->st_procpid == pid);
2085+
2086+
if (save_changecount == vbeentry->st_changecount &&
2087+
(save_changecount & 1) == 0)
2088+
break;
2089+
2090+
/* Make sure we can break out of loop if stuck... */
2091+
CHECK_FOR_INTERRUPTS();
2092+
}
2093+
2094+
if (found)
2095+
{
2096+
/* Now it is safe to use the non-volatile pointer */
2097+
if (!superuser() && beentry->st_userid != GetUserId())
2098+
return "<insufficient privilege>";
2099+
else if (*(beentry->st_activity) == '\0')
2100+
return "<command string not enabled>";
2101+
else
2102+
return beentry->st_activity;
2103+
}
2104+
2105+
beentry++;
2106+
}
2107+
2108+
/* If we get here, caller is in error ... */
2109+
return "<backend information not available>";
2110+
}
2111+
2112+
20392113
/* ------------------------------------------------------------
20402114
* Local support functions follow
20412115
* ------------------------------------------------------------

src/backend/storage/lmgr/deadlock.c

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*
1313
*
1414
* IDENTIFICATION
15-
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.51 2008/01/01 19:45:52 momjian Exp $
15+
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.52 2008/03/21 21:08:31 tgl Exp $
1616
*
1717
* Interface:
1818
*
@@ -26,6 +26,7 @@
2626
#include "postgres.h"
2727

2828
#include "miscadmin.h"
29+
#include "pgstat.h"
2930
#include "storage/lmgr.h"
3031
#include "storage/proc.h"
3132
#include "utils/memutils.h"
@@ -878,12 +879,14 @@ PrintLockQueue(LOCK *lock, const char *info)
878879
void
879880
DeadLockReport(void)
880881
{
881-
StringInfoData buf;
882-
StringInfoData buf2;
882+
StringInfoData detailbuf;
883+
StringInfoData contextbuf;
884+
StringInfoData locktagbuf;
883885
int i;
884886

885-
initStringInfo(&buf);
886-
initStringInfo(&buf2);
887+
initStringInfo(&detailbuf);
888+
initStringInfo(&contextbuf);
889+
initStringInfo(&locktagbuf);
887890

888891
for (i = 0; i < nDeadlockDetails; i++)
889892
{
@@ -896,26 +899,36 @@ DeadLockReport(void)
896899
else
897900
nextpid = deadlockDetails[0].pid;
898901

899-
if (i > 0)
900-
appendStringInfoChar(&buf, '\n');
902+
/* reset locktagbuf to hold next object description */
903+
resetStringInfo(&locktagbuf);
901904

902-
/* reset buf2 to hold next object description */
903-
resetStringInfo(&buf2);
905+
DescribeLockTag(&locktagbuf, &info->locktag);
904906

905-
DescribeLockTag(&buf2, &info->locktag);
907+
if (i > 0)
908+
appendStringInfoChar(&detailbuf, '\n');
906909

907-
appendStringInfo(&buf,
910+
appendStringInfo(&detailbuf,
908911
_("Process %d waits for %s on %s; blocked by process %d."),
909912
info->pid,
910913
GetLockmodeName(info->locktag.locktag_lockmethodid,
911914
info->lockmode),
912-
buf2.data,
915+
locktagbuf.data,
913916
nextpid);
917+
918+
if (i > 0)
919+
appendStringInfoChar(&contextbuf, '\n');
920+
921+
appendStringInfo(&contextbuf,
922+
_("Process %d: %s"),
923+
info->pid,
924+
pgstat_get_backend_current_activity(info->pid));
914925
}
926+
915927
ereport(ERROR,
916928
(errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
917929
errmsg("deadlock detected"),
918-
errdetail("%s", buf.data)));
930+
errdetail("%s", detailbuf.data),
931+
errcontext("%s", contextbuf.data)));
919932
}
920933

921934
/*

src/include/pgstat.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
77
*
8-
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.71 2008/01/01 19:45:56 momjian Exp $
8+
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.72 2008/03/21 21:08:31 tgl Exp $
99
* ----------
1010
*/
1111
#ifndef PGSTAT_H
@@ -507,6 +507,7 @@ extern void pgstat_bestart(void);
507507
extern void pgstat_report_activity(const char *what);
508508
extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
509509
extern void pgstat_report_waiting(bool waiting);
510+
extern const char *pgstat_get_backend_current_activity(int pid);
510511

511512
extern void pgstat_initstats(Relation rel);
512513

0 commit comments

Comments
 (0)