diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 8341879d89b..ef9186ba7ca 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -315,6 +315,10 @@ typedef struct LVRelStats TransactionId latestRemovedXid; bool lock_waiter_detected; + /* Statistics about indexes */ + IndexBulkDeleteResult **indstats; + int nindexes; + /* Used for error callback */ char *indname; BlockNumber blkno; /* used only for heap operations */ @@ -348,7 +352,6 @@ static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats); static bool lazy_check_needs_freeze(Buffer buf, bool *hastup, LVRelStats *vacrelstats); static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel, - IndexBulkDeleteResult **stats, LVRelStats *vacrelstats, LVParallelState *lps, int nindexes); static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats, @@ -371,21 +374,18 @@ static int vac_cmp_itemptr(const void *left, const void *right); static bool heap_page_is_all_visible(Relation rel, Buffer buf, LVRelStats *vacrelstats, TransactionId *visibility_cutoff_xid, bool *all_frozen); -static void lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes); -static void parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats, - LVShared *lvshared, LVDeadTuples *dead_tuples, - int nindexes, LVRelStats *vacrelstats); -static void vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes); +static void lazy_parallel_vacuum_indexes(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes); +static void parallel_vacuum_index(Relation *Irel, LVShared *lvshared, + LVDeadTuples *dead_tuples, int nindexes, + LVRelStats *vacrelstats); +static void vacuum_indexes_leader(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes); static void vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats, LVShared *lvshared, LVSharedIndStats *shared_indstats, LVDeadTuples *dead_tuples, LVRelStats *vacrelstats); -static void lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes); +static void lazy_cleanup_all_indexes(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes); static long compute_max_dead_tuples(BlockNumber relblocks, bool hasindex); static int compute_parallel_vacuum_workers(Relation *Irel, int nindexes, int nrequested, bool *can_parallel_vacuum); @@ -433,6 +433,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, write_rate; bool aggressive; /* should we scan all unfrozen pages? */ bool scanned_all_unfrozen; /* actually scanned all such pages? */ + char **indnames = NULL; TransactionId xidFullScanLimit; MultiXactId mxactFullScanLimit; BlockNumber new_rel_pages; @@ -512,6 +513,20 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, vacrelstats->useindex = (nindexes > 0 && params->index_cleanup == VACOPT_TERNARY_ENABLED); + vacrelstats->indstats = (IndexBulkDeleteResult **) + palloc0(nindexes * sizeof(IndexBulkDeleteResult *)); + vacrelstats->nindexes = nindexes; + + /* Save index names iff autovacuum logging requires it */ + if (IsAutoVacuumWorkerProcess() && + params->log_min_duration >= 0 && + vacrelstats->nindexes > 0) + { + indnames = palloc(sizeof(char *) * vacrelstats->nindexes); + for (int i = 0; i < vacrelstats->nindexes; i++) + indnames[i] = pstrdup(RelationGetRelationName(Irel[i])); + } + /* * Setup error traceback support for ereport(). The idea is to set up an * error context callback to display additional information on any error @@ -680,6 +695,21 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, (long long) VacuumPageHit, (long long) VacuumPageMiss, (long long) VacuumPageDirty); + for (int i = 0; i < vacrelstats->nindexes; i++) + { + IndexBulkDeleteResult *stats = vacrelstats->indstats[i]; + + if (!stats) + continue; + + appendStringInfo(&buf, + _("index \"%s\": pages: %u remain, %u newly deleted, %u currently deleted, %u reusable\n"), + indnames[i], + stats->num_pages, + stats->pages_newly_deleted, + stats->pages_deleted, + stats->pages_free); + } appendStringInfo(&buf, _("avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n"), read_rate, write_rate); if (track_io_timing) @@ -705,6 +735,16 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params, pfree(buf.data); } } + + /* Cleanup index statistics and index names */ + for (int i = 0; i < vacrelstats->nindexes; i++) + { + if (vacrelstats->indstats[i]) + pfree(vacrelstats->indstats[i]); + + if (indnames && indnames[i]) + pfree(indnames[i]); + } } /* @@ -787,7 +827,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, tups_vacuumed, /* tuples cleaned up by current vacuum */ nkeep, /* dead-but-not-removable tuples */ nunused; /* # existing unused line pointers */ - IndexBulkDeleteResult **indstats; int i; PGRUsage ru0; Buffer vmbuffer = InvalidBuffer; @@ -820,9 +859,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, next_fsm_block_to_vacuum = (BlockNumber) 0; num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0; - indstats = (IndexBulkDeleteResult **) - palloc0(nindexes * sizeof(IndexBulkDeleteResult *)); - nblocks = RelationGetNumberOfBlocks(onerel); vacrelstats->rel_pages = nblocks; vacrelstats->scanned_pages = 0; @@ -1070,8 +1106,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, } /* Work on all the indexes, then the heap */ - lazy_vacuum_all_indexes(onerel, Irel, indstats, - vacrelstats, lps, nindexes); + lazy_vacuum_all_indexes(onerel, Irel, vacrelstats, lps, nindexes); /* Remove tuples from heap */ lazy_vacuum_heap(onerel, vacrelstats); @@ -1728,8 +1763,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, if (dead_tuples->num_tuples > 0) { /* Work on all the indexes, and then the heap */ - lazy_vacuum_all_indexes(onerel, Irel, indstats, vacrelstats, - lps, nindexes); + lazy_vacuum_all_indexes(onerel, Irel, vacrelstats, lps, nindexes); /* Remove tuples from heap */ lazy_vacuum_heap(onerel, vacrelstats); @@ -1747,18 +1781,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, /* Do post-vacuum cleanup */ if (vacrelstats->useindex) - lazy_cleanup_all_indexes(Irel, indstats, vacrelstats, lps, nindexes); + lazy_cleanup_all_indexes(Irel, vacrelstats, lps, nindexes); /* * End parallel mode before updating index statistics as we cannot write * during parallel mode. */ if (ParallelVacuumIsActive(lps)) - end_parallel_vacuum(indstats, lps, nindexes); + end_parallel_vacuum(vacrelstats->indstats, lps, nindexes); /* Update index statistics */ if (vacrelstats->useindex) - update_index_statistics(Irel, indstats, nindexes); + update_index_statistics(Irel, vacrelstats->indstats, nindexes); /* If no indexes, make log report that lazy_vacuum_heap would've made */ if (vacuumed_pages) @@ -1803,7 +1837,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats, */ static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel, - IndexBulkDeleteResult **stats, LVRelStats *vacrelstats, LVParallelState *lps, int nindexes) { @@ -1831,14 +1864,15 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel, lps->lvshared->reltuples = vacrelstats->old_live_tuples; lps->lvshared->estimated_count = true; - lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes); + lazy_parallel_vacuum_indexes(Irel, vacrelstats, lps, nindexes); } else { int idx; for (idx = 0; idx < nindexes; idx++) - lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats->dead_tuples, + lazy_vacuum_index(Irel[idx], &(vacrelstats->indstats[idx]), + vacrelstats->dead_tuples, vacrelstats->old_live_tuples, vacrelstats); } @@ -2109,9 +2143,8 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup, LVRelStats *vacrelstats) * cleanup. */ static void -lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes) +lazy_parallel_vacuum_indexes(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes) { int nworkers; @@ -2199,14 +2232,14 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats, } /* Process the indexes that can be processed by only leader process */ - vacuum_indexes_leader(Irel, stats, vacrelstats, lps, nindexes); + vacuum_indexes_leader(Irel, vacrelstats, lps, nindexes); /* * Join as a parallel worker. The leader process alone processes all the * indexes in the case where no workers are launched. */ - parallel_vacuum_index(Irel, stats, lps->lvshared, - vacrelstats->dead_tuples, nindexes, vacrelstats); + parallel_vacuum_index(Irel, lps->lvshared, vacrelstats->dead_tuples, + nindexes, vacrelstats); /* * Next, accumulate buffer and WAL usage. (This must wait for the workers @@ -2239,9 +2272,9 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats, * vacuum worker processes to process the indexes in parallel. */ static void -parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats, - LVShared *lvshared, LVDeadTuples *dead_tuples, - int nindexes, LVRelStats *vacrelstats) +parallel_vacuum_index(Relation *Irel, LVShared *lvshared, + LVDeadTuples *dead_tuples, int nindexes, + LVRelStats *vacrelstats) { /* * Increment the active worker count if we are able to launch any worker. @@ -2274,8 +2307,8 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats, continue; /* Do vacuum or cleanup of the index */ - vacuum_one_index(Irel[idx], &(stats[idx]), lvshared, shared_indstats, - dead_tuples, vacrelstats); + vacuum_one_index(Irel[idx], &(vacrelstats->indstats[idx]), lvshared, + shared_indstats, dead_tuples, vacrelstats); } /* @@ -2291,9 +2324,8 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats, * because these indexes don't support parallel operation at that phase. */ static void -vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes) +vacuum_indexes_leader(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes) { int i; @@ -2314,7 +2346,7 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats, /* Process the indexes skipped by parallel workers */ if (shared_indstats == NULL || skip_parallel_vacuum_index(Irel[i], lps->lvshared)) - vacuum_one_index(Irel[i], &(stats[i]), lps->lvshared, + vacuum_one_index(Irel[i], &(vacrelstats->indstats[i]), lps->lvshared, shared_indstats, vacrelstats->dead_tuples, vacrelstats); } @@ -2394,9 +2426,8 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats, * parallel vacuum. */ static void -lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats, - LVRelStats *vacrelstats, LVParallelState *lps, - int nindexes) +lazy_cleanup_all_indexes(Relation *Irel, LVRelStats *vacrelstats, + LVParallelState *lps, int nindexes) { int idx; @@ -2427,12 +2458,12 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats, lps->lvshared->estimated_count = (vacrelstats->tupcount_pages < vacrelstats->rel_pages); - lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes); + lazy_parallel_vacuum_indexes(Irel, vacrelstats, lps, nindexes); } else { for (idx = 0; idx < nindexes; idx++) - lazy_cleanup_index(Irel[idx], &stats[idx], + lazy_cleanup_index(Irel[idx], &(vacrelstats->indstats[idx]), vacrelstats->new_rel_tuples, vacrelstats->tupcount_pages < vacrelstats->rel_pages, vacrelstats); @@ -3243,7 +3274,6 @@ update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats, InvalidTransactionId, InvalidMultiXactId, false); - pfree(stats[i]); } } @@ -3550,7 +3580,6 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) WalUsage *wal_usage; int nindexes; char *sharedquery; - IndexBulkDeleteResult **stats; LVRelStats vacrelstats; ErrorContextCallback errcallback; @@ -3597,7 +3626,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) VacuumSharedCostBalance = &(lvshared->cost_balance); VacuumActiveNWorkers = &(lvshared->active_nworkers); - stats = (IndexBulkDeleteResult **) + vacrelstats.indstats = (IndexBulkDeleteResult **) palloc0(nindexes * sizeof(IndexBulkDeleteResult *)); if (lvshared->maintenance_work_mem_worker > 0) @@ -3622,7 +3651,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) InstrStartParallelQuery(); /* Process indexes to perform vacuum/cleanup */ - parallel_vacuum_index(indrels, stats, lvshared, dead_tuples, nindexes, + parallel_vacuum_index(indrels, lvshared, dead_tuples, nindexes, &vacrelstats); /* Report buffer/WAL usage during parallel execution */ @@ -3636,7 +3665,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc) vac_close_indexes(nindexes, indrels, RowExclusiveLock); table_close(onerel, ShareUpdateExclusiveLock); - pfree(stats); + pfree(vacrelstats.indstats); } /*