pgstat: split reporting/fetching of bgwriter and checkpointer stats.
authorAndres Freund <andres@anarazel.de>
Thu, 5 Aug 2021 02:16:04 +0000 (19:16 -0700)
committerAndres Freund <andres@anarazel.de>
Thu, 5 Aug 2021 02:16:04 +0000 (19:16 -0700)
These have been unrelated since bgwriter and checkpointer were split into two
processes in 806a2aee379. As there several pending patches (shared memory
stats, extending the set of tracked IO / buffer statistics) that are made a
bit more awkward by the grouping, split them. Done separately to make
reviewing easier.

This does *not* change the contents of pg_stat_bgwriter or move fields out of
bgwriter/checkpointer stats that arguably do not belong in either. However
pgstat_fetch_global() was renamed and split into
pgstat_fetch_stat_checkpointer() and pgstat_fetch_stat_bgwriter().

Author: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/20210405092914.mmxqe7j56lsjfsej@alap3.anarazel.de

src/backend/access/transam/xlog.c
src/backend/postmaster/checkpointer.c
src/backend/postmaster/pgstat.c
src/backend/storage/buffer/bufmgr.c
src/backend/utils/adt/pgstatfuncs.c
src/include/pgstat.h

index 8b39a2fdaa506f6764b80153bb7e3f7cd3986f72..d0ec6a834be8cee431ac3f8f0719e1ffebc5b502 100644 (file)
@@ -8721,8 +8721,8 @@ LogCheckpointEnd(bool restartpoint)
                                                                                                 CheckpointStats.ckpt_sync_end_t);
 
        /* Accumulate checkpoint timing summary data, in milliseconds. */
-       BgWriterStats.m_checkpoint_write_time += write_msecs;
-       BgWriterStats.m_checkpoint_sync_time += sync_msecs;
+       PendingCheckpointerStats.m_checkpoint_write_time += write_msecs;
+       PendingCheckpointerStats.m_checkpoint_sync_time += sync_msecs;
 
        /*
         * All of the published timing statistics are accounted for.  Only
index bc9ac7ccfaf088bff13fe23dfd92dc1afb369bd8..be7366379d019200ab3dd77592ae1188cc44cd45 100644 (file)
@@ -357,7 +357,7 @@ CheckpointerMain(void)
                if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->ckpt_flags)
                {
                        do_checkpoint = true;
-                       BgWriterStats.m_requested_checkpoints++;
+                       PendingCheckpointerStats.m_requested_checkpoints++;
                }
 
                /*
@@ -371,7 +371,7 @@ CheckpointerMain(void)
                if (elapsed_secs >= CheckPointTimeout)
                {
                        if (!do_checkpoint)
-                               BgWriterStats.m_timed_checkpoints++;
+                               PendingCheckpointerStats.m_timed_checkpoints++;
                        do_checkpoint = true;
                        flags |= CHECKPOINT_CAUSE_TIME;
                }
@@ -493,13 +493,9 @@ CheckpointerMain(void)
                CheckArchiveTimeout();
 
                /*
-                * Send off activity statistics to the stats collector.  (The reason
-                * why we re-use bgwriter-related code for this is that the bgwriter
-                * and checkpointer used to be just one process.  It's probably not
-                * worth the trouble to split the stats support into two independent
-                * stats message types.)
+                * Send off activity statistics to the stats collector.
                 */
-               pgstat_send_bgwriter();
+               pgstat_send_checkpointer();
 
                /* Send WAL statistics to the stats collector. */
                pgstat_send_wal(true);
@@ -577,9 +573,9 @@ HandleCheckpointerInterrupts(void)
                 * updates the statistics, increment the checkpoint request and send
                 * the statistics to the stats collector.
                 */
-               BgWriterStats.m_requested_checkpoints++;
+               PendingCheckpointerStats.m_requested_checkpoints++;
                ShutdownXLOG(0, 0);
-               pgstat_send_bgwriter();
+               pgstat_send_checkpointer();
                pgstat_send_wal(true);
 
                /* Normal exit from the checkpointer is here */
@@ -719,9 +715,9 @@ CheckpointWriteDelay(int flags, double progress)
                CheckArchiveTimeout();
 
                /*
-                * Report interim activity statistics to the stats collector.
+                * Report interim activity statistics.
                 */
-               pgstat_send_bgwriter();
+               pgstat_send_checkpointer();
 
                /*
                 * This sleep used to be connected to bgwriter_delay, typically 200ms.
@@ -1265,8 +1261,10 @@ AbsorbSyncRequests(void)
        LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
        /* Transfer stats counts into pending pgstats message */
-       BgWriterStats.m_buf_written_backend += CheckpointerShmem->num_backend_writes;
-       BgWriterStats.m_buf_fsync_backend += CheckpointerShmem->num_backend_fsync;
+       PendingCheckpointerStats.m_buf_written_backend
+               += CheckpointerShmem->num_backend_writes;
+       PendingCheckpointerStats.m_buf_fsync_backend
+               += CheckpointerShmem->num_backend_fsync;
 
        CheckpointerShmem->num_backend_writes = 0;
        CheckpointerShmem->num_backend_fsync = 0;
index 11702f2a8040ae7dc9e91f17d002aad721fbaf24..56755cb92b65580e8d41b80ed9452d042c70979c 100644 (file)
@@ -128,7 +128,8 @@ char           *pgstat_stat_tmpname = NULL;
  * Stored directly in a stats message structure so they can be sent
  * without needing to copy things around.  We assume these init to zeroes.
  */
-PgStat_MsgBgWriter BgWriterStats;
+PgStat_MsgBgWriter PendingBgWriterStats;
+PgStat_MsgCheckpointer PendingCheckpointerStats;
 PgStat_MsgWal WalStats;
 
 /*
@@ -348,6 +349,7 @@ static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
 static void pgstat_recv_anl_ancestors(PgStat_MsgAnlAncestors *msg, int len);
 static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len);
 static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
+static void pgstat_recv_checkpointer(PgStat_MsgCheckpointer *msg, int len);
 static void pgstat_recv_wal(PgStat_MsgWal *msg, int len);
 static void pgstat_recv_slru(PgStat_MsgSLRU *msg, int len);
 static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
@@ -2830,6 +2832,37 @@ pgstat_fetch_stat_archiver(void)
        return &archiverStats;
 }
 
+/*
+ * ---------
+ * pgstat_fetch_stat_bgwriter() -
+ *
+ *     Support function for the SQL-callable pgstat* functions. Returns
+ *     a pointer to the bgwriter statistics struct.
+ * ---------
+ */
+PgStat_BgWriterStats *
+pgstat_fetch_stat_bgwriter(void)
+{
+       backend_read_statsfile();
+
+       return &globalStats.bgwriter;
+}
+
+/*
+ * ---------
+ * pgstat_fetch_stat_checkpointer() -
+ *
+ *     Support function for the SQL-callable pgstat* functions. Returns
+ *     a pointer to the checkpointer statistics struct.
+ * ---------
+ */
+PgStat_CheckpointerStats *
+pgstat_fetch_stat_checkpointer(void)
+{
+       backend_read_statsfile();
+
+       return &globalStats.checkpointer;
+}
 
 /*
  * ---------
@@ -3025,19 +3058,51 @@ pgstat_send_bgwriter(void)
         * this case, avoid sending a completely empty message to the stats
         * collector.
         */
-       if (memcmp(&BgWriterStats, &all_zeroes, sizeof(PgStat_MsgBgWriter)) == 0)
+       if (memcmp(&PendingBgWriterStats, &all_zeroes, sizeof(PgStat_MsgBgWriter)) == 0)
+               return;
+
+       /*
+        * Prepare and send the message
+        */
+       pgstat_setheader(&PendingBgWriterStats.m_hdr, PGSTAT_MTYPE_BGWRITER);
+       pgstat_send(&PendingBgWriterStats, sizeof(PendingBgWriterStats));
+
+       /*
+        * Clear out the statistics buffer, so it can be re-used.
+        */
+       MemSet(&PendingBgWriterStats, 0, sizeof(PendingBgWriterStats));
+}
+
+/* ----------
+ * pgstat_send_checkpointer() -
+ *
+ *             Send checkpointer statistics to the collector
+ * ----------
+ */
+void
+pgstat_send_checkpointer(void)
+{
+       /* We assume this initializes to zeroes */
+       static const PgStat_MsgCheckpointer 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(&PendingCheckpointerStats, &all_zeroes, sizeof(PgStat_MsgCheckpointer)) == 0)
                return;
 
        /*
         * Prepare and send the message
         */
-       pgstat_setheader(&BgWriterStats.m_hdr, PGSTAT_MTYPE_BGWRITER);
-       pgstat_send(&BgWriterStats, sizeof(BgWriterStats));
+       pgstat_setheader(&PendingCheckpointerStats.m_hdr, PGSTAT_MTYPE_CHECKPOINTER);
+       pgstat_send(&PendingCheckpointerStats, sizeof(PendingCheckpointerStats));
 
        /*
         * Clear out the statistics buffer, so it can be re-used.
         */
-       MemSet(&BgWriterStats, 0, sizeof(BgWriterStats));
+       MemSet(&PendingCheckpointerStats, 0, sizeof(PendingCheckpointerStats));
 }
 
 /* ----------
@@ -3382,6 +3447,10 @@ PgstatCollectorMain(int argc, char *argv[])
                                        pgstat_recv_bgwriter(&msg.msg_bgwriter, len);
                                        break;
 
+                               case PGSTAT_MTYPE_CHECKPOINTER:
+                                       pgstat_recv_checkpointer(&msg.msg_checkpointer, len);
+                                       break;
+
                                case PGSTAT_MTYPE_WAL:
                                        pgstat_recv_wal(&msg.msg_wal, len);
                                        break;
@@ -3934,6 +4003,7 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
        bool            found;
        const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
        int                     i;
+       TimestampTz     ts;
 
        /*
         * The tables will live in pgStatLocalContext.
@@ -3962,15 +4032,16 @@ 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();
-       archiverStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
-       walStats.stat_reset_timestamp = globalStats.stat_reset_timestamp;
+       ts = GetCurrentTimestamp();
+       globalStats.bgwriter.stat_reset_timestamp = ts;
+       archiverStats.stat_reset_timestamp = ts;
+       walStats.stat_reset_timestamp = ts;
 
        /*
         * Set the same reset timestamp for all SLRU items too.
         */
        for (i = 0; i < SLRU_NUM_ELEMENTS; i++)
-               slruStats[i].stat_reset_timestamp = globalStats.stat_reset_timestamp;
+               slruStats[i].stat_reset_timestamp = ts;
 
        /*
         * Try to open the stats file. If it doesn't exist, the backends simply
@@ -5055,9 +5126,9 @@ pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
 {
        if (msg->m_resettarget == RESET_BGWRITER)
        {
-               /* Reset the global background writer statistics for the cluster. */
+               /* Reset the global, bgwriter and checkpointer statistics for the cluster. */
                memset(&globalStats, 0, sizeof(globalStats));
-               globalStats.stat_reset_timestamp = GetCurrentTimestamp();
+               globalStats.bgwriter.stat_reset_timestamp = GetCurrentTimestamp();
        }
        else if (msg->m_resettarget == RESET_ARCHIVER)
        {
@@ -5345,16 +5416,27 @@ pgstat_recv_archiver(PgStat_MsgArchiver *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.bgwriter.buf_written_clean += msg->m_buf_written_clean;
+       globalStats.bgwriter.maxwritten_clean += msg->m_maxwritten_clean;
+       globalStats.bgwriter.buf_alloc += msg->m_buf_alloc;
+}
+
+/* ----------
+ * pgstat_recv_checkpointer() -
+ *
+ *     Process a CHECKPOINTER message.
+ * ----------
+ */
+static void
+pgstat_recv_checkpointer(PgStat_MsgCheckpointer *msg, int len)
+{
+       globalStats.checkpointer.timed_checkpoints += msg->m_timed_checkpoints;
+       globalStats.checkpointer.requested_checkpoints += msg->m_requested_checkpoints;
+       globalStats.checkpointer.checkpoint_write_time += msg->m_checkpoint_write_time;
+       globalStats.checkpointer.checkpoint_sync_time += msg->m_checkpoint_sync_time;
+       globalStats.checkpointer.buf_written_checkpoints += msg->m_buf_written_checkpoints;
+       globalStats.checkpointer.buf_written_backend += msg->m_buf_written_backend;
+       globalStats.checkpointer.buf_fsync_backend += msg->m_buf_fsync_backend;
 }
 
 /* ----------
index 33d99f604ade1d3cbef59da60818442320c6800f..77685bdde2864f413dc4dd564216ecc6fe7c00a3 100644 (file)
@@ -2137,7 +2137,7 @@ BufferSync(int flags)
                        if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN)
                        {
                                TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id);
-                               BgWriterStats.m_buf_written_checkpoints++;
+                               PendingCheckpointerStats.m_buf_written_checkpoints++;
                                num_written++;
                        }
                }
@@ -2247,7 +2247,7 @@ BgBufferSync(WritebackContext *wb_context)
        strategy_buf_id = StrategySyncStart(&strategy_passes, &recent_alloc);
 
        /* Report buffer alloc counts to pgstat */
-       BgWriterStats.m_buf_alloc += recent_alloc;
+       PendingBgWriterStats.m_buf_alloc += recent_alloc;
 
        /*
         * If we're not running the LRU scan, just stop after doing the stats
@@ -2437,7 +2437,7 @@ BgBufferSync(WritebackContext *wb_context)
                        reusable_buffers++;
                        if (++num_written >= bgwriter_lru_maxpages)
                        {
-                               BgWriterStats.m_maxwritten_clean++;
+                               PendingBgWriterStats.m_maxwritten_clean++;
                                break;
                        }
                }
@@ -2445,7 +2445,7 @@ BgBufferSync(WritebackContext *wb_context)
                        reusable_buffers++;
        }
 
-       BgWriterStats.m_buf_written_clean += num_written;
+       PendingBgWriterStats.m_buf_written_clean += num_written;
 
 #ifdef BGW_DEBUG
        elog(DEBUG1, "bgwriter: recent_alloc=%u smoothed=%.2f delta=%ld ahead=%d density=%.2f reusable_est=%d upcoming_est=%d scanned=%d wrote=%d reusable=%d",
index f0e09eae4d66267e2be75417dc64186067dd91cc..ff5aedc99cbdd81dc61f74fad13cb0f0e346d963 100644 (file)
@@ -36,9 +36,6 @@
 
 #define HAS_PGSTAT_PERMISSIONS(role)    (is_member_of_role(GetUserId(), ROLE_PG_READ_ALL_STATS) || has_privs_of_role(GetUserId(), role))
 
-/* Global bgwriter statistics, from bgwriter.c */
-extern PgStat_MsgBgWriter bgwriterStats;
-
 Datum
 pg_stat_get_numscans(PG_FUNCTION_ARGS)
 {
@@ -1732,69 +1729,71 @@ pg_stat_get_db_sessions_killed(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_stat_checkpointer()->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_stat_checkpointer()->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_stat_checkpointer()->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_stat_bgwriter()->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_stat_bgwriter()->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_stat_checkpointer()->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_stat_checkpointer()->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_stat_bgwriter()->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_stat_checkpointer()->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_stat_checkpointer()->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_stat_bgwriter()->buf_alloc);
 }
 
 /*
index 9612c0a6c2769a1f4bac2d22402bac256e3a8709..2068a68a5ff9466b5ee47106326f072ec3692861 100644 (file)
@@ -72,6 +72,7 @@ typedef enum StatMsgType
        PGSTAT_MTYPE_ANL_ANCESTORS,
        PGSTAT_MTYPE_ARCHIVER,
        PGSTAT_MTYPE_BGWRITER,
+       PGSTAT_MTYPE_CHECKPOINTER,
        PGSTAT_MTYPE_WAL,
        PGSTAT_MTYPE_SLRU,
        PGSTAT_MTYPE_FUNCSTAT,
@@ -470,17 +471,27 @@ typedef struct PgStat_MsgBgWriter
 {
        PgStat_MsgHdr m_hdr;
 
+       PgStat_Counter m_buf_written_clean;
+       PgStat_Counter m_maxwritten_clean;
+       PgStat_Counter m_buf_alloc;
+} PgStat_MsgBgWriter;
+
+/* ----------
+ * PgStat_MsgCheckpointer  Sent by the checkpointer to update statistics.
+ * ----------
+ */
+typedef struct PgStat_MsgCheckpointer
+{
+       PgStat_MsgHdr m_hdr;
+
        PgStat_Counter m_timed_checkpoints;
        PgStat_Counter m_requested_checkpoints;
        PgStat_Counter m_buf_written_checkpoints;
-       PgStat_Counter m_buf_written_clean;
-       PgStat_Counter m_maxwritten_clean;
        PgStat_Counter m_buf_written_backend;
        PgStat_Counter m_buf_fsync_backend;
-       PgStat_Counter m_buf_alloc;
        PgStat_Counter m_checkpoint_write_time; /* times in milliseconds */
        PgStat_Counter m_checkpoint_sync_time;
-} PgStat_MsgBgWriter;
+} PgStat_MsgCheckpointer;
 
 /* ----------
  * PgStat_MsgWal                       Sent by backends and background processes to update WAL statistics.
@@ -700,6 +711,7 @@ typedef union PgStat_Msg
        PgStat_MsgAnlAncestors msg_anl_ancestors;
        PgStat_MsgArchiver msg_archiver;
        PgStat_MsgBgWriter msg_bgwriter;
+       PgStat_MsgCheckpointer msg_checkpointer;
        PgStat_MsgWal msg_wal;
        PgStat_MsgSLRU msg_slru;
        PgStat_MsgFuncstat msg_funcstat;
@@ -721,7 +733,7 @@ typedef union PgStat_Msg
  * ------------------------------------------------------------
  */
 
-#define PGSTAT_FILE_FORMAT_ID  0x01A5BCA2
+#define PGSTAT_FILE_FORMAT_ID  0x01A5BCA3
 
 /* ----------
  * PgStat_StatDBEntry                  The collector's data per database
@@ -842,9 +854,20 @@ typedef struct PgStat_ArchiverStats
 } PgStat_ArchiverStats;
 
 /*
- * Global statistics kept in the stats collector
+ * Background writer statistics kept in the stats collector
  */
-typedef struct PgStat_GlobalStats
+typedef struct PgStat_BgWriterStats
+{
+       PgStat_Counter buf_written_clean;
+       PgStat_Counter maxwritten_clean;
+       PgStat_Counter buf_alloc;
+       TimestampTz stat_reset_timestamp;
+} PgStat_BgWriterStats;
+
+/*
+ * Checkpointer statistics kept in the stats collector
+ */
+typedef struct PgStat_CheckpointerStats
 {
        TimestampTz stats_timestamp;    /* time of stats file update */
        PgStat_Counter timed_checkpoints;
@@ -852,12 +875,19 @@ typedef struct PgStat_GlobalStats
        PgStat_Counter checkpoint_write_time;   /* times in milliseconds */
        PgStat_Counter checkpoint_sync_time;
        PgStat_Counter buf_written_checkpoints;
-       PgStat_Counter buf_written_clean;
-       PgStat_Counter maxwritten_clean;
        PgStat_Counter buf_written_backend;
        PgStat_Counter buf_fsync_backend;
-       PgStat_Counter buf_alloc;
-       TimestampTz stat_reset_timestamp;
+} PgStat_CheckpointerStats;
+
+/*
+ * Global statistics kept in the stats collector
+ */
+typedef struct PgStat_GlobalStats
+{
+       TimestampTz stats_timestamp;    /* time of stats file update */
+
+       PgStat_CheckpointerStats checkpointer;
+       PgStat_BgWriterStats bgwriter;
 } PgStat_GlobalStats;
 
 /*
@@ -939,7 +969,13 @@ extern char *pgstat_stat_filename;
 /*
  * BgWriter statistics counters are updated directly by bgwriter and bufmgr
  */
-extern PgStat_MsgBgWriter BgWriterStats;
+extern PgStat_MsgBgWriter PendingBgWriterStats;
+
+/*
+ * Checkpointer statistics counters are updated directly by checkpointer and
+ * bufmgr.
+ */
+extern PgStat_MsgCheckpointer PendingCheckpointerStats;
 
 /*
  * WAL statistics counter is updated by backends and background processes
@@ -1091,6 +1127,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_checkpointer(void);
 extern void pgstat_send_wal(bool force);
 
 /* ----------
@@ -1102,6 +1139,8 @@ extern PgStat_StatDBEntry *pgstat_fetch_stat_dbentry(Oid dbid);
 extern PgStat_StatTabEntry *pgstat_fetch_stat_tabentry(Oid relid);
 extern PgStat_StatFuncEntry *pgstat_fetch_stat_funcentry(Oid funcid);
 extern PgStat_ArchiverStats *pgstat_fetch_stat_archiver(void);
+extern PgStat_BgWriterStats *pgstat_fetch_stat_bgwriter(void);
+extern PgStat_CheckpointerStats *pgstat_fetch_stat_checkpointer(void);
 extern PgStat_GlobalStats *pgstat_fetch_global(void);
 extern PgStat_WalStats *pgstat_fetch_stat_wal(void);
 extern PgStat_SLRUStats *pgstat_fetch_slru(void);