diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 21275f9d5f..41600f8bb4 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1,4 +1,4 @@ - + Monitoring Database Activity @@ -245,7 +245,8 @@ postgres: user database host pg_stat_activity One row per server process, showing database OID, database name, - process ID, user OID, user name, current query, time at + process ID, user OID, user name, current query, query's + waiting status, time at which the current query began execution, time at which the process was started, and client's address and port number. The columns that report data on the current query are available unless the @@ -649,6 +650,17 @@ postgres: user database host + + pg_stat_get_backend_waiting(integer) + boolean + + True if the given server process is waiting for a lock, + but only if the current user is a superuser or the same user as that of + the session being queried (and + stats_command_string is on) + + + pg_stat_get_backend_activity_start(integer) timestamp with time zone diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index e88626aa59..b0c690c596 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -3,7 +3,7 @@ * * Copyright (c) 1996-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.29 2006/07/27 08:30:41 petere Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.30 2006/08/19 01:36:24 tgl Exp $ */ CREATE VIEW pg_roles AS @@ -332,7 +332,8 @@ CREATE VIEW pg_stat_activity AS pg_stat_get_backend_pid(S.backendid) AS procpid, pg_stat_get_backend_userid(S.backendid) AS usesysid, U.rolname AS usename, - pg_stat_get_backend_activity(S.backendid) AS current_query, + pg_stat_get_backend_activity(S.backendid) AS current_query, + pg_stat_get_backend_waiting(S.backendid) AS waiting, pg_stat_get_backend_activity_start(S.backendid) AS query_start, pg_stat_get_backend_start(S.backendid) AS backend_start, pg_stat_get_backend_client_addr(S.backendid) AS client_addr, diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index c971c06704..a37d9fa349 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -13,7 +13,7 @@ * * Copyright (c) 2001-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.136 2006/07/16 18:17:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/pgstat.c,v 1.137 2006/08/19 01:36:24 tgl Exp $ * ---------- */ #include "postgres.h" @@ -1358,6 +1358,7 @@ pgstat_bestart(void) beentry->st_databaseid = MyDatabaseId; beentry->st_userid = userid; beentry->st_clientaddr = clientaddr; + beentry->st_waiting = false; beentry->st_activity[0] = '\0'; /* Also make sure the last byte in the string area is always 0 */ beentry->st_activity[PGBE_ACTIVITY_SIZE - 1] = '\0'; @@ -1445,6 +1446,31 @@ pgstat_report_activity(const char *cmd_str) } +/* ---------- + * pgstat_report_waiting() - + * + * Called from lock manager to report beginning or end of a lock wait. + * ---------- + */ +void +pgstat_report_waiting(bool waiting) +{ + volatile PgBackendStatus *beentry; + + if (!pgstat_collect_querystring) + return; + + /* + * Since this is a single-byte field in a struct that only this process + * may modify, there seems no need to bother with the st_changecount + * protocol. The update must appear atomic in any case. + */ + beentry = MyBEEntry; + + beentry->st_waiting = waiting; +} + + /* ---------- * pgstat_read_current_status() - * diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 10049d593a..7fe011a2ba 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.170 2006/07/31 20:09:05 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.171 2006/08/19 01:36:28 tgl Exp $ * * NOTES * A lock table is a shared memory hash table. When @@ -36,6 +36,7 @@ #include "access/twophase.h" #include "access/twophase_rmgr.h" #include "miscadmin.h" +#include "pgstat.h" #include "storage/lmgr.h" #include "utils/memutils.h" #include "utils/ps_status.h" @@ -1114,6 +1115,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) LOCK_PRINT("WaitOnLock: sleeping on lock", locallock->lock, locallock->tag.mode); + /* Report change to waiting status */ if (update_process_title) { old_status = get_ps_display(&len); @@ -1123,7 +1125,8 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting" */ } - + pgstat_report_waiting(true); + awaitedLock = locallock; awaitedOwner = owner; @@ -1160,11 +1163,13 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) awaitedLock = NULL; + /* Report change to non-waiting status */ if (update_process_title) { set_ps_display(new_status, false); pfree(new_status); } + pgstat_report_waiting(false); LOCK_PRINT("WaitOnLock: wakeup on lock", locallock->lock, locallock->tag.mode); diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 4bb37bccd7..d14a4c8e2f 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.32 2006/07/14 14:52:24 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pgstatfuncs.c,v 1.33 2006/08/19 01:36:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,6 +42,7 @@ extern Datum pg_stat_get_backend_pid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_dbid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_userid(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_activity(PG_FUNCTION_ARGS); +extern Datum pg_stat_get_backend_waiting(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_start(PG_FUNCTION_ARGS); extern Datum pg_stat_get_backend_client_addr(PG_FUNCTION_ARGS); @@ -377,6 +378,25 @@ pg_stat_get_backend_activity(PG_FUNCTION_ARGS) } +Datum +pg_stat_get_backend_waiting(PG_FUNCTION_ARGS) +{ + int32 beid = PG_GETARG_INT32(0); + bool result; + PgBackendStatus *beentry; + + if ((beentry = pgstat_fetch_stat_beentry(beid)) == NULL) + PG_RETURN_NULL(); + + if (!superuser() && beentry->st_userid != GetUserId()) + PG_RETURN_NULL(); + + result = beentry->st_waiting; + + PG_RETURN_BOOL(result); +} + + Datum pg_stat_get_backend_activity_start(PG_FUNCTION_ARGS) { diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 6728188e50..b27acf5f85 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.350 2006/08/17 23:04:08 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.351 2006/08/19 01:36:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200608171 +#define CATALOG_VERSION_NO 200608181 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 93a1e0c1ed..b066babc14 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.421 2006/08/17 23:04:10 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.422 2006/08/19 01:36:33 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -2898,6 +2898,8 @@ DATA(insert OID = 1939 ( pg_stat_get_backend_userid PGNSP PGUID 12 f f t f s 1 DESCR("Statistics: User ID of backend"); DATA(insert OID = 1940 ( pg_stat_get_backend_activity PGNSP PGUID 12 f f t f s 1 25 "23" _null_ _null_ _null_ pg_stat_get_backend_activity - _null_ )); DESCR("Statistics: Current query of backend"); +DATA(insert OID = 2853 ( pg_stat_get_backend_waiting PGNSP PGUID 12 f f t f s 1 16 "23" _null_ _null_ _null_ pg_stat_get_backend_waiting - _null_ )); +DESCR("Statistics: Is backend currently waiting for a lock"); DATA(insert OID = 2094 ( pg_stat_get_backend_activity_start PGNSP PGUID 12 f f t f s 1 1184 "23" _null_ _null_ _null_ pg_stat_get_backend_activity_start - _null_)); DESCR("Statistics: Start time for current query of backend"); DATA(insert OID = 1391 ( pg_stat_get_backend_start PGNSP PGUID 12 f f t f s 1 1184 "23" _null_ _null_ _null_ pg_stat_get_backend_start - _null_)); diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 72e542f16c..35614eaa2d 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -5,7 +5,7 @@ * * Copyright (c) 2001-2006, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.48 2006/06/29 20:00:08 tgl Exp $ + * $PostgreSQL: pgsql/src/include/pgstat.h,v 1.49 2006/08/19 01:36:34 tgl Exp $ * ---------- */ #ifndef PGSTAT_H @@ -334,6 +334,9 @@ typedef struct PgBackendStatus Oid st_userid; SockAddr st_clientaddr; + /* Is backend currently waiting on an lmgr lock? */ + bool st_waiting; + /* current command string; MUST be null-terminated */ char st_activity[PGBE_ACTIVITY_SIZE]; } PgBackendStatus; @@ -387,6 +390,7 @@ extern void pgstat_report_analyze(Oid tableoid, bool shared, extern void pgstat_bestart(void); extern void pgstat_report_activity(const char *what); +extern void pgstat_report_waiting(bool waiting); extern void pgstat_initstats(PgStat_Info *stats, Relation rel); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 0815196bbc..2e1d491edd 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1287,7 +1287,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name); pg_settings | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, unit text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text); pg_shadow | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin; - pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid)); + pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_waiting(s.backendid) AS waiting, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid)); pg_stat_all_indexes | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])); pg_stat_all_tables | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname; pg_stat_database | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit FROM pg_database d;