@@ -221,6 +221,7 @@ static intlocalNumBackends = 0;
221221 * Contains statistics that are not collected per database
222222 * or per table.
223223 */
224+ static PgStat_ArchiverStats archiverStats ;
224225static PgStat_GlobalStats globalStats ;
225226
226227/* Write request info for each database */
@@ -292,6 +293,7 @@ static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, in
292293static void pgstat_recv_autovac (PgStat_MsgAutovacStart * msg ,int len );
293294static void pgstat_recv_vacuum (PgStat_MsgVacuum * msg ,int len );
294295static void pgstat_recv_analyze (PgStat_MsgAnalyze * msg ,int len );
296+ static void pgstat_recv_archiver (PgStat_MsgArchiver * msg ,int len );
295297static void pgstat_recv_bgwriter (PgStat_MsgBgWriter * msg ,int len );
296298static void pgstat_recv_funcstat (PgStat_MsgFuncstat * msg ,int len );
297299static void pgstat_recv_funcpurge (PgStat_MsgFuncpurge * msg ,int len );
@@ -1257,13 +1259,15 @@ pgstat_reset_shared_counters(const char *target)
12571259(errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
12581260errmsg ("must be superuser to reset statistics counters" )));
12591261
1260- if (strcmp (target ,"bgwriter" )== 0 )
1262+ if (strcmp (target ,"archiver" )== 0 )
1263+ msg .m_resettarget = RESET_ARCHIVER ;
1264+ else if (strcmp (target ,"bgwriter" )== 0 )
12611265msg .m_resettarget = RESET_BGWRITER ;
12621266else
12631267ereport (ERROR ,
12641268(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
12651269errmsg ("unrecognized reset target: \"%s\"" ,target ),
1266- errhint ("Target must be \"bgwriter\"." )));
1270+ errhint ("Target must be \"archiver\" or \" bgwriter\"." )));
12671271
12681272pgstat_setheader (& msg .m_hdr ,PGSTAT_MTYPE_RESETSHAREDCOUNTER );
12691273pgstat_send (& msg ,sizeof (msg ));
@@ -2321,6 +2325,23 @@ pgstat_fetch_stat_numbackends(void)
23212325return localNumBackends ;
23222326}
23232327
2328+ /*
2329+ * ---------
2330+ * pgstat_fetch_stat_archiver() -
2331+ *
2332+ *Support function for the SQL-callable pgstat* functions. Returns
2333+ *a pointer to the archiver statistics struct.
2334+ * ---------
2335+ */
2336+ PgStat_ArchiverStats *
2337+ pgstat_fetch_stat_archiver (void )
2338+ {
2339+ backend_read_statsfile ();
2340+
2341+ return & archiverStats ;
2342+ }
2343+
2344+
23242345/*
23252346 * ---------
23262347 * pgstat_fetch_global() -
@@ -3035,6 +3056,28 @@ pgstat_send(void *msg, int len)
30353056#endif
30363057}
30373058
3059+ /* ----------
3060+ * pgstat_send_archiver() -
3061+ *
3062+ *Tell the collector about the WAL file that we successfully
3063+ *archived or failed to archive.
3064+ * ----------
3065+ */
3066+ void
3067+ pgstat_send_archiver (const char * xlog ,bool failed )
3068+ {
3069+ PgStat_MsgArchiver msg ;
3070+
3071+ /*
3072+ * Prepare and send the message
3073+ */
3074+ pgstat_setheader (& msg .m_hdr ,PGSTAT_MTYPE_ARCHIVER );
3075+ msg .m_failed = failed ;
3076+ strncpy (msg .m_xlog ,xlog ,sizeof (msg .m_xlog ));
3077+ msg .m_timestamp = GetCurrentTimestamp ();
3078+ pgstat_send (& msg ,sizeof (msg ));
3079+ }
3080+
30383081/* ----------
30393082 * pgstat_send_bgwriter() -
30403083 *
@@ -3278,6 +3321,10 @@ PgstatCollectorMain(int argc, char *argv[])
32783321pgstat_recv_analyze ((PgStat_MsgAnalyze * )& msg ,len );
32793322break ;
32803323
3324+ case PGSTAT_MTYPE_ARCHIVER :
3325+ pgstat_recv_archiver ((PgStat_MsgArchiver * )& msg ,len );
3326+ break ;
3327+
32813328case PGSTAT_MTYPE_BGWRITER :
32823329pgstat_recv_bgwriter ((PgStat_MsgBgWriter * )& msg ,len );
32833330break ;
@@ -3562,6 +3609,12 @@ pgstat_write_statsfiles(bool permanent, bool allDbs)
35623609rc = fwrite (& globalStats ,sizeof (globalStats ),1 ,fpout );
35633610(void )rc ;/* we'll check for error with ferror */
35643611
3612+ /*
3613+ * Write archiver stats struct
3614+ */
3615+ rc = fwrite (& archiverStats ,sizeof (archiverStats ),1 ,fpout );
3616+ (void )rc ;/* we'll check for error with ferror */
3617+
35653618/*
35663619 * Walk through the database table.
35673620 */
@@ -3828,16 +3881,18 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
38283881HASH_ELEM |HASH_FUNCTION |HASH_CONTEXT );
38293882
38303883/*
3831- * Clear out global statistics so they start from zero in case we can't
3832- * load an existing statsfile.
3884+ * Clear out globaland archiver statistics so they start from zero
3885+ *in case we can't load an existing statsfile.
38333886 */
38343887memset (& globalStats ,0 ,sizeof (globalStats ));
3888+ memset (& archiverStats ,0 ,sizeof (archiverStats ));
38353889
38363890/*
38373891 * Set the current timestamp (will be kept only in case we can't load an
38383892 * existing statsfile).
38393893 */
38403894globalStats .stat_reset_timestamp = GetCurrentTimestamp ();
3895+ archiverStats .stat_reset_timestamp = globalStats .stat_reset_timestamp ;
38413896
38423897/*
38433898 * Try to open the stats file. If it doesn't exist, the backends simply
@@ -3879,6 +3934,16 @@ pgstat_read_statsfiles(Oid onlydb, bool permanent, bool deep)
38793934gotodone ;
38803935}
38813936
3937+ /*
3938+ * Read archiver stats struct
3939+ */
3940+ if (fread (& archiverStats ,1 ,sizeof (archiverStats ),fpin )!= sizeof (archiverStats ))
3941+ {
3942+ ereport (pgStatRunningInCollector ?LOG :WARNING ,
3943+ (errmsg ("corrupted statistics file \"%s\"" ,statfile )));
3944+ gotodone ;
3945+ }
3946+
38823947/*
38833948 * We found an existing collector stats file. Read it and put all the
38843949 * hashtable entries into place.
@@ -4159,7 +4224,7 @@ pgstat_read_db_statsfile(Oid databaseid, HTAB *tabhash, HTAB *funchash,
41594224 *stats_timestamp value.
41604225 *
41614226 *- if there's no db stat entry (e.g. for a new or inactive database),
4162- *there's nostat_timestamp value, but also nothing to write so we return
4227+ *there's nostats_timestamp value, but also nothing to write so we return
41634228 *the timestamp of the global statfile.
41644229 * ----------
41654230 */
@@ -4169,6 +4234,7 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
41694234{
41704235PgStat_StatDBEntry dbentry ;
41714236PgStat_GlobalStats myGlobalStats ;
4237+ PgStat_ArchiverStats myArchiverStats ;
41724238FILE * fpin ;
41734239int32 format_id ;
41744240const char * statfile = permanent ?PGSTAT_STAT_PERMANENT_FILENAME :pgstat_stat_filename ;
@@ -4211,6 +4277,18 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
42114277return false;
42124278}
42134279
4280+ /*
4281+ * Read archiver stats struct
4282+ */
4283+ if (fread (& myArchiverStats ,1 ,sizeof (myArchiverStats ),
4284+ fpin )!= sizeof (myArchiverStats ))
4285+ {
4286+ ereport (pgStatRunningInCollector ?LOG :WARNING ,
4287+ (errmsg ("corrupted statistics file \"%s\"" ,statfile )));
4288+ FreeFile (fpin );
4289+ return false;
4290+ }
4291+
42144292/* By default, we're going to return the timestamp of the global file. */
42154293* ts = myGlobalStats .stats_timestamp ;
42164294
@@ -4738,6 +4816,12 @@ pgstat_recv_resetsharedcounter(PgStat_MsgResetsharedcounter *msg, int len)
47384816memset (& globalStats ,0 ,sizeof (globalStats ));
47394817globalStats .stat_reset_timestamp = GetCurrentTimestamp ();
47404818}
4819+ else if (msg -> m_resettarget == RESET_ARCHIVER )
4820+ {
4821+ /* Reset the archiver statistics for the cluster. */
4822+ memset (& archiverStats ,0 ,sizeof (archiverStats ));
4823+ archiverStats .stat_reset_timestamp = GetCurrentTimestamp ();
4824+ }
47414825
47424826/*
47434827 * Presumably the sender of this message validated the target, don't
@@ -4867,6 +4951,33 @@ pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len)
48674951}
48684952
48694953
4954+ /* ----------
4955+ * pgstat_recv_archiver() -
4956+ *
4957+ *Process a ARCHIVER message.
4958+ * ----------
4959+ */
4960+ static void
4961+ pgstat_recv_archiver (PgStat_MsgArchiver * msg ,int len )
4962+ {
4963+ if (msg -> m_failed )
4964+ {
4965+ /* Failed archival attempt */
4966+ ++ archiverStats .failed_count ;
4967+ memcpy (archiverStats .last_failed_wal ,msg -> m_xlog ,
4968+ sizeof (archiverStats .last_failed_wal ));
4969+ archiverStats .last_failed_timestamp = msg -> m_timestamp ;
4970+ }
4971+ else
4972+ {
4973+ /* Successful archival operation */
4974+ ++ archiverStats .archived_count ;
4975+ memcpy (archiverStats .last_archived_wal ,msg -> m_xlog ,
4976+ sizeof (archiverStats .last_archived_wal ));
4977+ archiverStats .last_archived_timestamp = msg -> m_timestamp ;
4978+ }
4979+ }
4980+
48704981/* ----------
48714982 * pgstat_recv_bgwriter() -
48724983 *