Le 25/08/2014 19:00, Gilles Darold a écrit : > Le 21/08/2014 10:17, Julien Rouhaud a écrit : >> Hello, >> >> Attached patch implements the following TODO item : >> >> Track number of WAL files ready to be archived in pg_stat_archiver >> >> However, it will track the total number of any file ready to be >> archived, not only WAL files. >> >> Please let me know what you think about it. >> >> Regards. > > Hi, > > Maybe looking at archive ready count will be more efficient if it is > done in the view definition through a function. This will avoid any > issue with incrementing/decrement of archiverStats.ready_count and the > patch will be more simple. Also I don't think we need an other memory > allocation for that, the counter information is always in the number of > .ready files in the archive_status directory and the call to > pg_stat_archiver doesn't need high speed performances. > > For example having a new function called > pg_stat_get_archive_ready_count() that does the same at what you add > into pgstat_read_statsfiles() and the pg_stat_archiver defined as follow: > > CREATE VIEW pg_stat_archiver AS > s.failed_count, > s.last_failed_wal, > s.last_failed_time, > pg_stat_get_archive_ready() as ready_count, > s.stats_reset > FROM pg_stat_get_archiver() s; > > The function pg_stat_get_archive_ready_count() will also be available > for any other querying. >
Indeed, this approach should be more efficient. It also avoid unexpected results, like if someone has the bad idea to remove a .ready file in pg_xlog/archive_status directory. Attached v2 patch implements this approach. All the work is still done in pg_stat_get_archiver, as I don't think that having a specific function for that information would be really interesting. -- Julien Rouhaud http://dalibo.com - http://dalibo.org
*** a/doc/src/sgml/monitoring.sgml --- b/doc/src/sgml/monitoring.sgml *************** *** 728,733 **** postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser --- 728,738 ---- <entry>Time of the last failed archival operation</entry> </row> <row> + <entry><structfield>ready_count</></entry> + <entry><type>bigint</type></entry> + <entry>Number of files waiting to be archived</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> *** a/src/backend/catalog/system_views.sql --- b/src/backend/catalog/system_views.sql *************** *** 697,702 **** CREATE VIEW pg_stat_archiver AS --- 697,703 ---- s.failed_count, s.last_failed_wal, s.last_failed_time, + s.ready_count, s.stats_reset FROM pg_stat_get_archiver() s; *** a/src/backend/utils/adt/pgstatfuncs.c --- b/src/backend/utils/adt/pgstatfuncs.c *************** *** 15,25 **** --- 15,27 ---- #include "postgres.h" #include "access/htup_details.h" + #include "access/xlog_internal.h" #include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/ip.h" #include "miscadmin.h" #include "pgstat.h" + #include "storage/fd.h" #include "utils/builtins.h" #include "utils/inet.h" #include "utils/timestamp.h" *************** *** 1737,1752 **** Datum pg_stat_get_archiver(PG_FUNCTION_ARGS) { TupleDesc tupdesc; ! Datum values[7]; ! bool nulls[7]; PgStat_ArchiverStats *archiver_stats; /* Initialise values and NULL flags arrays */ MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); /* Initialise attributes information in the tuple descriptor */ ! tupdesc = CreateTemplateTupleDesc(7, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal", --- 1739,1758 ---- pg_stat_get_archiver(PG_FUNCTION_ARGS) { TupleDesc tupdesc; ! Datum values[8]; ! bool nulls[8]; PgStat_ArchiverStats *archiver_stats; + char XLogArchiveStatusDir[MAXPGPATH]; + DIR *rldir; + struct dirent *rlde; + int ready_count; /* Initialise values and NULL flags arrays */ MemSet(values, 0, sizeof(values)); MemSet(nulls, 0, sizeof(nulls)); /* Initialise attributes information in the tuple descriptor */ ! tupdesc = CreateTemplateTupleDesc(8, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "archived_count", INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "last_archived_wal", *************** *** 1759,1765 **** pg_stat_get_archiver(PG_FUNCTION_ARGS) TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time", TIMESTAMPTZOID, -1, 0); ! TupleDescInitEntry(tupdesc, (AttrNumber) 7, "stats_reset", TIMESTAMPTZOID, -1, 0); BlessTupleDesc(tupdesc); --- 1765,1773 ---- TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 6, "last_failed_time", TIMESTAMPTZOID, -1, 0); ! TupleDescInitEntry(tupdesc, (AttrNumber) 7, "ready_count", ! INT8OID, -1, 0); ! TupleDescInitEntry(tupdesc, (AttrNumber) 8, "stats_reset", TIMESTAMPTZOID, -1, 0); BlessTupleDesc(tupdesc); *************** *** 1790,1799 **** pg_stat_get_archiver(PG_FUNCTION_ARGS) else values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp); if (archiver_stats->stat_reset_timestamp == 0) ! nulls[6] = true; else ! values[6] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp); /* Returns the record as Datum */ PG_RETURN_DATUM(HeapTupleGetDatum( --- 1798,1830 ---- else values[5] = TimestampTzGetDatum(archiver_stats->last_failed_timestamp); + snprintf(XLogArchiveStatusDir, MAXPGPATH, XLOGDIR "/archive_status"); + rldir = AllocateDir(XLogArchiveStatusDir); + if (rldir == NULL) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not open archive status directory \"%s\": %m", + XLogArchiveStatusDir))); + + while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL) + { + int basenamelen = (int) strlen(rlde->d_name) - 6; + + if (basenamelen >= MIN_XFN_CHARS && + basenamelen <= MAX_XFN_CHARS && + strspn(rlde->d_name, VALID_XFN_CHARS) >= basenamelen && + strcmp(rlde->d_name + basenamelen, ".ready") == 0) + { + ++ready_count; + } + } + FreeDir(rldir); + values[6] = Int64GetDatum(ready_count); + if (archiver_stats->stat_reset_timestamp == 0) ! nulls[7] = true; else ! values[7] = TimestampTzGetDatum(archiver_stats->stat_reset_timestamp); /* Returns the record as Datum */ PG_RETURN_DATUM(HeapTupleGetDatum( *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 2751,2757 **** DATA(insert OID = 2844 ( pg_stat_get_db_blk_read_time PGNSP PGUID 12 1 0 0 0 f DESCR("statistics: block read time, in msec"); DATA(insert OID = 2845 ( pg_stat_get_db_blk_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 701 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_blk_write_time _null_ _null_ _null_ )); DESCR("statistics: block write time, in msec"); ! DATA(insert OID = 3195 ( pg_stat_get_archiver PGNSP PGUID 12 1 0 0 0 f f f f f f s 0 0 2249 "" "{20,25,1184,20,25,1184,1184}" "{o,o,o,o,o,o,o}" "{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}" _null_ pg_stat_get_archiver _null_ _null_ _null_ )); DESCR("statistics: information about WAL archiver"); DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ )); DESCR("statistics: number of timed checkpoints started by the bgwriter"); --- 2751,2757 ---- DESCR("statistics: block read time, in msec"); DATA(insert OID = 2845 ( pg_stat_get_db_blk_write_time PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 701 "26" _null_ _null_ _null_ _null_ pg_stat_get_db_blk_write_time _null_ _null_ _null_ )); DESCR("statistics: block write time, in msec"); ! DATA(insert OID = 3195 ( pg_stat_get_archiver PGNSP PGUID 12 1 0 0 0 f f f f f f s 0 0 2249 "" "{20,25,1184,20,25,1184,20,1184}" "{o,o,o,o,o,o,o,o}" "{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,ready_count,stats_reset}" _null_ pg_stat_get_archiver _null_ _null_ _null_ )); DESCR("statistics: information about WAL archiver"); DATA(insert OID = 2769 ( pg_stat_get_bgwriter_timed_checkpoints PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 20 "" _null_ _null_ _null_ _null_ pg_stat_get_bgwriter_timed_checkpoints _null_ _null_ _null_ )); DESCR("statistics: number of timed checkpoints started by the bgwriter"); *** a/src/test/regress/expected/rules.out --- b/src/test/regress/expected/rules.out *************** *** 1659,1666 **** pg_stat_archiver| SELECT s.archived_count, s.failed_count, s.last_failed_wal, s.last_failed_time, s.stats_reset ! FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset); pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_checkpoint_write_time() AS checkpoint_write_time, --- 1659,1667 ---- s.failed_count, s.last_failed_wal, s.last_failed_time, + s.ready_count, s.stats_reset ! FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, ready_count, stats_reset); pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed, pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req, pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers