From 32b0910efdeeefb75ab3aa74100f446302a68a2e Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 1 Jul 2026 15:56:11 +0900 Subject: [PATCH v3] Add pg_stat_kind_info view Blah.. --- src/include/catalog/pg_proc.dat | 10 ++ src/backend/catalog/system_views.sql | 12 ++ src/backend/utils/activity/Makefile | 1 + src/backend/utils/activity/meson.build | 1 + src/backend/utils/activity/pgstat_kind.c | 85 +++++++++++ .../test_custom_stats/t/001_custom_stats.pl | 14 +- src/test/regress/expected/rules.out | 9 ++ src/test/regress/expected/stats.out | 23 +++ src/test/regress/expected/sysviews.out | 7 + src/test/regress/sql/stats.sql | 7 + src/test/regress/sql/sysviews.sql | 3 + doc/src/sgml/monitoring.sgml | 142 ++++++++++++++++++ 12 files changed, 313 insertions(+), 1 deletion(-) create mode 100644 src/backend/utils/activity/pgstat_kind.c diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 73bb7fbb4304..9571f033aa85 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6078,6 +6078,16 @@ proargnames => '{backend_pid,backend_type,object,context,reads,read_bytes,read_time,writes,write_bytes,write_time,writebacks,writeback_time,extends,extend_bytes,extend_time,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}', prosrc => 'pg_stat_get_backend_io' }, +{ oid => '8683', + descr => 'statistics: information about loaded statistics kinds', + proname => 'pg_stat_get_kind_info', prorows => '20', proretset => 't', + provolatile => 'v', proparallel => 'r', prorettype => 'record', + proargtypes => '', + proallargtypes => '{int4,text,bool,bool,bool,bool,int8,int8}', + proargmodes => '{o,o,o,o,o,o,o,o}', + proargnames => '{id,name,builtin,fixed_amount,accessed_across_databases,write_to_file,entry_size,entry_count}', + prosrc => 'pg_stat_get_kind_info' }, + { oid => '1136', descr => 'statistics: information about WAL activity', proname => 'pg_stat_get_wal', proisstrict => 'f', provolatile => 's', proparallel => 'r', prorettype => 'record', proargtypes => '', diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 8f129baec906..6a9d94d78f34 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1282,6 +1282,18 @@ SELECT b.stats_reset FROM pg_stat_get_io() b; +CREATE VIEW pg_stat_kind_info AS + SELECT + k.id, + k.name, + k.builtin, + k.fixed_amount, + k.accessed_across_databases, + k.write_to_file, + k.entry_size, + k.entry_count + FROM pg_stat_get_kind_info() k; + CREATE VIEW pg_stat_wal AS SELECT w.wal_records, diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile index ca3ef89bf599..5fed953c28a7 100644 --- a/src/backend/utils/activity/Makefile +++ b/src/backend/utils/activity/Makefile @@ -26,6 +26,7 @@ OBJS = \ pgstat_database.o \ pgstat_function.o \ pgstat_io.o \ + pgstat_kind.o \ pgstat_lock.o \ pgstat_relation.o \ pgstat_replslot.o \ diff --git a/src/backend/utils/activity/meson.build b/src/backend/utils/activity/meson.build index 1aa7ece52908..470b5dac402b 100644 --- a/src/backend/utils/activity/meson.build +++ b/src/backend/utils/activity/meson.build @@ -11,6 +11,7 @@ backend_sources += files( 'pgstat_database.c', 'pgstat_function.c', 'pgstat_io.c', + 'pgstat_kind.c', 'pgstat_lock.c', 'pgstat_relation.c', 'pgstat_replslot.c', diff --git a/src/backend/utils/activity/pgstat_kind.c b/src/backend/utils/activity/pgstat_kind.c new file mode 100644 index 000000000000..bc43553170b5 --- /dev/null +++ b/src/backend/utils/activity/pgstat_kind.c @@ -0,0 +1,85 @@ +/*------------------------------------------------------------------------- + * + * pgstat_kind.c + * Functions related to statistics kinds. + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/activity/pgstat_kind.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "fmgr.h" +#include "funcapi.h" +#include "utils/builtins.h" +#include "utils/fmgrprotos.h" +#include "utils/pgstat_internal.h" +#include "utils/pgstat_kind.h" +#include "utils/tuplestore.h" + + +/* + * pg_stat_get_kind_info + * + * Get information about the statistics kinds loaded into the system. + */ +Datum +pg_stat_get_kind_info(PG_FUNCTION_ARGS) +{ +#define PG_STAT_KIND_INFO_COLS 8 + ReturnSetInfo *rsinfo; + + InitMaterializedSRF(fcinfo, 0); + rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + + for (int kind = PGSTAT_KIND_MIN; kind <= PGSTAT_KIND_MAX; kind++) + { + Datum values[PG_STAT_KIND_INFO_COLS] = {0}; + bool nulls[PG_STAT_KIND_INFO_COLS] = {0}; + const PgStat_KindInfo *info; + + info = pgstat_get_kind_info(kind); + if (info == NULL) + continue; + + values[0] = Int32GetDatum(kind); + values[1] = CStringGetTextDatum(info->name); + + values[2] = BoolGetDatum(pgstat_is_kind_builtin(kind)); + values[3] = BoolGetDatum(info->fixed_amount); + values[4] = BoolGetDatum(info->accessed_across_databases); + values[5] = BoolGetDatum(info->write_to_file); + + /* + * Built-in fixed-amount kinds store their single entry in + * PgStat_ShmemControl, so shared_size is unused and left zero in + * their PgStat_KindInfo. Reporting it would be misleading, so report + * NULL instead. Custom fixed-amount kinds declare shared_size to + * size their slot in custom_data[]. + */ + if (info->fixed_amount && pgstat_is_kind_builtin(kind)) + nulls[6] = true; + else + values[6] = Int64GetDatum(info->shared_size); + + /* + * When track_entry_count is disabled, use NULL. Fixed-sized stats + * kinds report NULL here. + */ + if (info->track_entry_count) + values[7] = Int64GetDatum(pgstat_get_entry_count(kind)); + else + nulls[7] = true; + + + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); + } + + return (Datum) 0; +#undef PG_STAT_KIND_INFO_COLS +} diff --git a/src/test/modules/test_custom_stats/t/001_custom_stats.pl b/src/test/modules/test_custom_stats/t/001_custom_stats.pl index 9e6a7a385775..f1774ba6f925 100644 --- a/src/test/modules/test_custom_stats/t/001_custom_stats.pl +++ b/src/test/modules/test_custom_stats/t/001_custom_stats.pl @@ -27,6 +27,18 @@ $node->start; $node->safe_psql('postgres', q(CREATE EXTENSION test_custom_var_stats)); $node->safe_psql('postgres', q(CREATE EXTENSION test_custom_fixed_stats)); +# Verify custom stats kinds appear in pg_stat_kind_info. +my $result = $node->safe_psql( + 'postgres', + q(SELECT id, name, builtin, fixed_amount, accessed_across_databases, + write_to_file, entry_size > 0 + FROM pg_stat_kind_info + WHERE name LIKE 'test_custom%' ORDER BY id)); +is( $result, + qq{25|test_custom_var_stats|f|f|t|t|t +26|test_custom_fixed_stats|f|t|f|t|t}, + "custom stats kinds visible in pg_stat_kind_info"); + # Create entries for variable-sized stats. $node->safe_psql('postgres', q(select test_custom_stats_var_create('entry1', 'Test entry 1'))); @@ -63,7 +75,7 @@ $node->safe_psql('postgres', q(select test_custom_stats_fixed_update())); $node->safe_psql('postgres', q(select test_custom_stats_fixed_update())); # Test data reports. -my $result = $node->safe_psql('postgres', +$result = $node->safe_psql('postgres', q(select * from test_custom_stats_var_report('entry1'))); is( $result, "entry1|2|Test entry 1", diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index a65a5bf0c4fb..4ed7b31528f9 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1967,6 +1967,15 @@ pg_stat_io| SELECT backend_type, fsync_time, stats_reset FROM pg_stat_get_io() b(backend_type, object, context, reads, read_bytes, read_time, writes, write_bytes, write_time, writebacks, writeback_time, extends, extend_bytes, extend_time, hits, evictions, reuses, fsyncs, fsync_time, stats_reset); +pg_stat_kind_info| SELECT id, + name, + builtin, + fixed_amount, + accessed_across_databases, + write_to_file, + entry_size, + entry_count + FROM pg_stat_get_kind_info() k(id, name, builtin, fixed_amount, accessed_across_databases, write_to_file, entry_size, entry_count); pg_stat_lock| SELECT locktype, waits, wait_time, diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out index fa550676f835..932613a6e767 100644 --- a/src/test/regress/expected/stats.out +++ b/src/test/regress/expected/stats.out @@ -113,6 +113,29 @@ walwriter|wal|init walwriter|wal|normal (95 rows) \a +-- List of loaded statistics kinds. +SELECT name, id, fixed_amount, + accessed_across_databases AS across_db, write_to_file + FROM pg_stat_kind_info + WHERE builtin + ORDER BY name COLLATE "C"; + name | id | fixed_amount | across_db | write_to_file +--------------+----+--------------+-----------+--------------- + archiver | 7 | t | f | t + backend | 6 | f | t | f + bgwriter | 8 | t | f | t + checkpointer | 9 | t | f | t + database | 1 | f | t | t + function | 3 | f | f | t + io | 10 | t | f | t + lock | 11 | t | f | t + relation | 2 | f | f | t + replslot | 4 | f | t | t + slru | 12 | t | f | t + subscription | 5 | f | t | t + wal | 13 | t | f | t +(13 rows) + -- ensure that both seqscan and indexscan plans are allowed SET enable_seqscan TO on; SET enable_indexscan TO on; diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out index 132b56a5864c..ac9e033c2ae1 100644 --- a/src/test/regress/expected/sysviews.out +++ b/src/test/regress/expected/sysviews.out @@ -129,6 +129,13 @@ select count(*) > 0 as ok from pg_stat_slru; t (1 row) +-- There should be at least one statistics kind loaded +select count(*) > 0 as ok from pg_stat_kind_info; + ok +---- + t +(1 row) + -- There must be only one record select count(*) = 1 as ok from pg_stat_wal; ok diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql index f5683302a75c..2c47c4b69b50 100644 --- a/src/test/regress/sql/stats.sql +++ b/src/test/regress/sql/stats.sql @@ -14,6 +14,13 @@ SELECT backend_type, object, context FROM pg_stat_io ORDER BY backend_type COLLATE "C", object COLLATE "C", context COLLATE "C"; \a +-- List of loaded statistics kinds. +SELECT name, id, fixed_amount, + accessed_across_databases AS across_db, write_to_file + FROM pg_stat_kind_info + WHERE builtin + ORDER BY name COLLATE "C"; + -- ensure that both seqscan and indexscan plans are allowed SET enable_seqscan TO on; SET enable_indexscan TO on; diff --git a/src/test/regress/sql/sysviews.sql b/src/test/regress/sql/sysviews.sql index 507e400ad4af..193bf84dad86 100644 --- a/src/test/regress/sql/sysviews.sql +++ b/src/test/regress/sql/sysviews.sql @@ -70,6 +70,9 @@ select count(*) >= 0 as ok from pg_prepared_xacts; -- There will surely be at least one SLRU cache select count(*) > 0 as ok from pg_stat_slru; +-- There should be at least one statistics kind loaded +select count(*) > 0 as ok from pg_stat_kind_info; + -- There must be only one record select count(*) = 1 as ok from pg_stat_wal; diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index 2ec2bdd000bc..d77bb30bc588 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -509,6 +509,16 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser + + pg_stat_kind_infopg_stat_kind_info + + One row for each loaded statistics kind, showing information about + each kind. + See + pg_stat_kind_info for details. + + + pg_stat_lockpg_stat_lock @@ -3303,6 +3313,138 @@ description | Waiting for a newly initialized WAL file to reach durable storage + + <structname>pg_stat_kind_info</structname> + + + pg_stat_kind_info + + + + The pg_stat_kind_info view contains one row for each + loaded statistics kind, including both built-in and custom kinds. + + + + <structname>pg_stat_kind_info</structname> View + + + + + + Column Type + + + Description + + + + + + + + + id integer + + + Numeric identifier of the statistics kind. + + + + + + + + name text + + + Name of the statistics kind. + + + + + + + + builtin boolean + + + True if this is a built-in statistics kind, false if it was registered + by an extension. + + + + + + + + fixed_amount boolean + + + True if this kind tracks a fixed amount of data (a single, statically + allocated entry), false if it tracks a variable number of entries + keyed by object identifier. + + + + + + + + accessed_across_databases boolean + + + True if entries of this kind are accessed across databases (cluster-wide + statistics), false if they are scoped to a single database. + + + + + + + + write_to_file boolean + + + True if entries of this kind are persisted to the statistics file at + shutdown and reloaded on startup, false if they are kept only in + shared memory. + + + + + + + + entry_size bigint + + + Size in bytes of a shared memory entry for this statistics kind. + NULL for built-in fixed-amount kinds, whose + single entry lives in a statically-allocated slot rather than a + sized shared memory entry. + + + + + + + + entry_count bigint + + + Number of tracked entries for this kind. For variable-numbered kinds, + this is the number of objects currently tracked. + NULL for fixed-sized statistics kinds, or if the + kind does not track entry counts. + + + + + +
+
+ <structname>pg_stat_lock</structname> -- 2.54.0