From 12f4596c25e15d1f7566b87334615ad112cfb64e Mon Sep 17 00:00:00 2001 From: Alena Rybakina Date: Sun, 21 Dec 2025 01:40:06 +0300 Subject: [PATCH 4/5] Vacuum statistics have been separated from regular relation and database statistics to reduce memory usage. Dedicated PGSTAT_KIND_VACUUM_RELATION and PGSTAT_KIND_VACUUM_DB entries were added to the stats collector to efficiently allocate memory for vacuum-specific metrics, which require significantly more space per relation. --- src/backend/access/heap/vacuumlazy.c | 124 +++++----- src/backend/catalog/heap.c | 1 + src/backend/catalog/index.c | 1 + src/backend/catalog/system_views.sql | 177 ++++++++------- src/backend/commands/dbcommands.c | 1 + src/backend/commands/vacuumparallel.c | 5 +- src/backend/utils/activity/Makefile | 1 + src/backend/utils/activity/pgstat.c | 30 ++- src/backend/utils/activity/pgstat_database.c | 10 +- src/backend/utils/activity/pgstat_relation.c | 75 +----- src/backend/utils/activity/pgstat_vacuum.c | 214 ++++++++++++++++++ src/backend/utils/adt/pgstatfuncs.c | 149 ++++++------ src/backend/utils/misc/guc_parameters.dat | 6 + src/include/commands/vacuum.h | 2 +- src/include/pgstat.h | 208 +++++++++-------- src/include/utils/pgstat_internal.h | 15 ++ src/include/utils/pgstat_kind.h | 4 +- .../t/050_vacuum_extending_basic_test.pl | 21 +- .../t/051_vacuum_extending_freeze_test.pl | 1 + src/test/regress/expected/rules.out | 146 ++++++------ 20 files changed, 735 insertions(+), 456 deletions(-) create mode 100644 src/backend/utils/activity/pgstat_vacuum.c diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index fcd92a43dda..3f1ed040908 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -413,7 +413,8 @@ typedef struct LVRelState int32 wraparound_failsafe_count; /* number of emergency vacuums to * prevent anti-wraparound * shutdown */ - ExtVacReport extVacReportIdx; + + PgStat_VacuumRelationCounts extVacReportIdx; } LVRelState; @@ -505,6 +506,9 @@ extvac_stats_start(Relation rel, LVExtStatCounters * counters) { TimestampTz starttime; + if (!pgstat_track_vacuum_statistics) + return; + memset(counters, 0, sizeof(LVExtStatCounters)); starttime = GetCurrentTimestamp(); @@ -536,7 +540,7 @@ extvac_stats_start(Relation rel, LVExtStatCounters * counters) */ static void extvac_stats_end(Relation rel, LVExtStatCounters * counters, - ExtVacReport * report) + PgStat_CommonCounts * report) { WalUsage walusage; BufferUsage bufusage; @@ -544,6 +548,11 @@ extvac_stats_end(Relation rel, LVExtStatCounters * counters, long secs; int usecs; + if (!pgstat_track_vacuum_statistics) + return; + + memset(report, 0, sizeof(PgStat_CommonCounts)); + /* Calculate diffs of global stat parameters on WAL and buffer usage. */ memset(&walusage, 0, sizeof(WalUsage)); WalUsageAccumDiff(&walusage, &pgWalUsage, &counters->walusage); @@ -592,6 +601,9 @@ void extvac_stats_start_idx(Relation rel, IndexBulkDeleteResult *stats, LVExtStatCountersIdx * counters) { + if (!pgstat_track_vacuum_statistics) + return; + /* Set initial values for common heap and index statistics */ extvac_stats_start(rel, &counters->common); counters->pages_deleted = counters->tuples_removed = 0; @@ -609,11 +621,15 @@ extvac_stats_start_idx(Relation rel, IndexBulkDeleteResult *stats, void extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats, - LVExtStatCountersIdx * counters, ExtVacReport * report) + LVExtStatCountersIdx * counters, PgStat_VacuumRelationCounts * report) { - memset(report, 0, sizeof(ExtVacReport)); + if (!pgstat_track_vacuum_statistics) + return; + + memset(report, 0, sizeof(PgStat_VacuumRelationCounts)); + + extvac_stats_end(rel, &counters->common, &report->common); - extvac_stats_end(rel, &counters->common, report); report->type = PGSTAT_EXTVAC_INDEX; if (stats != NULL) @@ -624,7 +640,7 @@ extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats, */ /* Fill index-specific extended stats fields */ - report->tuples_deleted = + report->common.tuples_deleted = stats->tuples_removed - counters->tuples_removed; report->index.pages_deleted = stats->pages_deleted - counters->pages_deleted; @@ -647,8 +663,11 @@ extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats, * procudure. */ static void -accumulate_heap_vacuum_statistics(LVRelState *vacrel, ExtVacReport * extVacStats) +accumulate_heap_vacuum_statistics(LVRelState *vacrel, PgStat_VacuumRelationCounts * extVacStats) { + if (!pgstat_track_vacuum_statistics) + return; + /* Fill heap-specific extended stats fields */ extVacStats->type = PGSTAT_EXTVAC_TABLE; extVacStats->table.pages_scanned = vacrel->scanned_pages; @@ -656,46 +675,45 @@ accumulate_heap_vacuum_statistics(LVRelState *vacrel, ExtVacReport * extVacStats extVacStats->table.vm_new_frozen_pages = vacrel->vm_new_frozen_pages; extVacStats->table.vm_new_visible_pages = vacrel->vm_new_visible_pages; extVacStats->table.vm_new_visible_frozen_pages = vacrel->vm_new_visible_frozen_pages; - extVacStats->tuples_deleted = vacrel->tuples_deleted; + extVacStats->common.tuples_deleted = vacrel->tuples_deleted; extVacStats->table.tuples_frozen = vacrel->tuples_frozen; extVacStats->table.recently_dead_tuples = vacrel->recently_dead_tuples; extVacStats->table.recently_dead_tuples = vacrel->recently_dead_tuples; extVacStats->table.missed_dead_tuples = vacrel->missed_dead_tuples; extVacStats->table.missed_dead_pages = vacrel->missed_dead_pages; extVacStats->table.index_vacuum_count = vacrel->num_index_scans; - extVacStats->wraparound_failsafe_count = vacrel->wraparound_failsafe_count; + extVacStats->common.wraparound_failsafe_count = vacrel->wraparound_failsafe_count; - extVacStats->blk_read_time -= vacrel->extVacReportIdx.blk_read_time; - extVacStats->blk_write_time -= vacrel->extVacReportIdx.blk_write_time; - extVacStats->total_blks_dirtied -= vacrel->extVacReportIdx.total_blks_dirtied; - extVacStats->total_blks_hit -= vacrel->extVacReportIdx.total_blks_hit; - extVacStats->total_blks_read -= vacrel->extVacReportIdx.total_blks_read; - extVacStats->total_blks_written -= vacrel->extVacReportIdx.total_blks_written; - extVacStats->wal_bytes -= vacrel->extVacReportIdx.wal_bytes; - extVacStats->wal_fpi -= vacrel->extVacReportIdx.wal_fpi; - extVacStats->wal_records -= vacrel->extVacReportIdx.wal_records; + extVacStats->common.blk_read_time -= vacrel->extVacReportIdx.common.blk_read_time; + extVacStats->common.blk_write_time -= vacrel->extVacReportIdx.common.blk_write_time; + extVacStats->common.total_blks_dirtied -= vacrel->extVacReportIdx.common.total_blks_dirtied; + extVacStats->common.total_blks_hit -= vacrel->extVacReportIdx.common.total_blks_hit; + extVacStats->common.total_blks_read -= vacrel->extVacReportIdx.common.total_blks_read; + extVacStats->common.total_blks_written -= vacrel->extVacReportIdx.common.total_blks_written; + extVacStats->common.wal_bytes -= vacrel->extVacReportIdx.common.wal_bytes; + extVacStats->common.wal_fpi -= vacrel->extVacReportIdx.common.wal_fpi; + extVacStats->common.wal_records -= vacrel->extVacReportIdx.common.wal_records; - extVacStats->total_time -= vacrel->extVacReportIdx.total_time; - extVacStats->delay_time -= vacrel->extVacReportIdx.delay_time; + extVacStats->common.total_time -= vacrel->extVacReportIdx.common.total_time; + extVacStats->common.delay_time -= vacrel->extVacReportIdx.common.delay_time; } static void -accumulate_idxs_vacuum_statistics(LVRelState *vacrel, ExtVacReport * extVacIdxStats) +accumulate_idxs_vacuum_statistics(LVRelState *vacrel, PgStat_VacuumRelationCounts * extVacIdxStats) { /* Fill heap-specific extended stats fields */ - vacrel->extVacReportIdx.blk_read_time += extVacIdxStats->blk_read_time; - vacrel->extVacReportIdx.blk_write_time += extVacIdxStats->blk_write_time; - vacrel->extVacReportIdx.total_blks_dirtied += extVacIdxStats->total_blks_dirtied; - vacrel->extVacReportIdx.total_blks_hit += extVacIdxStats->total_blks_hit; - vacrel->extVacReportIdx.total_blks_read += extVacIdxStats->total_blks_read; - vacrel->extVacReportIdx.total_blks_written += extVacIdxStats->total_blks_written; - vacrel->extVacReportIdx.wal_bytes += extVacIdxStats->wal_bytes; - vacrel->extVacReportIdx.wal_fpi += extVacIdxStats->wal_fpi; - vacrel->extVacReportIdx.wal_records += extVacIdxStats->wal_records; - vacrel->extVacReportIdx.delay_time += extVacIdxStats->delay_time; - - vacrel->extVacReportIdx.total_time += extVacIdxStats->total_time; + vacrel->extVacReportIdx.common.blk_read_time += extVacIdxStats->common.blk_read_time; + vacrel->extVacReportIdx.common.blk_write_time += extVacIdxStats->common.blk_write_time; + vacrel->extVacReportIdx.common.total_blks_dirtied += extVacIdxStats->common.total_blks_dirtied; + vacrel->extVacReportIdx.common.total_blks_hit += extVacIdxStats->common.total_blks_hit; + vacrel->extVacReportIdx.common.total_blks_read += extVacIdxStats->common.total_blks_read; + vacrel->extVacReportIdx.common.total_blks_written += extVacIdxStats->common.total_blks_written; + vacrel->extVacReportIdx.common.wal_bytes += extVacIdxStats->common.wal_bytes; + vacrel->extVacReportIdx.common.wal_fpi += extVacIdxStats->common.wal_fpi; + vacrel->extVacReportIdx.common.wal_records += extVacIdxStats->common.wal_records; + vacrel->extVacReportIdx.common.delay_time += extVacIdxStats->common.delay_time; + vacrel->extVacReportIdx.common.total_time += extVacIdxStats->common.total_time; } @@ -856,10 +874,10 @@ heap_vacuum_rel(Relation rel, const VacuumParams params, ErrorContextCallback errcallback; char **indnames = NULL; LVExtStatCounters extVacCounters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; /* Initialize vacuum statistics */ - memset(&extVacReport, 0, sizeof(ExtVacReport)); + memset(&extVacReport, 0, sizeof(PgStat_VacuumRelationCounts)); verbose = (params.options & VACOPT_VERBOSE) != 0; instrument = (verbose || (AmAutoVacuumWorkerProcess() && @@ -915,7 +933,8 @@ heap_vacuum_rel(Relation rel, const VacuumParams params, errcallback.previous = error_context_stack; error_context_stack = &errcallback; - memset(&vacrel->extVacReportIdx, 0, sizeof(ExtVacReport)); + memset(&vacrel->extVacReportIdx, 0, sizeof(PgStat_VacuumRelationCounts)); + memset(&extVacReport.common, 0, sizeof(PgStat_CommonCounts)); /* Set up high level stuff about rel and its indexes */ vacrel->rel = rel; @@ -1173,7 +1192,7 @@ heap_vacuum_rel(Relation rel, const VacuumParams params, &frozenxid_updated, &minmulti_updated, false); /* Make generic extended vacuum stats report */ - extvac_stats_end(rel, &extVacCounters, &extVacReport); + /* extvac_stats_end(rel, &extVacCounters, &extVacReport.common); */ /* * Report results to the cumulative stats system, too. @@ -1190,14 +1209,14 @@ heap_vacuum_rel(Relation rel, const VacuumParams params, * Make generic extended vacuum stats report and fill heap-specific * extended stats fields. */ - extvac_stats_end(vacrel->rel, &extVacCounters, &extVacReport); + extvac_stats_end(vacrel->rel, &extVacCounters, &extVacReport.common); accumulate_heap_vacuum_statistics(vacrel, &extVacReport); + pgstat_report_vacuum_extstats(vacrel->reloid, rel->rd_rel->relisshared, &extVacReport); pgstat_report_vacuum(rel, Max(vacrel->new_live_tuples, 0), vacrel->recently_dead_tuples + vacrel->missed_dead_tuples, - starttime, - &extVacReport); + starttime); pgstat_progress_end_command(); if (instrument) @@ -2902,9 +2921,9 @@ lazy_vacuum_all_indexes(LVRelState *vacrel) else { LVExtStatCounters counters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; - memset(&extVacReport, 0, sizeof(ExtVacReport)); + memset(&extVacReport.common, 0, sizeof(PgStat_CommonCounts)); extvac_stats_start(vacrel->rel, &counters); @@ -2912,7 +2931,7 @@ lazy_vacuum_all_indexes(LVRelState *vacrel) parallel_vacuum_bulkdel_all_indexes(vacrel->pvs, old_live_tuples, vacrel->num_index_scans); - extvac_stats_end(vacrel->rel, &counters, &extVacReport); + extvac_stats_end(vacrel->rel, &counters, &extVacReport.common); accumulate_idxs_vacuum_statistics(vacrel, &extVacReport); /* @@ -3345,9 +3364,9 @@ lazy_cleanup_all_indexes(LVRelState *vacrel) else { LVExtStatCounters counters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; - memset(&extVacReport, 0, sizeof(ExtVacReport)); + memset(&extVacReport.common, 0, sizeof(PgStat_CommonCounts)); extvac_stats_start(vacrel->rel, &counters); @@ -3356,7 +3375,7 @@ lazy_cleanup_all_indexes(LVRelState *vacrel) vacrel->num_index_scans, estimated_count); - extvac_stats_end(vacrel->rel, &counters, &extVacReport); + extvac_stats_end(vacrel->rel, &counters, &extVacReport.common); accumulate_idxs_vacuum_statistics(vacrel, &extVacReport); } @@ -3384,7 +3403,10 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat, IndexVacuumInfo ivinfo; LVSavedErrInfo saved_err_info; LVExtStatCountersIdx extVacCounters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; + + memset(&extVacReport, 0, sizeof(PgStat_VacuumRelationCounts)); + memset(&extVacReport.common, 0, sizeof(PgStat_CommonCounts)); /* Set initial statistics values to gather vacuum statistics for the index */ extvac_stats_start_idx(indrel, istat, &extVacCounters); @@ -3421,8 +3443,7 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat, if (!ParallelVacuumIsActive(vacrel)) accumulate_idxs_vacuum_statistics(vacrel, &extVacReport); - pgstat_report_vacuum(indrel, - 0, 0, 0, &extVacReport); + pgstat_report_vacuum_extstats(vacrel->indoid, indrel->rd_rel->relisshared, &extVacReport); /* Revert to the previous phase information for error traceback */ restore_vacuum_error_info(vacrel, &saved_err_info); @@ -3449,7 +3470,7 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat, IndexVacuumInfo ivinfo; LVSavedErrInfo saved_err_info; LVExtStatCountersIdx extVacCounters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; /* Set initial statistics values to gather vacuum statistics for the index */ extvac_stats_start_idx(indrel, istat, &extVacCounters); @@ -3485,8 +3506,7 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat, if (!ParallelVacuumIsActive(vacrel)) accumulate_idxs_vacuum_statistics(vacrel, &extVacReport); - pgstat_report_vacuum(indrel, - 0, 0, 0, &extVacReport); + pgstat_report_vacuum_extstats(RelationGetRelid(indrel), indrel->rd_rel->relisshared, &extVacReport); /* Revert to the previous phase information for error traceback */ restore_vacuum_error_info(vacrel, &saved_err_info); diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 265cc3e5fbf..680b76b8ef9 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -1883,6 +1883,7 @@ heap_drop_with_catalog(Oid relid) /* ensure that stats are dropped if transaction commits */ pgstat_drop_relation(rel); + pgstat_vacuum_relation_delete_pending_cb(RelationGetRelid(rel)); /* * Close relcache entry, but *keep* AccessExclusiveLock on the relation diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 8dea58ad96b..e906f9e1856 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2327,6 +2327,7 @@ index_drop(Oid indexId, bool concurrent, bool concurrent_lock_mode) /* ensure that stats are dropped if transaction commits */ pgstat_drop_relation(userIndexRelation); + pgstat_vacuum_relation_delete_pending_cb(RelationGetRelid(userIndexRelation)); /* * Close and flush the index's relcache entry, to ensure relcache doesn't diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index dc86b1ee212..4ec2a7d9f10 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1462,99 +1462,104 @@ GRANT EXECUTE ON FUNCTION pg_get_aios() TO pg_read_all_stats; -- CREATE VIEW pg_stat_vacuum_tables AS -SELECT - ns.nspname AS schemaname, - rel.relname AS relname, - stats.relid as relid, - - stats.total_blks_read AS total_blks_read, - stats.total_blks_hit AS total_blks_hit, - stats.total_blks_dirtied AS total_blks_dirtied, - stats.total_blks_written AS total_blks_written, - - stats.rel_blks_read AS rel_blks_read, - stats.rel_blks_hit AS rel_blks_hit, - - stats.pages_scanned AS pages_scanned, - stats.pages_removed AS pages_removed, - stats.vm_new_frozen_pages AS vm_new_frozen_pages, - stats.vm_new_visible_pages AS vm_new_visible_pages, - stats.vm_new_visible_frozen_pages AS vm_new_visible_frozen_pages, - stats.missed_dead_pages AS missed_dead_pages, - stats.tuples_deleted AS tuples_deleted, - stats.tuples_frozen AS tuples_frozen, - stats.recently_dead_tuples AS recently_dead_tuples, - stats.missed_dead_tuples AS missed_dead_tuples, - - stats.wraparound_failsafe AS wraparound_failsafe, - stats.index_vacuum_count AS index_vacuum_count, - stats.wal_records AS wal_records, - stats.wal_fpi AS wal_fpi, - stats.wal_bytes AS wal_bytes, - - stats.blk_read_time AS blk_read_time, - stats.blk_write_time AS blk_write_time, - - stats.delay_time AS delay_time, - stats.total_time AS total_time - -FROM pg_class rel - JOIN pg_namespace ns ON ns.oid = rel.relnamespace, - LATERAL pg_stat_get_vacuum_tables(rel.oid) stats -WHERE rel.relkind = 'r'; + SELECT + N.nspname AS schemaname, + C.relname AS relname, + S.relid as relid, + + S.total_blks_read AS total_blks_read, + S.total_blks_hit AS total_blks_hit, + S.total_blks_dirtied AS total_blks_dirtied, + S.total_blks_written AS total_blks_written, + + S.rel_blks_read AS rel_blks_read, + S.rel_blks_hit AS rel_blks_hit, + + S.pages_scanned AS pages_scanned, + S.pages_removed AS pages_removed, + S.vm_new_frozen_pages AS vm_new_frozen_pages, + S.vm_new_visible_pages AS vm_new_visible_pages, + S.vm_new_visible_frozen_pages AS vm_new_visible_frozen_pages, + S.missed_dead_pages AS missed_dead_pages, + S.tuples_deleted AS tuples_deleted, + S.tuples_frozen AS tuples_frozen, + S.recently_dead_tuples AS recently_dead_tuples, + S.missed_dead_tuples AS missed_dead_tuples, + + S.wraparound_failsafe AS wraparound_failsafe, + S.index_vacuum_count AS index_vacuum_count, + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes, + + S.blk_read_time AS blk_read_time, + S.blk_write_time AS blk_write_time, + + S.delay_time AS delay_time, + S.total_time AS total_time + + FROM pg_class C JOIN + pg_namespace N ON N.oid = C.relnamespace, + LATERAL pg_stat_get_vacuum_tables(C.oid) S + WHERE C.relkind IN ('r', 't', 'm'); CREATE VIEW pg_stat_vacuum_indexes AS -SELECT - rel.oid as relid, - ns.nspname AS schemaname, - rel.relname AS relname, + SELECT + C.oid AS relid, + I.oid AS indexrelid, + N.nspname AS schemaname, + C.relname AS relname, + I.relname AS indexrelname, - total_blks_read AS total_blks_read, - total_blks_hit AS total_blks_hit, - total_blks_dirtied AS total_blks_dirtied, - total_blks_written AS total_blks_written, + S.total_blks_read AS total_blks_read, + S.total_blks_hit AS total_blks_hit, + S.total_blks_dirtied AS total_blks_dirtied, + S.total_blks_written AS total_blks_written, - rel_blks_read AS rel_blks_read, - rel_blks_hit AS rel_blks_hit, + S.rel_blks_read AS rel_blks_read, + S.rel_blks_hit AS rel_blks_hit, - pages_deleted AS pages_deleted, - tuples_deleted AS tuples_deleted, + S.pages_deleted AS pages_deleted, + S.tuples_deleted AS tuples_deleted, - wal_records AS wal_records, - wal_fpi AS wal_fpi, - wal_bytes AS wal_bytes, + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes, - blk_read_time AS blk_read_time, - blk_write_time AS blk_write_time, + S.blk_read_time AS blk_read_time, + S.blk_write_time AS blk_write_time, - delay_time AS delay_time, - total_time AS total_time -FROM - pg_class rel - JOIN pg_namespace ns ON ns.oid = rel.relnamespace, - LATERAL pg_stat_get_vacuum_indexes(rel.oid) stats -WHERE rel.relkind = 'i'; + S.delay_time AS delay_time, + S.total_time AS total_time + FROM + pg_class C JOIN + pg_index X ON C.oid = X.indrelid JOIN + pg_class I ON I.oid = X.indexrelid + LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace), + LATERAL pg_stat_get_vacuum_indexes(I.oid) S + WHERE C.relkind IN ('r', 't', 'm'); CREATE VIEW pg_stat_vacuum_database AS -SELECT - db.oid as dboid, - db.datname AS dbname, - - stats.db_blks_read AS db_blks_read, - stats.db_blks_hit AS db_blks_hit, - stats.total_blks_dirtied AS total_blks_dirtied, - stats.total_blks_written AS total_blks_written, - - stats.wal_records AS wal_records, - stats.wal_fpi AS wal_fpi, - stats.wal_bytes AS wal_bytes, - - stats.blk_read_time AS blk_read_time, - stats.blk_write_time AS blk_write_time, - - stats.delay_time AS delay_time, - stats.total_time AS total_time, - stats.wraparound_failsafe AS wraparound_failsafe -FROM - pg_database db, - LATERAL pg_stat_get_vacuum_database(db.oid) stats; \ No newline at end of file + SELECT + D.oid as dboid, + D.datname AS dbname, + + S.db_blks_read AS db_blks_read, + S.db_blks_hit AS db_blks_hit, + S.total_blks_dirtied AS total_blks_dirtied, + S.total_blks_written AS total_blks_written, + + S.wal_records AS wal_records, + S.wal_fpi AS wal_fpi, + S.wal_bytes AS wal_bytes, + + S.blk_read_time AS blk_read_time, + S.blk_write_time AS blk_write_time, + + S.delay_time AS delay_time, + S.total_time AS total_time, + S.wraparound_failsafe AS wraparound_failsafe, + S.errors AS errors + FROM + pg_database D, + LATERAL pg_stat_get_vacuum_database(D.oid) S; diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c index d1f3be89b35..bf3cd3b1cc9 100644 --- a/src/backend/commands/dbcommands.c +++ b/src/backend/commands/dbcommands.c @@ -1815,6 +1815,7 @@ dropdb(const char *dbname, bool missing_ok, bool force) * Tell the cumulative stats system to forget it immediately, too. */ pgstat_drop_database(db_id); + pgstat_drop_vacuum_database(db_id); /* * Except for the deletion of the catalog row, subsequent actions are not diff --git a/src/backend/commands/vacuumparallel.c b/src/backend/commands/vacuumparallel.c index 43450685b09..c7dd2bb52f6 100644 --- a/src/backend/commands/vacuumparallel.c +++ b/src/backend/commands/vacuumparallel.c @@ -869,7 +869,7 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel, IndexBulkDeleteResult *istat_res; IndexVacuumInfo ivinfo; LVExtStatCountersIdx extVacCounters; - ExtVacReport extVacReport; + PgStat_VacuumRelationCounts extVacReport; /* * Update the pointer to the corresponding bulk-deletion result if someone @@ -911,8 +911,7 @@ parallel_vacuum_process_one_index(ParallelVacuumState *pvs, Relation indrel, /* Make extended vacuum stats report for index */ extvac_stats_end_idx(indrel, istat_res, &extVacCounters, &extVacReport); - pgstat_report_vacuum(indrel, - 0, 0, 0, &extVacReport); + pgstat_report_vacuum_extstats(RelationGetRelid(indrel), indrel->rd_rel->relisshared, &extVacReport); /* * Copy the index bulk-deletion result returned from ambulkdelete and diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile index 9c2443e1ecd..183f7514d2d 100644 --- a/src/backend/utils/activity/Makefile +++ b/src/backend/utils/activity/Makefile @@ -27,6 +27,7 @@ OBJS = \ pgstat_function.o \ pgstat_io.o \ pgstat_relation.o \ + pgstat_vacuum.o \ pgstat_replslot.o \ pgstat_shmem.o \ pgstat_slru.o \ diff --git a/src/backend/utils/activity/pgstat.c b/src/backend/utils/activity/pgstat.c index f317c6e8e90..cdc9cab01cf 100644 --- a/src/backend/utils/activity/pgstat.c +++ b/src/backend/utils/activity/pgstat.c @@ -203,7 +203,7 @@ static inline bool pgstat_is_kind_valid(PgStat_Kind kind); bool pgstat_track_counts = false; int pgstat_fetch_consistency = PGSTAT_FETCH_CONSISTENCY_CACHE; - +bool pgstat_track_vacuum_statistics = false; /* ---------- * state shared with pgstat_*.c @@ -482,6 +482,34 @@ static const PgStat_KindInfo pgstat_kind_builtin_infos[PGSTAT_KIND_BUILTIN_SIZE] .reset_all_cb = pgstat_wal_reset_all_cb, .snapshot_cb = pgstat_wal_snapshot_cb, }, + [PGSTAT_KIND_VACUUM_DB] = { + .name = "vacuum statistics", + + .fixed_amount = false, + .write_to_file = true, + /* so pg_stat_database entries can be seen in all databases */ + .accessed_across_databases = true, + + .shared_size = sizeof(PgStatShared_VacuumDB), + .shared_data_off = offsetof(PgStatShared_VacuumDB, stats), + .shared_data_len = sizeof(((PgStatShared_VacuumDB *) 0)->stats), + .pending_size = sizeof(PgStat_VacuumDBCounts), + + .flush_pending_cb = pgstat_vacuum_db_flush_cb, + }, + [PGSTAT_KIND_VACUUM_RELATION] = { + .name = "vacuum statistics", + + .fixed_amount = false, + .write_to_file = true, + + .shared_size = sizeof(PgStatShared_VacuumRelation), + .shared_data_off = offsetof(PgStatShared_VacuumRelation, stats), + .shared_data_len = sizeof(((PgStatShared_VacuumRelation *) 0)->stats), + .pending_size = sizeof(PgStat_RelationVacuumPending), + + .flush_pending_cb = pgstat_vacuum_relation_flush_cb + }, }; /* diff --git a/src/backend/utils/activity/pgstat_database.c b/src/backend/utils/activity/pgstat_database.c index 65207d30378..80e6c7c229a 100644 --- a/src/backend/utils/activity/pgstat_database.c +++ b/src/backend/utils/activity/pgstat_database.c @@ -46,6 +46,15 @@ pgstat_drop_database(Oid databaseid) pgstat_drop_transactional(PGSTAT_KIND_DATABASE, databaseid, InvalidOid); } +/* + * Remove entry for the database being dropped. + */ +void +pgstat_drop_vacuum_database(Oid databaseid) +{ + pgstat_drop_transactional(PGSTAT_KIND_VACUUM_DB, databaseid, InvalidOid); +} + /* * Called from autovacuum.c to report startup of an autovacuum process. * We are called before InitPostgres is done, so can't rely on MyDatabaseId; @@ -485,7 +494,6 @@ pgstat_database_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) pgstat_unlock_entry(entry_ref); memset(pendingent, 0, sizeof(*pendingent)); - memset(&(pendingent)->vacuum_ext, 0, sizeof(ExtVacReport)); return true; } diff --git a/src/backend/utils/activity/pgstat_relation.c b/src/backend/utils/activity/pgstat_relation.c index 2675c541369..e8665d23099 100644 --- a/src/backend/utils/activity/pgstat_relation.c +++ b/src/backend/utils/activity/pgstat_relation.c @@ -47,8 +47,6 @@ static void add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_lev static void ensure_tabstat_xact_level(PgStat_TableStatus *pgstat_info); static void save_truncdrop_counters(PgStat_TableXactStatus *trans, bool is_drop); static void restore_truncdrop_counters(PgStat_TableXactStatus *trans); -static void pgstat_accumulate_extvac_stats(ExtVacReport * dst, ExtVacReport * src, - bool accumulate_reltype_specific_info); /* @@ -210,12 +208,11 @@ pgstat_drop_relation(Relation rel) */ void pgstat_report_vacuum(Relation rel, PgStat_Counter livetuples, - PgStat_Counter deadtuples, TimestampTz starttime, ExtVacReport * params) + PgStat_Counter deadtuples, TimestampTz starttime) { PgStat_EntryRef *entry_ref; PgStatShared_Relation *shtabentry; PgStat_StatTabEntry *tabentry; - PgStatShared_Database *dbentry; Oid dboid = (rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId); TimestampTz ts; PgStat_Counter elapsedtime; @@ -237,8 +234,6 @@ pgstat_report_vacuum(Relation rel, PgStat_Counter livetuples, tabentry->live_tuples = livetuples; tabentry->dead_tuples = deadtuples; - pgstat_accumulate_extvac_stats(&tabentry->vacuum_ext, params, true); - /* * It is quite possible that a non-aggressive VACUUM ended up skipping * various pages, however, we'll zero the insert counter here regardless. @@ -274,16 +269,6 @@ pgstat_report_vacuum(Relation rel, PgStat_Counter livetuples, */ pgstat_flush_io(false); (void) pgstat_flush_backend(false, PGSTAT_BACKEND_FLUSH_IO); - - if (dboid != InvalidOid) - { - entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_DATABASE, - dboid, InvalidOid, false); - dbentry = (PgStatShared_Database *) entry_ref->shared_stats; - - pgstat_accumulate_extvac_stats(&dbentry->stats.vacuum_ext, params, false); - pgstat_unlock_entry(entry_ref); - } } /* @@ -918,6 +903,12 @@ pgstat_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) return true; } +void +pgstat_vacuum_relation_delete_pending_cb(Oid relid) +{ + pgstat_drop_transactional(PGSTAT_KIND_VACUUM_RELATION, relid, InvalidOid); +} + void pgstat_relation_delete_pending_cb(PgStat_EntryRef *entry_ref) { @@ -1027,55 +1018,3 @@ restore_truncdrop_counters(PgStat_TableXactStatus *trans) trans->tuples_deleted = trans->deleted_pre_truncdrop; } } - -static void -pgstat_accumulate_extvac_stats(ExtVacReport * dst, ExtVacReport * src, - bool accumulate_reltype_specific_info) -{ - dst->total_blks_read += src->total_blks_read; - dst->total_blks_hit += src->total_blks_hit; - dst->total_blks_dirtied += src->total_blks_dirtied; - dst->total_blks_written += src->total_blks_written; - dst->wal_bytes += src->wal_bytes; - dst->wal_fpi += src->wal_fpi; - dst->wal_records += src->wal_records; - dst->blk_read_time += src->blk_read_time; - dst->blk_write_time += src->blk_write_time; - dst->delay_time += src->delay_time; - dst->total_time += src->total_time; - dst->wraparound_failsafe_count += src->wraparound_failsafe_count; - - if (!accumulate_reltype_specific_info) - return; - - if (dst->type == PGSTAT_EXTVAC_INVALID) - dst->type = src->type; - - Assert(src->type == PGSTAT_EXTVAC_INVALID || src->type == dst->type); - - if (dst->type == src->type) - { - dst->blks_fetched += src->blks_fetched; - dst->blks_hit += src->blks_hit; - - if (dst->type == PGSTAT_EXTVAC_TABLE) - { - dst->table.pages_scanned += src->table.pages_scanned; - dst->table.pages_removed += src->table.pages_removed; - dst->table.vm_new_frozen_pages += src->table.vm_new_frozen_pages; - dst->table.vm_new_visible_pages += src->table.vm_new_visible_pages; - dst->table.vm_new_visible_frozen_pages += src->table.vm_new_visible_frozen_pages; - dst->tuples_deleted += src->tuples_deleted; - dst->table.tuples_frozen += src->table.tuples_frozen; - dst->table.recently_dead_tuples += src->table.recently_dead_tuples; - dst->table.index_vacuum_count += src->table.index_vacuum_count; - dst->table.missed_dead_pages += src->table.missed_dead_pages; - dst->table.missed_dead_tuples += src->table.missed_dead_tuples; - } - else if (dst->type == PGSTAT_EXTVAC_INDEX) - { - dst->index.pages_deleted += src->index.pages_deleted; - dst->tuples_deleted += src->tuples_deleted; - } - } -} diff --git a/src/backend/utils/activity/pgstat_vacuum.c b/src/backend/utils/activity/pgstat_vacuum.c new file mode 100644 index 00000000000..340ee24f26a --- /dev/null +++ b/src/backend/utils/activity/pgstat_vacuum.c @@ -0,0 +1,214 @@ +#include "postgres.h" + +#include "pgstat.h" +#include "utils/pgstat_internal.h" +#include "utils/memutils.h" + +/* ---------- + * GUC parameters + * ---------- + */ +bool pgstat_track_vacuum_statistics_for_relations = false; + +#define ACCUMULATE_FIELD(field) dst->field += src->field; + +#define ACCUMULATE_SUBFIELD(substruct, field) \ + (dst->substruct.field += src->substruct.field) + +static void +pgstat_accumulate_common(PgStat_CommonCounts * dst, const PgStat_CommonCounts * src) +{ + ACCUMULATE_FIELD(total_blks_read); + ACCUMULATE_FIELD(total_blks_hit); + ACCUMULATE_FIELD(total_blks_dirtied); + ACCUMULATE_FIELD(total_blks_written); + + ACCUMULATE_FIELD(blks_fetched); + ACCUMULATE_FIELD(blks_hit); + + ACCUMULATE_FIELD(wal_records); + ACCUMULATE_FIELD(wal_fpi); + ACCUMULATE_FIELD(wal_bytes); + + ACCUMULATE_FIELD(blk_read_time); + ACCUMULATE_FIELD(blk_write_time); + ACCUMULATE_FIELD(delay_time); + ACCUMULATE_FIELD(total_time); + + ACCUMULATE_FIELD(tuples_deleted); + ACCUMULATE_FIELD(wraparound_failsafe_count); +} + +static void +pgstat_accumulate_extvac_stats_relations(PgStat_VacuumRelationCounts * dst, PgStat_VacuumRelationCounts * src) +{ + if (!pgstat_track_vacuum_statistics) + return; + + if (dst->type == PGSTAT_EXTVAC_INVALID) + dst->type = src->type; + + Assert(src->type != PGSTAT_EXTVAC_INVALID && src->type != PGSTAT_EXTVAC_DB && src->type == dst->type); + + pgstat_accumulate_common(&dst->common, &src->common); + + ACCUMULATE_SUBFIELD(common, blks_fetched); + ACCUMULATE_SUBFIELD(common, blks_hit); + + if (dst->type == PGSTAT_EXTVAC_TABLE) + { + ACCUMULATE_SUBFIELD(common, tuples_deleted); + ACCUMULATE_SUBFIELD(table, pages_scanned); + ACCUMULATE_SUBFIELD(table, pages_removed); + ACCUMULATE_SUBFIELD(table, vm_new_frozen_pages); + ACCUMULATE_SUBFIELD(table, vm_new_visible_pages); + ACCUMULATE_SUBFIELD(table, vm_new_visible_frozen_pages); + ACCUMULATE_SUBFIELD(table, tuples_frozen); + ACCUMULATE_SUBFIELD(table, recently_dead_tuples); + ACCUMULATE_SUBFIELD(table, index_vacuum_count); + ACCUMULATE_SUBFIELD(table, missed_dead_pages); + ACCUMULATE_SUBFIELD(table, missed_dead_tuples); + } + else if (dst->type == PGSTAT_EXTVAC_INDEX) + { + ACCUMULATE_SUBFIELD(common, tuples_deleted); + ACCUMULATE_SUBFIELD(index, pages_deleted); + } +} + +static void +pgstat_accumulate_extvac_stats_db(PgStat_VacuumDBCounts * dst, PgStat_VacuumDBCounts * src) +{ + if (!pgstat_track_vacuum_statistics) + return; + + pgstat_accumulate_common(&dst->common, &src->common); +} + +/* + * Report that the table was just vacuumed and flush statistics. + */ +void +pgstat_report_vacuum_extstats(Oid tableoid, bool shared, + PgStat_VacuumRelationCounts * params) +{ + PgStat_EntryRef *entry_ref; + PgStatShared_VacuumRelation *shtabentry; + PgStatShared_VacuumDB *shdbentry; + Oid dboid = (shared ? InvalidOid : MyDatabaseId); + + if (!pgstat_track_vacuum_statistics) + return; + + entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_VACUUM_RELATION, + dboid, tableoid, false); + shtabentry = (PgStatShared_VacuumRelation *) entry_ref->shared_stats; + pgstat_accumulate_extvac_stats_relations(&shtabentry->stats, params); + + pgstat_unlock_entry(entry_ref); + + + entry_ref = pgstat_get_entry_ref_locked(PGSTAT_KIND_VACUUM_DB, + dboid, InvalidOid, false); + + shdbentry = (PgStatShared_VacuumDB *) entry_ref->shared_stats; + + pgstat_accumulate_common(&shdbentry->stats.common, ¶ms->common); + + pgstat_unlock_entry(entry_ref); +} + +/* + * Flush out pending stats for the entry + * + * If nowait is true, this function returns false if lock could not + * immediately acquired, otherwise true is returned. + */ +bool +pgstat_vacuum_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) +{ + PgStatShared_VacuumRelation *shtabstats; + PgStat_RelationVacuumPending *pendingent; /* table entry of shared stats */ + + pendingent = (PgStat_RelationVacuumPending *) entry_ref->pending; + shtabstats = (PgStatShared_VacuumRelation *) entry_ref->shared_stats; + + /* + * Ignore entries that didn't accumulate any actual counts. + */ + if (pg_memory_is_all_zeros(&pendingent, + sizeof(struct PgStat_RelationVacuumPending))) + return true; + + if (!pgstat_lock_entry(entry_ref, nowait)) + { + return false; + } + + pgstat_accumulate_extvac_stats_relations(&(shtabstats->stats), &(pendingent->counts)); + + pgstat_unlock_entry(entry_ref); + + return true; +} + +/* + * Support function for the SQL-callable pgstat* functions. Returns + * the vacuum collected statistics for one relation or NULL. + */ +PgStat_VacuumRelationCounts * +pgstat_fetch_stat_vacuum_tabentry(Oid relid, Oid dbid) +{ + return (PgStat_VacuumRelationCounts *) + pgstat_fetch_entry(PGSTAT_KIND_VACUUM_RELATION, dbid, relid); +} + +PgStat_VacuumDBCounts * +pgstat_fetch_stat_vacuum_dbentry(Oid dbid) +{ + return (PgStat_VacuumDBCounts *) + pgstat_fetch_entry(PGSTAT_KIND_VACUUM_DB, dbid, InvalidOid); +} + +bool +pgstat_vacuum_db_flush_cb(PgStat_EntryRef *entry_ref, bool nowait) +{ + PgStatShared_VacuumDB *sharedent; + PgStat_VacuumDBCounts *pendingent; + + pendingent = (PgStat_VacuumDBCounts *) entry_ref->pending; + sharedent = (PgStatShared_VacuumDB *) entry_ref->shared_stats; + + if (!pgstat_lock_entry(entry_ref, nowait)) + return false; + + /* The entry was successfully flushed, add the same to database stats */ + pgstat_accumulate_extvac_stats_db(&(sharedent->stats), pendingent); + + pgstat_unlock_entry(entry_ref); + + return true; +} + +/* + * Find or create a local PgStat_VacuumDBCounts entry for dboid. + */ +PgStat_VacuumDBCounts * +pgstat_prep_vacuum_database_pending(Oid dboid) +{ + PgStat_EntryRef *entry_ref; + + /* + * This should not report stats on database objects before having + * connected to a database. + */ + Assert(!OidIsValid(dboid) || OidIsValid(MyDatabaseId)); + + entry_ref = pgstat_prep_pending_entry(PGSTAT_KIND_VACUUM_DB, dboid, InvalidOid, + NULL); + + if (entry_ref == NULL) + return NULL; + + return entry_ref->pending; +} diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 4e2714f2e6a..0a64f034a3f 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -2314,7 +2314,6 @@ pg_stat_have_stats(PG_FUNCTION_ARGS) PG_RETURN_BOOL(pgstat_have_entry(kind, dboid, objid)); } - /* * Get the vacuum statistics for the heap tables. */ @@ -2324,41 +2323,45 @@ pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS) #define PG_STAT_GET_VACUUM_TABLES_STATS_COLS 26 Oid relid = PG_GETARG_OID(0); - PgStat_StatTabEntry *tabentry; - ExtVacReport *extvacuum; + PgStat_VacuumRelationCounts *extvacuum; + PgStat_VacuumRelationCounts *pending; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_TABLES_STATS_COLS] = {0}; char buf[256]; int i = 0; + /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); - tabentry = pgstat_fetch_stat_tabentry(relid); + pending = pgstat_fetch_stat_vacuum_tabentry(relid, MyDatabaseId); - if (!tabentry) - { - InitMaterializedSRF(fcinfo, 0); - PG_RETURN_VOID(); - } - else + if (!pending) { - extvacuum = &(tabentry->vacuum_ext); + pending = pgstat_fetch_stat_vacuum_tabentry(relid, 0); + + if (!pending) + { + InitMaterializedSRF(fcinfo, 0); + PG_RETURN_VOID(); + } } + extvacuum = pending; + i = 0; values[i++] = ObjectIdGetDatum(relid); - values[i++] = Int64GetDatum(extvacuum->total_blks_read); - values[i++] = Int64GetDatum(extvacuum->total_blks_hit); - values[i++] = Int64GetDatum(extvacuum->total_blks_dirtied); - values[i++] = Int64GetDatum(extvacuum->total_blks_written); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_read); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_dirtied); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_written); - values[i++] = Int64GetDatum(extvacuum->blks_fetched - - extvacuum->blks_hit); - values[i++] = Int64GetDatum(extvacuum->blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.blks_fetched - + extvacuum->common.blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.blks_hit); values[i++] = Int64GetDatum(extvacuum->table.pages_scanned); values[i++] = Int64GetDatum(extvacuum->table.pages_removed); @@ -2366,28 +2369,28 @@ pg_stat_get_vacuum_tables(PG_FUNCTION_ARGS) values[i++] = Int64GetDatum(extvacuum->table.vm_new_visible_pages); values[i++] = Int64GetDatum(extvacuum->table.vm_new_visible_frozen_pages); values[i++] = Int64GetDatum(extvacuum->table.missed_dead_pages); - values[i++] = Int64GetDatum(extvacuum->tuples_deleted); + values[i++] = Int64GetDatum(extvacuum->common.tuples_deleted); values[i++] = Int64GetDatum(extvacuum->table.tuples_frozen); values[i++] = Int64GetDatum(extvacuum->table.recently_dead_tuples); values[i++] = Int64GetDatum(extvacuum->table.missed_dead_tuples); - values[i++] = Int32GetDatum(extvacuum->wraparound_failsafe_count); + values[i++] = Int32GetDatum(extvacuum->common.wraparound_failsafe_count); values[i++] = Int64GetDatum(extvacuum->table.index_vacuum_count); - values[i++] = Int64GetDatum(extvacuum->wal_records); - values[i++] = Int64GetDatum(extvacuum->wal_fpi); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); /* Convert to numeric, like pg_stat_statements */ - snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->wal_bytes); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); values[i++] = DirectFunctionCall3(numeric_in, CStringGetDatum(buf), ObjectIdGetDatum(0), Int32GetDatum(-1)); - values[i++] = Float8GetDatum(extvacuum->blk_read_time); - values[i++] = Float8GetDatum(extvacuum->blk_write_time); - values[i++] = Float8GetDatum(extvacuum->delay_time); - values[i++] = Float8GetDatum(extvacuum->total_time); + values[i++] = Float8GetDatum(extvacuum->common.blk_read_time); + values[i++] = Float8GetDatum(extvacuum->common.blk_write_time); + values[i++] = Float8GetDatum(extvacuum->common.delay_time); + values[i++] = Float8GetDatum(extvacuum->common.total_time); Assert(i == PG_STAT_GET_VACUUM_TABLES_STATS_COLS); @@ -2404,8 +2407,8 @@ pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS) #define PG_STAT_GET_VACUUM_INDEX_STATS_COLS 16 Oid relid = PG_GETARG_OID(0); - PgStat_StatTabEntry *tabentry; - ExtVacReport *extvacuum; + PgStat_VacuumRelationCounts *extvacuum; + PgStat_VacuumRelationCounts *pending; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_INDEX_STATS_COLS] = {0}; @@ -2415,48 +2418,51 @@ pg_stat_get_vacuum_indexes(PG_FUNCTION_ARGS) if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); - tabentry = pgstat_fetch_stat_tabentry(relid); + pending = pgstat_fetch_stat_vacuum_tabentry(relid, MyDatabaseId); - if (tabentry == NULL) - { - InitMaterializedSRF(fcinfo, 0); - PG_RETURN_VOID(); - } - else + if (!pending) { - extvacuum = &(tabentry->vacuum_ext); + pending = pgstat_fetch_stat_vacuum_tabentry(relid, 0); + + if (!pending) + { + InitMaterializedSRF(fcinfo, 0); + PG_RETURN_VOID(); + } } + extvacuum = pending; + i = 0; values[i++] = ObjectIdGetDatum(relid); - values[i++] = Int64GetDatum(extvacuum->total_blks_read); - values[i++] = Int64GetDatum(extvacuum->total_blks_hit); - values[i++] = Int64GetDatum(extvacuum->total_blks_dirtied); - values[i++] = Int64GetDatum(extvacuum->total_blks_written); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_read); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_dirtied); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_written); - values[i++] = Int64GetDatum(extvacuum->blks_fetched - - extvacuum->blks_hit); - values[i++] = Int64GetDatum(extvacuum->blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.blks_fetched - + extvacuum->common.blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.blks_hit); values[i++] = Int64GetDatum(extvacuum->index.pages_deleted); - values[i++] = Int64GetDatum(extvacuum->tuples_deleted); + values[i++] = Int64GetDatum(extvacuum->common.tuples_deleted); - values[i++] = Int64GetDatum(extvacuum->wal_records); - values[i++] = Int64GetDatum(extvacuum->wal_fpi); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); /* Convert to numeric, like pg_stat_statements */ - snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->wal_bytes); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); values[i++] = DirectFunctionCall3(numeric_in, CStringGetDatum(buf), ObjectIdGetDatum(0), Int32GetDatum(-1)); - values[i++] = Float8GetDatum(extvacuum->blk_read_time); - values[i++] = Float8GetDatum(extvacuum->blk_write_time); - values[i++] = Float8GetDatum(extvacuum->delay_time); - values[i++] = Float8GetDatum(extvacuum->total_time); + values[i++] = Float8GetDatum(extvacuum->common.blk_read_time); + values[i++] = Float8GetDatum(extvacuum->common.blk_write_time); + values[i++] = Float8GetDatum(extvacuum->common.delay_time); + values[i++] = Float8GetDatum(extvacuum->common.total_time); Assert(i == PG_STAT_GET_VACUUM_INDEX_STATS_COLS); @@ -2470,8 +2476,8 @@ pg_stat_get_vacuum_database(PG_FUNCTION_ARGS) #define PG_STAT_GET_VACUUM_DATABASE_STATS_COLS 14 Oid dbid = PG_GETARG_OID(0); - PgStat_StatDBEntry *dbentry; - ExtVacReport *extvacuum; + PgStat_VacuumDBCounts *extvacuum; + PgStat_VacuumDBCounts *pending; TupleDesc tupdesc; Datum values[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0}; bool nulls[PG_STAT_GET_VACUUM_DATABASE_STATS_COLS] = {0}; @@ -2481,42 +2487,41 @@ pg_stat_get_vacuum_database(PG_FUNCTION_ARGS) if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); - dbentry = pgstat_fetch_stat_dbentry(dbid); + pending = pgstat_fetch_stat_vacuum_dbentry(dbid); - if (dbentry == NULL) + if (!pending) { InitMaterializedSRF(fcinfo, 0); PG_RETURN_VOID(); } - else - { - extvacuum = &(dbentry->vacuum_ext); - } + + extvacuum = pending; i = 0; values[i++] = ObjectIdGetDatum(dbid); - values[i++] = Int64GetDatum(extvacuum->total_blks_read); - values[i++] = Int64GetDatum(extvacuum->total_blks_hit); - values[i++] = Int64GetDatum(extvacuum->total_blks_dirtied); - values[i++] = Int64GetDatum(extvacuum->total_blks_written); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_read); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_hit); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_dirtied); + values[i++] = Int64GetDatum(extvacuum->common.total_blks_written); - values[i++] = Int64GetDatum(extvacuum->wal_records); - values[i++] = Int64GetDatum(extvacuum->wal_fpi); + values[i++] = Int64GetDatum(extvacuum->common.wal_records); + values[i++] = Int64GetDatum(extvacuum->common.wal_fpi); /* Convert to numeric, like pg_stat_statements */ - snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->wal_bytes); + snprintf(buf, sizeof buf, UINT64_FORMAT, extvacuum->common.wal_bytes); values[i++] = DirectFunctionCall3(numeric_in, CStringGetDatum(buf), ObjectIdGetDatum(0), Int32GetDatum(-1)); - values[i++] = Float8GetDatum(extvacuum->blk_read_time); - values[i++] = Float8GetDatum(extvacuum->blk_write_time); - values[i++] = Float8GetDatum(extvacuum->delay_time); - values[i++] = Float8GetDatum(extvacuum->total_time); - values[i++] = Int32GetDatum(extvacuum->wraparound_failsafe_count); + values[i++] = Float8GetDatum(extvacuum->common.blk_read_time); + values[i++] = Float8GetDatum(extvacuum->common.blk_write_time); + values[i++] = Float8GetDatum(extvacuum->common.delay_time); + values[i++] = Float8GetDatum(extvacuum->common.total_time); + values[i++] = Int32GetDatum(extvacuum->common.wraparound_failsafe_count); + values[i++] = Int32GetDatum(extvacuum->errors); Assert(i == PG_STAT_GET_VACUUM_DATABASE_STATS_COLS); diff --git a/src/backend/utils/misc/guc_parameters.dat b/src/backend/utils/misc/guc_parameters.dat index 3b9d8349078..631df3a57c3 100644 --- a/src/backend/utils/misc/guc_parameters.dat +++ b/src/backend/utils/misc/guc_parameters.dat @@ -3084,6 +3084,12 @@ boot_val => 'false', }, +{ name => 'track_vacuum_statistics', type => 'bool', context => 'PGC_SUSET', group => 'STATS_CUMULATIVE', + short_desc => 'Collects vacuum statistics for vacuum activity.', + variable => 'pgstat_track_vacuum_statistics', + boot_val => 'false', +}, + { name => 'track_wal_io_timing', type => 'bool', context => 'PGC_SUSET', group => 'STATS_CUMULATIVE', short_desc => 'Collects timing statistics for WAL I/O activity.', variable => 'track_wal_io_timing', diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index b48ace6084b..6e85b08aa89 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -437,5 +437,5 @@ extern double anl_get_next_S(double t, int n, double *stateptr); extern void extvac_stats_start_idx(Relation rel, IndexBulkDeleteResult *stats, LVExtStatCountersIdx * counters); extern void extvac_stats_end_idx(Relation rel, IndexBulkDeleteResult *stats, - LVExtStatCountersIdx * counters, ExtVacReport * report); + LVExtStatCountersIdx * counters, PgStat_VacuumRelationCounts * report); #endif /* VACUUM_H */ diff --git a/src/include/pgstat.h b/src/include/pgstat.h index f3bdc1c38df..61d488f1bf8 100644 --- a/src/include/pgstat.h +++ b/src/include/pgstat.h @@ -119,54 +119,100 @@ typedef enum ExtVacReportType { PGSTAT_EXTVAC_INVALID = 0, PGSTAT_EXTVAC_TABLE = 1, - PGSTAT_EXTVAC_INDEX = 2 -} ExtVacReportType; + PGSTAT_EXTVAC_INDEX = 2, + PGSTAT_EXTVAC_DB = 3, +} ExtVacReportType; /* ---------- + * PgStat_TableCounts The actual per-table counts kept by a backend * - * ExtVacReport + * This struct should contain only actual event counters, because we make use + * of pg_memory_is_all_zeros() to detect whether there are any stats updates + * to apply. * - * Additional statistics of vacuum processing over a relation. - * pages_removed is the amount by which the physically shrank, - * if any (ie the change in its total size on disk) - * pages_deleted refer to free space within the index file + * It is a component of PgStat_TableStatus (within-backend state). + * + * Note: for a table, tuples_returned is the number of tuples successfully + * fetched by heap_getnext, while tuples_fetched is the number of tuples + * successfully fetched by heap_fetch under the control of bitmap indexscans. + * For an index, tuples_returned is the number of index entries returned by + * the index AM, while tuples_fetched is the number of tuples successfully + * fetched by heap_fetch under the control of simple indexscans for this index. + * + * tuples_inserted/updated/deleted/hot_updated/newpage_updated count attempted + * actions, regardless of whether the transaction committed. delta_live_tuples, + * delta_dead_tuples, and changed_tuples are set depending on commit or abort. + * Note that delta_live_tuples and delta_dead_tuples can be negative! * ---------- */ -typedef struct ExtVacReport +typedef struct PgStat_TableCounts { - /* - * number of blocks missed, hit, dirtied and written during a vacuum of - * specific relation - */ + PgStat_Counter numscans; + + PgStat_Counter tuples_returned; + PgStat_Counter tuples_fetched; + + PgStat_Counter tuples_inserted; + PgStat_Counter tuples_updated; + PgStat_Counter tuples_deleted; + PgStat_Counter tuples_hot_updated; + PgStat_Counter tuples_newpage_updated; + bool truncdropped; + + PgStat_Counter delta_live_tuples; + PgStat_Counter delta_dead_tuples; + PgStat_Counter changed_tuples; + + PgStat_Counter blocks_fetched; + PgStat_Counter blocks_hit; + + PgStat_Counter rev_all_visible_pages; + PgStat_Counter rev_all_frozen_pages; +} PgStat_TableCounts; + +typedef struct PgStat_CommonCounts +{ + /* blocks */ int64 total_blks_read; int64 total_blks_hit; int64 total_blks_dirtied; int64 total_blks_written; - /* - * blocks missed and hit for just the heap during a vacuum of specific - * relation - */ + /* heap blocks */ int64 blks_fetched; int64 blks_hit; - /* Vacuum WAL usage stats */ - int64 wal_records; /* wal usage: number of WAL records */ - int64 wal_fpi; /* wal usage: number of WAL full page images - * produced */ - uint64 wal_bytes; /* wal usage: size of WAL records produced */ + /* WAL */ + int64 wal_records; + int64 wal_fpi; + uint64 wal_bytes; - /* Time stats. */ - double blk_read_time; /* time spent reading pages, in msec */ - double blk_write_time; /* time spent writing pages, in msec */ - double delay_time; /* how long vacuum slept in vacuum delay - * point, in msec */ - double total_time; /* total time of a vacuum operation, in msec */ + /* Time */ + double blk_read_time; + double blk_write_time; + double delay_time; + double total_time; - int64 tuples_deleted; /* tuples deleted by vacuum */ + /* tuples */ + int64 tuples_deleted; - int32 wraparound_failsafe_count; /* the number of times to prevent - * wraparound problem */ + /* failsafe */ + int32 wraparound_failsafe_count; +} PgStat_CommonCounts; + +/* ---------- + * + * PgStat_VacuumRelationCounts + * + * Additional statistics of vacuum processing over a relation. + * pages_removed is the amount by which the physically shrank, + * if any (ie the change in its total size on disk) + * pages_deleted refer to free space within the index file + * ---------- + */ +typedef struct PgStat_VacuumRelationCounts +{ + PgStat_CommonCounts common; ExtVacReportType type; /* heap, index, etc. */ @@ -185,6 +231,13 @@ typedef struct ExtVacReport { struct { + int64 tuples_frozen; /* tuples frozen up by vacuum */ + int64 recently_dead_tuples; /* deleted tuples that are + * still visible to some + * transaction */ + int64 missed_dead_tuples; /* tuples not pruned by vacuum due + * to failure to get a cleanup + * lock */ int64 pages_scanned; /* heap pages examined (not skipped by * VM) */ int64 pages_removed; /* heap pages removed by vacuum @@ -192,10 +245,6 @@ typedef struct ExtVacReport int64 pages_frozen; /* pages marked in VM as frozen */ int64 pages_all_visible; /* pages marked in VM as * all-visible */ - int64 tuples_frozen; /* tuples frozen up by vacuum */ - int64 recently_dead_tuples; /* deleted tuples that are - * still visible to some - * transaction */ int64 vm_new_frozen_pages; /* pages marked in VM as * frozen */ int64 vm_new_visible_pages; /* pages marked in VM as @@ -203,9 +252,6 @@ typedef struct ExtVacReport int64 vm_new_visible_frozen_pages; /* pages marked in VM as * all-visible and * frozen */ - int64 missed_dead_tuples; /* tuples not pruned by vacuum due - * to failure to get a cleanup - * lock */ int64 missed_dead_pages; /* pages with missed dead tuples */ int64 index_vacuum_count; /* number of index vacuumings */ } table; @@ -214,60 +260,21 @@ typedef struct ExtVacReport int64 pages_deleted; /* number of pages deleted by vacuum */ } index; } /* per_type_stats */ ; -} ExtVacReport; +} PgStat_VacuumRelationCounts; -/* ---------- - * PgStat_TableCounts The actual per-table counts kept by a backend - * - * This struct should contain only actual event counters, because we make use - * of pg_memory_is_all_zeros() to detect whether there are any stats updates - * to apply. - * - * It is a component of PgStat_TableStatus (within-backend state). - * - * Note: for a table, tuples_returned is the number of tuples successfully - * fetched by heap_getnext, while tuples_fetched is the number of tuples - * successfully fetched by heap_fetch under the control of bitmap indexscans. - * For an index, tuples_returned is the number of index entries returned by - * the index AM, while tuples_fetched is the number of tuples successfully - * fetched by heap_fetch under the control of simple indexscans for this index. - * - * tuples_inserted/updated/deleted/hot_updated/newpage_updated count attempted - * actions, regardless of whether the transaction committed. delta_live_tuples, - * delta_dead_tuples, and changed_tuples are set depending on commit or abort. - * Note that delta_live_tuples and delta_dead_tuples can be negative! - * ---------- - */ -typedef struct PgStat_TableCounts +typedef struct PgStat_VacuumRelationStatus { - PgStat_Counter numscans; - - PgStat_Counter tuples_returned; - PgStat_Counter tuples_fetched; - - PgStat_Counter tuples_inserted; - PgStat_Counter tuples_updated; - PgStat_Counter tuples_deleted; - PgStat_Counter tuples_hot_updated; - PgStat_Counter tuples_newpage_updated; - bool truncdropped; - - PgStat_Counter delta_live_tuples; - PgStat_Counter delta_dead_tuples; - PgStat_Counter changed_tuples; - - PgStat_Counter blocks_fetched; - PgStat_Counter blocks_hit; - - PgStat_Counter rev_all_visible_pages; - PgStat_Counter rev_all_frozen_pages; + Oid id; /* table's OID */ + bool shared; /* is it a shared catalog? */ + PgStat_VacuumRelationCounts counts; /* event counts to be sent */ +} PgStat_VacuumRelationStatus; - /* - * Additional cumulative stat on vacuum operations. Use an expensive - * structure as an abstraction for different types of relations. - */ - ExtVacReport vacuum_ext; -} PgStat_TableCounts; +typedef struct PgStat_VacuumDBCounts +{ + Oid dbjid; + PgStat_CommonCounts common; + int32 errors; +} PgStat_VacuumDBCounts; /* ---------- * PgStat_TableStatus Per-table status within a backend @@ -293,6 +300,12 @@ typedef struct PgStat_TableStatus Relation relation; /* rel that is using this entry */ } PgStat_TableStatus; +typedef struct PgStat_RelationVacuumPending +{ + Oid id; /* table's OID */ + PgStat_VacuumRelationCounts counts; /* event counts to be sent */ +} PgStat_RelationVacuumPending; + /* ---------- * PgStat_TableXactStatus Per-table, per-subtransaction status * ---------- @@ -489,8 +502,6 @@ typedef struct PgStat_StatDBEntry PgStat_Counter parallel_workers_launched; TimestampTz stat_reset_timestamp; - - ExtVacReport vacuum_ext; /* extended vacuum statistics */ } PgStat_StatDBEntry; typedef struct PgStat_StatFuncEntry @@ -578,8 +589,6 @@ typedef struct PgStat_StatTabEntry PgStat_Counter rev_all_visible_pages; PgStat_Counter rev_all_frozen_pages; - - ExtVacReport vacuum_ext; } PgStat_StatTabEntry; /* ------ @@ -788,7 +797,7 @@ extern void pgstat_unlink_relation(Relation rel); extern void pgstat_report_vacuum(Relation rel, PgStat_Counter livetuples, PgStat_Counter deadtuples, - TimestampTz starttime, ExtVacReport * params); + TimestampTz starttime); extern void pgstat_report_analyze(Relation rel, PgStat_Counter livetuples, PgStat_Counter deadtuples, bool resetcounter, TimestampTz starttime); @@ -924,6 +933,16 @@ extern int pgstat_get_transactional_drops(bool isCommit, struct xl_xact_stats_it extern void pgstat_execute_transactional_drops(int ndrops, struct xl_xact_stats_item *items, bool is_redo); +extern void pgstat_drop_vacuum_database(Oid databaseid); +extern void pgstat_vacuum_relation_delete_pending_cb(Oid relid); +extern void + pgstat_report_vacuum_extstats(Oid tableoid, bool shared, + PgStat_VacuumRelationCounts * params); +extern PgStat_RelationVacuumPending * find_vacuum_relation_entry(Oid relid); +extern PgStat_VacuumDBCounts * pgstat_prep_vacuum_database_pending(Oid dboid); +extern PgStat_VacuumRelationCounts * pgstat_fetch_stat_vacuum_tabentry(Oid relid, Oid dbid); +PgStat_VacuumDBCounts *pgstat_fetch_stat_vacuum_dbentry(Oid dbid); + /* * Functions in pgstat_wal.c */ @@ -940,7 +959,8 @@ extern PgStat_WalStats *pgstat_fetch_stat_wal(void); extern PGDLLIMPORT bool pgstat_track_counts; extern PGDLLIMPORT int pgstat_track_functions; extern PGDLLIMPORT int pgstat_fetch_consistency; - +extern PGDLLIMPORT bool pgstat_track_vacuum_statistics; +extern PGDLLIMPORT bool pgstat_track_vacuum_statistics_for_relations; /* * Variables in pgstat_bgwriter.c diff --git a/src/include/utils/pgstat_internal.h b/src/include/utils/pgstat_internal.h index 7dffab8dbdd..4abe70cb54e 100644 --- a/src/include/utils/pgstat_internal.h +++ b/src/include/utils/pgstat_internal.h @@ -500,6 +500,18 @@ typedef struct PgStatShared_Relation PgStat_StatTabEntry stats; } PgStatShared_Relation; +typedef struct PgStatShared_VacuumDB +{ + PgStatShared_Common header; + PgStat_VacuumDBCounts stats; +} PgStatShared_VacuumDB; + +typedef struct PgStatShared_VacuumRelation +{ + PgStatShared_Common header; + PgStat_VacuumRelationCounts stats; +} PgStatShared_VacuumRelation; + typedef struct PgStatShared_Function { PgStatShared_Common header; @@ -678,6 +690,9 @@ extern PgStat_EntryRef *pgstat_fetch_pending_entry(PgStat_Kind kind, extern void *pgstat_fetch_entry(PgStat_Kind kind, Oid dboid, uint64 objid); extern void pgstat_snapshot_fixed(PgStat_Kind kind); +bool pgstat_vacuum_db_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); +extern bool pgstat_vacuum_relation_flush_cb(PgStat_EntryRef *entry_ref, bool nowait); + /* * Functions in pgstat_archiver.c diff --git a/src/include/utils/pgstat_kind.h b/src/include/utils/pgstat_kind.h index eb5f0b3ae6d..52e884fbf8b 100644 --- a/src/include/utils/pgstat_kind.h +++ b/src/include/utils/pgstat_kind.h @@ -38,9 +38,11 @@ #define PGSTAT_KIND_IO 10 #define PGSTAT_KIND_SLRU 11 #define PGSTAT_KIND_WAL 12 +#define PGSTAT_KIND_VACUUM_DB 13 +#define PGSTAT_KIND_VACUUM_RELATION 14 #define PGSTAT_KIND_BUILTIN_MIN PGSTAT_KIND_DATABASE -#define PGSTAT_KIND_BUILTIN_MAX PGSTAT_KIND_WAL +#define PGSTAT_KIND_BUILTIN_MAX PGSTAT_KIND_VACUUM_RELATION #define PGSTAT_KIND_BUILTIN_SIZE (PGSTAT_KIND_BUILTIN_MAX + 1) /* Custom stats kinds */ diff --git a/src/test/recovery/t/050_vacuum_extending_basic_test.pl b/src/test/recovery/t/050_vacuum_extending_basic_test.pl index bd3cb544e30..e2fd541fd89 100644 --- a/src/test/recovery/t/050_vacuum_extending_basic_test.pl +++ b/src/test/recovery/t/050_vacuum_extending_basic_test.pl @@ -28,6 +28,7 @@ $node->init; # Configure the server logging level for the test $node->append_conf('postgresql.conf', q{ log_min_messages = notice + track_vacuum_statistics = on }); my $stderr; @@ -64,8 +65,9 @@ $node->safe_psql($dbname, q{ $node->safe_psql( $dbname, - "CREATE TABLE vestat (x int PRIMARY KEY) + "CREATE TABLE vestat (x int) WITH (autovacuum_enabled = off, fillfactor = 10); + create index vestat_pkey on vestat (x); INSERT INTO vestat SELECT x FROM generate_series(1, $size_tab) AS g(x); ANALYZE vestat;" ); @@ -115,7 +117,7 @@ sub wait_for_vacuum_stats { AND (SELECT (tuples_deleted > $idx_tuples_deleted AND wal_records > $idx_wal_records) FROM pg_stat_vacuum_indexes - WHERE relname = 'vestat_pkey');" + WHERE indexrelname = 'vestat_pkey');" ); return 1 if ($result_query eq 't'); @@ -183,7 +185,7 @@ sub fetch_vacuum_stats { $dbname, "SELECT tuples_deleted, pages_deleted, wal_records, wal_bytes, wal_fpi FROM pg_stat_vacuum_indexes - WHERE relname = 'vestat_pkey';" + WHERE indexrelname = 'vestat_pkey';" ); $index_base_statistics =~ s/\s*\|\s*/ /g; # transform " | " into space @@ -321,7 +323,7 @@ sub fetch_error_base_idx_vacuum_statistics { $dbname, "SELECT tuples_deleted, pages_deleted FROM pg_stat_vacuum_indexes - WHERE relname = 'vestat_pkey';" + WHERE indexrelname = 'vestat_pkey';" ); $base_statistics =~ s/\s*\|\s*/ /g; # transform " | " in space my ($cur_tuples_deleted, $cur_pages_deleted) = split /\s+/, $base_statistics; @@ -343,7 +345,7 @@ sub fetch_error_wal_idx_vacuum_statistics { $dbname, "SELECT wal_records, wal_bytes, wal_fpi FROM pg_stat_vacuum_indexes - WHERE relname = 'vestat_pkey';" + WHERE indexrelname = 'vestat_pkey';" ); $wal_raw =~ s/\s*\|\s*/ /g; # transform " | " in space @@ -707,7 +709,7 @@ $base_stats = $node->safe_psql( 'postgres', "SELECT count(*) = 0 FROM pg_stat_vacuum_indexes - WHERE relname = 'vestat_pkey';" + WHERE indexrelname = 'vestat_pkey';" ); ok($base_stats eq 't', 'check the printing index vacuum extended statistics from another database are not available'); @@ -742,6 +744,9 @@ $reloid = $node->safe_psql( } ); +# Run VACUUM on shared table to ensure stats entry is created +$node->safe_psql($dbname, "VACUUM pg_shdepend;"); + # Check if we can get vacuum statistics for cluster relations (dbid = 0) $base_stats = $node->safe_psql( $dbname, @@ -760,6 +765,10 @@ my $indoid = $node->safe_psql( } ); +# Run VACUUM on shared index to ensure stats entry is created +# Note: VACUUM on the table will also vacuum its indexes +$node->safe_psql($dbname, "VACUUM pg_shdepend;"); + $base_stats = $node->safe_psql( $dbname, qq{ diff --git a/src/test/recovery/t/051_vacuum_extending_freeze_test.pl b/src/test/recovery/t/051_vacuum_extending_freeze_test.pl index 7528f20098b..2a1c506a22f 100644 --- a/src/test/recovery/t/051_vacuum_extending_freeze_test.pl +++ b/src/test/recovery/t/051_vacuum_extending_freeze_test.pl @@ -37,6 +37,7 @@ $node->append_conf('postgresql.conf', q{ vacuum_max_eager_freeze_failure_rate = 1.0 vacuum_failsafe_age = 0 vacuum_multixact_failsafe_age = 0 + track_vacuum_statistics = on }); $node->start(); diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index b627c85e332..4e8b8b8a2b1 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -2330,77 +2330,81 @@ pg_stat_user_tables| SELECT relid, rev_all_visible_pages FROM pg_stat_all_tables WHERE ((schemaname <> ALL (ARRAY['pg_catalog'::name, 'information_schema'::name])) AND (schemaname !~ '^pg_toast'::text)); -pg_stat_vacuum_database| SELECT db.oid AS dboid, - db.datname AS dbname, - stats.db_blks_read, - stats.db_blks_hit, - stats.total_blks_dirtied, - stats.total_blks_written, - stats.wal_records, - stats.wal_fpi, - stats.wal_bytes, - stats.blk_read_time, - stats.blk_write_time, - stats.delay_time, - stats.total_time, - stats.wraparound_failsafe, - stats.errors - FROM pg_database db, - LATERAL pg_stat_get_vacuum_database(db.oid) stats(dboid, db_blks_read, db_blks_hit, total_blks_dirtied, total_blks_written, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time, wraparound_failsafe, errors); -pg_stat_vacuum_indexes| SELECT rel.oid AS relid, - ns.nspname AS schemaname, - rel.relname, - stats.total_blks_read, - stats.total_blks_hit, - stats.total_blks_dirtied, - stats.total_blks_written, - stats.rel_blks_read, - stats.rel_blks_hit, - stats.pages_deleted, - stats.tuples_deleted, - stats.wal_records, - stats.wal_fpi, - stats.wal_bytes, - stats.blk_read_time, - stats.blk_write_time, - stats.delay_time, - stats.total_time - FROM (pg_class rel - JOIN pg_namespace ns ON ((ns.oid = rel.relnamespace))), - LATERAL pg_stat_get_vacuum_indexes(rel.oid) stats(relid, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, pages_deleted, tuples_deleted, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time) - WHERE (rel.relkind = 'i'::"char"); -pg_stat_vacuum_tables| SELECT ns.nspname AS schemaname, - rel.relname, - stats.relid, - stats.total_blks_read, - stats.total_blks_hit, - stats.total_blks_dirtied, - stats.total_blks_written, - stats.rel_blks_read, - stats.rel_blks_hit, - stats.pages_scanned, - stats.pages_removed, - stats.vm_new_frozen_pages, - stats.vm_new_visible_pages, - stats.vm_new_visible_frozen_pages, - stats.missed_dead_pages, - stats.tuples_deleted, - stats.tuples_frozen, - stats.recently_dead_tuples, - stats.missed_dead_tuples, - stats.wraparound_failsafe, - stats.index_vacuum_count, - stats.wal_records, - stats.wal_fpi, - stats.wal_bytes, - stats.blk_read_time, - stats.blk_write_time, - stats.delay_time, - stats.total_time - FROM (pg_class rel - JOIN pg_namespace ns ON ((ns.oid = rel.relnamespace))), - LATERAL pg_stat_get_vacuum_tables(rel.oid) stats(relid, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, pages_scanned, pages_removed, vm_new_frozen_pages, vm_new_visible_pages, vm_new_visible_frozen_pages, missed_dead_pages, tuples_deleted, tuples_frozen, recently_dead_tuples, missed_dead_tuples, wraparound_failsafe, index_vacuum_count, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time) - WHERE (rel.relkind = 'r'::"char"); +pg_stat_vacuum_database| SELECT d.oid AS dboid, + d.datname AS dbname, + s.db_blks_read, + s.db_blks_hit, + s.total_blks_dirtied, + s.total_blks_written, + s.wal_records, + s.wal_fpi, + s.wal_bytes, + s.blk_read_time, + s.blk_write_time, + s.delay_time, + s.total_time, + s.wraparound_failsafe, + s.errors + FROM pg_database d, + LATERAL pg_stat_get_vacuum_database(d.oid) s(dboid, db_blks_read, db_blks_hit, total_blks_dirtied, total_blks_written, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time, wraparound_failsafe, errors); +pg_stat_vacuum_indexes| SELECT c.oid AS relid, + i.oid AS indexrelid, + n.nspname AS schemaname, + c.relname, + i.relname AS indexrelname, + s.total_blks_read, + s.total_blks_hit, + s.total_blks_dirtied, + s.total_blks_written, + s.rel_blks_read, + s.rel_blks_hit, + s.pages_deleted, + s.tuples_deleted, + s.wal_records, + s.wal_fpi, + s.wal_bytes, + s.blk_read_time, + s.blk_write_time, + s.delay_time, + s.total_time + FROM (((pg_class c + JOIN pg_index x ON ((c.oid = x.indrelid))) + JOIN pg_class i ON ((i.oid = x.indexrelid))) + LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))), + LATERAL pg_stat_get_vacuum_indexes(i.oid) s(relid, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, pages_deleted, tuples_deleted, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time) + WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])); +pg_stat_vacuum_tables| SELECT n.nspname AS schemaname, + c.relname, + s.relid, + s.total_blks_read, + s.total_blks_hit, + s.total_blks_dirtied, + s.total_blks_written, + s.rel_blks_read, + s.rel_blks_hit, + s.pages_scanned, + s.pages_removed, + s.vm_new_frozen_pages, + s.vm_new_visible_pages, + s.vm_new_visible_frozen_pages, + s.missed_dead_pages, + s.tuples_deleted, + s.tuples_frozen, + s.recently_dead_tuples, + s.missed_dead_tuples, + s.wraparound_failsafe, + s.index_vacuum_count, + s.wal_records, + s.wal_fpi, + s.wal_bytes, + s.blk_read_time, + s.blk_write_time, + s.delay_time, + s.total_time + FROM (pg_class c + JOIN pg_namespace n ON ((n.oid = c.relnamespace))), + LATERAL pg_stat_get_vacuum_tables(c.oid) s(relid, total_blks_read, total_blks_hit, total_blks_dirtied, total_blks_written, rel_blks_read, rel_blks_hit, pages_scanned, pages_removed, vm_new_frozen_pages, vm_new_visible_pages, vm_new_visible_frozen_pages, missed_dead_pages, tuples_deleted, tuples_frozen, recently_dead_tuples, missed_dead_tuples, wraparound_failsafe, index_vacuum_count, wal_records, wal_fpi, wal_bytes, blk_read_time, blk_write_time, delay_time, total_time) + WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char", 'm'::"char"])); pg_stat_wal| SELECT wal_records, wal_fpi, wal_bytes, -- 2.39.5 (Apple Git-154)