mirror of
https://github.com/postgres/postgres.git
synced 2025-06-01 14:21:49 +03:00
Add WAL data to backend statistics
This commit adds per-backend WAL statistics, providing the same information as pg_stat_wal, except that it is now possible to know how much WAL activity is happening in each backend rather than an overall aggregate of all the activity. Like pg_stat_wal, the implementation relies on pgWalUsage, tracking the difference of activity between two reports to pgstats. This data can be retrieved with a new system function called pg_stat_get_backend_wal(), that returns one tuple based on the PID provided in input. Like pg_stat_get_backend_io(), this is useful when joined with pg_stat_activity to get a live picture of the WAL generated for each running backend, showing how the activity is [un]balanced. pgstat_flush_backend() gains a new flag value, able to control the flush of the WAL stats. This commit relies mostly on the infrastructure provided by 9aea73fc61d4, that has introduced backend statistics. Bump catalog version. A bump of PGSTAT_FILE_FORMAT_ID is not required, as backend stats do not persist on disk. Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com> Reviewed-by: Michael Paquier <michael@paquier.xyz> Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com> Reviewed-by: Xuneng Zhou <xunengzhou@gmail.com> Discussion: https://postgr.es/m/Z3zqc4o09dM/Ezyz@ip-10-97-1-34.eu-west-3.compute.internal
This commit is contained in:
parent
59a1592e39
commit
76def4cdd7
@ -4866,6 +4866,25 @@ description | Waiting for a newly initialized WAL file to reach durable storage
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry id="pg-stat-get-backend-wal" role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
<primary>pg_stat_get_backend_wal</primary>
|
||||
</indexterm>
|
||||
<function>pg_stat_get_backend_wal</function> ( <type>integer</type> )
|
||||
<returnvalue>record</returnvalue>
|
||||
</para>
|
||||
<para>
|
||||
Returns WAL statistics about the backend with the specified
|
||||
process ID. The output fields are exactly the same as the ones in the
|
||||
<structname>pg_stat_wal</structname> view.
|
||||
</para>
|
||||
<para>
|
||||
The function does not return WAL statistics for the checkpointer,
|
||||
the background writer, the startup process and the autovacuum launcher.
|
||||
</para></entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry role="func_table_entry"><para role="func_signature">
|
||||
<indexterm>
|
||||
|
@ -38,6 +38,14 @@
|
||||
*/
|
||||
static PgStat_BackendPending PendingBackendStats = {0};
|
||||
|
||||
/*
|
||||
* WAL usage counters saved from pgWalUsage at the previous call to
|
||||
* pgstat_report_wal(). This is used to calculate how much WAL usage
|
||||
* happens between pgstat_report_wal() calls, by subtracting the previous
|
||||
* counters from the current ones.
|
||||
*/
|
||||
static WalUsage prevBackendWalUsage;
|
||||
|
||||
/*
|
||||
* Utility routines to report I/O stats for backends, kept here to avoid
|
||||
* exposing PendingBackendStats to the outside world.
|
||||
@ -184,6 +192,57 @@ pgstat_flush_backend_entry_io(PgStat_EntryRef *entry_ref)
|
||||
MemSet(&PendingBackendStats.pending_io, 0, sizeof(PgStat_PendingIO));
|
||||
}
|
||||
|
||||
/*
|
||||
* To determine whether WAL usage happened.
|
||||
*/
|
||||
static inline bool
|
||||
pgstat_backend_wal_have_pending(void)
|
||||
{
|
||||
return (pgWalUsage.wal_records != prevBackendWalUsage.wal_records);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush out locally pending backend WAL statistics. Locking is managed
|
||||
* by the caller.
|
||||
*/
|
||||
static void
|
||||
pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref)
|
||||
{
|
||||
PgStatShared_Backend *shbackendent;
|
||||
PgStat_WalCounters *bktype_shstats;
|
||||
WalUsage wal_usage_diff = {0};
|
||||
|
||||
/*
|
||||
* This function can be called even if nothing at all has happened for WAL
|
||||
* statistics. In this case, avoid unnecessarily modifying the stats
|
||||
* entry.
|
||||
*/
|
||||
if (!pgstat_backend_wal_have_pending())
|
||||
return;
|
||||
|
||||
shbackendent = (PgStatShared_Backend *) entry_ref->shared_stats;
|
||||
bktype_shstats = &shbackendent->stats.wal_counters;
|
||||
|
||||
/*
|
||||
* Calculate how much WAL usage counters were increased by subtracting the
|
||||
* previous counters from the current ones.
|
||||
*/
|
||||
WalUsageAccumDiff(&wal_usage_diff, &pgWalUsage, &prevBackendWalUsage);
|
||||
|
||||
#define WALSTAT_ACC(fld, var_to_add) \
|
||||
(bktype_shstats->fld += var_to_add.fld)
|
||||
WALSTAT_ACC(wal_buffers_full, wal_usage_diff);
|
||||
WALSTAT_ACC(wal_records, wal_usage_diff);
|
||||
WALSTAT_ACC(wal_fpi, wal_usage_diff);
|
||||
WALSTAT_ACC(wal_bytes, wal_usage_diff);
|
||||
#undef WALSTAT_ACC
|
||||
|
||||
/*
|
||||
* Save the current counters for the subsequent calculation of WAL usage.
|
||||
*/
|
||||
prevBackendWalUsage = pgWalUsage;
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush out locally pending backend statistics
|
||||
*
|
||||
@ -194,12 +253,23 @@ bool
|
||||
pgstat_flush_backend(bool nowait, bits32 flags)
|
||||
{
|
||||
PgStat_EntryRef *entry_ref;
|
||||
bool has_pending_data = false;
|
||||
|
||||
if (!pgstat_tracks_backend_bktype(MyBackendType))
|
||||
return false;
|
||||
|
||||
if (pg_memory_is_all_zeros(&PendingBackendStats,
|
||||
sizeof(struct PgStat_BackendPending)))
|
||||
/* Some IO data pending? */
|
||||
if ((flags & PGSTAT_BACKEND_FLUSH_IO) &&
|
||||
!pg_memory_is_all_zeros(&PendingBackendStats.pending_io,
|
||||
sizeof(struct PgStat_PendingIO)))
|
||||
has_pending_data = true;
|
||||
|
||||
/* Some WAL data pending? */
|
||||
if ((flags & PGSTAT_BACKEND_FLUSH_WAL) &&
|
||||
pgstat_backend_wal_have_pending())
|
||||
has_pending_data = true;
|
||||
|
||||
if (!has_pending_data)
|
||||
return false;
|
||||
|
||||
entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_BACKEND, InvalidOid,
|
||||
@ -211,6 +281,9 @@ pgstat_flush_backend(bool nowait, bits32 flags)
|
||||
if (flags & PGSTAT_BACKEND_FLUSH_IO)
|
||||
pgstat_flush_backend_entry_io(entry_ref);
|
||||
|
||||
if (flags & PGSTAT_BACKEND_FLUSH_WAL)
|
||||
pgstat_flush_backend_entry_wal(entry_ref);
|
||||
|
||||
pgstat_unlock_entry(entry_ref);
|
||||
|
||||
return false;
|
||||
@ -226,7 +299,8 @@ pgstat_backend_have_pending_cb(void)
|
||||
return false;
|
||||
|
||||
return (!pg_memory_is_all_zeros(&PendingBackendStats,
|
||||
sizeof(struct PgStat_BackendPending)));
|
||||
sizeof(struct PgStat_BackendPending)) ||
|
||||
pgstat_backend_wal_have_pending());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -261,6 +335,13 @@ pgstat_create_backend(ProcNumber procnum)
|
||||
pgstat_unlock_entry(entry_ref);
|
||||
|
||||
MemSet(&PendingBackendStats, 0, sizeof(PgStat_BackendPending));
|
||||
|
||||
/*
|
||||
* Initialize prevBackendWalUsage with pgWalUsage so that
|
||||
* pgstat_backend_flush_cb() can calculate how much pgWalUsage counters
|
||||
* are increased by subtracting prevBackendWalUsage from pgWalUsage.
|
||||
*/
|
||||
prevBackendWalUsage = pgWalUsage;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -52,6 +52,7 @@ pgstat_report_wal(bool force)
|
||||
|
||||
/* flush wal stats */
|
||||
(void) pgstat_wal_flush_cb(nowait);
|
||||
pgstat_flush_backend(nowait, PGSTAT_BACKEND_FLUSH_WAL);
|
||||
|
||||
/* flush IO stats */
|
||||
pgstat_flush_io(nowait);
|
||||
|
@ -1609,8 +1609,8 @@ pg_stat_get_backend_io(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* pg_stat_wal_build_tuple
|
||||
*
|
||||
* Helper routine for pg_stat_get_wal() returning one tuple based on the
|
||||
* contents of wal_counters.
|
||||
* Helper routine for pg_stat_get_wal() and pg_stat_get_backend_wal()
|
||||
* returning one tuple based on the contents of wal_counters.
|
||||
*/
|
||||
static Datum
|
||||
pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters,
|
||||
@ -1659,6 +1659,28 @@ pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters,
|
||||
PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls)));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns WAL statistics for a backend with given PID.
|
||||
*/
|
||||
Datum
|
||||
pg_stat_get_backend_wal(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int pid;
|
||||
PgStat_Backend *backend_stats;
|
||||
PgStat_WalCounters bktype_stats;
|
||||
|
||||
pid = PG_GETARG_INT32(0);
|
||||
backend_stats = pgstat_fetch_stat_backend_by_pid(pid, NULL);
|
||||
|
||||
if (!backend_stats)
|
||||
PG_RETURN_NULL();
|
||||
|
||||
bktype_stats = backend_stats->wal_counters;
|
||||
|
||||
/* save tuples with data from this PgStat_WalCounters */
|
||||
return (pg_stat_wal_build_tuple(bktype_stats, backend_stats->stat_reset_timestamp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns statistics of WAL activity
|
||||
*/
|
||||
|
@ -57,6 +57,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 202503071
|
||||
#define CATALOG_VERSION_NO 202503111
|
||||
|
||||
#endif
|
||||
|
@ -5973,6 +5973,13 @@
|
||||
proargmodes => '{o,o,o,o,o}',
|
||||
proargnames => '{wal_records,wal_fpi,wal_bytes,wal_buffers_full,stats_reset}',
|
||||
prosrc => 'pg_stat_get_wal' },
|
||||
{ oid => '8037', descr => 'statistics: backend WAL activity',
|
||||
proname => 'pg_stat_get_backend_wal', provolatile => 'v', proparallel => 'r',
|
||||
prorettype => 'record', proargtypes => 'int4',
|
||||
proallargtypes => '{int4,int8,int8,numeric,int8,timestamptz}',
|
||||
proargmodes => '{i,o,o,o,o,o}',
|
||||
proargnames => '{backend_pid,wal_records,wal_fpi,wal_bytes,wal_buffers_full,stats_reset}',
|
||||
prosrc => 'pg_stat_get_backend_wal' },
|
||||
{ oid => '6248', descr => 'statistics: information about WAL prefetching',
|
||||
proname => 'pg_stat_get_recovery_prefetch', prorows => '1', proretset => 't',
|
||||
provolatile => 'v', prorettype => 'record', proargtypes => '',
|
||||
|
@ -340,24 +340,6 @@ typedef struct PgStat_IO
|
||||
PgStat_BktypeIO stats[BACKEND_NUM_TYPES];
|
||||
} PgStat_IO;
|
||||
|
||||
typedef struct PgStat_Backend
|
||||
{
|
||||
TimestampTz stat_reset_timestamp;
|
||||
PgStat_BktypeIO io_stats;
|
||||
} PgStat_Backend;
|
||||
|
||||
/* ---------
|
||||
* PgStat_BackendPending Non-flushed backend stats.
|
||||
* ---------
|
||||
*/
|
||||
typedef struct PgStat_BackendPending
|
||||
{
|
||||
/*
|
||||
* Backend statistics store the same amount of IO data as PGSTAT_KIND_IO.
|
||||
*/
|
||||
PgStat_PendingIO pending_io;
|
||||
} PgStat_BackendPending;
|
||||
|
||||
typedef struct PgStat_StatDBEntry
|
||||
{
|
||||
PgStat_Counter xact_commit;
|
||||
@ -500,6 +482,29 @@ typedef struct PgStat_WalStats
|
||||
TimestampTz stat_reset_timestamp;
|
||||
} PgStat_WalStats;
|
||||
|
||||
/* -------
|
||||
* PgStat_Backend Backend statistics
|
||||
* -------
|
||||
*/
|
||||
typedef struct PgStat_Backend
|
||||
{
|
||||
TimestampTz stat_reset_timestamp;
|
||||
PgStat_BktypeIO io_stats;
|
||||
PgStat_WalCounters wal_counters;
|
||||
} PgStat_Backend;
|
||||
|
||||
/* ---------
|
||||
* PgStat_BackendPending Non-flushed backend stats.
|
||||
* ---------
|
||||
*/
|
||||
typedef struct PgStat_BackendPending
|
||||
{
|
||||
/*
|
||||
* Backend statistics store the same amount of IO data as PGSTAT_KIND_IO.
|
||||
*/
|
||||
PgStat_PendingIO pending_io;
|
||||
} PgStat_BackendPending;
|
||||
|
||||
/*
|
||||
* Functions in pgstat.c
|
||||
*/
|
||||
|
@ -622,7 +622,8 @@ extern void pgstat_archiver_snapshot_cb(void);
|
||||
|
||||
/* flags for pgstat_flush_backend() */
|
||||
#define PGSTAT_BACKEND_FLUSH_IO (1 << 0) /* Flush I/O statistics */
|
||||
#define PGSTAT_BACKEND_FLUSH_ALL (PGSTAT_BACKEND_FLUSH_IO)
|
||||
#define PGSTAT_BACKEND_FLUSH_WAL (1 << 1) /* Flush WAL statistics */
|
||||
#define PGSTAT_BACKEND_FLUSH_ALL (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL)
|
||||
|
||||
extern bool pgstat_flush_backend(bool nowait, bits32 flags);
|
||||
extern bool pgstat_backend_flush_cb(bool nowait);
|
||||
|
@ -908,8 +908,11 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
|
||||
|
||||
-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
|
||||
SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
|
||||
-- Test pg_stat_wal (and make a temp table so our temp schema exists)
|
||||
-- Test pg_stat_wal
|
||||
SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
|
||||
-- Test pg_stat_get_backend_wal()
|
||||
SELECT wal_bytes AS backend_wal_bytes_before from pg_stat_get_backend_wal(pg_backend_pid()) \gset
|
||||
-- Make a temp table so our temp schema exists
|
||||
CREATE TEMP TABLE test_stats_temp AS SELECT 17;
|
||||
DROP TABLE test_stats_temp;
|
||||
-- Checkpoint twice: The checkpointer reports stats after reporting completion
|
||||
@ -929,6 +932,18 @@ SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT pg_stat_force_next_flush();
|
||||
pg_stat_force_next_flush
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT wal_bytes > :backend_wal_bytes_before FROM pg_stat_get_backend_wal(pg_backend_pid());
|
||||
?column?
|
||||
----------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
-- Test pg_stat_get_backend_idset() and some allied functions.
|
||||
-- In particular, verify that their notion of backend ID matches
|
||||
-- our temp schema index.
|
||||
|
@ -426,9 +426,13 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
|
||||
-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
|
||||
SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
|
||||
|
||||
-- Test pg_stat_wal (and make a temp table so our temp schema exists)
|
||||
-- Test pg_stat_wal
|
||||
SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
|
||||
|
||||
-- Test pg_stat_get_backend_wal()
|
||||
SELECT wal_bytes AS backend_wal_bytes_before from pg_stat_get_backend_wal(pg_backend_pid()) \gset
|
||||
|
||||
-- Make a temp table so our temp schema exists
|
||||
CREATE TEMP TABLE test_stats_temp AS SELECT 17;
|
||||
DROP TABLE test_stats_temp;
|
||||
|
||||
@ -441,6 +445,9 @@ CHECKPOINT;
|
||||
SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
|
||||
SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
|
||||
|
||||
SELECT pg_stat_force_next_flush();
|
||||
SELECT wal_bytes > :backend_wal_bytes_before FROM pg_stat_get_backend_wal(pg_backend_pid());
|
||||
|
||||
-- Test pg_stat_get_backend_idset() and some allied functions.
|
||||
-- In particular, verify that their notion of backend ID matches
|
||||
-- our temp schema index.
|
||||
|
Loading…
x
Reference in New Issue
Block a user