Skip to content

Commit 9132b18

Browse files
committed
Add pg_stat_archiver statistics view.
This view shows the statistics about the WAL archiver process's activity. Gabriele Bartolini, reviewed by Michael Paquier, refactored a bit by me.
1 parent 98d62c2 commit 9132b18

File tree

9 files changed

+327
-19
lines changed

9 files changed

+327
-19
lines changed

doc/src/sgml/monitoring.sgml

+67
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
269269
</entry>
270270
</row>
271271

272+
<row>
273+
<entry><structname>pg_stat_archiver</><indexterm><primary>pg_stat_archiver</primary></indexterm></entry>
274+
<entry>One row only, showing statistics about the
275+
WAL archiver process's activity. See
276+
<xref linkend="pg-stat-archiver-view"> for details.
277+
</entry>
278+
</row>
279+
272280
<row>
273281
<entry><structname>pg_stat_bgwriter</><indexterm><primary>pg_stat_bgwriter</primary></indexterm></entry>
274282
<entry>One row only, showing statistics about the
@@ -648,6 +656,63 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
648656
</para>
649657
</note>
650658

659+
<table id="pg-stat-archiver-view" xreflabel="pg_stat_archiver">
660+
<title><structname>pg_stat_archiver</structname> View</title>
661+
662+
<tgroup cols="3">
663+
<thead>
664+
<row>
665+
<entry>Column</entry>
666+
<entry>Type</entry>
667+
<entry>Description</entry>
668+
</row>
669+
</thead>
670+
671+
<tbody>
672+
<row>
673+
<entry><structfield>archived_count</></entry>
674+
<entry><type>bigint</type></entry>
675+
<entry>Number of WAL files that have been successfully archived</entry>
676+
</row>
677+
<row>
678+
<entry><structfield>last_archived_wal</></entry>
679+
<entry><type>text</type></entry>
680+
<entry>Name of the last WAL file successfully archived</entry>
681+
</row>
682+
<row>
683+
<entry><structfield>last_archived_time</></entry>
684+
<entry><type>timestamp with time zone</type></entry>
685+
<entry>Time of the last successful archive operation</entry>
686+
</row>
687+
<row>
688+
<entry><structfield>failed_count</></entry>
689+
<entry><type>bigint</type></entry>
690+
<entry>Number of failed attempts for archiving WAL files</entry>
691+
</row>
692+
<row>
693+
<entry><structfield>last_failed_wal</></entry>
694+
<entry><type>text</type></entry>
695+
<entry>Name of the WAL file of the last failed archival operation</entry>
696+
</row>
697+
<row>
698+
<entry><structfield>last_failed_time</></entry>
699+
<entry><type>timestamp with time zone</type></entry>
700+
<entry>Time of the last failed archival operation</entry>
701+
</row>
702+
<row>
703+
<entry><structfield>stats_reset</></entry>
704+
<entry><type>timestamp with time zone</type></entry>
705+
<entry>Time at which these statistics were last reset</entry>
706+
</row>
707+
</tbody>
708+
</tgroup>
709+
</table>
710+
711+
<para>
712+
The <structname>pg_stat_archiver</structname> view will always have a
713+
single row, containing data about the archiver process of the cluster.
714+
</para>
715+
651716
<table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
652717
<title><structname>pg_stat_bgwriter</structname> View</title>
653718

@@ -1613,6 +1678,8 @@ postgres: <replaceable>user</> <replaceable>database</> <replaceable>host</> <re
16131678
argument (requires superuser privileges).
16141679
Calling <literal>pg_stat_reset_shared('bgwriter')</> will zero all the
16151680
counters shown in the <structname>pg_stat_bgwriter</> view.
1681+
Calling <literal>pg_stat_reset_shared('archiver')</> will zero all the
1682+
counters shown in the <structname>pg_stat_archiver</> view.
16161683
</entry>
16171684
</row>
16181685

src/backend/catalog/system_views.sql

+11
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,17 @@ CREATE VIEW pg_stat_xact_user_functions AS
672672
WHERE P.prolang != 12 -- fast check to eliminate built-in functions
673673
AND pg_stat_get_xact_function_calls(P.oid) IS NOT NULL;
674674

675+
CREATE VIEW pg_stat_archiver AS
676+
SELECT
677+
s.archived_count,
678+
s.last_archived_wal,
679+
s.last_archived_time,
680+
s.failed_count,
681+
s.last_failed_wal,
682+
s.last_failed_time,
683+
s.stats_reset
684+
FROM pg_stat_get_archiver() s;
685+
675686
CREATE VIEW pg_stat_bgwriter AS
676687
SELECT
677688
pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,

src/backend/postmaster/pgarch.c

+8-13
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "access/xlog_internal.h"
3737
#include "libpq/pqsignal.h"
3838
#include "miscadmin.h"
39+
#include "pgstat.h"
3940
#include "postmaster/fork_process.h"
4041
#include "postmaster/pgarch.h"
4142
#include "postmaster/postmaster.h"
@@ -58,19 +59,6 @@
5859
#define PGARCH_RESTART_INTERVAL 10 /* How often to attempt to restart a
5960
* failed archiver; in seconds. */
6061

61-
/* ----------
62-
* Archiver control info.
63-
*
64-
* We expect that archivable files within pg_xlog will have names between
65-
* MIN_XFN_CHARS and MAX_XFN_CHARS in length, consisting only of characters
66-
* appearing in VALID_XFN_CHARS. The status files in archive_status have
67-
* corresponding names with ".ready" or ".done" appended.
68-
* ----------
69-
*/
70-
#define MIN_XFN_CHARS 16
71-
#define MAX_XFN_CHARS 40
72-
#define VALID_XFN_CHARS "0123456789ABCDEF.history.backup"
73-
7462
#define NUM_ARCHIVE_RETRIES 3
7563

7664

@@ -496,10 +484,17 @@ pgarch_ArchiverCopyLoop(void)
496484
{
497485
/* successful */
498486
pgarch_archiveDone(xlog);
487+
488+
/* Tell the collector about the WAL file that we successfully archived */
489+
pgstat_send_archiver(xlog, false);
490+
499491
break; /* out of inner retry loop */
500492
}
501493
else
502494
{
495+
/* Tell the collector about the WAL file that we failed to archive */
496+
pgstat_send_archiver(xlog, true);
497+
503498
if (++failures >= NUM_ARCHIVE_RETRIES)
504499
{
505500
ereport(WARNING,

src/backend/postmaster/pgstat.c

+116-5
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ static int localNumBackends = 0;
221221
* Contains statistics that are not collected per database
222222
* or per table.
223223
*/
224+
static PgStat_ArchiverStats archiverStats;
224225
static PgStat_GlobalStats globalStats;
225226

226227
/* Write request info for each database */
@@ -292,6 +293,7 @@ static void pgstat_recv_resetsinglecounter(PgStat_MsgResetsinglecounter *msg, in
292293
static void pgstat_recv_autovac(PgStat_MsgAutovacStart *msg, int len);
293294
static void pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len);
294295
static void pgstat_recv_analyze(PgStat_MsgAnalyze *msg, int len);
296+
static void pgstat_recv_archiver(PgStat_MsgArchiver *msg, int len);
295297
static void pgstat_recv_bgwriter(PgStat_MsgBgWriter *msg, int len);
296298
static void pgstat_recv_funcstat(PgStat_MsgFuncstat *msg, int len);
297299
static 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),
12581260
errmsg("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)
12611265
msg.m_resettarget = RESET_BGWRITER;
12621266
else
12631267
ereport(ERROR,
12641268
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
12651269
errmsg("unrecognized reset target: \"%s\"", target),
1266-
errhint("Target must be \"bgwriter\".")));
1270+
errhint("Target must be \"archiver\" or \"bgwriter\".")));
12671271

12681272
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_RESETSHAREDCOUNTER);
12691273
pgstat_send(&msg, sizeof(msg));
@@ -2321,6 +2325,23 @@ pgstat_fetch_stat_numbackends(void)
23212325
return 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[])
32783321
pgstat_recv_analyze((PgStat_MsgAnalyze *) &msg, len);
32793322
break;
32803323

3324+
case PGSTAT_MTYPE_ARCHIVER:
3325+
pgstat_recv_archiver((PgStat_MsgArchiver *) &msg, len);
3326+
break;
3327+
32813328
case PGSTAT_MTYPE_BGWRITER:
32823329
pgstat_recv_bgwriter((PgStat_MsgBgWriter *) &msg, len);
32833330
break;
@@ -3562,6 +3609,12 @@ pgstat_write_statsfiles(bool permanent, bool allDbs)
35623609
rc = 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)
38283881
HASH_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 global and archiver statistics so they start from zero
3885+
* in case we can't load an existing statsfile.
38333886
*/
38343887
memset(&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
*/
38403894
globalStats.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)
38793934
goto done;
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+
goto done;
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 no stat_timestamp value, but also nothing to write so we return
4227+
* there's no stats_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
{
41704235
PgStat_StatDBEntry dbentry;
41714236
PgStat_GlobalStats myGlobalStats;
4237+
PgStat_ArchiverStats myArchiverStats;
41724238
FILE *fpin;
41734239
int32 format_id;
41744240
const char *statfile = permanent ? PGSTAT_STAT_PERMANENT_FILENAME : pgstat_stat_filename;
@@ -4211,6 +4277,18 @@ pgstat_read_db_statsfile_timestamp(Oid databaseid, bool permanent,
42114277
return 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)
47384816
memset(&globalStats, 0, sizeof(globalStats));
47394817
globalStats.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
*

0 commit comments

Comments
 (0)