Hi,

The revised patch for wal buffer statistics is attached.
A test script is also attached. Please take a look.

Regards,

(2013/07/19 7:49), Satoshi Nagayasu wrote:
Will revise and re-resubmit for the next CF.

Regards,

2013/07/19 1:06, Alvaro Herrera wrote:

What happened to this patch?  We were waiting on an updated version from
you.


Satoshi Nagayasu wrote:
(2012/12/10 3:06), Tomas Vondra wrote:
On 29.10.2012 04:58, Satoshi Nagayasu wrote:
2012/10/24 1:12, Alvaro Herrera wrote:
Satoshi Nagayasu escribi�:

With this patch, walwriter process and each backend process
would sum up dirty writes, and send it to the stat collector.
So, the value could be saved in the stat file, and could be
kept on restarting.

The statistics could be retreive with using
pg_stat_get_xlog_dirty_writes() function, and could be reset
with calling pg_stat_reset_shared('walwriter').

Now, I have one concern.

The reset time could be captured in
globalStats.stat_reset_timestamp,
but this value is the same with the bgwriter one.

So, once pg_stat_reset_shared('walwriter') is called,
stats_reset column in pg_stat_bgwriter does represent
the reset time for walwriter, not for bgwriter.

How should we handle this?  Should we split this value?
And should we have new system view for walwriter?

I think the answer to the two last questions is yes.  It doesn't
seem to
make sense, to me, to have a single reset timings for what are
effectively two separate things.

Please submit an updated patch to next CF.  I'm marking this one
returned with feedback.  Thanks.


I attached the latest one, which splits the reset_time
for bgwriter and walwriter, and provides new system view,
called pg_stat_walwriter, to show the dirty write counter
and the reset time.

I've done a quick review of the v4 patch:

Thanks for the review, and sorry for my delayed response.

1) applies fine on HEAD, compiles fine

2) "make installcheck" fails because of a difference in the 'rules'
    test suite (there's a new view "pg_stat_walwriter" - see the
    attached patch for a fixed version or expected/rules.out)

Ah, I forgot about the regression test. I will fix it. Thanks.

3) I do agree with Alvaro that using the same struct for two separate
    components (bgwriter and walwriter) seems a bit awkward. For
example
    you need to have two separate stat_reset fields, the reset code
    becomes much more verbose (because you need to list individual
    fields) etc.

    So I'd vote to either split this into two structures or keeping it
    as a single structure (although with two views on top of it).

Ok, I will split it into two structs, PgStat_BgWriterGlobalStats and
PgStat_WalWriterGlobalStats, and will modify PgStat_GlobalStats to
hold those two structs in the stat collector.

4) Are there any other fields that might be interesting? Right now
    there's just "dirty_writes" but I guess there are other values.
E.g.
    how much data was actually written etc.?

AFAIK, I think those numbers can be obtained by calling
pg_current_xlog_insert_location() or pg_current_xlog_location(),
but if we need it, I will add it.

Regards,





--
Satoshi Nagayasu <sn...@uptime.jp>
Uptime Technologies, LLC. http://www.uptime.jp
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 23ebc11..cdced7f 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -1878,6 +1878,13 @@ include 'filename'
         results in most cases.
        </para>
 
+       <para>
+        When you see pg_stat_walwriter.dirty_write, which means number
+        of buffer flushing at buffer full, is continuously increasing
+        in your running server, you may need to enlarge this buffer
+        size.
+       </para>
+
       </listitem>
      </varlistentry>
 
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4ec6981..15d9202 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -278,6 +278,14 @@ postgres: <replaceable>user</> <replaceable>database</> 
<replaceable>host</> <re
      </row>
 
      <row>
+      
<entry><structname>pg_stat_walwriter</><indexterm><primary>pg_stat_walwriter</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the wal writer
+       process's activity. See <xref linkend="pg-stat-walwriter-view">
+       for details.
+     </entry>
+     </row>
+
+     <row>
       
<entry><structname>pg_stat_database</><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
        <xref linkend="pg-stat-database-view"> for details.
@@ -735,6 +743,39 @@ postgres: <replaceable>user</> <replaceable>database</> 
<replaceable>host</> <re
    single row, containing global data for the cluster.
   </para>
 
+  <table id="pg-stat-walwriter-view" xreflabel="pg_stat_walwriter">
+   <title><structname>pg_stat_walwriter</structname> View</title>
+
+   <tgroup cols="3">
+    <thead>
+    <row>
+      <entry>Column</entry>
+      <entry>Type</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry><structfield>dirty_writes</></entry>
+      <entry><type>bigint</type></entry>
+      <entry>Number of dirty writes, which means flushing wal buffers
+       because of its full.</entry>
+     </row>
+     <row>
+      <entry><structfield>stats_reset</></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_walwriter</structname> view will always have a
+   single row, containing global data for the cluster.
+  </para>
+
   <table id="pg-stat-database-view" xreflabel="pg_stat_database">
    <title><structname>pg_stat_database</structname> View</title>
    <tgroup cols="3">
diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index dc47c47..d0e85c9 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2467,6 +2467,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
                                        WriteRqst.Write = OldPageRqstPtr;
                                        WriteRqst.Flush = 0;
                                        XLogWrite(WriteRqst, false);
+                                       WalWriterStats.m_xlog_dirty_writes++;
                                        LWLockRelease(WALWriteLock);
                                        
TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_DONE();
                                }
diff --git a/src/backend/catalog/system_views.sql 
b/src/backend/catalog/system_views.sql
index 575a40f..12a2ed0 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -686,6 +686,11 @@ 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_walwriter AS
+    SELECT
+        pg_stat_get_xlog_dirty_writes() AS dirty_writes,
+        pg_stat_get_wal_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_user_mappings AS
     SELECT
         U.oid       AS umid,
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index b5ce2f6..8c56af5 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -129,6 +129,14 @@ char          *pgstat_stat_tmpname = NULL;
  */
 PgStat_MsgBgWriter BgWriterStats;
 
+/*
+ * WalWriter statistics counter.
+ * This counter is incremented by each XLogWrite call,
+ * both in the wal writer process and each backend.
+ * And then, sent to the stat collector process.
+ */
+PgStat_MsgWalWriter WalWriterStats;
+
 /* ----------
  * Local data
  * ----------
@@ -293,6 +301,7 @@ static void pgstat_recv_autovac(PgStat_MsgAutovacStart 
*msg, int len);
 static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
 static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
 static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
+static void pgstat_recv_walwriter(PgStat_MsgWalWriter *msg, int len);
 static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
 static void pgstat_recv_funcpurge(PgStat_MsgFuncpurge *msg, int len);
 static void pgstat_recv_recoveryconflict(PgStat_MsgRecoveryConflict *msg, int 
len);
@@ -820,6 +829,9 @@ pgstat_report_stat(bool force)
 
        /* Now, send function statistics */
        pgstat_send_funcstats();
+
+       /* Now, send wal buffer flush statistics */
+       pgstat_send_walwriter();
 }
 
 /*
@@ -1249,11 +1261,13 @@ pgstat_reset_shared_counters(const char *target)
 
        if (strcmp(target, "bgwriter") == 0)
                msg.m_resettarget = RESET_BGWRITER;
+       else if (strcmp(target, "walwriter") == 0)
+               msg.m_resettarget = RESET_WALWRITER;
        else
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                 errmsg("unrecognized reset target: \"%s\"", 
target),
-                                errhint("Target must be \"bgwriter\".")));
+                                errhint("Target must be \"bgwriter\" or 
\"walwriter\".")));
 
        pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
        pgstat_send(&msg, sizeof(msg));
@@ -3055,6 +3069,38 @@ pgstat_send_bgwriter(void)
        MemSet(&BgWriterStats, 0, sizeof(BgWriterStats));
 }
 
+/* ----------
+ * pgstat_send_walwriter() -
+ *
+ *             Send walwriter statistics to the collector
+ * ----------
+ */
+void
+pgstat_send_walwriter(void)
+{
+       /* We assume this initializes to zeroes */
+       static const PgStat_MsgBgWriter 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(&WalWriterStats, &all_zeroes, sizeof(PgStat_MsgWalWriter)) 
== 0)
+               return;
+
+       /*
+        * Prepare and send the message
+        */
+       pgstat_setheader(&WalWriterStats.m_hdr, PGSTAT_MTYPE_WALWRITER);
+       pgstat_send(&WalWriterStats, sizeof(WalWriterStats));
+
+       /*
+        * Clear out the statistics buffer, so it can be re-used.
+        */
+       MemSet(&WalWriterStats, 0, sizeof(WalWriterStats));
+}
+
 
 /* ----------
  * PgstatCollectorMain() -
@@ -3270,6 +3316,10 @@ PgstatCollectorMain(int argc, char *argv[])
                                        
pgstat_recv_bgwriter((PgStat_MsgBgWriter *) &msg, len);
                                        break;
 
+                               case PGSTAT_MTYPE_WALWRITER:
+                                       
pgstat_recv_walwriter((PgStat_MsgWalWriter *) &msg, len);
+                                       break;
+
                                case PGSTAT_MTYPE_FUNCSTAT:
                                        
pgstat_recv_funcstat((PgStat_MsgFuncstat *) &msg, len);
                                        break;
@@ -3825,7 +3875,8 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool 
deep)
         * Set the current timestamp (will be kept only in case we can't load an
         * existing statsfile).
         */
-       globalStats.stat_reset_timestamp = GetCurrentTimestamp();
+       globalStats.bgWriterGlobalStats.stat_reset_timestamp = 
GetCurrentTimestamp();
+       globalStats.walWriterGlobalStats.stat_reset_timestamp = 
GetCurrentTimestamp();
 
        /*
         * Try to open the stats file. If it doesn't exist, the backends simply
@@ -4723,8 +4774,23 @@ 
pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
        if (msg->m_resettarget == RESET_BGWRITER)
        {
                /* Reset the global background writer statistics for the 
cluster. */
-               memset(&globalStats, 0, sizeof(globalStats));
-               globalStats.stat_reset_timestamp = GetCurrentTimestamp();
+               globalStats.bgWriterGlobalStats.timed_checkpoints       = 0;
+               globalStats.bgWriterGlobalStats.requested_checkpoints   = 0;
+               globalStats.bgWriterGlobalStats.checkpoint_write_time   = 0;
+               globalStats.bgWriterGlobalStats.checkpoint_sync_time    = 0;
+               globalStats.bgWriterGlobalStats.buf_written_checkpoints = 0;
+               globalStats.bgWriterGlobalStats.buf_written_clean       = 0;
+               globalStats.bgWriterGlobalStats.maxwritten_clean        = 0;
+               globalStats.bgWriterGlobalStats.buf_written_backend     = 0;
+               globalStats.bgWriterGlobalStats.buf_fsync_backend       = 0;
+               globalStats.bgWriterGlobalStats.buf_alloc               = 0;
+               globalStats.bgWriterGlobalStats.stat_reset_timestamp = 
GetCurrentTimestamp();
+       }
+       else if (msg->m_resettarget == RESET_WALWRITER)
+       {
+               /* Reset the global walwriter statistics for the cluster. */
+               globalStats.walWriterGlobalStats.xlog_dirty_writes = 0;
+               globalStats.walWriterGlobalStats.stat_reset_timestamp = 
GetCurrentTimestamp();
        }
 
        /*
@@ -4865,16 +4931,28 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
 static void
 pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len)
 {
-       globalStats.timed_checkpoints += msg->m_timed_checkpoints;
-       globalStats.requested_checkpoints += msg->m_requested_checkpoints;
-       globalStats.checkpoint_write_time += msg->m_checkpoint_write_time;
-       globalStats.checkpoint_sync_time += msg->m_checkpoint_sync_time;
-       globalStats.buf_written_checkpoints += msg->m_buf_written_checkpoints;
-       globalStats.buf_written_clean += msg->m_buf_written_clean;
-       globalStats.maxwritten_clean += msg->m_maxwritten_clean;
-       globalStats.buf_written_backend += msg->m_buf_written_backend;
-       globalStats.buf_fsync_backend += msg->m_buf_fsync_backend;
-       globalStats.buf_alloc += msg->m_buf_alloc;
+       globalStats.bgWriterGlobalStats.timed_checkpoints += 
msg->m_timed_checkpoints;
+       globalStats.bgWriterGlobalStats.requested_checkpoints += 
msg->m_requested_checkpoints;
+       globalStats.bgWriterGlobalStats.checkpoint_write_time += 
msg->m_checkpoint_write_time;
+       globalStats.bgWriterGlobalStats.checkpoint_sync_time += 
msg->m_checkpoint_sync_time;
+       globalStats.bgWriterGlobalStats.buf_written_checkpoints += 
msg->m_buf_written_checkpoints;
+       globalStats.bgWriterGlobalStats.buf_written_clean += 
msg->m_buf_written_clean;
+       globalStats.bgWriterGlobalStats.maxwritten_clean += 
msg->m_maxwritten_clean;
+       globalStats.bgWriterGlobalStats.buf_written_backend += 
msg->m_buf_written_backend;
+       globalStats.bgWriterGlobalStats.buf_fsync_backend += 
msg->m_buf_fsync_backend;
+       globalStats.bgWriterGlobalStats.buf_alloc += msg->m_buf_alloc;
+}
+
+/* ----------
+ * pgstat_recv_walwriter() -
+ *
+ *     Process a WALWRITER message.
+ * ----------
+ */
+static void
+pgstat_recv_walwriter(PgStat_MsgWalWriter *msg, int len)
+{
+       globalStats.walWriterGlobalStats.xlog_dirty_writes += 
msg->m_xlog_dirty_writes;
 }
 
 /* ----------
diff --git a/src/backend/postmaster/walwriter.c 
b/src/backend/postmaster/walwriter.c
index 8359da6..dedec0d 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -290,6 +290,8 @@ WalWriterMain(void)
                else if (left_till_hibernate > 0)
                        left_till_hibernate--;
 
+               pgstat_send_walwriter();
+
                /*
                 * 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 0533cd6..df9f1d8 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -98,6 +98,7 @@ extern Datum 
pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_buf_alloc(PG_FUNCTION_ARGS);
+extern Datum pg_stat_get_wal_stat_reset_time(PG_FUNCTION_ARGS);
 
 extern Datum pg_stat_get_xact_numscans(PG_FUNCTION_ARGS);
 extern Datum pg_stat_get_xact_tuples_returned(PG_FUNCTION_ARGS);
@@ -119,6 +120,8 @@ extern Datum pg_stat_reset_shared(PG_FUNCTION_ARGS);
 extern Datum pg_stat_reset_single_table_counters(PG_FUNCTION_ARGS);
 extern Datum pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS);
 
+extern Datum pg_stat_get_xlog_dirty_writes(PG_FUNCTION_ARGS);
+
 /* Global bgwriter statistics, from bgwriter.c */
 extern PgStat_MsgBgWriter bgwriterStats;
 
@@ -1409,69 +1412,75 @@ pg_stat_get_db_blk_write_time(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->timed_checkpoints);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.timed_checkpoints);
 }
 
 Datum
 pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->requested_checkpoints);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.requested_checkpoints);
 }
 
 Datum
 pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->buf_written_checkpoints);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.buf_written_checkpoints);
 }
 
 Datum
 pg_stat_get_bgwriter_buf_written_clean(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->buf_written_clean);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.buf_written_clean);
 }
 
 Datum
 pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->maxwritten_clean);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.maxwritten_clean);
 }
 
 Datum
 pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
 {
        /* time is already in msec, just convert to double for presentation */
-       PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_write_time);
+       PG_RETURN_FLOAT8((double) 
pgstat_fetch_global()->bgWriterGlobalStats.checkpoint_write_time);
 }
 
 Datum
 pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 {
        /* time is already in msec, just convert to double for presentation */
-       PG_RETURN_FLOAT8((double) pgstat_fetch_global()->checkpoint_sync_time);
+       PG_RETURN_FLOAT8((double) 
pgstat_fetch_global()->bgWriterGlobalStats.checkpoint_sync_time);
 }
 
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->stat_reset_timestamp);
+       
PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->bgWriterGlobalStats.stat_reset_timestamp);
 }
 
 Datum
 pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->buf_written_backend);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.buf_written_backend);
 }
 
 Datum
 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->buf_fsync_backend);
+       
PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.buf_fsync_backend);
 }
 
 Datum
 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
 {
-       PG_RETURN_INT64(pgstat_fetch_global()->buf_alloc);
+       PG_RETURN_INT64(pgstat_fetch_global()->bgWriterGlobalStats.buf_alloc);
+}
+
+Datum
+pg_stat_get_wal_stat_reset_time(PG_FUNCTION_ARGS)
+{
+       
PG_RETURN_TIMESTAMPTZ(pgstat_fetch_global()->walWriterGlobalStats.stat_reset_timestamp);
 }
 
 Datum
@@ -1711,3 +1720,9 @@ pg_stat_reset_single_function_counters(PG_FUNCTION_ARGS)
 
        PG_RETURN_VOID();
 }
+
+Datum
+pg_stat_get_xlog_dirty_writes(PG_FUNCTION_ARGS)
+{
+       
PG_RETURN_INT64(pgstat_fetch_global()->walWriterGlobalStats.xlog_dirty_writes);
+}
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index f03dd0b..add47dc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2709,6 +2709,8 @@ DATA(insert OID = 3063 ( pg_stat_get_buf_fsync_backend 
PGNSP PGUID 12 1 0 0 0 f
 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 0 0 20 "" _null_ _null_ _null_ _null_ 
pg_stat_get_buf_alloc _null_ _null_ _null_ ));
 DESCR("statistics: number of buffer allocations");
+DATA(insert OID = 2860 ( pg_stat_get_wal_stat_reset_time PGNSP PGUID 12 1 0 0 
0 f f f f t f s 0 0 1184 "" _null_ _null_ _null_ _null_  
pg_stat_get_wal_stat_reset_time _null_ _null_ _null_ ));
+DESCR("statistics: last reset for the wal");
 
 DATA(insert OID = 2978 (  pg_stat_get_function_calls           PGNSP PGUID 12 
1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ 
pg_stat_get_function_calls _null_ _null_ _null_ ));
 DESCR("statistics: number of function calls");
@@ -2753,6 +2755,9 @@ DESCR("statistics: reset collected statistics for a 
single table or index in the
 DATA(insert OID = 3777 (  pg_stat_reset_single_function_counters       PGNSP 
PGUID 12 1 0 0 0 f f f f f f v 1 0 2278 "26" _null_ _null_ _null_ _null_  
pg_stat_reset_single_function_counters _null_ _null_ _null_ ));
 DESCR("statistics: reset collected statistics for a single function in the 
current database");
 
+DATA(insert OID = 3766 (  pg_stat_get_xlog_dirty_writes  PGNSP PGUID 12 1 0 0 
0 f f f f f f v 0 0 20 "" _null_ _null_ _null_ _null_ 
pg_stat_get_xlog_dirty_writes _null_ _null_ _null_ ));
+DESCR("statistics: get xlog dirty buffer write statistics");
+
 DATA(insert OID = 3163 (  pg_trigger_depth                             PGNSP 
PGUID 12 1 0 0 0 f f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ 
pg_trigger_depth _null_ _null_ _null_ ));
 DESCR("current trigger depth");
 
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index fb242e4..1213964 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -45,6 +45,7 @@ typedef enum StatMsgType
        PGSTAT_MTYPE_VACUUM,
        PGSTAT_MTYPE_ANALYZE,
        PGSTAT_MTYPE_BGWRITER,
+       PGSTAT_MTYPE_WALWRITER,
        PGSTAT_MTYPE_FUNCSTAT,
        PGSTAT_MTYPE_FUNCPURGE,
        PGSTAT_MTYPE_RECOVERYCONFLICT,
@@ -102,7 +103,8 @@ typedef struct PgStat_TableCounts
 /* Possible targets for resetting cluster-wide shared values */
 typedef enum PgStat_Shared_Reset_Target
 {
-       RESET_BGWRITER
+       RESET_BGWRITER,
+       RESET_WALWRITER
 } PgStat_Shared_Reset_Target;
 
 /* Possible object types for resetting single counters */
@@ -373,6 +375,17 @@ typedef struct PgStat_MsgBgWriter
 } PgStat_MsgBgWriter;
 
 /* ----------
+ * PgStat_MsgWalWriter                 Sent by the walwriter to update 
statistics.
+ * ----------
+ */
+typedef struct PgStat_MsgWalWriter
+{
+       PgStat_MsgHdr m_hdr;
+
+       PgStat_Counter m_xlog_dirty_writes;
+} PgStat_MsgWalWriter;
+
+/* ----------
  * PgStat_MsgRecoveryConflict  Sent by the backend upon recovery conflict
  * ----------
  */
@@ -500,6 +513,7 @@ typedef union PgStat_Msg
        PgStat_MsgVacuum msg_vacuum;
        PgStat_MsgAnalyze msg_analyze;
        PgStat_MsgBgWriter msg_bgwriter;
+       PgStat_MsgWalWriter msg_walwriter;
        PgStat_MsgFuncstat msg_funcstat;
        PgStat_MsgFuncpurge msg_funcpurge;
        PgStat_MsgRecoveryConflict msg_recoveryconflict;
@@ -608,12 +622,8 @@ typedef struct PgStat_StatFuncEntry
 } PgStat_StatFuncEntry;
 
 
-/*
- * Global statistics kept in the stats collector
- */
-typedef struct PgStat_GlobalStats
+typedef struct PgStat_BgWriterGlobalStats
 {
-       TimestampTz stats_timestamp;    /* time of stats file update */
        PgStat_Counter timed_checkpoints;
        PgStat_Counter requested_checkpoints;
        PgStat_Counter checkpoint_write_time;           /* times in 
milliseconds */
@@ -625,6 +635,22 @@ typedef struct PgStat_GlobalStats
        PgStat_Counter buf_fsync_backend;
        PgStat_Counter buf_alloc;
        TimestampTz stat_reset_timestamp;
+} PgStat_BgWriterGlobalStats;
+
+typedef struct PgStat_WalWriterGlobalStats
+{
+       PgStat_Counter xlog_dirty_writes;
+       TimestampTz stat_reset_timestamp;
+} PgStat_WalWriterGlobalStats;
+
+/*
+ * Global statistics kept in the stats collector
+ */
+typedef struct PgStat_GlobalStats
+{
+       TimestampTz stats_timestamp;    /* time of stats file update */
+       PgStat_BgWriterGlobalStats bgWriterGlobalStats;
+       PgStat_WalWriterGlobalStats walWriterGlobalStats;
 } PgStat_GlobalStats;
 
 
@@ -733,6 +759,8 @@ extern char *pgstat_stat_filename;
  */
 extern PgStat_MsgBgWriter BgWriterStats;
 
+extern PgStat_MsgWalWriter WalWriterStats;
+
 /*
  * Updated by pgstat_count_buffer_*_time macros
  */
@@ -861,6 +889,7 @@ extern void pgstat_twophase_postabort(TransactionId xid, 
uint16 info,
                                                  void *recdata, uint32 len);
 
 extern void pgstat_send_bgwriter(void);
+extern void pgstat_send_walwriter(void);
 
 /* ----------
  * Support functions for the SQL-callable functions to
diff --git a/src/test/regress/expected/rules.out 
b/src/test/regress/expected/rules.out
index 8f24c51..4074c61 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1775,6 +1775,8 @@ SELECT viewname, definition FROM pg_views WHERE 
schemaname <> 'information_schem
                                  |     pg_stat_all_tables.autoanalyze_count    
                                                                                
                                                                                
   +
                                  |    FROM pg_stat_all_tables                  
                                                                                
                                                                                
   +
                                  |   WHERE ((pg_stat_all_tables.schemaname <> 
ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND 
(pg_stat_all_tables.schemaname !~ '^pg_toast'::text));
+ pg_stat_walwriter               |  SELECT pg_stat_get_xlog_dirty_writes() AS 
dirty_writes,                                                                   
                                                                                
    +
+                                 |     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,                              
                                                                                
                                                                                
   +
@@ -2142,7 +2144,7 @@ SELECT viewname, definition FROM pg_views WHERE 
schemaname <> 'information_schem
                                  |    FROM tv;
  tvvmv                           |  SELECT tvvm.grandtot                       
                                                                                
                                                                                
   +
                                  |    FROM tvvm;
-(64 rows)
+(65 rows)
 
 SELECT tablename, rulename, definition FROM pg_rules
        ORDER BY tablename, rulename;
#!/bin/sh

# test_xlogdirtywrite.sh

PGHOME=/tmp/pgsql
PATH=$PGHOME/bin:$PATH
export PATH

pgbench -s 10 -i postgres

psql -e postgres << EOF
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;
\q
EOF

pgbench -s 10 -c 32 -t 1000 postgres

psql -e postgres << EOF
CHECKPOINT;
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;

--
-- generates wal records in single transaction
-- to fill the wal buffers.
--
BEGIN;
DELETE FROM pgbench_accounts;
COMMIT;
CHECKPOINT;

--
-- confirm that those shared counters got increased.
--
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;

--
-- pg_stat_reset() does not affect to the shared counters.
--
SELECT pg_stat_reset();
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;

--
-- resetting the walwriter counter.
--
SELECT pg_stat_reset_shared('walwriter');
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;

--
-- resetting the bgwriter counters.
--
SELECT pg_stat_reset_shared('bgwriter');
SELECT pg_sleep(1);
SELECT * FROM pg_stat_bgwriter;
SELECT * FROM pg_stat_walwriter;

\q
EOF
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to