diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index e82a53a..cf3fb1b 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -624,7 +624,8 @@ CREATE VIEW pg_stat_activity AS S.state, S.backend_xid, s.backend_xmin, - S.query + S.query, + S.percent_complete FROM pg_database D, pg_stat_get_activity(NULL) AS S, pg_authid U WHERE S.datid = D.oid AND S.usesysid = U.oid; diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index a01cfb4..04c8547 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -439,7 +439,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, Relation *Irel, int nindexes, bool scan_all) { BlockNumber nblocks, - blkno; + blkno, + total_pages_scanned; HeapTupleData tuple; char *relname; BlockNumber empty_pages, @@ -456,6 +457,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, bool skipping_all_visible_blocks; xl_heap_freeze_tuple *frozen; StringInfoData buf; + TimestampTz previous_time; + TimestampTz current_time; pg_rusage_init(&ru0); @@ -471,12 +474,13 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, indstats = (IndexBulkDeleteResult **) palloc0(nindexes * sizeof(IndexBulkDeleteResult *)); - nblocks = RelationGetNumberOfBlocks(onerel); + total_pages_scanned = nblocks = RelationGetNumberOfBlocks(onerel); vacrelstats->rel_pages = nblocks; vacrelstats->scanned_pages = 0; vacrelstats->nonempty_pages = 0; vacrelstats->latestRemovedXid = InvalidTransactionId; + previous_time = GetCurrentTimestamp(); lazy_space_alloc(vacrelstats, nblocks); frozen = palloc(sizeof(xl_heap_freeze_tuple) * MaxHeapTuplesPerPage); @@ -520,7 +524,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, vacuum_delay_point(); } if (next_not_all_visible_block >= SKIP_PAGES_THRESHOLD) + { skipping_all_visible_blocks = true; + total_pages_scanned = total_pages_scanned - next_not_all_visible_block; + } else skipping_all_visible_blocks = false; @@ -559,7 +566,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, * following blocks. */ if (next_not_all_visible_block - blkno > SKIP_PAGES_THRESHOLD) + { skipping_all_visible_blocks = true; + total_pages_scanned = total_pages_scanned - (next_not_all_visible_block - blkno); + } else skipping_all_visible_blocks = false; all_visible_according_to_vm = false; @@ -1062,6 +1072,17 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats, */ if (vacrelstats->num_dead_tuples == prev_dead_count) RecordPageWithFreeSpace(onerel, blkno, freespace); + + /* + * Reporting vacuum progress to statistics collector + */ + if (pgstat_track_progress == 0 || (pgstat_track_progress > 0 && + TimestampDifferenceExceeds(previous_time, current_time = GetCurrentTimestamp(), + pgstat_track_progress))) + { + previous_time = current_time; + pgstat_report_progress(total_pages_scanned, vacrelstats->scanned_pages); + } } pfree(frozen); diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c index e9fbc38..e7ed315 100644 --- a/src/backend/postmaster/pgstat.c +++ b/src/backend/postmaster/pgstat.c @@ -67,6 +67,7 @@ #include "utils/tqual.h" + /* ---------- * Timer definitions. * ---------- @@ -108,6 +109,7 @@ bool pgstat_track_activities = false; bool pgstat_track_counts = false; int pgstat_track_functions = TRACK_FUNC_OFF; int pgstat_track_activity_query_size = 1024; +int pgstat_track_progress; /* ---------- * Built from GUC parameter @@ -2720,7 +2722,7 @@ pgstat_bestart(void) beentry->st_clienthostname[NAMEDATALEN - 1] = '\0'; beentry->st_appname[NAMEDATALEN - 1] = '\0'; beentry->st_activity[pgstat_track_activity_query_size - 1] = '\0'; - + beentry->percent_complete = 0; pgstat_increment_changecount_after(beentry); /* Update app name to current GUC setting */ @@ -2805,6 +2807,7 @@ pgstat_report_activity(BackendState state, const char *cmd_str) /* st_xact_start_timestamp and st_waiting are also disabled */ beentry->st_xact_start_timestamp = 0; beentry->st_waiting = false; + beentry->percent_complete = 0; pgstat_increment_changecount_after(beentry); } return; @@ -2837,7 +2840,33 @@ pgstat_report_activity(BackendState state, const char *cmd_str) beentry->st_activity_start_timestamp = start_timestamp; } + beentry->percent_complete = 0; + pgstat_increment_changecount_after(beentry); +} + +/* --------------------------------------------- + * Called after every fixed interval from vacuum's scan of the relation + * in order to calculate and store vacuum progress. + * --------------------------------------------- + */ + +void +pgstat_report_progress(BlockNumber total_pages, BlockNumber scanned_pages) +{ + volatile PgBackendStatus *beentry = MyBEEntry; + + if (!beentry) + return; + + if (!pgstat_track_activities) + return; + + pgstat_increment_changecount_before(beentry); + beentry->percent_complete = scanned_pages * 100 / total_pages; pgstat_increment_changecount_after(beentry); + + elog(LOG,"%d scanned_pages %d total pages\n", scanned_pages, total_pages); + elog(LOG,"%d percent_complete", beentry->percent_complete); } /* ---------- @@ -2994,6 +3023,8 @@ pgstat_read_current_status(void) strcpy(localactivity, (char *) beentry->st_activity); localentry->backendStatus.st_activity = localactivity; localentry->backendStatus.st_ssl = beentry->st_ssl; + localentry->backendStatus.percent_complete = beentry->percent_complete; + #ifdef USE_SSL if (beentry->st_ssl) { diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index f7c9bf6..7a05fd1 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -530,7 +530,7 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS) Datum pg_stat_get_activity(PG_FUNCTION_ARGS) { -#define PG_STAT_GET_ACTIVITY_COLS 22 +#define PG_STAT_GET_ACTIVITY_COLS 23 int num_backends = pgstat_fetch_stat_numbackends(); int curr_backend; int pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0); @@ -777,6 +777,11 @@ pg_stat_get_activity(PG_FUNCTION_ARGS) nulls[13] = true; } + if (beentry->percent_complete != 0) + values[22] = Int32GetDatum(beentry->percent_complete); + else + nulls[22] = true; + tuplestore_putvalues(tupstore, tupdesc, values, nulls); /* If only a single backend was requested, and we found it, break. */ diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 1bed525..fc86289 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -2309,7 +2309,15 @@ static struct config_int ConfigureNamesInt[] = -1, -1, INT_MAX, NULL, NULL, NULL }, - + { + {"track_activity_progress", PGC_SUSET, STATS_COLLECTOR, + gettext_noop("Collects progress information of executing commands."), + GUC_UNIT_MS + }, + &pgstat_track_progress, + -1, -1, INT_MAX, + NULL, NULL, NULL + }, { {"log_autovacuum_min_duration", PGC_SIGHUP, LOGGING_WHAT, gettext_noop("Sets the minimum execution time above which " diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 6fd1278..9c75bec 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -2777,7 +2777,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f DESCR("statistics: number of auto analyzes for a table"); DATA(insert OID = 1936 ( pg_stat_get_backend_idset PGNSP PGUID 12 1 100 0 0 f f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ )); DESCR("statistics: currently active backend IDs"); -DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ )); +DATA(insert OID = 2022 ( pg_stat_get_activity PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25,23}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn,percent_complete}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ )); DESCR("statistics: information about currently active backends"); DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ )); DESCR("statistics: information about currently active replication"); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index e3a31af..e5f1ac9 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -155,7 +155,6 @@ extern int vacuum_freeze_table_age; extern int vacuum_multixact_freeze_min_age; extern int vacuum_multixact_freeze_table_age; - /* in commands/vacuum.c */ extern void ExecVacuum(VacuumStmt *vacstmt, bool isTopLevel); extern void vacuum(int options, RangeVar *relation, Oid relid, diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 9ecc163..704584b 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -20,6 +20,7 @@ #include "utils/hsearch.h" #include "utils/relcache.h" +#include "storage/block.h" /* ---------- * Paths for the statistics files (relative to installation's $PGDATA). @@ -776,6 +777,9 @@ typedef struct PgBackendStatus /* current command string; MUST be null-terminated */ char *st_activity; + + int percent_complete; + } PgBackendStatus; /* @@ -871,6 +875,7 @@ extern PGDLLIMPORT int pgstat_track_activity_query_size; extern char *pgstat_stat_directory; extern char *pgstat_stat_tmpname; extern char *pgstat_stat_filename; +extern int pgstat_track_progress; /* * BgWriter statistics counters are updated directly by bgwriter and bufmgr @@ -928,6 +933,7 @@ extern void pgstat_initialize(void); extern void pgstat_bestart(void); extern void pgstat_report_activity(BackendState state, const char *cmd_str); +extern void pgstat_report_progress(BlockNumber total_pages, BlockNumber scanned_pages); extern void pgstat_report_tempfile(size_t filesize); extern void pgstat_report_appname(const char *appname); extern void pgstat_report_xact_timestamp(TimestampTz tstamp);