postgresql/src/backend/utils/activity/pgstat_wal.c

175 lines
4.7 KiB
C

/* -------------------------------------------------------------------------
*
* 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-2023, 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_PendingWalStats 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 WAL and IO statistics.
*
* Must be called by processes that generate WAL, that do not call
* pgstat_report_stat(), like walwriter.
*/
void
pgstat_report_wal(bool force)
{
pgstat_flush_wal(force);
pgstat_flush_io(force);
}
/*
* 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 wal_usage_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(&wal_usage_diff, &pgWalUsage, &prevWalUsage);
if (!nowait)
LWLockAcquire(&stats_shmem->lock, LW_EXCLUSIVE);
else if (!LWLockConditionalAcquire(&stats_shmem->lock, LW_EXCLUSIVE))
return true;
#define WALSTAT_ACC(fld, var_to_add) \
(stats_shmem->stats.fld += var_to_add.fld)
#define WALSTAT_ACC_INSTR_TIME(fld) \
(stats_shmem->stats.fld += INSTR_TIME_GET_MICROSEC(PendingWalStats.fld))
WALSTAT_ACC(wal_records, wal_usage_diff);
WALSTAT_ACC(wal_fpi, wal_usage_diff);
WALSTAT_ACC(wal_bytes, wal_usage_diff);
WALSTAT_ACC(wal_buffers_full, PendingWalStats);
WALSTAT_ACC(wal_write, PendingWalStats);
WALSTAT_ACC(wal_sync, PendingWalStats);
WALSTAT_ACC_INSTR_TIME(wal_write_time);
WALSTAT_ACC_INSTR_TIME(wal_sync_time);
#undef WALSTAT_ACC_INSTR_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);
}