From 205e22a432753760b3110e851955fd3421ff3564 Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot Date: Wed, 28 Jan 2026 07:53:13 +0000 Subject: [PATCH v11 3/5] Add GUC to specify non-transactional statistics flush interval Adding pgstat_flush_interval, a new GUC to set the interval between flushes of non-transactional statistics. --- doc/src/sgml/config.sgml | 32 +++++++++++++++++++ src/backend/utils/activity/pgstat.c | 13 ++++++++ src/backend/utils/misc/guc_parameters.dat | 10 ++++++ src/backend/utils/misc/postgresql.conf.sample | 1 + src/backend/utils/misc/timeout.c | 6 ++++ src/include/pgstat.h | 6 ++-- src/include/utils/guc_hooks.h | 1 + src/include/utils/timeout.h | 1 + .../test_custom_stats/t/001_custom_stats.pl | 6 ++-- 9 files changed, 70 insertions(+), 6 deletions(-) 51.0% doc/src/sgml/ 10.6% src/backend/utils/activity/ 15.9% src/backend/utils/misc/ 3.6% src/include/utils/ 9.0% src/include/ 9.6% src/test/modules/test_custom_stats/t/ diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml index 20dbcaeb3ee..1eed71007a7 100644 --- a/doc/src/sgml/config.sgml +++ b/doc/src/sgml/config.sgml @@ -8929,6 +8929,38 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; + + stats_flush_interval (integer) + + stats_flush_interval configuration parameter + + + + + Sets the interval at which certain statistics, which can be updated while a + transaction is in progress, are made visible. These include WAL activity + and I/O operations. + Such statistics are refreshed at the specified interval and can be observed + during active transactions in monitoring views such as + pg_stat_wal + and + pg_stat_io. + If the value is specified without a unit, milliseconds are assumed. + The default is 10 seconds (10s), which is generally + the smallest practical value for long-running transactions. + + + + This parameter does not affect statistics that are only reported at + transaction end, such as the columns of pg_stat_all_tables + (for example, n_tup_ins, n_tup_upd, + and n_tup_del). These statistics are always + flushed at the end of a transaction. + + + + + diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index ddd331e2c81..fd6ab0db16f 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -124,6 +124,8 @@ * ---------- */ +/* minimum interval non-forced stats flushes.*/ +#define PGSTAT_MIN_INTERVAL 1000 /* how long until to block flushing pending stats updates */ #define PGSTAT_MAX_INTERVAL 60000 /* when to call pgstat_report_stat() again, even when idle */ @@ -204,6 +206,7 @@ static inline bool pgstat_is_kind_valid(PgStat_Kind kind); bool pgstat_track_counts = false; int pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE; +int pgstat_flush_interval = 10000; /* ---------- @@ -2171,6 +2174,16 @@ assign_stats_fetch_consistency(int newval, void *extra) force_stats_snapshot_clear = true; } +/* + * GUC assign_hook for stats_flush_interval. + */ +void +assign_stats_flush_interval(int newval, void *extra) +{ + if (get_all_timeouts_initialized()) + enable_timeout_after(ANYTIME_STATS_UPDATE_TIMEOUT, newval); +} + /* * Flushes only FLUSH_ANYTIME stats using non-blocking locks. Transactional * stats (FLUSH_AT_TXN_BOUNDARY) remain pending until transaction boundary. diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat index 9507778415d..073e08c7892 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -2801,6 +2801,16 @@ assign_hook => 'assign_stats_fetch_consistency', }, +{ name => 'stats_flush_interval', type => 'int', context => 'PGC_USERSET', group => 'STATS_CUMULATIVE', + short_desc => 'Sets the interval between flushes of non-transactional statistics.', + flags => 'GUC_UNIT_MS', + variable => 'pgstat_flush_interval', + boot_val => '10000', + min => '1000', + max => 'INT_MAX', + assign_hook => 'assign_stats_flush_interval' +}, + { name => 'subtransaction_buffers', type => 'int', context => 'PGC_POSTMASTER', group => 'RESOURCES_MEM', short_desc => 'Sets the size of the dedicated buffer pool used for the subtransaction cache.', long_desc => '0 means use a fraction of "shared_buffers".', diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index f938cc65a3a..8bd37a25b38 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -688,6 +688,7 @@ #track_wal_io_timing = off #track_functions = none # none, pl, all #stats_fetch_consistency = cache # cache, none, snapshot +#stats_flush_interval = 10s # in milliseconds # - Monitoring - diff --git a/src/backend/utils/misc/timeout.c b/src/backend/utils/misc/timeout.c index ddba5dc607c..85c4260d1db 100644 --- a/src/backend/utils/misc/timeout.c +++ b/src/backend/utils/misc/timeout.c @@ -828,3 +828,9 @@ get_timeout_finish_time(TimeoutId id) { return all_timeouts[id].fin_time; } + +bool +get_all_timeouts_initialized(void) +{ + return all_timeouts_initialized; +} diff --git a/src/include/pgstat.h b/src/include/pgstat.h index b011a315679..90237c70829 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -34,9 +34,6 @@ /* Default directory to store temporary statistics data in */ #define PG_STAT_TMP_DIR "pg_stat_tmp" -/* Minimum interval non-forced stats flushes */ -#define PGSTAT_MIN_INTERVAL 1000 - /* Values for track_functions GUC variable --- order is significant! */ typedef enum TrackFunctionsLevel { @@ -548,7 +545,7 @@ extern void pgstat_force_next_flush(void); do { \ if (IsUnderPostmaster && !pgstat_pending_anytime) \ { \ - enable_timeout_after(ANYTIME_STATS_UPDATE_TIMEOUT, PGSTAT_MIN_INTERVAL); \ + enable_timeout_after(ANYTIME_STATS_UPDATE_TIMEOUT, pgstat_flush_interval); \ pgstat_pending_anytime = true; \ } \ } while (0) @@ -831,6 +828,7 @@ extern PGDLLIMPORT bool pgstat_pending_anytime; extern PGDLLIMPORT bool pgstat_track_counts; extern PGDLLIMPORT int pgstat_track_functions; extern PGDLLIMPORT int pgstat_fetch_consistency; +extern PGDLLIMPORT int pgstat_flush_interval; /* diff --git a/src/include/utils/guc_hooks.h b/src/include/utils/guc_hooks.h index 9c90670d9b8..9b5d2a90387 100644 --- a/src/include/utils/guc_hooks.h +++ b/src/include/utils/guc_hooks.h @@ -132,6 +132,7 @@ extern bool check_session_authorization(char **newval, void **extra, GucSource s extern void assign_session_authorization(const char *newval, void *extra); extern void assign_session_replication_role(int newval, void *extra); extern void assign_stats_fetch_consistency(int newval, void *extra); +extern void assign_stats_flush_interval(int newval, void *extra); extern bool check_ssl(bool *newval, void **extra, GucSource source); extern bool check_stage_log_stats(bool *newval, void **extra, GucSource source); extern bool check_standard_conforming_strings(bool *newval, void **extra, diff --git a/src/include/utils/timeout.h b/src/include/utils/timeout.h index 10723bb664c..fe7327de209 100644 --- a/src/include/utils/timeout.h +++ b/src/include/utils/timeout.h @@ -93,5 +93,6 @@ extern bool get_timeout_active(TimeoutId id); extern bool get_timeout_indicator(TimeoutId id, bool reset_indicator); extern TimestampTz get_timeout_start_time(TimeoutId id); extern TimestampTz get_timeout_finish_time(TimeoutId id); +extern bool get_all_timeouts_initialized(void); #endif /* TIMEOUT_H */ 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 6ba4022418f..920443487c0 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 @@ -164,11 +164,12 @@ $node->safe_psql('postgres', q(select test_custom_stats_fixed_reset())); $node->safe_psql('postgres', q(select pg_stat_force_next_flush())); my $anytime_test = q[ + SET stats_flush_interval = '1s'; BEGIN; SET LOCAL stats_fetch_consistency = none; -- Accumulate stats select test_custom_stats_fixed_anytime_update() from generate_series(1, 2); - -- Wait (has to be greater than PGSTAT_MIN_INTERVAL) + -- Wait (has to be greater than stats_flush_interval) select pg_sleep(1.5); -- Check select 'fixed_anytime:'||numcalls from test_custom_stats_fixed_report(); @@ -184,12 +185,13 @@ like($result, qr/^fixed_anytime:2/m, $node->safe_psql('postgres', q(select pg_stat_force_next_flush())); $anytime_test = q[ + SET stats_flush_interval = '1s'; BEGIN; SET LOCAL stats_fetch_consistency = none; -- Accumulate stats select test_custom_stats_var_anytime_update('entry2'); select test_custom_stats_var_anytime_update('entry2'); - -- Wait (has to be greater than PGSTAT_MIN_INTERVAL) + -- Wait (has to be greater than stats_flush_interval) select pg_sleep(1.5); -- Check select 'var_anytime:'||calls from test_custom_stats_var_report('entry2'); -- 2.34.1