aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/postmaster/pgstat.c76
-rw-r--r--src/backend/storage/lmgr/deadlock.c39
-rw-r--r--src/include/pgstat.h3
3 files changed, 103 insertions, 15 deletions
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index eaf0491933d..8259b759e71 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -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
* ------------------------------------------------------------
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index cad85e9d8a0..e1a66456f54 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -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)));
}
/*
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 95589eb51e7..49fd149d55c 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -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);