diff options
Diffstat (limited to 'src/backend/utils/activity/pgstat_wal.c')
-rw-r--r-- | src/backend/utils/activity/pgstat_wal.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/backend/utils/activity/pgstat_wal.c b/src/backend/utils/activity/pgstat_wal.c new file mode 100644 index 0000000..305a925 --- /dev/null +++ b/src/backend/utils/activity/pgstat_wal.c @@ -0,0 +1,182 @@ +/* ------------------------------------------------------------------------- + * + * pgstat_wal.c + * Implementation of WAL statistics. + * + * This file contains the implementation of WAL statistics. It is kept + * separate from pgstat.c to enforce the line between the statistics access / + * storage implementation and the details about individual types of + * statistics. + * + * Copyright (c) 2001-2022, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/backend/utils/activity/pgstat_wal.c + * ------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "utils/pgstat_internal.h" +#include "executor/instrument.h" + + +PgStat_WalStats PendingWalStats = {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 prevWalUsage; + + +/* + * Calculate how much WAL usage counters have increased and update + * shared statistics. + * + * Must be called by processes that generate WAL, that do not call + * pgstat_report_stat(), like walwriter. + * + * "force" set to true ensures that the statistics are flushed; note that + * this needs to acquire the pgstat shmem LWLock, waiting on it. When + * set to false, the statistics may not be flushed if the lock could not + * be acquired. + */ +void +pgstat_report_wal(bool force) +{ + bool nowait; + + /* like in pgstat.c, don't wait for lock acquisition when !force */ + nowait = !force; + + /* flush wal stats */ + pgstat_flush_wal(nowait); +} + +/* + * Support function for the SQL-callable pgstat* functions. Returns + * a pointer to the WAL statistics struct. + */ +PgStat_WalStats * +pgstat_fetch_stat_wal(void) +{ + pgstat_snapshot_fixed(PGSTAT_KIND_WAL); + + return &pgStatLocal.snapshot.wal; +} + +/* + * Calculate how much WAL usage counters have increased by subtracting the + * previous counters from the current ones. + * + * If nowait is true, this function returns true if the lock could not be + * acquired. Otherwise return false. + */ +bool +pgstat_flush_wal(bool nowait) +{ + PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; + WalUsage diff = {0}; + + Assert(IsUnderPostmaster || !IsPostmasterEnvironment); + Assert(pgStatLocal.shmem != NULL && + !pgStatLocal.shmem->is_shutdown); + + /* + * This function can be called even if nothing at all has happened. Avoid + * taking lock for nothing in that case. + */ + if (!pgstat_have_pending_wal()) + return false; + + /* + * We don't update the WAL usage portion of the local WalStats elsewhere. + * Calculate how much WAL usage counters were increased by subtracting the + * previous counters from the current ones. + */ + WalUsageAccumDiff(&diff, &pgWalUsage, &prevWalUsage); + PendingWalStats.wal_records = diff.wal_records; + PendingWalStats.wal_fpi = diff.wal_fpi; + PendingWalStats.wal_bytes = diff.wal_bytes; + + if (!nowait) + LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); + else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE)) + return true; + +#define WALSTAT_ACC(fld) stats_shmem->stats.fld += PendingWalStats.fld + WALSTAT_ACC(wal_records); + WALSTAT_ACC(wal_fpi); + WALSTAT_ACC(wal_bytes); + WALSTAT_ACC(wal_buffers_full); + WALSTAT_ACC(wal_write); + WALSTAT_ACC(wal_sync); + WALSTAT_ACC(wal_write_time); + WALSTAT_ACC(wal_sync_time); +#undef WALSTAT_ACC + + LWLockRelease(&stats_shmem->lock); + + /* + * Save the current counters for the subsequent calculation of WAL usage. + */ + prevWalUsage = pgWalUsage; + + /* + * Clear out the statistics buffer, so it can be re-used. + */ + MemSet(&PendingWalStats, 0, sizeof(PendingWalStats)); + + return false; +} + +void +pgstat_init_wal(void) +{ + /* + * Initialize prevWalUsage with pgWalUsage so that pgstat_flush_wal() can + * calculate how much pgWalUsage counters are increased by subtracting + * prevWalUsage from pgWalUsage. + */ + prevWalUsage = pgWalUsage; +} + +/* + * To determine whether any WAL activity has occurred since last time, not + * only the number of generated WAL records but also the numbers of WAL + * writes and syncs need to be checked. Because even transaction that + * generates no WAL records can write or sync WAL data when flushing the + * data pages. + */ +bool +pgstat_have_pending_wal(void) +{ + return pgWalUsage.wal_records != prevWalUsage.wal_records || + PendingWalStats.wal_write != 0 || + PendingWalStats.wal_sync != 0; +} + +void +pgstat_wal_reset_all_cb(TimestampTz ts) +{ + PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; + + LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE); + memset(&stats_shmem->stats, 0, sizeof(stats_shmem->stats)); + stats_shmem->stats.stat_reset_timestamp = ts; + LWLockRelease(&stats_shmem->lock); +} + +void +pgstat_wal_snapshot_cb(void) +{ + PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal; + + LWLockAcquire(&stats_shmem->lock, LW_SHARED); + memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats, + sizeof(pgStatLocal.snapshot.wal)); + LWLockRelease(&stats_shmem->lock); +} |