From be6bcf386e92a8b92da3da2c4c59792e9d0e01a4 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Tue, 12 Dec 2017 20:14:16 +1100
Subject: [PATCH] pg_stat_walwrites statistics view

This view will provide the details of how many blocks,
writes and the time taken to write the WAL data to disk
by the backend, walwriter and other background process.
Based on this data, it is configure walwriter to reduce
the load on the backend processes, thus it should improve
the performance.

All the stats are collected and stored in a shared memory
strucuture protected by the WALWriteLock
---
 doc/src/sgml/monitoring.sgml           | 86 ++++++++++++++++++++++++++++++++++
 src/backend/access/transam/xlog.c      | 62 ++++++++++++++++++++++++
 src/backend/catalog/system_views.sql   |  3 ++
 src/backend/postmaster/autovacuum.c    |  1 -
 src/backend/postmaster/pgstat.c        | 48 ++++++++++++++++++-
 src/backend/storage/ipc/ipci.c         |  2 +
 src/backend/utils/adt/pgstatfuncs.c    | 36 ++++++++++++++
 src/backend/utils/init/globals.c       |  1 +
 src/include/catalog/pg_proc.h          |  3 ++
 src/include/miscadmin.h                |  2 +
 src/include/pgstat.h                   | 47 +++++++++++++++++++
 src/test/regress/expected/rules.out    | 10 ++++
 src/test/regress/expected/sysviews.out |  7 +++
 src/test/regress/sql/sysviews.sql      |  3 ++
 14 files changed, 309 insertions(+), 2 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index b6f80d9708..dd2c2cec7e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -364,6 +364,14 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_walwrites</structname><indexterm><primary>pg_stat_walwrites</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       WAL writing activity. See
+       <xref linkend="pg-stat-walwrites-view"/> for details.
+      </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_database</structname><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
@@ -2267,6 +2275,82 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
    single row, containing global data for the cluster.
   </para>
 
+  <table id="pg-stat-walwrites-view" xreflabel="pg_stat_walwrites">
+   <title><structname>pg_stat_walwrites</structname> View</title>
+
+   <tgroup cols="3">
+    <thead>
+     <row>
+      <entry>Column</entry>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>writes</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>
+      Number of WAL writes that are carried out by background processes and workers. 
+      </entry>
+     </row>
+     <row>
+      <entry><structfield>walwriter_writes</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of WAL writes that are carried out by the wal writer process</entry>
+     </row>
+     <row>
+      <entry><structfield>backend_writes</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of WAL writes that are carried out by the backend processes</entry>
+     </row>
+     <row>
+      <entry><structfield>dirty_writes</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>
+      Number of dirty WAL writes that are carried out by background processes and workers
+      when the <xref linkend="guc-wal-buffers"/> are full.
+      </entry>
+     </row>
+     <row>
+      <entry><structfield>backend_dirty_writes</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>
+      Number of dirty WAL writes that are carried out by the backend processes when 
+      the <xref linkend="guc-wal-buffers"/> are full. 
+      </entry>
+     </row>
+     <row>
+      <entry><structfield>write_blocks</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of WAL pages written to the disk by the background processes/workers</entry>
+     </row>
+     <row>
+      <entry><structfield>walwriter_write_blocks</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of WAL pages written to the disk by the wal writer process</entry>
+     </row>
+     <row>
+      <entry><structfield>backend_write_blocks</structfield></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of WAL pages written to the disk by the backend processes</entry>
+     </row>
+     <row>
+      <entry><structfield>stats_reset</structfield></entry>
+      <entry><type>timestamp with time zone</type></entry>
+      <entry>Time at which these statistics were last reset</entry>
+     </row>
+     </tbody>
+   </tgroup>
+  </table>
+
+  <para>
+   The <structname>pg_stat_walwrites</structname> view will always have a
+   single row, containing data about the WAL writing activity of the cluster.
+  </para>
+
+
   <table id="pg-stat-database-view" xreflabel="pg_stat_database">
    <title><structname>pg_stat_database</structname> View</title>
    <tgroup cols="3">
@@ -3046,6 +3130,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        counters shown in the <structname>pg_stat_bgwriter</structname> view.
        Calling <literal>pg_stat_reset_shared('archiver')</literal> will zero all the
        counters shown in the <structname>pg_stat_archiver</structname> view.
+       Calling <literal>pg_stat_reset_shared('walwrites')</literal> will zero all the
+       counters shown in the <structname>pg_stat_walwrites</structname> view.
       </entry>
      </row>
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 0791404263..54f2b1448f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -866,6 +866,7 @@ static XLogRecPtr XLogGetReplicationSlotMinimumLSN(void);
 
 static void AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic);
 static bool XLogCheckpointNeeded(XLogSegNo new_segno);
+static bool am_background_process(void);
 static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible);
 static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
 					   bool find_free, XLogSegNo max_segno,
@@ -2118,6 +2119,17 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
 					WriteRqst.Write = OldPageRqstPtr;
 					WriteRqst.Flush = 0;
 					XLogWrite(WriteRqst, false);
+					if (AmWalWriterProcess())
+					{
+						/*
+						 * Don't consider the writes of wal writer process as
+						 * dirty writes, so skipping.
+						 */
+					}
+					else if (am_background_process())
+						WALWriteStats->stats.dirty_writes++;
+					else
+						WALWriteStats->stats.backend_dirty_writes++;
 					LWLockRelease(WALWriteLock);
 					TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_DONE();
 				}
@@ -2321,6 +2333,33 @@ XLogCheckpointNeeded(XLogSegNo new_segno)
 	return false;
 }
 
+/*
+ * Check whether the current process is a background process/worker
+ * or not. This function checks for the background processes that
+ * does some WAL write activity only and other background processes
+ * are not considered. It considers all the background workers
+ * as WAL write activity workers.
+ *
+ * Returns false - when the current process is a normal backend
+ *		   true - when the current process a background process/worker
+ */
+static bool
+am_background_process()
+{
+	/* check whether current process is a background process/worker? */
+	if (!AmBackgroundWriterProcess() &&
+		!AmCheckpointerProcess() &&
+		!AmStartupProcess() &&
+		!IsBackgroundWorker &&
+		!am_walsender &&
+		!am_autovacuum_worker)
+	{
+		return false;
+	}
+
+	return true;
+}
+
 /*
  * Write and/or fsync the log at least as far as WriteRqst indicates.
  *
@@ -2344,6 +2383,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 	int			npages;
 	int			startidx;
 	uint32		startoffset;
+	PgStat_Counter writes = 0;
+	PgStat_Counter write_blocks = 0;
+	bool		is_background_process = am_background_process();
 
 	/* We should always be inside a critical section here */
 	Assert(CritSectionCount > 0);
@@ -2487,6 +2529,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 				from += written;
 			} while (nleft > 0);
 
+			/* check whether writer is a normal backend or not? */
+			writes++;
+			write_blocks += npages;
+
 			/* Update state for write */
 			openLogOff += nbytes;
 			npages = 0;
@@ -2586,6 +2632,22 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 		LogwrtResult.Flush = LogwrtResult.Write;
 	}
 
+	if (is_background_process)
+	{
+		WALWriteStats->stats.writes += writes;
+		WALWriteStats->stats.write_blocks += write_blocks;
+	}
+	else if (AmWalWriterProcess())
+	{
+		WALWriteStats->stats.walwriter_writes += writes;
+		WALWriteStats->stats.walwriter_write_blocks += write_blocks;
+	}
+	else
+	{
+		WALWriteStats->stats.backend_writes += writes;
+		WALWriteStats->stats.backend_write_blocks += write_blocks;
+	}
+
 	/*
 	 * Update shared-memory status
 	 *
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 394aea8e0f..9843db1c8b 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -881,6 +881,9 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_walwrites AS
+   SELECT * FROM pg_stat_get_walwrites() AS A;
+
 CREATE VIEW pg_stat_progress_vacuum AS
 	SELECT
 		S.pid AS pid, S.datid AS datid, D.datname AS datname,
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 48765bb01b..5fbcbcc0a9 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -136,7 +136,6 @@ int			Log_autovacuum_min_duration = -1;
 
 /* Flags to tell if we are in an autovacuum process */
 static bool am_autovacuum_launcher = false;
-static bool am_autovacuum_worker = false;
 
 /* Flags set by signal handlers */
 static volatile sig_atomic_t got_SIGHUP = false;
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 5c256ff8ab..202ea9c355 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -142,6 +142,15 @@ char	   *pgstat_stat_tmpname = NULL;
  */
 PgStat_MsgBgWriter BgWriterStats;
 
+/*
+ * WalWrites Local statistics counters.
+ * The statistics data gets populated in XLogWrite function.
+ * Stored directly in a stats message structure so it can be sent
+ * to stats collector process without needing to copy things around.
+ * We assume this inits to zeroes.
+ */
+PgStat_WalWritesStats *WALWriteStats;
+
 /* ----------
  * Local data
  * ----------
@@ -630,6 +639,29 @@ startup_failed:
 	SetConfigOption("track_counts", "off", PGC_INTERNAL, PGC_S_OVERRIDE);
 }
 
+/*
+ * Initialization of shared memory for WALWritesStats
+ */
+Size
+WALWritesShmemSize(void)
+{
+	return sizeof(PgStat_WalWritesStats);
+}
+
+void
+WALWritesShmemInit(void)
+{
+	bool		foundWALWrites;
+
+	WALWriteStats = (PgStat_WalWritesStats *)
+		ShmemInitStruct("WAL WriteStats", WALWritesShmemSize(), &foundWALWrites);
+
+	if (!foundWALWrites)
+	{
+		MemSet(WALWriteStats, 0, sizeof(PgStat_WalWritesStats));
+	}
+}
+
 /*
  * subroutine for pgstat_reset_all
  */
@@ -1336,11 +1368,25 @@ pgstat_reset_shared_counters(const char *target)
 		msg.m_resettarget = RESET_ARCHIVER;
 	else if (strcmp(target, "bgwriter") == 0)
 		msg.m_resettarget = RESET_BGWRITER;
+	else if (strcmp(target, "walwrites") == 0)
+	{
+		/*
+		 * Reset the wal writes statistics of the cluster. These statistics
+		 * are not reset by the stats collector because these are resides in a
+		 * shared memory, so it is not possible for the stats collector to
+		 * reset them. FIXME: This may need a sepearate function entirely to
+		 * reset the stats.
+		 */
+		LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
+		memset(WALWriteStats, 0, sizeof(PgStat_WalWritesStats));
+		WALWriteStats->stat_reset_timestamp = GetCurrentTimestamp();
+		LWLockRelease(WALWriteLock);
+	}
 	else
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("unrecognized reset target: \"%s\"", target),
-				 errhint("Target must be \"archiver\" or \"bgwriter\".")));
+				 errhint("Target must be \"archiver\" or \"bgwriter\" or \"walwrites\".")));
 
 	pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
 	pgstat_send(&msg, sizeof(msg));
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 2d1ed143e0..d9e244b5f4 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -150,6 +150,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		size = add_size(size, SyncScanShmemSize());
 		size = add_size(size, AsyncShmemSize());
 		size = add_size(size, BackendRandomShmemSize());
+		size = add_size(size, WALWritesShmemSize());
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
 #endif
@@ -218,6 +219,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	 * Set up xlog, clog, and buffers
 	 */
 	XLOGShmemInit();
+	WALWritesShmemInit();
 	CLOGShmemInit();
 	CommitTsShmemInit();
 	SUBTRANSShmemInit();
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 04cf209b5b..08dd1533d4 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1882,3 +1882,39 @@ pg_stat_get_archiver(PG_FUNCTION_ARGS)
 	PG_RETURN_DATUM(HeapTupleGetDatum(
 									  heap_form_tuple(tupdesc, values, nulls)));
 }
+
+Datum
+pg_stat_get_walwrites(PG_FUNCTION_ARGS)
+{
+	TupleDesc	tupdesc;
+#define NUM_PG_STAT_WALWRITE_COLS 9
+	Datum		values[NUM_PG_STAT_WALWRITE_COLS];
+	bool		nulls[NUM_PG_STAT_WALWRITE_COLS];
+
+	/* Initialize values and NULL flags arrays */
+	MemSet(values, 0, sizeof(values));
+	MemSet(nulls, 0, sizeof(nulls));
+
+	/* Build a tuple descriptor for our result type */
+	if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
+		elog(ERROR, "return type must be a row type");
+
+	LWLockAcquire(WALWriteLock, LW_EXCLUSIVE);
+
+	/* Get statistics about the archiver process */
+	/* Fill values and NULLs */
+	values[0] = Int64GetDatum(WALWriteStats->stats.writes);
+	values[1] = Int64GetDatum(WALWriteStats->stats.walwriter_writes);
+	values[2] = Int64GetDatum(WALWriteStats->stats.backend_writes);
+	values[3] = Int64GetDatum(WALWriteStats->stats.dirty_writes);
+	values[4] = Int64GetDatum(WALWriteStats->stats.backend_dirty_writes);
+	values[5] = Int64GetDatum(WALWriteStats->stats.write_blocks);
+	values[6] = Int64GetDatum(WALWriteStats->stats.walwriter_write_blocks);
+	values[7] = Int64GetDatum(WALWriteStats->stats.backend_write_blocks);
+	values[8] = TimestampTzGetDatum(WALWriteStats->stat_reset_timestamp);
+
+	LWLockRelease(WALWriteLock);
+	/* Returns the record as Datum */
+	PG_RETURN_DATUM(HeapTupleGetDatum(
+									  heap_form_tuple(tupdesc, values, nulls)));
+}
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 9680a4b0f7..317be66ab3 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -101,6 +101,7 @@ bool		IsPostmasterEnvironment = false;
 bool		IsUnderPostmaster = false;
 bool		IsBinaryUpgrade = false;
 bool		IsBackgroundWorker = false;
+bool		am_autovacuum_worker = false;
 
 bool		ExitOnAnyError = false;
 
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c969375981..a0bb323e1d 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2980,6 +2980,9 @@ DESCR("statistics: number of backend buffer writes that did their own fsync");
 DATA(insert OID = 2859 ( pg_stat_get_buf_alloc			PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 20 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_buf_alloc _null_ _null_ _null_ ));
 DESCR("statistics: number of buffer allocations");
 
+DATA(insert OID = 3998 (  pg_stat_get_walwrites		PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{20,20,20,20,20,20,20,20,1184}" "{o,o,o,o,o,o,o,o,o}" "{writes,walwriter_writes,backend_writes,dirty_writes,backend_dirty_writes,write_blocks,walwriter_write_blocks,backend_write_blocks,stats_reset}" _null_ _null_ pg_stat_get_walwrites _null_ _null_ _null_ ));
+DESCR("statistics: information about WAL writes activity");
+
 DATA(insert OID = 2978 (  pg_stat_get_function_calls		PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 20 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_calls _null_ _null_ _null_ ));
 DESCR("statistics: number of function calls");
 DATA(insert OID = 2979 (  pg_stat_get_function_total_time	PGNSP PGUID 12 1 0 0 0 f f f f t f s r 1 0 701 "26" _null_ _null_ _null_ _null_ _null_ pg_stat_get_function_total_time _null_ _null_ _null_ ));
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 59da7a6091..220a23e8e2 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -242,6 +242,8 @@ extern PGDLLIMPORT bool allowSystemTableMods;
 extern PGDLLIMPORT int work_mem;
 extern PGDLLIMPORT int maintenance_work_mem;
 
+extern bool am_autovacuum_worker;
+
 extern int	VacuumCostPageHit;
 extern int	VacuumCostPageMiss;
 extern int	VacuumCostPageDirty;
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 089b7c3a10..39f04dbde3 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -422,6 +422,37 @@ typedef struct PgStat_MsgBgWriter
 	PgStat_Counter m_checkpoint_sync_time;
 } PgStat_MsgBgWriter;
 
+/*
+ * Walwrites statistics counters
+ */
+typedef struct PgStat_WalWritesCounts
+{
+	PgStat_Counter writes;		/* No of writes by background
+								 * processes/workers */
+	PgStat_Counter walwriter_writes;	/* No of writes by walwriter */
+	PgStat_Counter backend_writes;	/* No of writes by backends */
+	PgStat_Counter dirty_writes;	/* No of dirty writes by background
+									 * processes/workers when WAL buffers full */
+	PgStat_Counter backend_dirty_writes;	/* No of dirty writes by backends
+											 * when WAL buffers full */
+	PgStat_Counter write_blocks;	/* Total no of pages written by background
+									 * processes/workers */
+	PgStat_Counter walwriter_write_blocks;	/* Total no of pages written by
+											 * walwriter */
+	PgStat_Counter backend_write_blocks;	/* Total no of pages written by
+											 * backends */
+} PgStat_WalWritesCounts;
+
+/* ----------
+ * PgStat_MsgWalWrites			Sent by the walwriter after collecting all shared stats
+ * ----------
+ */
+typedef struct PgStat_MsgWalWrites
+{
+	PgStat_MsgHdr m_hdr;
+	PgStat_WalWritesCounts stats;
+} PgStat_MsgWalWrites;
+
 /* ----------
  * PgStat_MsgRecoveryConflict	Sent by the backend upon recovery conflict
  * ----------
@@ -694,6 +725,14 @@ typedef struct PgStat_GlobalStats
 	TimestampTz stat_reset_timestamp;
 } PgStat_GlobalStats;
 
+/*
+ * Walwrites statistics kept in the stats collector
+ */
+typedef struct PgStat_WalWritesStats
+{
+	PgStat_WalWritesCounts stats;
+	TimestampTz stat_reset_timestamp;	/* Last time when the stats reset */
+}			PgStat_WalWritesStats;
 
 /* ----------
  * Backend types
@@ -1125,6 +1164,11 @@ extern char *pgstat_stat_filename;
  */
 extern PgStat_MsgBgWriter BgWriterStats;
 
+/*
+ * Wal writes statistics updated in XLogWrite function
+ */
+extern PgStat_WalWritesStats * WALWriteStats;
+
 /*
  * Updated by pgstat_count_buffer_*_time macros
  */
@@ -1143,6 +1187,9 @@ extern int	pgstat_start(void);
 extern void pgstat_reset_all(void);
 extern void allow_immediate_pgstat_restart(void);
 
+extern Size WALWritesShmemSize(void);
+extern void WALWritesShmemInit(void);
+
 #ifdef EXEC_BACKEND
 extern void PgstatCollectorMain(int argc, char *argv[]) pg_attribute_noreturn();
 #endif
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..6a84e3f980 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1973,6 +1973,16 @@ pg_stat_wal_receiver| SELECT s.pid,
     s.conninfo
    FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
   WHERE (s.pid IS NOT NULL);
+pg_stat_walwrites| SELECT a.writes,
+    a.walwriter_writes,
+    a.backend_writes,
+    a.dirty_writes,
+    a.backend_dirty_writes,
+    a.write_blocks,
+    a.walwriter_write_blocks,
+    a.backend_write_blocks,
+    a.stats_reset
+   FROM pg_stat_get_walwrites() a(writes, walwriter_writes, backend_writes, dirty_writes, backend_dirty_writes, write_blocks, walwriter_write_blocks, backend_write_blocks, stats_reset);
 pg_stat_xact_all_tables| SELECT c.oid AS relid,
     n.nspname AS schemaname,
     c.relname,
diff --git a/src/test/regress/expected/sysviews.out b/src/test/regress/expected/sysviews.out
index 2b738aae7c..89619bebaa 100644
--- a/src/test/regress/expected/sysviews.out
+++ b/src/test/regress/expected/sysviews.out
@@ -67,6 +67,13 @@ select count(*) >= 0 as ok from pg_prepared_xacts;
  t
 (1 row)
 
+-- There will surely and maximum one record
+select count(*) = 1 as ok from pg_stat_walwrites;
+ ok 
+----
+ t
+(1 row)
+
 -- This is to record the prevailing planner enable_foo settings during
 -- a regression test run.
 select name, setting from pg_settings where name like 'enable%';
diff --git a/src/test/regress/sql/sysviews.sql b/src/test/regress/sql/sysviews.sql
index 28e412b735..21f49c9a3b 100644
--- a/src/test/regress/sql/sysviews.sql
+++ b/src/test/regress/sql/sysviews.sql
@@ -32,6 +32,9 @@ select count(*) = 0 as ok from pg_prepared_statements;
 -- See also prepared_xacts.sql
 select count(*) >= 0 as ok from pg_prepared_xacts;
 
+-- There will surely and maximum one record
+select count(*) = 1 as ok from pg_stat_walwrites;
+
 -- This is to record the prevailing planner enable_foo settings during
 -- a regression test run.
 select name, setting from pg_settings where name like 'enable%';
-- 
2.15.0.windows.1

