Skip to content

Commit 54dc3de

Browse files
Alena0704danolivozubkov-andrei
committed
Track index and database vacuum time and cost-based delay
Add cumulative elapsed and delay time for indexes and databases, and delay time for tables. Keep manual VACUUM and autovacuum totals separate. Database totals use table timings, which already include index work. Adapt v44-0002 to Cloudberry's PostgreSQL 14 UDP collector, including AO vacuum. Store times in microseconds and report delay in VACUUM VERBOSE and autovacuum logs. Collection follows track_counts; delay measurement also requires track_cost_delay_timing and excludes ANALYZE calls. SQL access is provided separately through vacuum_stats. Bump the statistics-file format for the new fields; the system catalog is unchanged. Based-on: https://www.postgresql.org/message-id/attachment/204703/v44-0002-Track-vacuum-times-for-indexes-and-databases-and.patch (cherry picked from commit 77a3ffa32d07d8a2947bf7e8dbb8d342ce05549d) Co-authored-by: Andrei Lepikhov <lepihov@gmail.com> Co-authored-by: Andrei Zubkov <zubkov@moonset.ru>
1 parent e368cc1 commit 54dc3de

5 files changed

Lines changed: 137 additions & 20 deletions

File tree

‎src/backend/access/heap/vacuumlazy.c‎

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,9 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
517517
bool aggressive; /* should we scan all unfrozen pages? */
518518
bool scanned_all_unfrozen; /* actually scanned all such pages? */
519519
bool freeze_age_vacuum; /* aggressive due to freeze age? */
520+
instr_time vacstart;
521+
int64 startdelaytime;
522+
instr_time vacend;
520523
char **indnames = NULL;
521524
TransactionId xidFullScanLimit;
522525
MultiXactId mxactFullScanLimit;
@@ -535,6 +538,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
535538
/* Used for instrumentation and cumulative maintenance statistics. */
536539
starttime = GetCurrentTimestamp();
537540

541+
/* measure elapsed and delay time for the vacuum statistics */
542+
INSTR_TIME_SET_CURRENT(vacstart);
543+
startdelaytime = VacuumDelayTime;
544+
538545
/* measure elapsed time iff autovacuum logging requires it */
539546
if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
540547
{
@@ -767,11 +774,13 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
767774
pgstat_report_vacuum(RelationGetRelid(rel),
768775
rel->rd_rel->relisshared,
769776
Max(new_live_tuples, 0),
770-
vacrel->new_dead_tuples, starttime);
777+
vacrel->new_dead_tuples, starttime,
778+
VacuumDelayTime - startdelaytime);
771779

772780
/* assemble the per-vacuum measurements for subsequent reporting */
773781
{
774782
PgStat_VacuumStats vacstats;
783+
PgStat_Counter elapsedtime;
775784

776785
MemSet(&vacstats, 0, sizeof(vacstats));
777786
vacstats.tuples_deleted = (PgStat_Counter) vacrel->tuples_deleted;
@@ -782,9 +791,16 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
782791
vacstats.pages_all_visible = (PgStat_Counter) vacrel->pages_all_visible;
783792
vacstats.freeze_age_vacuum_count = freeze_age_vacuum ? 1 : 0;
784793

794+
INSTR_TIME_SET_CURRENT(vacend);
795+
INSTR_TIME_SUBTRACT(vacend, vacstart);
796+
elapsedtime = (PgStat_Counter) INSTR_TIME_GET_MICROSEC(vacend);
797+
785798
ereport(elevel,
786799
(errmsg("table \"%s\": vacuum statistics", vacrel->relname),
787-
errdetail("aggressive scan required by freeze age: %s",
800+
errdetail("elapsed: %.3f ms, cost-based delay: %.3f ms\n"
801+
"aggressive scan required by freeze age: %s",
802+
elapsedtime / 1000.0,
803+
(VacuumDelayTime - startdelaytime) / 1000.0,
788804
freeze_age_vacuum ? _("yes") : _("no"))));
789805

790806
}
@@ -930,6 +946,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
930946
(long long) walusage.wal_records,
931947
(long long) walusage.wal_fpi,
932948
(unsigned long long) walusage.wal_bytes);
949+
appendStringInfo(&buf, _("cost-based delay: %.3f ms\n"),
950+
(VacuumDelayTime - startdelaytime) / 1000.0);
933951
appendStringInfo(&buf, _("system usage: %s"), pg_rusage_show(&ru0));
934952

935953
ereport(LOG,
@@ -3117,7 +3135,8 @@ lazy_cleanup_all_indexes(LVRelState *vacrel)
31173135
* is skipped, and keeps it from being counted twice when it is not.
31183136
*/
31193137
static IndexBulkDeleteResult
3120-
lazy_index_vacstats_start(IndexBulkDeleteResult *istat)
3138+
lazy_index_vacstats_start(IndexBulkDeleteResult *istat,
3139+
instr_time *starttime, int64 *startdelaytime)
31213140
{
31223141
IndexBulkDeleteResult before;
31233142

@@ -3126,6 +3145,9 @@ lazy_index_vacstats_start(IndexBulkDeleteResult *istat)
31263145
else
31273146
MemSet(&before, 0, sizeof(before));
31283147

3148+
INSTR_TIME_SET_CURRENT(*starttime);
3149+
*startdelaytime = VacuumDelayTime;
3150+
31293151
return before;
31303152
}
31313153

@@ -3139,9 +3161,14 @@ lazy_index_vacstats_start(IndexBulkDeleteResult *istat)
31393161
*/
31403162
static void
31413163
lazy_index_vacstats_finish(Relation indrel, IndexBulkDeleteResult *istat,
3142-
IndexBulkDeleteResult *before, bool cleanup)
3164+
IndexBulkDeleteResult *before, bool cleanup,
3165+
instr_time starttime, int64 startdelaytime)
31433166
{
31443167
PgStat_VacuumStats vacstats;
3168+
instr_time endtime;
3169+
3170+
INSTR_TIME_SET_CURRENT(endtime);
3171+
INSTR_TIME_SUBTRACT(endtime, starttime);
31453172

31463173
MemSet(&vacstats, 0, sizeof(vacstats));
31473174
if (istat)
@@ -3162,6 +3189,11 @@ lazy_index_vacstats_finish(Relation indrel, IndexBulkDeleteResult *istat,
31623189
(PgStat_Counter) (istat->pages_deleted - istat->pages_free);
31633190
}
31643191

3192+
pgstat_report_index_vacuum_time(indrel,
3193+
(PgStat_Counter) INSTR_TIME_GET_MICROSEC(endtime),
3194+
VacuumDelayTime - startdelaytime,
3195+
IsAutoVacuumWorkerProcess());
3196+
31653197
}
31663198

31673199
/*
@@ -3183,6 +3215,8 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
31833215
PGRUsage ru0;
31843216
LVSavedErrInfo saved_err_info;
31853217
IndexBulkDeleteResult istat_before;
3218+
instr_time starttime;
3219+
int64 startdelaytime;
31863220

31873221
pg_rusage_init(&ru0);
31883222

@@ -3207,15 +3241,19 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
32073241
InvalidBlockNumber, InvalidOffsetNumber);
32083242

32093243
/* Do bulk deletion */
3210-
istat_before = lazy_index_vacstats_start(istat);
3244+
istat_before = lazy_index_vacstats_start(istat, &starttime,
3245+
&startdelaytime);
32113246
istat = index_bulk_delete(&ivinfo, istat, lazy_tid_reaped,
32123247
(void *) vacrel->dead_tuples);
3213-
lazy_index_vacstats_finish(indrel, istat, &istat_before, false);
3248+
lazy_index_vacstats_finish(indrel, istat, &istat_before, false,
3249+
starttime, startdelaytime);
32143250

32153251
ereport(elevel,
32163252
(errmsg("scanned index \"%s\" to remove %d row versions",
32173253
vacrel->indname, vacrel->dead_tuples->num_tuples),
3218-
errdetail_internal("%s", pg_rusage_show(&ru0))));
3254+
errdetail("cost-based delay: %.3f ms\n%s",
3255+
(VacuumDelayTime - startdelaytime) / 1000.0,
3256+
pg_rusage_show(&ru0))));
32193257

32203258
/* Revert to the previous phase information for error traceback */
32213259
restore_vacuum_error_info(vacrel, &saved_err_info);
@@ -3242,6 +3280,8 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
32423280
PGRUsage ru0;
32433281
LVSavedErrInfo saved_err_info;
32443282
IndexBulkDeleteResult istat_before;
3283+
instr_time starttime;
3284+
int64 startdelaytime;
32453285

32463286
pg_rusage_init(&ru0);
32473287

@@ -3266,9 +3306,11 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
32663306
VACUUM_ERRCB_PHASE_INDEX_CLEANUP,
32673307
InvalidBlockNumber, InvalidOffsetNumber);
32683308

3269-
istat_before = lazy_index_vacstats_start(istat);
3309+
istat_before = lazy_index_vacstats_start(istat, &starttime,
3310+
&startdelaytime);
32703311
istat = index_vacuum_cleanup(&ivinfo, istat);
3271-
lazy_index_vacstats_finish(indrel, istat, &istat_before, true);
3312+
lazy_index_vacstats_finish(indrel, istat, &istat_before, true,
3313+
starttime, startdelaytime);
32723314

32733315
if (istat)
32743316
{
@@ -3280,10 +3322,12 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
32803322
errdetail("%.0f index row versions were removed.\n"
32813323
"%u index pages were newly deleted.\n"
32823324
"%u index pages are currently deleted, of which %u are currently reusable.\n"
3325+
"cost-based delay: %.3f ms\n"
32833326
"%s.",
32843327
(istat)->tuples_removed,
32853328
(istat)->pages_newly_deleted,
32863329
(istat)->pages_deleted, (istat)->pages_free,
3330+
(VacuumDelayTime - startdelaytime) / 1000.0,
32873331
pg_rusage_show(&ru0))));
32883332
}
32893333

‎src/backend/commands/vacuum_ao.c‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,9 @@ ao_vacuum_rel_post_cleanup(Relation onerel, VacuumParams *params, BufferAccessSt
322322
onerel->rd_rel->relisshared,
323323
reltuples,
324324
deadtuples,
325-
vacrelstats->starttime);
325+
vacrelstats->starttime,
326+
vacrelstats->delay_time +
327+
(VacuumDelayTime - vacrelstats->phase_start_delay));
326328

327329
/*
328330
* Remember what is left behind for the vacuum statistics, which
@@ -491,6 +493,7 @@ ao_vacuum_rel(Relation rel, VacuumParams *params, BufferAccessStrategy bstrategy
491493
*/
492494
INSTR_TIME_SET_CURRENT(phasestart);
493495
startdelaytime = VacuumDelayTime;
496+
vacrelstats->phase_start_delay = startdelaytime;
494497

495498
if (ao_vacuum_phase == VACOPT_AO_PRE_CLEANUP_PHASE)
496499
ao_vacuum_rel_pre_cleanup(rel, params, bstrategy, vacrelstats);

‎src/backend/postmaster/pgstat.c‎

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,7 @@ pgstat_report_autovac(Oid dboid)
15901590
void
15911591
pgstat_report_vacuum(Oid tableoid, bool shared,
15921592
PgStat_Counter livetuples, PgStat_Counter deadtuples,
1593-
TimestampTz starttime)
1593+
TimestampTz starttime, PgStat_Counter delaytime)
15941594
{
15951595
PgStat_MsgVacuum msg;
15961596

@@ -1601,13 +1601,36 @@ pgstat_report_vacuum(Oid tableoid, bool shared,
16011601
msg.m_databaseid = shared ? InvalidOid : MyDatabaseId;
16021602
msg.m_tableoid = tableoid;
16031603
msg.m_autovacuum = IsAutoVacuumWorkerProcess();
1604+
msg.m_isindex = false;
1605+
msg.m_delaytime = delaytime;
16041606
msg.m_vacuumtime = GetCurrentTimestamp();
16051607
msg.m_elapsedtime = Max(msg.m_vacuumtime - starttime, 0);
16061608
msg.m_live_tuples = livetuples;
16071609
msg.m_dead_tuples = deadtuples;
16081610
pgstat_send(&msg, sizeof(msg));
16091611
}
16101612

1613+
/* Report an index pass without changing table estimates or vacuum counts. */
1614+
void
1615+
pgstat_report_index_vacuum_time(Relation rel, PgStat_Counter elapsedtime,
1616+
PgStat_Counter delaytime, bool is_autovacuum)
1617+
{
1618+
PgStat_MsgVacuum msg;
1619+
1620+
if (pgStatSock == PGINVALID_SOCKET || !pgstat_track_counts)
1621+
return;
1622+
1623+
MemSet(&msg, 0, sizeof(msg));
1624+
pgstat_setheader(&msg.m_hdr, PGSTAT_MTYPE_VACUUM);
1625+
msg.m_databaseid = rel->rd_rel->relisshared ? InvalidOid : MyDatabaseId;
1626+
msg.m_tableoid = RelationGetRelid(rel);
1627+
msg.m_autovacuum = is_autovacuum;
1628+
msg.m_isindex = true;
1629+
msg.m_elapsedtime = elapsedtime;
1630+
msg.m_delaytime = delaytime;
1631+
pgstat_send(&msg, sizeof(msg));
1632+
}
1633+
16111634
/* --------
16121635
* pgstat_report_analyze() -
16131636
*
@@ -3823,9 +3846,14 @@ reset_dbentry_counters(PgStat_StatDBEntry *dbentry)
38233846
dbentry->n_sessions_abandoned = 0;
38243847
dbentry->n_sessions_fatal = 0;
38253848
dbentry->n_sessions_killed = 0;
3849+
dbentry->total_vacuum_time = 0;
3850+
dbentry->total_autovacuum_time = 0;
3851+
dbentry->total_vacuum_delay_time = 0;
3852+
dbentry->total_autovacuum_delay_time = 0;
38263853
dbentry->n_frozen_page_marks_cleared = 0;
38273854
dbentry->n_visible_page_marks_cleared = 0;
38283855

3856+
38293857
dbentry->stat_reset_timestamp = GetCurrentTimestamp();
38303858
dbentry->stats_timestamp = 0;
38313859

@@ -3919,12 +3947,14 @@ pgstat_get_tab_entry(PgStat_StatDBEntry *dbentry, Oid tableoid, bool create)
39193947
result->analyze_count = 0;
39203948
result->autovac_analyze_timestamp = 0;
39213949
result->autovac_analyze_count = 0;
3922-
result->frozen_page_marks_cleared = 0;
3923-
result->visible_page_marks_cleared = 0;
39243950
result->total_vacuum_time = 0;
39253951
result->total_autovacuum_time = 0;
39263952
result->total_analyze_time = 0;
39273953
result->total_autoanalyze_time = 0;
3954+
result->total_vacuum_delay_time = 0;
3955+
result->total_autovacuum_delay_time = 0;
3956+
result->frozen_page_marks_cleared = 0;
3957+
result->visible_page_marks_cleared = 0;
39283958
}
39293959

39303960
return result;
@@ -5286,12 +5316,14 @@ pgstat_recv_tabstat(PgStat_MsgTabstat *msg, int len)
52865316
tabentry->analyze_count = 0;
52875317
tabentry->autovac_analyze_timestamp = 0;
52885318
tabentry->autovac_analyze_count = 0;
5289-
tabentry->frozen_page_marks_cleared = 0;
5290-
tabentry->visible_page_marks_cleared = 0;
52915319
tabentry->total_vacuum_time = 0;
52925320
tabentry->total_autovacuum_time = 0;
52935321
tabentry->total_analyze_time = 0;
52945322
tabentry->total_autoanalyze_time = 0;
5323+
tabentry->total_vacuum_delay_time = 0;
5324+
tabentry->total_autovacuum_delay_time = 0;
5325+
tabentry->frozen_page_marks_cleared = 0;
5326+
tabentry->visible_page_marks_cleared = 0;
52955327
}
52965328
else
52975329
{
@@ -5630,6 +5662,32 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
56305662

56315663
tabentry = pgstat_get_tab_entry(dbentry, msg->m_tableoid, true);
56325664

5665+
if (msg->m_autovacuum)
5666+
{
5667+
tabentry->total_autovacuum_time += msg->m_elapsedtime;
5668+
tabentry->total_autovacuum_delay_time += msg->m_delaytime;
5669+
}
5670+
else
5671+
{
5672+
tabentry->total_vacuum_time += msg->m_elapsedtime;
5673+
tabentry->total_vacuum_delay_time += msg->m_delaytime;
5674+
}
5675+
5676+
/* Index passes are already included in the owning table's elapsed time. */
5677+
if (msg->m_isindex)
5678+
return;
5679+
5680+
if (msg->m_autovacuum)
5681+
{
5682+
dbentry->total_autovacuum_time += msg->m_elapsedtime;
5683+
dbentry->total_autovacuum_delay_time += msg->m_delaytime;
5684+
}
5685+
else
5686+
{
5687+
dbentry->total_vacuum_time += msg->m_elapsedtime;
5688+
dbentry->total_vacuum_delay_time += msg->m_delaytime;
5689+
}
5690+
56335691
tabentry->n_live_tuples = msg->m_live_tuples;
56345692
tabentry->n_dead_tuples = msg->m_dead_tuples;
56355693

@@ -5649,13 +5707,11 @@ pgstat_recv_vacuum(PgStat_MsgVacuum *msg, int len)
56495707
{
56505708
tabentry->autovac_vacuum_timestamp = msg->m_vacuumtime;
56515709
tabentry->autovac_vacuum_count++;
5652-
tabentry->total_autovacuum_time += msg->m_elapsedtime;
56535710
}
56545711
else
56555712
{
56565713
tabentry->vacuum_timestamp = msg->m_vacuumtime;
56575714
tabentry->vacuum_count++;
5658-
tabentry->total_vacuum_time += msg->m_elapsedtime;
56595715
}
56605716
}
56615717

‎src/include/access/appendonly_compaction.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ typedef struct AOVacuumRelStats
3636

3737
/* for the vacuum statistics, accumulated over all the phases */
3838
int64 vacuum_time; /* time spent in the phases, in microseconds */
39+
int64 phase_start_delay; /* counter at the start of the current phase */
3940
int64 delay_time; /* of which the cost-based vacuum delay */
4041
int64 dead_tuples_left; /* tuples the post-cleanup found still hidden */
4142
} AOVacuumRelStats;

0 commit comments

Comments
 (0)