Skip to content

Commit 5aed6a1

Browse files
committed
Add per-index stats information in verbose logs of autovacuum
Once a relation's autovacuum is completed, the logs include more information about this relation state if the threshold of log_autovacuum_min_duration (or its relation option) is reached, with for example contents about the statistics of the VACUUM operation for the relation, WAL and system usage. This commit adds more information about the statistics of the relation's indexes, with one line of logs generated for each index. The index stats were already calculated, but not printed in the context of autovacuum yet. While on it, some refactoring is done to keep track of the index statistics directly within LVRelStats, simplifying some routines related to parallel VACUUMs. Author: Masahiko Sawada Reviewed-by: Michael Paquier, Euler Taveira Discussion: https://postgr.es/m/CAD21AoAy6SxHiTivh5yAPJSUE4S=QRPpSZUdafOSz0R+fRcM6Q@mail.gmail.com
1 parent 4b82ed6 commit 5aed6a1

File tree

1 file changed

+81
-52
lines changed

1 file changed

+81
-52
lines changed

src/backend/access/heap/vacuumlazy.c

Lines changed: 81 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,10 @@ typedef struct LVRelStats
315315
TransactionId latestRemovedXid;
316316
bool lock_waiter_detected;
317317

318+
/* Statistics about indexes */
319+
IndexBulkDeleteResult **indstats;
320+
int nindexes;
321+
318322
/* Used for error callback */
319323
char *indname;
320324
BlockNumber blkno; /* used only for heap operations */
@@ -348,7 +352,6 @@ static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
348352
static bool lazy_check_needs_freeze(Buffer buf, bool *hastup,
349353
LVRelStats *vacrelstats);
350354
static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
351-
IndexBulkDeleteResult **stats,
352355
LVRelStats *vacrelstats, LVParallelState *lps,
353356
int nindexes);
354357
static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
@@ -371,21 +374,18 @@ static int vac_cmp_itemptr(const void *left, const void *right);
371374
static bool heap_page_is_all_visible(Relation rel, Buffer buf,
372375
LVRelStats *vacrelstats,
373376
TransactionId *visibility_cutoff_xid, bool *all_frozen);
374-
static void lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
375-
LVRelStats *vacrelstats, LVParallelState *lps,
376-
int nindexes);
377-
static void parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
378-
LVShared *lvshared, LVDeadTuples *dead_tuples,
379-
int nindexes, LVRelStats *vacrelstats);
380-
static void vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
381-
LVRelStats *vacrelstats, LVParallelState *lps,
382-
int nindexes);
377+
static void lazy_parallel_vacuum_indexes(Relation *Irel, LVRelStats *vacrelstats,
378+
LVParallelState *lps, int nindexes);
379+
static void parallel_vacuum_index(Relation *Irel, LVShared *lvshared,
380+
LVDeadTuples *dead_tuples, int nindexes,
381+
LVRelStats *vacrelstats);
382+
static void vacuum_indexes_leader(Relation *Irel, LVRelStats *vacrelstats,
383+
LVParallelState *lps, int nindexes);
383384
static void vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
384385
LVShared *lvshared, LVSharedIndStats *shared_indstats,
385386
LVDeadTuples *dead_tuples, LVRelStats *vacrelstats);
386-
static void lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
387-
LVRelStats *vacrelstats, LVParallelState *lps,
388-
int nindexes);
387+
static void lazy_cleanup_all_indexes(Relation *Irel, LVRelStats *vacrelstats,
388+
LVParallelState *lps, int nindexes);
389389
static long compute_max_dead_tuples(BlockNumber relblocks, bool hasindex);
390390
static int compute_parallel_vacuum_workers(Relation *Irel, int nindexes, int nrequested,
391391
bool *can_parallel_vacuum);
@@ -433,6 +433,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
433433
write_rate;
434434
bool aggressive; /* should we scan all unfrozen pages? */
435435
bool scanned_all_unfrozen; /* actually scanned all such pages? */
436+
char **indnames = NULL;
436437
TransactionId xidFullScanLimit;
437438
MultiXactId mxactFullScanLimit;
438439
BlockNumber new_rel_pages;
@@ -512,6 +513,20 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
512513
vacrelstats->useindex = (nindexes > 0 &&
513514
params->index_cleanup == VACOPT_TERNARY_ENABLED);
514515

516+
vacrelstats->indstats = (IndexBulkDeleteResult **)
517+
palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
518+
vacrelstats->nindexes = nindexes;
519+
520+
/* Save index names iff autovacuum logging requires it */
521+
if (IsAutoVacuumWorkerProcess() &&
522+
params->log_min_duration >= 0 &&
523+
vacrelstats->nindexes > 0)
524+
{
525+
indnames = palloc(sizeof(char *) * vacrelstats->nindexes);
526+
for (int i = 0; i < vacrelstats->nindexes; i++)
527+
indnames[i] = pstrdup(RelationGetRelationName(Irel[i]));
528+
}
529+
515530
/*
516531
* Setup error traceback support for ereport(). The idea is to set up an
517532
* error context callback to display additional information on any error
@@ -680,6 +695,21 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
680695
(long long) VacuumPageHit,
681696
(long long) VacuumPageMiss,
682697
(long long) VacuumPageDirty);
698+
for (int i = 0; i < vacrelstats->nindexes; i++)
699+
{
700+
IndexBulkDeleteResult *stats = vacrelstats->indstats[i];
701+
702+
if (!stats)
703+
continue;
704+
705+
appendStringInfo(&buf,
706+
_("index \"%s\": pages: %u remain, %u newly deleted, %u currently deleted, %u reusable\n"),
707+
indnames[i],
708+
stats->num_pages,
709+
stats->pages_newly_deleted,
710+
stats->pages_deleted,
711+
stats->pages_free);
712+
}
683713
appendStringInfo(&buf, _("avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n"),
684714
read_rate, write_rate);
685715
if (track_io_timing)
@@ -705,6 +735,16 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
705735
pfree(buf.data);
706736
}
707737
}
738+
739+
/* Cleanup index statistics and index names */
740+
for (int i = 0; i < vacrelstats->nindexes; i++)
741+
{
742+
if (vacrelstats->indstats[i])
743+
pfree(vacrelstats->indstats[i]);
744+
745+
if (indnames && indnames[i])
746+
pfree(indnames[i]);
747+
}
708748
}
709749

710750
/*
@@ -787,7 +827,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
787827
tups_vacuumed, /* tuples cleaned up by current vacuum */
788828
nkeep, /* dead-but-not-removable tuples */
789829
nunused; /* # existing unused line pointers */
790-
IndexBulkDeleteResult **indstats;
791830
int i;
792831
PGRUsage ru0;
793832
Buffer vmbuffer = InvalidBuffer;
@@ -820,9 +859,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
820859
next_fsm_block_to_vacuum = (BlockNumber) 0;
821860
num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0;
822861

823-
indstats = (IndexBulkDeleteResult **)
824-
palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
825-
826862
nblocks = RelationGetNumberOfBlocks(onerel);
827863
vacrelstats->rel_pages = nblocks;
828864
vacrelstats->scanned_pages = 0;
@@ -1070,8 +1106,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
10701106
}
10711107

10721108
/* Work on all the indexes, then the heap */
1073-
lazy_vacuum_all_indexes(onerel, Irel, indstats,
1074-
vacrelstats, lps, nindexes);
1109+
lazy_vacuum_all_indexes(onerel, Irel, vacrelstats, lps, nindexes);
10751110

10761111
/* Remove tuples from heap */
10771112
lazy_vacuum_heap(onerel, vacrelstats);
@@ -1728,8 +1763,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
17281763
if (dead_tuples->num_tuples > 0)
17291764
{
17301765
/* Work on all the indexes, and then the heap */
1731-
lazy_vacuum_all_indexes(onerel, Irel, indstats, vacrelstats,
1732-
lps, nindexes);
1766+
lazy_vacuum_all_indexes(onerel, Irel, vacrelstats, lps, nindexes);
17331767

17341768
/* Remove tuples from heap */
17351769
lazy_vacuum_heap(onerel, vacrelstats);
@@ -1747,18 +1781,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
17471781

17481782
/* Do post-vacuum cleanup */
17491783
if (vacrelstats->useindex)
1750-
lazy_cleanup_all_indexes(Irel, indstats, vacrelstats, lps, nindexes);
1784+
lazy_cleanup_all_indexes(Irel, vacrelstats, lps, nindexes);
17511785

17521786
/*
17531787
* End parallel mode before updating index statistics as we cannot write
17541788
* during parallel mode.
17551789
*/
17561790
if (ParallelVacuumIsActive(lps))
1757-
end_parallel_vacuum(indstats, lps, nindexes);
1791+
end_parallel_vacuum(vacrelstats->indstats, lps, nindexes);
17581792

17591793
/* Update index statistics */
17601794
if (vacrelstats->useindex)
1761-
update_index_statistics(Irel, indstats, nindexes);
1795+
update_index_statistics(Irel, vacrelstats->indstats, nindexes);
17621796

17631797
/* If no indexes, make log report that lazy_vacuum_heap would've made */
17641798
if (vacuumed_pages)
@@ -1803,7 +1837,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
18031837
*/
18041838
static void
18051839
lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
1806-
IndexBulkDeleteResult **stats,
18071840
LVRelStats *vacrelstats, LVParallelState *lps,
18081841
int nindexes)
18091842
{
@@ -1831,14 +1864,15 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
18311864
lps->lvshared->reltuples = vacrelstats->old_live_tuples;
18321865
lps->lvshared->estimated_count = true;
18331866

1834-
lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes);
1867+
lazy_parallel_vacuum_indexes(Irel, vacrelstats, lps, nindexes);
18351868
}
18361869
else
18371870
{
18381871
int idx;
18391872

18401873
for (idx = 0; idx < nindexes; idx++)
1841-
lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats->dead_tuples,
1874+
lazy_vacuum_index(Irel[idx], &(vacrelstats->indstats[idx]),
1875+
vacrelstats->dead_tuples,
18421876
vacrelstats->old_live_tuples, vacrelstats);
18431877
}
18441878

@@ -2109,9 +2143,8 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup, LVRelStats *vacrelstats)
21092143
* cleanup.
21102144
*/
21112145
static void
2112-
lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
2113-
LVRelStats *vacrelstats, LVParallelState *lps,
2114-
int nindexes)
2146+
lazy_parallel_vacuum_indexes(Relation *Irel, LVRelStats *vacrelstats,
2147+
LVParallelState *lps, int nindexes)
21152148
{
21162149
int nworkers;
21172150

@@ -2199,14 +2232,14 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
21992232
}
22002233

22012234
/* Process the indexes that can be processed by only leader process */
2202-
vacuum_indexes_leader(Irel, stats, vacrelstats, lps, nindexes);
2235+
vacuum_indexes_leader(Irel, vacrelstats, lps, nindexes);
22032236

22042237
/*
22052238
* Join as a parallel worker. The leader process alone processes all the
22062239
* indexes in the case where no workers are launched.
22072240
*/
2208-
parallel_vacuum_index(Irel, stats, lps->lvshared,
2209-
vacrelstats->dead_tuples, nindexes, vacrelstats);
2241+
parallel_vacuum_index(Irel, lps->lvshared, vacrelstats->dead_tuples,
2242+
nindexes, vacrelstats);
22102243

22112244
/*
22122245
* Next, accumulate buffer and WAL usage. (This must wait for the workers
@@ -2239,9 +2272,9 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
22392272
* vacuum worker processes to process the indexes in parallel.
22402273
*/
22412274
static void
2242-
parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
2243-
LVShared *lvshared, LVDeadTuples *dead_tuples,
2244-
int nindexes, LVRelStats *vacrelstats)
2275+
parallel_vacuum_index(Relation *Irel, LVShared *lvshared,
2276+
LVDeadTuples *dead_tuples, int nindexes,
2277+
LVRelStats *vacrelstats)
22452278
{
22462279
/*
22472280
* Increment the active worker count if we are able to launch any worker.
@@ -2274,8 +2307,8 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
22742307
continue;
22752308

22762309
/* Do vacuum or cleanup of the index */
2277-
vacuum_one_index(Irel[idx], &(stats[idx]), lvshared, shared_indstats,
2278-
dead_tuples, vacrelstats);
2310+
vacuum_one_index(Irel[idx], &(vacrelstats->indstats[idx]), lvshared,
2311+
shared_indstats, dead_tuples, vacrelstats);
22792312
}
22802313

22812314
/*
@@ -2291,9 +2324,8 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
22912324
* because these indexes don't support parallel operation at that phase.
22922325
*/
22932326
static void
2294-
vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
2295-
LVRelStats *vacrelstats, LVParallelState *lps,
2296-
int nindexes)
2327+
vacuum_indexes_leader(Relation *Irel, LVRelStats *vacrelstats,
2328+
LVParallelState *lps, int nindexes)
22972329
{
22982330
int i;
22992331

@@ -2314,7 +2346,7 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
23142346
/* Process the indexes skipped by parallel workers */
23152347
if (shared_indstats == NULL ||
23162348
skip_parallel_vacuum_index(Irel[i], lps->lvshared))
2317-
vacuum_one_index(Irel[i], &(stats[i]), lps->lvshared,
2349+
vacuum_one_index(Irel[i], &(vacrelstats->indstats[i]), lps->lvshared,
23182350
shared_indstats, vacrelstats->dead_tuples,
23192351
vacrelstats);
23202352
}
@@ -2394,9 +2426,8 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
23942426
* parallel vacuum.
23952427
*/
23962428
static void
2397-
lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
2398-
LVRelStats *vacrelstats, LVParallelState *lps,
2399-
int nindexes)
2429+
lazy_cleanup_all_indexes(Relation *Irel, LVRelStats *vacrelstats,
2430+
LVParallelState *lps, int nindexes)
24002431
{
24012432
int idx;
24022433

@@ -2427,12 +2458,12 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
24272458
lps->lvshared->estimated_count =
24282459
(vacrelstats->tupcount_pages < vacrelstats->rel_pages);
24292460

2430-
lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes);
2461+
lazy_parallel_vacuum_indexes(Irel, vacrelstats, lps, nindexes);
24312462
}
24322463
else
24332464
{
24342465
for (idx = 0; idx < nindexes; idx++)
2435-
lazy_cleanup_index(Irel[idx], &stats[idx],
2466+
lazy_cleanup_index(Irel[idx], &(vacrelstats->indstats[idx]),
24362467
vacrelstats->new_rel_tuples,
24372468
vacrelstats->tupcount_pages < vacrelstats->rel_pages,
24382469
vacrelstats);
@@ -3243,7 +3274,6 @@ update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats,
32433274
InvalidTransactionId,
32443275
InvalidMultiXactId,
32453276
false);
3246-
pfree(stats[i]);
32473277
}
32483278
}
32493279

@@ -3550,7 +3580,6 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
35503580
WalUsage *wal_usage;
35513581
int nindexes;
35523582
char *sharedquery;
3553-
IndexBulkDeleteResult **stats;
35543583
LVRelStats vacrelstats;
35553584
ErrorContextCallback errcallback;
35563585

@@ -3597,7 +3626,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
35973626
VacuumSharedCostBalance = &(lvshared->cost_balance);
35983627
VacuumActiveNWorkers = &(lvshared->active_nworkers);
35993628

3600-
stats = (IndexBulkDeleteResult **)
3629+
vacrelstats.indstats = (IndexBulkDeleteResult **)
36013630
palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
36023631

36033632
if (lvshared->maintenance_work_mem_worker > 0)
@@ -3622,7 +3651,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
36223651
InstrStartParallelQuery();
36233652

36243653
/* Process indexes to perform vacuum/cleanup */
3625-
parallel_vacuum_index(indrels, stats, lvshared, dead_tuples, nindexes,
3654+
parallel_vacuum_index(indrels, lvshared, dead_tuples, nindexes,
36263655
&vacrelstats);
36273656

36283657
/* Report buffer/WAL usage during parallel execution */
@@ -3636,7 +3665,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
36363665

36373666
vac_close_indexes(nindexes, indrels, RowExclusiveLock);
36383667
table_close(onerel, ShareUpdateExclusiveLock);
3639-
pfree(stats);
3668+
pfree(vacrelstats.indstats);
36403669
}
36413670

36423671
/*

0 commit comments

Comments
 (0)