diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 21275f9d5f0ac22dbad301dbab8134e9925f46b6..41600f8bb428730024cd636d704feae26455ca2b 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.36 2006/06/29 20:00:08 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/monitoring.sgml,v 1.37 2006/08/19 01:36:23 tgl Exp $ --> <chapter id="monitoring"> <title>Monitoring Database Activity</title> @@ -245,7 +245,8 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re <row> <entry><structname>pg_stat_activity</></entry> <entry>One row per server process, showing database OID, database name, - process <acronym>ID</>, user OID, user name, current query, time at + process <acronym>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: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re </entry> </row> + <row> + <entry><literal><function>pg_stat_get_backend_waiting</function>(<type>integer</type>)</literal></entry> + <entry><type>boolean</type></entry> + <entry> + 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 + <varname>stats_command_string</varname> is on) + </entry> + </row> + <row> <entry><literal><function>pg_stat_get_backend_activity_start</function>(<type>integer</type>)</literal></entry> <entry><type>timestamp with time zone</type></entry> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index e88626aa5970ff53bde0b1eb38e53b74f3a9d15e..b0c690c596d6a1f26d2985abfd634bedfdd3d536 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 c971c06704a3e897de7a3ab9f1d4c98c17748d7d..a37d9fa349fd282bc253d0e9f3a2bb26bda84a18 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 10049d593a0772f5ab06e60ce7b3a820782a45db..7fe011a2baf0bba541f524927aa3dea1f84c3405 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 4bb37bccd7cfc0eab0d6c93070e99d82e96a02fc..d14a4c8e2f6628f754720b867a67c8176a78528d 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 6728188e501ec154b813e6c05c3a061d7f4c4d28..b27acf5f8599ba5574b1c7642f3edd8ec352a153 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 93a1e0c1ed079b7c89756a99377f51f03da28c2b..b066babc14de2bf9591d25acbfce49b8c5c6b748 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 72e542f16c8a7bdeb19e4e761564d764d6a41385..35614eaa2d29078c47e2e59b9470dd08c7965d32 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 0815196bbceb31da390313ca40cc67eaad7841b2..2e1d491edd6bfdc922ea15c28318bde8dac70d98 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;