Hello hackers. This patch adds the backend's statement_timeout value to pg_stat_activity.
This would provide some insights on clients that are disabling a default statement timeout or overriding it through a pgbouncer, messing with other sessions. pg_stat_activity seemed like the best place to have this information. Regards, Anthonin
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index d5a45f996d..2109595c40 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -861,6 +861,15 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser </para></entry> </row> + <row> + <entry role="catalog_table_entry"><para role="column_definition"> + <structfield>statement_timeout</structfield> <type>integer</type> + </para> + <para> + The current backend's <structfield>statement_timeout</structfield>. + </para></entry> + </row> + <row> <entry role="catalog_table_entry"><para role="column_definition"> <structfield>wait_event_type</structfield> <type>text</type> diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 574cbc2e44..7c24ef92bf 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -860,6 +860,7 @@ CREATE VIEW pg_stat_activity AS S.xact_start, S.query_start, S.state_change, + S.statement_timeout, S.wait_event_type, S.wait_event, S.state, diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index f0f2e07655..0a2ba26070 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -1054,6 +1054,16 @@ assign_application_name(const char *newval, void *extra) pgstat_report_appname(newval); } +/* + * GUC assign_hook for statement_timeout + */ +void +assign_statement_timeout(int newval, void *extra) +{ + /* Update the pg_stat_activity view */ + pgstat_report_statement_timeout(newval); +} + /* * GUC check_hook for cluster_name */ diff --git a/src/backend/utils/activity/backend_status.c b/src/backend/utils/activity/backend_status.c index 608d01ea0d..5d94cb0ba6 100644 --- a/src/backend/utils/activity/backend_status.c +++ b/src/backend/utils/activity/backend_status.c @@ -336,6 +336,7 @@ pgstat_bestart(void) lbeentry.st_activity_start_timestamp = 0; lbeentry.st_state_start_timestamp = 0; lbeentry.st_xact_start_timestamp = 0; + lbeentry.st_statement_timeout = 0; lbeentry.st_databaseid = MyDatabaseId; /* We have userid for client-backends, wal-sender and bgworker processes */ @@ -446,9 +447,11 @@ pgstat_bestart(void) PGSTAT_END_WRITE_ACTIVITY(vbeentry); - /* Update app name to current GUC setting */ - if (application_name) + /* Update app name and statement timeout to current GUC setting */ + if (application_name) { pgstat_report_appname(application_name); + pgstat_report_statement_timeout(StatementTimeout); + } } /* @@ -692,6 +695,33 @@ pgstat_report_appname(const char *appname) PGSTAT_END_WRITE_ACTIVITY(beentry); } +/* ---------- + * pgstat_report_statement_timeout() - + * + * Called to update statement_timeout. + * ---------- + */ +void +pgstat_report_statement_timeout(int statement_timeout) +{ + volatile PgBackendStatus *beentry = MyBEEntry; + + if (!beentry) + return; + + /* + * Update my status entry, following the protocol of bumping + * st_changecount before and after. We use a volatile pointer here to + * ensure the compiler doesn't try to get cute. + */ + PGSTAT_BEGIN_WRITE_ACTIVITY(beentry); + + beentry->st_statement_timeout = statement_timeout; + + PGSTAT_END_WRITE_ACTIVITY(beentry); +} + + /* * Report current transaction start timestamp as the specified value. * Zero means there is no active transaction. diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index eec9f3cf9b..de72c2c1d0 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -303,7 +303,7 @@ pg_stat_get_progress_info(PG_FUNCTION_ARGS) Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_ACTIVITY_COLS 30 +#define PG_STAT_GET_ACTIVITY_COLS 31 int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); @@ -612,6 +612,12 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[29] = true; else values[29] = UInt64GetDatum(beentry->st_query_id); + /* Only report statement_timeout for client backend */ + if (beentry->st_backendType == B_BACKEND) { + values[30] = Int32GetDatum(beentry->st_statement_timeout); + } else { + nulls[30] = true; + } } else { @@ -640,6 +646,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[27] = true; nulls[28] = true; nulls[29] = true; + nulls[30] = true; } tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c index 8062589efd..5dd33f583f 100644 --- a/src/backend/utils/misc/guc_tables.c +++ b/src/backend/utils/misc/guc_tables.c @@ -2478,7 +2478,7 @@ struct config_int ConfigureNamesInt[] = }, &StatementTimeout, 0, 0, INT_MAX, - NULL, NULL, NULL + NULL, assign_statement_timeout, NULL }, { diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f9f2642201..05719ccfd9 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5432,9 +5432,9 @@ proname => 'pg_stat_get_activity', prorows => '100', proisstrict => 'f', proretset => 't', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => 'int4', - proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,text,numeric,text,bool,text,bool,int4,int8}', - proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', - proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid,query_id}', + proallargtypes => '{int4,oid,int4,oid,text,text,text,text,text,timestamptz,timestamptz,timestamptz,timestamptz,inet,text,int4,xid,xid,text,bool,text,text,int4,text,numeric,text,bool,text,bool,int4,int8,int4}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{pid,datid,pid,usesysid,application_name,state,query,wait_event_type,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,backend_type,ssl,sslversion,sslcipher,sslbits,ssl_client_dn,ssl_client_serial,ssl_issuer_dn,gss_auth,gss_princ,gss_enc,leader_pid,query_id,statement_timeout}', prosrc => 'pg_stat_get_activity' }, { oid => '3318', descr => 'statistics: information about progress of backends running maintenance command', diff --git a/src/include/utils/backend_status.h b/src/include/utils/backend_status.h index f7bd83113a..64d73b8fda 100644 --- a/src/include/utils/backend_status.h +++ b/src/include/utils/backend_status.h @@ -145,6 +145,9 @@ typedef struct PgBackendStatus /* application name; MUST be null-terminated */ char *st_appname; + /* current statement_timeout */ + int st_statement_timeout; + /* * Current command string; MUST be null-terminated. Note that this string * possibly is truncated in the middle of a multi-byte character. As @@ -319,6 +322,7 @@ extern void pgstat_report_activity(BackendState state, const char *cmd_str); extern void pgstat_report_query_id(uint64 query_id, bool force); extern void pgstat_report_tempfile(size_t filesize); extern void pgstat_report_appname(const char *appname); +extern void pgstat_report_statement_timeout(int statement_timeout); extern void pgstat_report_xact_timestamp(TimestampTz tstamp); extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser); extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer, diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index aeb3663071..117f986cdd 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -77,6 +77,7 @@ extern void assign_log_timezone(const char *newval, void *extra); extern const char *show_log_timezone(void); extern bool check_maintenance_io_concurrency(int *newval, void **extra, GucSource source); +extern void assign_statement_timeout(int newval, void *extra); extern void assign_maintenance_io_concurrency(int newval, void *extra); extern bool check_max_connections(int *newval, void **extra, GucSource source); extern bool check_max_wal_senders(int *newval, void **extra, GucSource source); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index ab1aebfde4..d8c0cf4eae 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1751,6 +1751,7 @@ pg_stat_activity| SELECT s.datid, s.xact_start, s.query_start, s.state_change, + s.statement_timeout, s.wait_event_type, s.wait_event, s.state, @@ -1759,7 +1760,7 @@ pg_stat_activity| SELECT s.datid, s.query_id, s.query, s.backend_type - FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id) + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id, statement_timeout) LEFT JOIN pg_database d ON ((s.datid = d.oid))) LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_all_indexes| SELECT c.oid AS relid, @@ -1875,7 +1876,7 @@ pg_stat_gssapi| SELECT pid, gss_auth AS gss_authenticated, gss_princ AS principal, gss_enc AS encrypted - FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id) + FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id, statement_timeout) WHERE (client_port IS NOT NULL); pg_stat_io| SELECT backend_type, io_object, @@ -2069,7 +2070,7 @@ pg_stat_replication| SELECT s.pid, w.sync_priority, w.sync_state, w.reply_time - FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id) + FROM ((pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id, statement_timeout) JOIN pg_stat_get_wal_senders() w(pid, state, sent_lsn, write_lsn, flush_lsn, replay_lsn, write_lag, flush_lag, replay_lag, sync_priority, sync_state, reply_time) ON ((s.pid = w.pid))) LEFT JOIN pg_authid u ON ((s.usesysid = u.oid))); pg_stat_replication_slots| SELECT s.slot_name, @@ -2103,7 +2104,7 @@ pg_stat_ssl| SELECT pid, ssl_client_dn AS client_dn, ssl_client_serial AS client_serial, ssl_issuer_dn AS issuer_dn - FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id) + FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, wait_event_type, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, backend_type, ssl, sslversion, sslcipher, sslbits, ssl_client_dn, ssl_client_serial, ssl_issuer_dn, gss_auth, gss_princ, gss_enc, leader_pid, query_id, statement_timeout) WHERE (client_port IS NOT NULL); pg_stat_subscription| SELECT su.oid AS subid, su.subname, diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index 5f1821938d..ebd8a9f976 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -1126,6 +1126,21 @@ SELECT pg_stat_get_subscription_stats(NULL); (1 row) +-- Test statement_timeout report +set statement_timeout = '1d'; +SELECT statement_timeout FROM pg_stat_activity WHERE pid=pg_backend_pid(); + statement_timeout +------------------- + 86400000 +(1 row) + +set statement_timeout = 0; +SELECT statement_timeout FROM pg_stat_activity WHERE pid=pg_backend_pid(); + statement_timeout +------------------- + 0 +(1 row) + -- Test that the following operations are tracked in pg_stat_io: -- - reads of target blocks into shared buffers -- - writes of shared buffers to permanent storage diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index 58db803ed6..0734cb2870 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -535,6 +535,11 @@ SET enable_seqscan TO on; SELECT pg_stat_get_replication_slot(NULL); SELECT pg_stat_get_subscription_stats(NULL); +-- Test statement_timeout report +set statement_timeout = '1d'; +SELECT statement_timeout FROM pg_stat_activity WHERE pid=pg_backend_pid(); +set statement_timeout = 0; +SELECT statement_timeout FROM pg_stat_activity WHERE pid=pg_backend_pid(); -- Test that the following operations are tracked in pg_stat_io: -- - reads of target blocks into shared buffers