From 753426d6e851c9942985e0bd90583c6de3deaaa8 Mon Sep 17 00:00:00 2001
From: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Date: Wed, 29 Jul 2026 14:13:28 +0000
Subject: [PATCH v1 3/5] pgstat: move WAL statistics to new per-backend
 infrastructure

PGSTAT_KIND_BACKEND stores each backend's WAL, Lock, and IO statistics
together in one variable-numbered entry keyed by ProcNumber. Move WAL
statistics into a dedicated ProcNumber keyed dshash associated with the
fixed WAL statistics kind. The global WAL stats hold data for backends that
have exited, while the dshash holds statistics for live backends.

Build pg_stat_wal snapshots by copying the global stats and adding every live
per-backend entry.

Transfer the current process's entry into the global stats before deleting it
at process exit or ProcNumber reuse. Transfer all entries before a clean shutdown
writes the statistics file.

Remove WAL counters from PGSTAT_KIND_BACKEND and make use of the new infrastructure
in pg_stat_get_backend_wal(). This also makes WAL statistics available for auxiliary
and shared memory-only workers. Update the documentation to describe the new
behavior.

Author: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Reviewed-by:
Discussion:
---
 doc/src/sgml/monitoring.sgml                |   7 +-
 src/backend/utils/activity/pgstat.c         |  18 ++
 src/backend/utils/activity/pgstat_backend.c |  75 --------
 src/backend/utils/activity/pgstat_wal.c     | 179 +++++++++++++++++---
 src/backend/utils/adt/pgstatfuncs.c         |  37 +++-
 src/include/pgstat.h                        |   3 +-
 src/include/utils/pgstat_internal.h         |  22 ++-
 src/tools/pgindent/typedefs.list            |   1 +
 8 files changed, 232 insertions(+), 110 deletions(-)
   3.6% doc/src/sgml/
  78.0% src/backend/utils/activity/
  10.2% src/backend/utils/adt/
   6.0% src/include/utils/

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 099e9b6f4e9..bd5881beb61 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -5853,10 +5853,6 @@ description | Waiting for a newly initialized WAL file to reach durable storage
         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>
 
@@ -5996,7 +5992,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
         <listitem>
          <para>
           <literal>wal</literal>: Reset all the counters shown in the
-          <structname>pg_stat_wal</structname> view.
+          <structname>pg_stat_wal</structname> view, as well as per-backend
+          WAL statistics returned by <function>pg_stat_get_backend_wal</function>.
          </para>
         </listitem>
         <listitem>
diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c
index efc7d427f22..19a98cdd8b7 100644
--- a/src/backend/utils/activity/pgstat.c
+++ b/src/backend/utils/activity/pgstat.c
@@ -535,6 +535,11 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE]
 		.init_shmem_cb = pgstat_wal_init_shmem_cb,
 		.reset_all_cb = pgstat_wal_reset_all_cb,
 		.snapshot_cb = pgstat_wal_snapshot_cb,
+
+		.per_backend_data_off = offsetof(PgStatShared_WalBackendEntry, stats),
+		.per_backend_data_len = sizeof(PgStat_WalStats),
+		.per_backend_hash_handle_off = offsetof(PgStatShared_Wal, backend_hash_handle),
+		.per_backend_acc_cb = pgstat_wal_per_backend_acc_cb,
 	},
 };
 
@@ -646,6 +651,9 @@ pgstat_before_server_shutdown(int code, Datum arg)
 	 */
 	if (code == 0)
 	{
+		/* Transfer all live per-backend stats before writing the stats file. */
+		pgstat_wal_acc_all_backends();
+
 		pgStatLocal.shmem->is_shutdown = true;
 		pgstat_write_statsfile();
 	}
@@ -689,6 +697,9 @@ pgstat_shutdown_hook(int code, Datum arg)
 	if (!pgstat_drop_entry(PGSTAT_KIND_BACKEND, InvalidOid, MyProcNumber, false))
 		pgstat_request_entry_refs_gc();
 
+	/* Accumulate per-backend WAL stats into the global stats */
+	pgstat_wal_acc_backend_cb();
+
 	pgstat_detach_shmem();
 
 #ifdef USE_ASSERT_CHECKING
@@ -709,6 +720,13 @@ pgstat_initialize(void)
 
 	pgstat_attach_shmem();
 
+	/*
+	 * NB: need to accept that there might be stats from an older backend that
+	 * used the same proc number. Accumulate them into the global stats before
+	 * we start using the entry.
+	 */
+	pgstat_wal_acc_backend_cb();
+
 	/*
 	 * Create and cache per-backend statistics entries here. This also covers
 	 * processes that never call InitPostgres(), such as shared-memory-only
diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c
index b736b2ccc6f..76b970a8c41 100644
--- a/src/backend/utils/activity/pgstat_backend.c
+++ b/src/backend/utils/activity/pgstat_backend.c
@@ -41,14 +41,6 @@ static PgStat_BackendPending PendingBackendStats;
 static bool backend_has_iostats = false;
 static bool backend_has_lockstats = false;
 
-/*
- * WAL usage counters saved from pgWalUsage at the previous call to
- * pgstat_flush_backend().  This is used to calculate how much WAL usage
- * happens between pgstat_flush_backend() 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.
@@ -244,58 +236,6 @@ pgstat_flush_backend_entry_io(PgStat_EntryRef *entry_ref)
 	backend_has_iostats = false;
 }
 
-/*
- * 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);
-	WALSTAT_ACC(wal_fpi_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 lock statistics.  Locking is managed
  * by the caller.
@@ -345,11 +285,6 @@ pgstat_flush_backend(bool nowait, uint32 flags)
 	if ((flags & PGSTAT_BACKEND_FLUSH_IO) && backend_has_iostats)
 		has_pending_data = true;
 
-	/* Some WAL data pending? */
-	if ((flags & PGSTAT_BACKEND_FLUSH_WAL) &&
-		pgstat_backend_wal_have_pending())
-		has_pending_data = true;
-
 	/* Some lock data pending? */
 	if ((flags & PGSTAT_BACKEND_FLUSH_LOCK) && backend_has_lockstats)
 		has_pending_data = true;
@@ -366,9 +301,6 @@ pgstat_flush_backend(bool nowait, uint32 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);
-
 	if (flags & PGSTAT_BACKEND_FLUSH_LOCK)
 		pgstat_flush_backend_entry_lock(entry_ref);
 
@@ -411,13 +343,6 @@ pgstat_create_backend(ProcNumber procnum)
 	MemSet(&PendingBackendStats, 0, sizeof(PgStat_BackendPending));
 	backend_has_iostats = false;
 	backend_has_lockstats = false;
-
-	/*
-	 * 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;
 }
 
 /*
diff --git a/src/backend/utils/activity/pgstat_wal.c b/src/backend/utils/activity/pgstat_wal.c
index 183e0a7a97b..ece4d91ed70 100644
--- a/src/backend/utils/activity/pgstat_wal.c
+++ b/src/backend/utils/activity/pgstat_wal.c
@@ -8,6 +8,11 @@
  * storage implementation and the details about individual types of
  * statistics.
  *
+ * WAL statistics use a per-backend dshash to avoid double-counting. Each
+ * backend flushes WAL usage to its own entry in the dshash (keyed by
+ * ProcNumber). The global pg_stat_wal view aggregates the global stats
+ * (which holds stats from exited backends) plus all live per-backend entries.
+ *
  * Copyright (c) 2001-2026, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
@@ -52,7 +57,6 @@ 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);
@@ -84,13 +88,15 @@ pgstat_wal_have_pending(void)
  * Calculate how much WAL usage counters have increased by subtracting the
  * previous counters from the current ones.
  *
+ * Flush WAL usage counters to the per-backend dshash entry.
+ *
  * If nowait is true, this function returns true if the lock could not be
  * acquired. Otherwise return false.
  */
 bool
 pgstat_wal_flush_cb(bool nowait)
 {
-	PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
+	PgStatShared_WalBackendEntry *entry;
 	WalUsage	wal_usage_diff = {0};
 
 	Assert(IsUnderPostmaster || !IsPostmasterEnvironment);
@@ -105,19 +111,18 @@ pgstat_wal_flush_cb(bool nowait)
 		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;
+	entry = pgstat_lock_my_per_backend_entry(PGSTAT_KIND_WAL, nowait);
+
+	if (entry == NULL)
+		return nowait;
 
 #define WALSTAT_ACC(fld, var_to_add) \
-	(stats_shmem->stats.wal_counters.fld += var_to_add.fld)
+	(entry->stats.wal_counters.fld += var_to_add.fld)
 	WALSTAT_ACC(wal_records, wal_usage_diff);
 	WALSTAT_ACC(wal_fpi, wal_usage_diff);
 	WALSTAT_ACC(wal_bytes, wal_usage_diff);
@@ -125,7 +130,7 @@ pgstat_wal_flush_cb(bool nowait)
 	WALSTAT_ACC(wal_buffers_full, wal_usage_diff);
 #undef WALSTAT_ACC
 
-	LWLockRelease(&stats_shmem->lock);
+	LWLockRelease(&entry->header.lock);
 
 	/*
 	 * Save the current counters for the subsequent calculation of WAL usage.
@@ -157,21 +162,157 @@ pgstat_wal_init_shmem_cb(void *stats)
 void
 pgstat_wal_reset_all_cb(TimestampTz ts)
 {
-	PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
+	PgStatShared_Wal *shmem = &pgStatLocal.shmem->wal;
+	dshash_seq_status hstat;
+	PgStatShared_WalBackendEntry *entry;
+	dshash_table *hash;
+
+	hash = pgstat_per_backend_attach(PGSTAT_KIND_WAL);
+
+	/*
+	 * Hold the kind lock while resetting both the global stats and live
+	 * entries. Transfers hold the same lock, so pre-reset counters cannot be
+	 * moved into the global stats after it is reset.
+	 */
+	LWLockAcquire(&shmem->lock, LW_EXCLUSIVE);
+	memset(&shmem->stats, 0, sizeof(shmem->stats));
+	shmem->stats.stat_reset_timestamp = ts;
+
+	/* Reset all per-backend entries */
+	if (hash != NULL)
+	{
+		dshash_seq_init(&hstat, hash, true);
+		while ((entry = dshash_seq_next(&hstat)) != NULL)
+		{
+			LWLockAcquire(&entry->header.lock, LW_EXCLUSIVE);
+			memset(&entry->stats.wal_counters, 0, sizeof(PgStat_WalCounters));
+			entry->stats.stat_reset_timestamp = ts;
+			LWLockRelease(&entry->header.lock);
+		}
+		dshash_seq_term(&hstat);
+	}
 
-	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);
+	LWLockRelease(&shmem->lock);
 }
 
+/*
+ * Build WAL stats snapshot by aggregating global stats and all live
+ * per-backend entries.
+ */
 void
 pgstat_wal_snapshot_cb(void)
 {
-	PgStatShared_Wal *stats_shmem = &pgStatLocal.shmem->wal;
+	PgStatShared_Wal *shmem = &pgStatLocal.shmem->wal;
+	PgStat_WalStats *snap = &pgStatLocal.snapshot.wal;
+	dshash_table *hash;
+
+	hash = pgstat_per_backend_attach(PGSTAT_KIND_WAL);
+
+	/*
+	 * Prevent entries from moving to the global stats between copying it and
+	 * scanning the per-backend hash.
+	 */
+	LWLockAcquire(&shmem->lock, LW_SHARED);
+	memcpy(snap, &shmem->stats, sizeof(PgStat_WalStats));
+
+	/* Add in all live per-backend entries */
+	if (hash != NULL)
+		pgstat_per_backend_snapshot(PGSTAT_KIND_WAL, hash, snap);
 
-	LWLockAcquire(&stats_shmem->lock, LW_SHARED);
-	memcpy(&pgStatLocal.snapshot.wal, &stats_shmem->stats,
-		   sizeof(pgStatLocal.snapshot.wal));
-	LWLockRelease(&stats_shmem->lock);
+	LWLockRelease(&shmem->lock);
+}
+
+/* Macro to accumulate WAL counters from src into dst */
+#define WAL_ACCUMULATE_COUNTERS(dst, src) \
+do { \
+	(dst).wal_records += (src).wal_records; \
+	(dst).wal_fpi += (src).wal_fpi; \
+	(dst).wal_bytes += (src).wal_bytes; \
+	(dst).wal_fpi_bytes += (src).wal_fpi_bytes; \
+	(dst).wal_buffers_full += (src).wal_buffers_full; \
+} while (0)
+
+/*
+ * Accumulate one per-backend WAL entry into a snapshot or the global stats.
+ */
+void
+pgstat_wal_per_backend_acc_cb(void *dst, void *entry)
+{
+	PgStat_WalStats *stats = dst;
+	PgStatShared_WalBackendEntry *e = (PgStatShared_WalBackendEntry *) entry;
+
+	WAL_ACCUMULATE_COUNTERS(stats->wal_counters, e->stats.wal_counters);
+}
+
+/*
+ * Accumulate a backend's WAL stats into the global stats, then
+ * remove the entry from the dshash.
+ *
+ * Called at backend exit after the final flush, or when a ProcNumber is
+ * being reused.
+ */
+void
+pgstat_wal_acc_backend_cb(void)
+{
+	pgstat_acc_my_per_backend(PGSTAT_KIND_WAL, &pgStatLocal.shmem->wal.lock);
+}
+
+/*
+ * Returns per-backend WAL statistics for the given ProcNumber.
+ */
+PgStat_WalStats *
+pgstat_fetch_stat_backend_wal(ProcNumber procnum)
+{
+	return (PgStat_WalStats *) pgstat_fetch_per_backend(PGSTAT_KIND_WAL, procnum);
+}
+
+/*
+ * Reset a backend's WAL stats. Accumulate the entry's counters into the
+ * global stats, then zero the stats and set the reset timestamp.
+ */
+void
+pgstat_wal_reset_backend_cb(ProcNumber procnum, TimestampTz ts)
+{
+	PgStatShared_Wal *shmem = &pgStatLocal.shmem->wal;
+	dshash_table *hash;
+	PgStatShared_WalBackendEntry *entry;
+
+	hash = pgstat_per_backend_attach(PGSTAT_KIND_WAL);
+
+	if (hash == NULL)
+		return;
+
+	LWLockAcquire(&shmem->lock, LW_EXCLUSIVE);
+
+	entry = dshash_find(hash, &procnum, true);
+
+	if (entry == NULL)
+	{
+		LWLockRelease(&shmem->lock);
+		return;
+	}
+
+	LWLockAcquire(&entry->header.lock, LW_EXCLUSIVE);
+
+	/* Accumulate current stats into global before zeroing */
+	WAL_ACCUMULATE_COUNTERS(shmem->stats.wal_counters, entry->stats.wal_counters);
+
+	/* Zero stats and set reset timestamp */
+	memset(&entry->stats.wal_counters, 0, sizeof(PgStat_WalCounters));
+	entry->stats.stat_reset_timestamp = ts;
+
+	LWLockRelease(&entry->header.lock);
+	dshash_release_lock(hash, entry);
+	LWLockRelease(&shmem->lock);
+}
+
+/*
+ * Accumulate all per-backend WAL stats entries into the global stats and remove
+ * them. Called at clean server shutdown to ensure all flushed data is preserved
+ * in the stats file.
+ */
+void
+pgstat_wal_acc_all_backends(void)
+{
+	pgstat_acc_all_per_backend(PGSTAT_KIND_WAL, &pgStatLocal.shmem->wal.lock);
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 565d0e70768..5b0c819492a 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1707,19 +1707,33 @@ Datum
 pg_stat_get_backend_wal(PG_FUNCTION_ARGS)
 {
 	int			pid;
-	PgStat_Backend *backend_stats;
-	PgStat_WalCounters bktype_stats;
+	PGPROC	   *proc;
+	ProcNumber	procnum;
+	PgBackendStatus *beentry;
+	PgStat_WalStats *wal_stats;
 
 	pid = PG_GETARG_INT32(0);
-	backend_stats = pgstat_fetch_stat_backend_by_pid(pid, NULL);
 
-	if (!backend_stats)
+	proc = BackendPidGetProc(pid);
+
+	if (!proc)
+		proc = AuxiliaryPidGetProc(pid);
+	if (!proc)
+		PG_RETURN_NULL();
+
+	procnum = GetNumberFromPGProc(proc);
+	beentry = pgstat_get_beentry_by_proc_number(procnum);
+
+	if (!beentry || beentry->st_procpid != pid)
 		PG_RETURN_NULL();
 
-	bktype_stats = backend_stats->wal_counters;
+	wal_stats = pgstat_fetch_stat_backend_wal(procnum);
 
-	/* save tuples with data from this PgStat_WalCounters */
-	return (pg_stat_wal_build_tuple(bktype_stats, backend_stats->stat_reset_timestamp));
+	if (!wal_stats)
+		PG_RETURN_NULL();
+
+	return (pg_stat_wal_build_tuple(wal_stats->wal_counters,
+									wal_stats->stat_reset_timestamp));
 }
 
 /*
@@ -2066,6 +2080,7 @@ pg_stat_reset_backend_stats(PG_FUNCTION_ARGS)
 	PGPROC	   *proc;
 	PgBackendStatus *beentry;
 	ProcNumber	procNumber;
+	TimestampTz ts;
 	int			backend_pid = PG_GETARG_INT32(0);
 
 	proc = BackendPidGetProc(backend_pid);
@@ -2087,6 +2102,14 @@ pg_stat_reset_backend_stats(PG_FUNCTION_ARGS)
 	if (!pgstat_tracks_backend_bktype(beentry->st_backendType))
 		PG_RETURN_VOID();
 
+	/*
+	 * Accumulate the backend's WAL stats into the global stats, then zero the
+	 * entry.
+	 */
+	ts = GetCurrentTimestamp();
+	pgstat_wal_reset_backend_cb(procNumber, ts);
+
+	/* Reset IO and Lock stats still in PGSTAT_KIND_BACKEND */
 	pgstat_reset(PGSTAT_KIND_BACKEND, InvalidOid, procNumber);
 
 	PG_RETURN_VOID();
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 58a44857f13..0ade7f2f053 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -522,7 +522,6 @@ typedef struct PgStat_Backend
 {
 	TimestampTz stat_reset_timestamp;
 	PgStat_BktypeIO io_stats;
-	PgStat_WalCounters wal_counters;
 	PgStat_PendingLock lock_stats;
 } PgStat_Backend;
 
@@ -842,6 +841,8 @@ extern void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_
 
 extern void pgstat_report_wal(bool force);
 extern PgStat_WalStats *pgstat_fetch_stat_wal(void);
+extern PgStat_WalStats *pgstat_fetch_stat_backend_wal(ProcNumber procnum);
+extern void pgstat_wal_reset_backend_cb(ProcNumber procnum, TimestampTz ts);
 
 
 /*
diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h
index 340244252c9..23ed4bdb4cc 100644
--- a/src/include/utils/pgstat_internal.h
+++ b/src/include/utils/pgstat_internal.h
@@ -510,11 +510,25 @@ typedef struct PgStatShared_PerBackendEntry
 	LWLock		lock;
 } PgStatShared_PerBackendEntry;
 
+/*
+ * Per-backend entry for WAL statistics, stored in a dshash keyed by
+ * ProcNumber.
+ */
+typedef struct PgStatShared_WalBackendEntry
+{
+	PgStatShared_PerBackendEntry header;
+	PgStat_WalStats stats;
+} PgStatShared_WalBackendEntry;
+
 typedef struct PgStatShared_Wal
 {
-	/* lock protects ->stats */
 	LWLock		lock;
 	PgStat_WalStats stats;
+
+	/*
+	 * Per-backend dshash, keyed by ProcNumber.
+	 */
+	dshash_table_handle backend_hash_handle;
 } PgStatShared_Wal;
 
 
@@ -749,9 +763,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_WAL   (1 << 1) /* Flush WAL statistics */
 #define PGSTAT_BACKEND_FLUSH_LOCK  (1 << 2) /* Flush lock statistics */
-#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_WAL | PGSTAT_BACKEND_FLUSH_LOCK)
+#define PGSTAT_BACKEND_FLUSH_ALL   (PGSTAT_BACKEND_FLUSH_IO | PGSTAT_BACKEND_FLUSH_LOCK)
 
 extern bool pgstat_flush_backend(bool nowait, uint32 flags);
 extern bool pgstat_backend_flush_cb(bool nowait);
@@ -890,6 +903,9 @@ extern bool pgstat_wal_flush_cb(bool nowait);
 extern void pgstat_wal_init_shmem_cb(void *stats);
 extern void pgstat_wal_reset_all_cb(TimestampTz ts);
 extern void pgstat_wal_snapshot_cb(void);
+extern void pgstat_wal_acc_backend_cb(void);
+extern void pgstat_wal_acc_all_backends(void);
+extern void pgstat_wal_per_backend_acc_cb(void *dst, void *entry);
 
 
 /*
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 0b7dbc42e80..5a4be198ada 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2333,6 +2333,7 @@ PgStatShared_ReplSlot
 PgStatShared_SLRU
 PgStatShared_Subscription
 PgStatShared_Wal
+PgStatShared_WalBackendEntry
 PgStat_ArchiverStats
 PgStat_Backend
 PgStat_BackendPending
-- 
2.34.1

