From c15216bbf15e288acc758abdb88a4ec1ad17f9d1 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Wed, 8 Nov 2023 16:00:15 -0500 Subject: [PATCH v1 8/9] Display freeze statistics Display the number of freezes and unfreezes for a relation in pg_stat_all_tables. Also add a new function pg_stat_get_table_vacuums() which returns all the PgStat_Frz entries in a table's PgStat_StatTabEntry->frz_buckets. --- doc/src/sgml/monitoring.sgml | 20 +++ src/backend/catalog/system_views.sql | 2 + src/backend/utils/adt/pgstatfuncs.c | 178 +++++++++++++++++++++++++++ src/include/catalog/pg_proc.dat | 20 +++ src/test/regress/expected/rules.out | 6 + 5 files changed, 226 insertions(+) diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml index e068f7e247..5bb7dda326 100644 --- a/doc/src/sgml/monitoring.sgml +++ b/doc/src/sgml/monitoring.sgml @@ -3864,6 +3864,26 @@ description | Waiting for a newly initialized WAL file to reach durable storage + + + page_freezes bigint + + + Number of times pages were marked frozen in the visibility map by + vacuums of this table. + + + + + + page_unfreezes bigint + + + Number of times frozen pages of this table were modified and the frozen + bit unset in the visibility map. + + + analyze_count bigint diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index b65f6b5249..64b8dc7f7c 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -675,6 +675,8 @@ CREATE VIEW pg_stat_all_tables AS 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_vacuum_count(C.oid) AS vacuum_count, + pg_stat_get_page_freezes(C.oid) AS page_freezes, + pg_stat_get_page_unfreezes(C.oid) AS page_unfreezes, pg_stat_get_autovacuum_count(C.oid) AS autovacuum_count, pg_stat_get_analyze_count(C.oid) AS analyze_count, pg_stat_get_autoanalyze_count(C.oid) AS autoanalyze_count diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 1fb8b31863..bee3980623 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -32,6 +32,7 @@ #include "utils/acl.h" #include "utils/builtins.h" #include "utils/inet.h" +#include "utils/pg_lsn.h" #include "utils/timestamp.h" #define UINT32_ACCESS_ONCE(var) ((uint32)(*((volatile uint32 *)&(var)))) @@ -108,6 +109,53 @@ PG_STAT_GET_RELENTRY_INT64(tuples_updated) /* pg_stat_get_vacuum_count */ PG_STAT_GET_RELENTRY_INT64(vacuum_count) +Datum +pg_stat_get_page_freezes(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 freezes = 0; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + PG_RETURN_NULL(); + + for (int i = 0; i < tabentry->frz_nbuckets_used; i++) + { + PgStat_Frz *frz = &tabentry->frz_buckets[i]; + + if (frz->start_lsn == InvalidXLogRecPtr) + continue; + + freezes += frz->vm_page_freezes; + } + + PG_RETURN_INT64(freezes); +} + +Datum +pg_stat_get_page_unfreezes(PG_FUNCTION_ARGS) +{ + Oid relid = PG_GETARG_OID(0); + int64 unfreezes = 0; + PgStat_StatTabEntry *tabentry; + + if ((tabentry = pgstat_fetch_stat_tabentry(relid)) == NULL) + PG_RETURN_NULL(); + + for (int i = 0; i < tabentry->frz_nbuckets_used; i++) + { + PgStat_Frz *frz = &tabentry->frz_buckets[i]; + + if (frz->start_lsn == InvalidXLogRecPtr) + continue; + + unfreezes += frz->unfreezes; + } + + PG_RETURN_INT64(unfreezes); +} + + #define PG_STAT_GET_RELENTRY_TIMESTAMPTZ(stat) \ Datum \ CppConcat(pg_stat_get_,stat)(PG_FUNCTION_ARGS) \ @@ -1446,6 +1494,136 @@ pg_stat_get_io(PG_FUNCTION_ARGS) return (Datum) 0; } +/* + * Calculate the LSN generation rate for a given freeze bucket in LSNs/second. + */ +static float +pgstat_frz_vac_lsn_gen_rate(PgStat_Frz *vacuum) +{ + TimestampTz end_time; + XLogRecPtr end_lsn; + int64 time_elapsed; + int64 lsns_elapsed; + + Assert(vacuum->start_lsn != InvalidXLogRecPtr); + Assert(vacuum->start_time >= 0); + + if (vacuum->end_lsn == InvalidXLogRecPtr) + { + /* get exact current LSN since cost isn't very important here */ + end_lsn = GetXLogInsertRecPtr(); + end_time = GetCurrentTimestamp(); + } + else + { + end_lsn = vacuum->end_lsn; + end_time = vacuum->end_time; + } + + time_elapsed = end_time - vacuum->start_time; + lsns_elapsed = end_lsn - vacuum->start_lsn; + + /* If nothing happened during this vacuum, it is possible 0 LSNs elapsed. */ + if (lsns_elapsed <= 0) + return 0; + + return (float) time_elapsed * USECS_PER_SEC / lsns_elapsed; +} + + +#define TABLE_VACUUM_STAT_NCOLS 21 +Datum +pg_stat_get_table_vacuums(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo; + PgStat_StatTabEntry *tabentry; + Oid tableoid = PG_GETARG_OID(0); + + InitMaterializedSRF(fcinfo, 0); + rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + + if ((tabentry = pgstat_fetch_stat_tabentry(tableoid)) == NULL) + return (Datum) 0; + + for (int i = 0; i < tabentry->frz_nbuckets_used; i++) + { + PgStat_Frz *frz; + Datum values[TABLE_VACUUM_STAT_NCOLS] = {0}; + bool nulls[TABLE_VACUUM_STAT_NCOLS] = {0}; + + frz = &tabentry->frz_buckets[ + (tabentry->frz_oldest + i) % VAC_FRZ_STATS_MAX_NBUCKETS + ]; + + Assert(frz->start_lsn != InvalidXLogRecPtr); + + values[0] = ObjectIdGetDatum(tableoid); + values[1] = Int32GetDatum(frz->count); + values[2] = LSNGetDatum(frz->start_time); + values[3] = LSNGetDatum(frz->start_lsn); + values[4] = LSNGetDatum(frz->end_time); + values[5] = LSNGetDatum(frz->end_lsn); + values[6] = Float8GetDatum(pgstat_frz_vac_lsn_gen_rate(frz)); + + values[7] = Int64GetDatum(frz->vm_page_freezes); + values[8] = Int64GetDatum(frz->freezes); + + if (frz->freezes > 0) + { + int64 page_age_range; + + values[9] = Float8GetDatum(frz->sum_page_age_lsns / frz->freezes); + + page_age_range = + Int64GetDatum(frz->max_frz_page_age - frz->min_frz_page_age); + + values[10] = Int64GetDatum(page_age_range); + } + else + { + nulls[9] = true; + nulls[10] = true; + } + + values[11] = Int64GetDatum(frz->unfreezes); + + if (frz->unfreezes > 0) + { + int64 frz_duration_range; + + values[12] = Float8GetDatum(frz->total_frozen_duration_lsns / frz->unfreezes); + + frz_duration_range = + Int64GetDatum(frz->max_frozen_duration_lsns - frz->min_frozen_duration_lsns); + + values[13] = Int64GetDatum(frz_duration_range); + } + else + { + nulls[12] = true; + nulls[13] = true; + } + + if (frz->early_unfreezes > 0) + values[14] = Int64GetDatum(frz->early_unfreezes); + else + nulls[14] = true; + + values[15] = Int64GetDatum(frz->relsize_start); + values[16] = Int64GetDatum(frz->frozen_pages_start); + values[17] = Int64GetDatum(frz->relsize_end); + values[18] = Int64GetDatum(frz->frozen_pages_end); + values[19] = Int64GetDatum(frz->scanned_pages); + values[20] = Int64GetDatum(frz->freeze_fpis); + + tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, + values, nulls); + } + + return (Datum) 0; +} + + /* * Returns statistics of WAL activity */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f14aed422a..c113adcebc 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5407,6 +5407,17 @@ proname => 'pg_stat_get_vacuum_count', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', prosrc => 'pg_stat_get_vacuum_count' }, + +{ oid => '9998', descr => 'statistics: number of page freezes for this relation', + proname => 'pg_stat_get_page_freezes', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_page_freezes' }, + +{ oid => '9997', descr => 'statistics: number of page unfreezes for this relation', + proname => 'pg_stat_get_page_unfreezes', provolatile => 's', proparallel => 'r', + prorettype => 'int8', proargtypes => 'oid', + prosrc => 'pg_stat_get_page_unfreezes' }, + { oid => '3055', descr => 'statistics: number of auto vacuums for a table', proname => 'pg_stat_get_autovacuum_count', provolatile => 's', proparallel => 'r', prorettype => 'int8', proargtypes => 'oid', @@ -5755,6 +5766,15 @@ proargnames => '{backend_type,object,context,reads,read_time,writes,write_time,writebacks,writeback_time,extends,extend_time,op_bytes,hits,evictions,reuses,fsyncs,fsync_time,stats_reset}', prosrc => 'pg_stat_get_io' }, +{ oid => '9999', descr => 'statistics: table freeze heuristic info', + proname => 'pg_stat_get_table_vacuums', prorows => '15', proretset => 't', + provolatile => 'v', proparallel => 'r', prorettype => 'record', + proargtypes => 'oid', + proallargtypes => '{oid,oid,int4,timestamptz,pg_lsn,timestamptz,pg_lsn,float8,int8,int8,float8,int8,int8,float8,int8,int8,int8,int8,int8,int8,int8,int8}', + proargmodes => '{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}', + proargnames => '{reloid,reloid,members,start_time,start_lsn,end_time,end_lsn,lsn_gen_rate,vm_page_freezes,freezes,avg_page_age_lsns,range_page_age_lsns,unfreezes,avg_frozen_duration_lsns,range_frozen_duration_lsns,early_unfreezes,npages_start,nfrozen_start,npages_end,nfrozen_end,scanned_pages,freeze_fpis}', + prosrc => 'pg_stat_get_table_vacuums' }, + { 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/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index 1442c43d9c..ff592e1f6b 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1800,6 +1800,8 @@ pg_stat_all_tables| SELECT c.oid AS relid, 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_vacuum_count(c.oid) AS vacuum_count, + pg_stat_get_page_freezes(c.oid) AS page_freezes, + pg_stat_get_page_unfreezes(c.oid) AS page_unfreezes, pg_stat_get_autovacuum_count(c.oid) AS autovacuum_count, pg_stat_get_analyze_count(c.oid) AS analyze_count, pg_stat_get_autoanalyze_count(c.oid) AS autoanalyze_count @@ -2169,6 +2171,8 @@ pg_stat_sys_tables| SELECT relid, last_analyze, last_autoanalyze, vacuum_count, + page_freezes, + page_unfreezes, autovacuum_count, analyze_count, autoanalyze_count @@ -2217,6 +2221,8 @@ pg_stat_user_tables| SELECT relid, last_analyze, last_autoanalyze, vacuum_count, + page_freezes, + page_unfreezes, autovacuum_count, analyze_count, autoanalyze_count -- 2.37.2