diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 5b67def..ef6bc1c 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -357,6 +357,14 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
+ pg_stat_walwrites>pg_stat_walwrites
+ One row only, showing statistics about the
+ wal writing activity. See
+ for details.
+
+
+
+
pg_stat_database>pg_stat_database
One row per database, showing database-wide statistics. See
for details.
@@ -1833,6 +1841,70 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
single row, containing global data for the cluster.
+
+ pg_stat_walwrites View
+
+
+
+
+ Column
+ Type
+ Description
+
+
+
+
+
+ backend_writes>
+ bigint
+ Number of wal writes that are carried out by the backend process
+
+
+ writes>
+ bigint
+
+ Number of wal writes that are carried out by background workers such as checkpointer,
+ writer and walwriter.
+
+
+
+ write_blocks>
+ bigint
+ Number of wal pages written to the disk
+
+
+ write_time>
+ double precision
+
+ Total amount of time that has been spent in the portion of wal write processing where files
+ are written to disk, in milliseconds.
+ This field data will be populated only when the track_io_timing GUC is enabled
+
+
+
+ sync_time>
+ double precision
+
+ Total amount of time that has been spent in the portion of wal write processing where files
+ are synchronized to disk, in milliseconds.
+ This field data will be populated only when the track_io_timing GUC is enabled
+
+
+
+ stats_reset>
+ timestamp with time zone
+ Time at which these statistics were last reset
+
+
+
+
+
+
+ The pg_stat_walwrites view will always have a
+ single row, containing data about the wal writing activity of the cluster.
+
+
+
pg_stat_database View
@@ -2612,6 +2684,8 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
counters shown in the pg_stat_bgwriter> view.
Calling pg_stat_reset_shared('archiver')> will zero all the
counters shown in the pg_stat_archiver> view.
+ Calling pg_stat_reset_shared('walwrites')> will zero all the
+ counters shown in the pg_stat_walwrites> view.
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f23e108..2219433 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2333,6 +2333,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
int npages;
int startidx;
uint32 startoffset;
+ instr_time io_start,
+ io_time;
/* We should always be inside a critical section here */
Assert(CritSectionCount > 0);
@@ -2450,6 +2452,11 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
/* OK to write the page(s) */
from = XLogCtl->pages + startidx * (Size) XLOG_BLCKSZ;
nbytes = npages * (Size) XLOG_BLCKSZ;
+
+ /* Start timer to acquire start time of the wal write */
+ if (track_io_timing)
+ INSTR_TIME_SET_CURRENT(io_start);
+
nleft = nbytes;
do
{
@@ -2470,6 +2477,33 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
from += written;
} while (nleft > 0);
+ /* calculate the total time spent for wal writing */
+ if (track_io_timing)
+ {
+ INSTR_TIME_SET_CURRENT(io_time);
+ INSTR_TIME_SUBTRACT(io_time, io_start);
+
+ LocalWalWritesStats.m_wal_total_write_time += INSTR_TIME_GET_MILLISEC(io_time);
+ }
+ else
+ {
+ LocalWalWritesStats.m_wal_total_write_time = 0;
+ }
+
+ /* check whether writer is a background process or not? */
+ if (AmBackgroundWriterProcess() ||
+ AmWalWriterProcess() ||
+ AmCheckpointerProcess())
+ {
+ LocalWalWritesStats.m_writes++;
+ }
+ else
+ {
+ LocalWalWritesStats.m_backend_writes++;
+ }
+
+ LocalWalWritesStats.m_write_blocks += npages;
+
/* Update state for write */
openLogOff += nbytes;
npages = 0;
@@ -2489,8 +2523,25 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
*/
if (finishing_seg)
{
+ /* Start timer to acquire start time of the wal sync */
+ if (track_io_timing)
+ INSTR_TIME_SET_CURRENT(io_start);
+
issue_xlog_fsync(openLogFile, openLogSegNo);
+ /* calculate the total time spent for wal sync */
+ if (track_io_timing)
+ {
+ INSTR_TIME_SET_CURRENT(io_time);
+ INSTR_TIME_SUBTRACT(io_time, io_start);
+
+ LocalWalWritesStats.m_wal_total_sync_time += INSTR_TIME_GET_MILLISEC(io_time);
+ }
+ else
+ {
+ LocalWalWritesStats.m_wal_total_sync_time = 0;
+ }
+
/* signal that we need to wakeup walsenders later */
WalSndWakeupRequest();
@@ -2558,7 +2609,24 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
openLogOff = 0;
}
+ /* Start timer to acquire start time of the wal sync */
+ if (track_io_timing)
+ INSTR_TIME_SET_CURRENT(io_start);
+
issue_xlog_fsync(openLogFile, openLogSegNo);
+
+ /* calculate the total time spent for wal sync */
+ if (track_io_timing)
+ {
+ INSTR_TIME_SET_CURRENT(io_time);
+ INSTR_TIME_SUBTRACT(io_time, io_start);
+
+ LocalWalWritesStats.m_wal_total_sync_time += INSTR_TIME_GET_MILLISEC(io_time);
+ }
+ else
+ {
+ LocalWalWritesStats.m_wal_total_sync_time = 0;
+ }
}
/* signal that we need to wakeup walsenders later */
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 38be9cf..27223e2 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -854,6 +854,16 @@ 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
+ pg_stat_get_wal_backend_writes() AS backend_writes,
+ pg_stat_get_wal_writes() AS writes,
+ pg_stat_get_wal_write_blocks() AS write_blocks,
+ pg_stat_get_wal_write_time() AS write_time,
+ pg_stat_get_wal_sync_time() AS sync_time,
+ pg_stat_get_wal_stat_reset_time() AS stats_reset;
+
+
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/bgwriter.c b/src/backend/postmaster/bgwriter.c
index dcb4cf2..1cd623d 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -284,6 +284,7 @@ BackgroundWriterMain(void)
* Send off activity statistics to the stats collector
*/
pgstat_send_bgwriter();
+ pgstat_send_walwrites();
if (FirstCallSinceLastCheckpoint())
{
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index fe9041f..8549f8f 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -538,6 +538,7 @@ CheckpointerMain(void)
* stats message types.)
*/
pgstat_send_bgwriter();
+ pgstat_send_walwrites();
/*
* Sleep until we are signaled or it's time for another checkpoint or
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7176cf1..fe88411 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -126,6 +126,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_MsgWalWrites LocalWalWritesStats;
+
/* ----------
* Local data
* ----------
@@ -222,6 +231,7 @@ static int localNumBackends = 0;
*/
static PgStat_ArchiverStats archiverStats;
static PgStat_GlobalStats globalStats;
+static PgStat_WalWritesStats walwritesStats;
/*
* List of OIDs of databases we need to write out. If an entry is InvalidOid,
@@ -301,6 +311,7 @@ static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int len);
static void pgstat_recv_deadlock(PgStat_MsgDeadlock *msg, int len);
static void pgstat_recv_tempfile(PgStat_MsgTempFile *msg, int len);
+static void pgstat_recv_walwrites(PgStat_MsgWalWrites * msg, int len);
/* ------------------------------------------------------------
* Public functions called from postmaster follow
@@ -834,6 +845,9 @@ pgstat_report_stat(bool force)
/* Now, send function statistics */
pgstat_send_funcstats();
+
+ /* Now, send wal writes statistics */
+ pgstat_send_walwrites();
}
/*
@@ -1260,11 +1274,13 @@ 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)
+ msg.m_resettarget = RESET_WALWRITES;
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));
@@ -2478,6 +2494,21 @@ pgstat_fetch_global(void)
return &globalStats;
}
+/*
+ * ---------
+ * pgstat_fetch_stat_walwrites() -
+ *
+ * Support function for the SQL-callable pgstat* functions. Returns
+ * a pointer to the walwrites statistics struct.
+ * ---------
+ */
+PgStat_WalWritesStats *
+pgstat_fetch_stat_walwrites(void)
+{
+ backend_read_statsfile();
+
+ return &walwritesStats;
+}
/* ------------------------------------------------------------
* Functions for management of the shared-memory PgBackendStatus array
@@ -3687,6 +3718,39 @@ pgstat_send_bgwriter(void)
MemSet(&BgWriterStats, 0, sizeof(BgWriterStats));
}
+/* ----------
+ * pgstat_send_walwrites() -
+ *
+ * Send wal writes statistics to the collector
+ * ----------
+ */
+
+void
+pgstat_send_walwrites(void)
+{
+ /* We assume this initializes to zeroes */
+ static const PgStat_MsgWalWrites all_zeroes;
+
+ /*
+ * This function can be called even if nothing at all has happened. In
+ * this case, avoid sending a completely empty message to the stats
+ * collector.
+ */
+ if (memcmp(&LocalWalWritesStats, &all_zeroes, sizeof(PgStat_MsgWalWrites)) == 0)
+ return;
+
+ /*
+ * Prepare and send the message
+ */
+ pgstat_setheader(&LocalWalWritesStats.m_hdr, PGSTAT_MTYPE_WALWRITES);
+ pgstat_send(&LocalWalWritesStats, sizeof(LocalWalWritesStats));
+
+ /*
+ * Clear out the statistics buffer, so it can be re-used.
+ */
+ MemSet(&LocalWalWritesStats, 0, sizeof(LocalWalWritesStats));
+}
+
/* ----------
* PgstatCollectorMain() -
@@ -3903,6 +3967,10 @@ PgstatCollectorMain(int argc, char *argv[])
pgstat_recv_tempfile((PgStat_MsgTempFile *) &msg, len);
break;
+ case PGSTAT_MTYPE_WALWRITES:
+ pgstat_recv_walwrites((PgStat_MsgWalWrites *) &msg, len);
+ break;
+
default:
break;
}
@@ -4169,6 +4237,12 @@ pgstat_write_statsfiles(bool permanent, bool allDbs)
(void) rc; /* we'll check for error with ferror */
/*
+ * Write wal writes stats struct
+ */
+ rc = fwrite(&walwritesStats, sizeof(walwritesStats), 1, fpout);
+ (void) rc; /* we'll check for error with ferror */
+
+ /*
* Walk through the database table.
*/
hash_seq_init(&hstat, pgStatDBHash);
@@ -4425,6 +4499,7 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
*/
memset(&globalStats, 0, sizeof(globalStats));
memset(&archiverStats, 0, sizeof(archiverStats));
+ memset(&walwritesStats, 0, sizeof(walwritesStats));
/*
* Set the current timestamp (will be kept only in case we can't load an
@@ -4432,6 +4507,7 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
*/
globalStats.stat_reset_timestamp = GetCurrentTimestamp();
archiverStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
+ walwritesStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
/*
* Try to open the stats file. If it doesn't exist, the backends simply
@@ -4484,6 +4560,16 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
}
/*
+ * Read wal writes stats struct
+ */
+ if (fread(&walwritesStats, 1, sizeof(walwritesStats), fpin) != sizeof(walwritesStats))
+ {
+ ereport(pgStatRunningInCollector ? LOG : WARNING,
+ (errmsg("corrupted statistics file \"%s\"", statfile)));
+ goto done;
+ }
+
+ /*
* We found an existing collector stats file. Read it and put all the
* hashtable entries into place.
*/
@@ -4772,6 +4858,7 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
PgStat_StatDBEntry dbentry;
PgStat_GlobalStats myGlobalStats;
PgStat_ArchiverStats myArchiverStats;
+ PgStat_WalWritesStats myWalwritesStats;
FILE *fpin;
int32 format_id;
const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
@@ -4826,6 +4913,18 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
return false;
}
+ /*
+ * Read wal writes stats struct
+ */
+ if (fread(&myWalwritesStats, 1, sizeof(myWalwritesStats),
+ fpin) != sizeof(myWalwritesStats))
+ {
+ ereport(pgStatRunningInCollector ? LOG : WARNING,
+ (errmsg("corrupted statistics file \"%s\"", statfile)));
+ FreeFile(fpin);
+ return false;
+ }
+
/* By default, we're going to return the timestamp of the global file. */
*ts = myGlobalStats.stats_timestamp;
@@ -5388,6 +5487,12 @@ pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
memset(&archiverStats, 0, sizeof(archiverStats));
archiverStats.stat_reset_timestamp = GetCurrentTimestamp();
}
+ else if (msg->m_resettarget == RESET_WALWRITES)
+ {
+ /* Reset the wal writes statistics of the cluster. */
+ memset(&walwritesStats, 0, sizeof(walwritesStats));
+ walwritesStats.stat_reset_timestamp = GetCurrentTimestamp();
+ }
/*
* Presumably the sender of this message validated the target, don't
@@ -5568,6 +5673,22 @@ pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len)
}
/* ----------
+ * pgstat_recv_walwrites() -
+ *
+ * Process a WALWRITES message.
+ * ----------
+ */
+static void
+pgstat_recv_walwrites(PgStat_MsgWalWrites * msg, int len)
+{
+ walwritesStats.backend_writes += msg->m_backend_writes;
+ walwritesStats.writes += msg->m_writes;
+ walwritesStats.write_blocks += msg->m_write_blocks;
+ walwritesStats.total_write_time += msg->m_wal_total_write_time;
+ walwritesStats.total_sync_time += msg->m_wal_total_sync_time;
+}
+
+/* ----------
* pgstat_recv_recoveryconflict() -
*
* Process a RECOVERYCONFLICT message.
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index a575d8f..cf0c279 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -280,6 +280,8 @@ WalWriterMain(void)
else if (left_till_hibernate > 0)
left_till_hibernate--;
+ pgstat_send_walwrites();
+
/*
* Sleep until we are signaled or WalWriterDelay has elapsed. If we
* haven't done anything useful for quite some time, lengthen the
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index a987d0d..b8dcfc8 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1521,6 +1521,44 @@ pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
}
Datum
+pg_stat_get_wal_backend_writes(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_INT64(pgstat_fetch_stat_walwrites()->backend_writes);
+}
+
+Datum
+pg_stat_get_wal_writes(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_INT64(pgstat_fetch_stat_walwrites()->writes);
+}
+
+Datum
+pg_stat_get_wal_write_blocks(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_INT64(pgstat_fetch_stat_walwrites()->write_blocks);
+}
+
+Datum
+pg_stat_get_wal_write_time(PG_FUNCTION_ARGS)
+{
+ /* time is already in msec, just convert to double for presentation */
+ PG_RETURN_FLOAT8((double) pgstat_fetch_stat_walwrites()->total_write_time);
+}
+
+Datum
+pg_stat_get_wal_sync_time(PG_FUNCTION_ARGS)
+{
+ /* time is already in msec, just convert to double for presentation */
+ PG_RETURN_FLOAT8((double) pgstat_fetch_stat_walwrites()->total_sync_time);
+}
+
+Datum
+pg_stat_get_wal_stat_reset_time(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_walwrites()->stat_reset_timestamp);
+}
+
+Datum
pg_stat_get_xact_numscans(PG_FUNCTION_ARGS)
{
Oid relid = PG_GETARG_OID(0);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 41c12af..722ad53 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2871,6 +2871,18 @@ 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 = 3354 ( pg_stat_get_wal_backend_writes 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_wal_backend_writes _null_ _null_ _null_ ));
+DESCR("statistics: number of backend wal writes statistics");
+DATA(insert OID = 3355 ( pg_stat_get_wal_writes 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_wal_writes _null_ _null_ _null_ ));
+DESCR("statistics: number of background process wal writes statistics");
+DATA(insert OID = 3356 ( pg_stat_get_wal_write_blocks 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_wal_write_blocks _null_ _null_ _null_ ));
+DESCR("statistics: number of wal blocks written statistics");
+DATA(insert OID = 3357 ( pg_stat_get_wal_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_wal_write_time _null_ _null_ _null_ ));
+DESCR("statistics: get total time spent in writing wal blocks to disk, in milliseconds");
+DATA(insert OID = 3358 ( pg_stat_get_wal_sync_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 701 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_wal_sync_time _null_ _null_ _null_ ));
+DESCR("statistics: get total time spent in synchronizing buffers to disk, in milliseconds");
+DATA(insert OID = 3359 ( pg_stat_get_wal_stat_reset_time PGNSP PGUID 12 1 0 0 0 f f f f t f s r 0 0 1184 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_wal_stat_reset_time _null_ _null_ _null_ ));
+DESCR("statistics: last reset for the wal writes statistics");
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/pgstat.h b/src/include/pgstat.h
index de8225b..1c62e5a 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -64,7 +64,8 @@ typedef enum StatMsgType
PGSTAT_MTYPE_FUNCPURGE,
PGSTAT_MTYPE_RECOVERYCONFLICT,
PGSTAT_MTYPE_TEMPFILE,
- PGSTAT_MTYPE_DEADLOCK
+ PGSTAT_MTYPE_DEADLOCK,
+ PGSTAT_MTYPE_WALWRITES
} StatMsgType;
/* ----------
@@ -119,7 +120,8 @@ typedef struct PgStat_TableCounts
typedef enum PgStat_Shared_Reset_Target
{
RESET_ARCHIVER,
- RESET_BGWRITER
+ RESET_BGWRITER,
+ RESET_WALWRITES
} PgStat_Shared_Reset_Target;
/* Possible object types for resetting single counters */
@@ -423,6 +425,22 @@ typedef struct PgStat_MsgBgWriter
} PgStat_MsgBgWriter;
/* ----------
+ * PgStat_MsgWalWrites Sent by the backend or walwriter or writer
+ * or checkpointer process
+ * ----------
+ */
+typedef struct PgStat_MsgWalWrites
+{
+ PgStat_MsgHdr m_hdr;
+
+ PgStat_Counter m_backend_writes; /* No of writes by backend */
+ PgStat_Counter m_writes; /* No of writes by background processes */
+ PgStat_Counter m_write_blocks; /* Total no of pages written */
+ PgStat_Counter m_wal_total_write_time; /* times in milliseconds */
+ PgStat_Counter m_wal_total_sync_time; /* times in milliseconds */
+} PgStat_MsgWalWrites;
+
+/* ----------
* PgStat_MsgRecoveryConflict Sent by the backend upon recovery conflict
* ----------
*/
@@ -555,6 +573,7 @@ typedef union PgStat_Msg
PgStat_MsgFuncpurge msg_funcpurge;
PgStat_MsgRecoveryConflict msg_recoveryconflict;
PgStat_MsgDeadlock msg_deadlock;
+ PgStat_MsgWalWrites msg_walwrites;
} PgStat_Msg;
@@ -694,6 +713,18 @@ typedef struct PgStat_GlobalStats
TimestampTz stat_reset_timestamp;
} PgStat_GlobalStats;
+/*
+ * Walwrites statistics kept in the stats collector
+ */
+typedef struct PgStat_WalWritesStats
+{
+ PgStat_Counter backend_writes; /* No of writes by backend */
+ PgStat_Counter writes; /* No of writes by background processes */
+ PgStat_Counter write_blocks; /* Total no of pages written */
+ PgStat_Counter total_write_time; /* Total write time */
+ PgStat_Counter total_sync_time; /* Total sync time */
+ TimestampTz stat_reset_timestamp; /* Last time when the stats reset */
+} PgStat_WalWritesStats;
/* ----------
* Backend states
@@ -1008,6 +1039,11 @@ extern char *pgstat_stat_filename;
extern PgStat_MsgBgWriter BgWriterStats;
/*
+ * Wal writes statistics updated in XLogWrite function
+ */
+extern PgStat_MsgWalWrites LocalWalWritesStats;
+
+/*
* Updated by pgstat_count_buffer_*_time macros
*/
extern PgStat_Counter pgStatBlockReadTime;
@@ -1200,6 +1236,7 @@ extern void pgstat_twophase_postabort(TransactionId xid, uint16 info,
extern void pgstat_send_archiver(const char *xlog, bool failed);
extern void pgstat_send_bgwriter(void);
+extern void pgstat_send_walwrites(void);
/* ----------
* Support functions for the SQL-callable functions to
@@ -1214,5 +1251,7 @@ extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
extern int pgstat_fetch_stat_numbackends(void);
extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
extern PgStat_GlobalStats *pgstat_fetch_global(void);
+extern PgStat_WalWritesStats *pgstat_fetch_stat_walwrites(void);
+
#endif /* PGSTAT_H */
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c661f1d..402a396 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1945,6 +1945,12 @@ 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 pg_stat_get_wal_backend_writes() AS backend_writes,
+ pg_stat_get_wal_writes() AS writes,
+ pg_stat_get_wal_write_blocks() AS write_blocks,
+ pg_stat_get_wal_write_time() AS write_time,
+ pg_stat_get_wal_sync_time() AS sync_time,
+ pg_stat_get_wal_stat_reset_time() AS 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 d48abd7..b852069 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(*) > 0 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 28e412b..3769880 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(*) > 0 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%';