summaryrefslogtreecommitdiffstats
path: root/src/backend/utils/activity/pgstat_wal.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/activity/pgstat_wal.c')
-rw-r--r--src/backend/utils/activity/pgstat_wal.c182
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);
+}