diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index eaf0491933dd568feda5c79b2c0467955c756f4c..8259b759e71b57214c0bd8b9e82f3e9cdb4b5828 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 cad85e9d8a057b5a2e3ef763a93cb9edb47e7427..e1a66456f5429ea572167b21f661933e5e957969 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 95589eb51e72b147866f95a30ad241b1a5924eb7..49fd149d55cbad82a130e031a19c4354443d07d9 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);