@@ -315,6 +315,10 @@ typedef struct LVRelStats
315315TransactionId latestRemovedXid ;
316316bool lock_waiter_detected ;
317317
318+ /* Statistics about indexes */
319+ IndexBulkDeleteResult * * indstats ;
320+ int nindexes ;
321+
318322/* Used for error callback */
319323char * indname ;
320324BlockNumber blkno ;/* used only for heap operations */
@@ -348,7 +352,6 @@ static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
348352static bool lazy_check_needs_freeze (Buffer buf ,bool * hastup ,
349353LVRelStats * vacrelstats );
350354static void lazy_vacuum_all_indexes (Relation onerel ,Relation * Irel ,
351- IndexBulkDeleteResult * * stats ,
352355LVRelStats * vacrelstats ,LVParallelState * lps ,
353356int nindexes );
354357static void lazy_vacuum_index (Relation indrel ,IndexBulkDeleteResult * * stats ,
@@ -371,21 +374,18 @@ static intvac_cmp_itemptr(const void *left, const void *right);
371374static bool heap_page_is_all_visible (Relation rel ,Buffer buf ,
372375LVRelStats * vacrelstats ,
373376TransactionId * 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 );
383384static void vacuum_one_index (Relation indrel ,IndexBulkDeleteResult * * stats ,
384385LVShared * lvshared ,LVSharedIndStats * shared_indstats ,
385386LVDeadTuples * 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 );
389389static long compute_max_dead_tuples (BlockNumber relblocks ,bool hasindex );
390390static int compute_parallel_vacuum_workers (Relation * Irel ,int nindexes ,int nrequested ,
391391bool * can_parallel_vacuum );
@@ -433,6 +433,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
433433write_rate ;
434434bool aggressive ;/* should we scan all unfrozen pages? */
435435bool scanned_all_unfrozen ;/* actually scanned all such pages? */
436+ char * * indnames = NULL ;
436437TransactionId xidFullScanLimit ;
437438MultiXactId mxactFullScanLimit ;
438439BlockNumber new_rel_pages ;
@@ -512,6 +513,20 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
512513vacrelstats -> useindex = (nindexes > 0 &&
513514params -> 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+ }
683713appendStringInfo (& buf ,_ ("avg read rate: %.3f MB/s, avg write rate: %.3f MB/s\n" ),
684714read_rate ,write_rate );
685715if (track_io_timing )
@@ -705,6 +735,16 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
705735pfree (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,
787827tups_vacuumed ,/* tuples cleaned up by current vacuum */
788828nkeep ,/* dead-but-not-removable tuples */
789829nunused ;/* # existing unused line pointers */
790- IndexBulkDeleteResult * * indstats ;
791830int i ;
792831PGRUsage ru0 ;
793832Buffer vmbuffer = InvalidBuffer ;
@@ -820,9 +859,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
820859next_fsm_block_to_vacuum = (BlockNumber )0 ;
821860num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0 ;
822861
823- indstats = (IndexBulkDeleteResult * * )
824- palloc0 (nindexes * sizeof (IndexBulkDeleteResult * ));
825-
826862nblocks = RelationGetNumberOfBlocks (onerel );
827863vacrelstats -> rel_pages = nblocks ;
828864vacrelstats -> 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 */
10771112lazy_vacuum_heap (onerel ,vacrelstats );
@@ -1728,8 +1763,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
17281763if (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 */
17351769lazy_vacuum_heap (onerel ,vacrelstats );
@@ -1747,18 +1781,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
17471781
17481782/* Do post-vacuum cleanup */
17491783if (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 */
17561790if (ParallelVacuumIsActive (lps ))
1757- end_parallel_vacuum (indstats ,lps ,nindexes );
1791+ end_parallel_vacuum (vacrelstats -> indstats ,lps ,nindexes );
17581792
17591793/* Update index statistics */
17601794if (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 */
17641798if (vacuumed_pages )
@@ -1803,7 +1837,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
18031837 */
18041838static void
18051839lazy_vacuum_all_indexes (Relation onerel ,Relation * Irel ,
1806- IndexBulkDeleteResult * * stats ,
18071840LVRelStats * vacrelstats ,LVParallelState * lps ,
18081841int nindexes )
18091842{
@@ -1831,14 +1864,15 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
18311864lps -> lvshared -> reltuples = vacrelstats -> old_live_tuples ;
18321865lps -> 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}
18361869else
18371870{
18381871int idx ;
18391872
18401873for (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 ,
18421876vacrelstats -> old_live_tuples ,vacrelstats );
18431877}
18441878
@@ -2109,9 +2143,8 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup, LVRelStats *vacrelstats)
21092143 * cleanup.
21102144 */
21112145static 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{
21162149int 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 */
22412274static 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,
22742307continue ;
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 */
22932326static 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{
22982330int i ;
22992331
@@ -2314,7 +2346,7 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
23142346/* Process the indexes skipped by parallel workers */
23152347if (shared_indstats == NULL ||
23162348skip_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 ,
23182350shared_indstats ,vacrelstats -> dead_tuples ,
23192351vacrelstats );
23202352}
@@ -2394,9 +2426,8 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
23942426 * parallel vacuum.
23952427 */
23962428static 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{
24012432int idx ;
24022433
@@ -2427,12 +2458,12 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
24272458lps -> 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}
24322463else
24332464{
24342465for (idx = 0 ;idx < nindexes ;idx ++ )
2435- lazy_cleanup_index (Irel [idx ],& stats [idx ],
2466+ lazy_cleanup_index (Irel [idx ],& ( vacrelstats -> indstats [idx ]) ,
24362467vacrelstats -> new_rel_tuples ,
24372468vacrelstats -> tupcount_pages < vacrelstats -> rel_pages ,
24382469vacrelstats );
@@ -3243,7 +3274,6 @@ update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats,
32433274InvalidTransactionId ,
32443275InvalidMultiXactId ,
32453276false);
3246- pfree (stats [i ]);
32473277}
32483278}
32493279
@@ -3550,7 +3580,6 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
35503580WalUsage * wal_usage ;
35513581int nindexes ;
35523582char * sharedquery ;
3553- IndexBulkDeleteResult * * stats ;
35543583LVRelStats vacrelstats ;
35553584ErrorContextCallback errcallback ;
35563585
@@ -3597,7 +3626,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
35973626VacuumSharedCostBalance = & (lvshared -> cost_balance );
35983627VacuumActiveNWorkers = & (lvshared -> active_nworkers );
35993628
3600- stats = (IndexBulkDeleteResult * * )
3629+ vacrelstats . indstats = (IndexBulkDeleteResult * * )
36013630palloc0 (nindexes * sizeof (IndexBulkDeleteResult * ));
36023631
36033632if (lvshared -> maintenance_work_mem_worker > 0 )
@@ -3622,7 +3651,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
36223651InstrStartParallelQuery ();
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
36373666vac_close_indexes (nindexes ,indrels ,RowExclusiveLock );
36383667table_close (onerel ,ShareUpdateExclusiveLock );
3639- pfree (stats );
3668+ pfree (vacrelstats . indstats );
36403669}
36413670
36423671/*