Commit 4b7ae4af authored by Tom Lane's avatar Tom Lane

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.
parent df812e91
......@@ -13,7 +13,7 @@
*
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.169 2008/01/01 19:45:51 momjian Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.170 2008/03/21 21:08:31 tgl Exp $
* ----------
*/
#include "postgres.h"
......@@ -2036,6 +2036,80 @@ pgstat_read_current_status(void)
}
/* ----------
* pgstat_get_backend_current_activity() -
*
* Return a string representing the current activity of the backend with
* the specified PID. This looks directly at the BackendStatusArray,
* and so will provide current information regardless of the age of our
* transaction's snapshot of the status array.
*
* It is the caller's responsibility to invoke this only for backends whose
* state is expected to remain stable while the result is in use. The
* only current use is in deadlock reporting, where we can expect that
* the target backend is blocked on a lock. (There are corner cases
* where the target's wait could get aborted while we are looking at it,
* but the very worst consequence is to return a pointer to a string
* that's been changed, so we won't worry too much.)
*
* Note: return strings for special cases match pg_stat_get_backend_activity.
* ----------
*/
const char *
pgstat_get_backend_current_activity(int pid)
{
PgBackendStatus *beentry;
int i;
beentry = BackendStatusArray;
for (i = 1; i <= MaxBackends; i++)
{
/*
* Although we expect the target backend's entry to be stable, that
* doesn't imply that anyone else's is. To avoid identifying the
* wrong backend, while we check for a match to the desired PID we
* must follow the protocol of retrying if st_changecount changes
* while we examine the entry, or if it's odd. (This might be
* unnecessary, since fetching or storing an int is almost certainly
* atomic, but let's play it safe.) We use a volatile pointer here
* to ensure the compiler doesn't try to get cute.
*/
volatile PgBackendStatus *vbeentry = beentry;
bool found;
for (;;)
{
int save_changecount = vbeentry->st_changecount;
found = (vbeentry->st_procpid == pid);
if (save_changecount == vbeentry->st_changecount &&
(save_changecount & 1) == 0)
break;
/* Make sure we can break out of loop if stuck... */
CHECK_FOR_INTERRUPTS();
}
if (found)
{
/* Now it is safe to use the non-volatile pointer */
if (!superuser() && beentry->st_userid != GetUserId())
return "<insufficient privilege>";
else if (*(beentry->st_activity) == '\0')
return "<command string not enabled>";
else
return beentry->st_activity;
}
beentry++;
}
/* If we get here, caller is in error ... */
return "<backend information not available>";
}
/* ------------------------------------------------------------
* Local support functions follow
* ------------------------------------------------------------
......
......@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.51 2008/01/01 19:45:52 momjian Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.52 2008/03/21 21:08:31 tgl Exp $
*
* Interface:
*
......@@ -26,6 +26,7 @@
#include "postgres.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "utils/memutils.h"
......@@ -878,12 +879,14 @@ PrintLockQueue(LOCK *lock, const char *info)
void
DeadLockReport(void)
{
StringInfoData buf;
StringInfoData buf2;
StringInfoData detailbuf;
StringInfoData contextbuf;
StringInfoData locktagbuf;
int i;
initStringInfo(&buf);
initStringInfo(&buf2);
initStringInfo(&detailbuf);
initStringInfo(&contextbuf);
initStringInfo(&locktagbuf);
for (i = 0; i < nDeadlockDetails; i++)
{
......@@ -896,26 +899,36 @@ DeadLockReport(void)
else
nextpid = deadlockDetails[0].pid;
if (i > 0)
appendStringInfoChar(&buf, '\n');
/* reset locktagbuf to hold next object description */
resetStringInfo(&locktagbuf);
/* reset buf2 to hold next object description */
resetStringInfo(&buf2);
DescribeLockTag(&locktagbuf, &info->locktag);
DescribeLockTag(&buf2, &info->locktag);
if (i > 0)
appendStringInfoChar(&detailbuf, '\n');
appendStringInfo(&buf,
appendStringInfo(&detailbuf,
_("Process %d waits for %s on %s; blocked by process %d."),
info->pid,
GetLockmodeName(info->locktag.locktag_lockmethodid,
info->lockmode),
buf2.data,
locktagbuf.data,
nextpid);
if (i > 0)
appendStringInfoChar(&contextbuf, '\n');
appendStringInfo(&contextbuf,
_("Process %d: %s"),
info->pid,
pgstat_get_backend_current_activity(info->pid));
}
ereport(ERROR,
(errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
errmsg("deadlock detected"),
errdetail("%s", buf.data)));
errdetail("%s", detailbuf.data),
errcontext("%s", contextbuf.data)));
}
/*
......
......@@ -5,7 +5,7 @@
*
* Copyright (c) 2001-2008, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.71 2008/01/01 19:45:56 momjian Exp $
* $PostgreSQL: pgsql/src/include/pgstat.h,v 1.72 2008/03/21 21:08:31 tgl Exp $
* ----------
*/
#ifndef PGSTAT_H
......@@ -507,6 +507,7 @@ extern void pgstat_bestart(void);
extern void pgstat_report_activity(const char *what);
extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
extern void pgstat_report_waiting(bool waiting);
extern const char *pgstat_get_backend_current_activity(int pid);
extern void pgstat_initstats(Relation rel);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment