Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 872770f

Browse files
Add VACUUM instrumentation for scanned pages, relfrozenxid.
Report on scanned pages within VACUUM VERBOSE and autovacuum logging. These are pages that were physically examined during the VACUUM operation. Note that this can include a small number of pages that were marked all-visible in the visibility map by some earlier VACUUM operation. VACUUM won't skip all-visible pages that aren't part of a range of all-visible pages that's at least 32 blocks in length (partly to avoid missing out on opportunities to advance relfrozenxid during non-aggressive VACUUMs). Commit 44fa848 simplified the definition of scanned pages. It became the complement of the pages (of those pages from rel_pages) that were skipped using the visibility map. And so scanned pages precisely indicates how effective the visibility map was at saving work. (Before now we displayed the number of pages skipped via the visibility map when happened to be frozen pages, but not when they were merely all-visible, which was less useful to users.) Rename the user-visible OldestXmin output field to "removal cutoff", and show some supplementary information: how far behind the cutoff is (number of XIDs behind) by the time the VACUUM operation finished. This will help users to figure out what's _not_ working in extreme cases where VACUUM is fundamentally unable to remove dead tuples or freeze older tuples (e.g., due to a leaked replication slot). Also report when relfrozenxid is advanced by VACUUM in output that immediately follows "removal cutoff". This structure is intended to highlight the relationship between the new relfrozenxid value for the table, and the VACUUM operation's removal cutoff. Finally, add instrumentation of "missed dead tuples", and the number of pages that had at least one such tuple. These are fully DEAD (not just RECENTLY_DEAD) tuples with storage that could not be pruned due to failure to acquire a cleanup lock on a heap page. This is a replacement for the "skipped due to pin" instrumentation removed by commit 44fa848. It shows more details than before for pages where failing to get a cleanup lock actually resulted in VACUUM missing out on useful work, but usually shows nothing at all instead (the mere fact that we couldn't get a cleanup lock is usually of no consequence whatsoever now). Author: Peter Geoghegan <pg@bowt.ie> Reviewed-By: Andres Freund <andres@anarazel.de> Discussion: https://postgr.es/m/CAH2-Wznp=c=Opj8Z7RMR3G=ec3_JfGYMN_YvmCEjoPCHzWbx0g@mail.gmail.com
1 parent 80901b3 commit 872770f

File tree

4 files changed

+82
-29
lines changed

4 files changed

+82
-29
lines changed

src/backend/access/heap/vacuumlazy.c

+68-29
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ typedef struct LVRelState
199199
BlockNumber frozenskipped_pages; /* # frozen pages skipped via VM */
200200
BlockNumber removed_pages; /* # pages removed by relation truncation */
201201
BlockNumber lpdead_item_pages; /* # pages with LP_DEAD items */
202+
BlockNumber missed_dead_pages; /* # pages with missed dead tuples */
202203
BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
203204

204205
/* Statistics output by us, for table */
@@ -212,8 +213,8 @@ typedef struct LVRelState
212213
/* Counters that follow are only for scanned_pages */
213214
int64 tuples_deleted; /* # deleted from table */
214215
int64 lpdead_items; /* # deleted from indexes */
215-
int64 new_dead_tuples; /* new estimated total # of dead items in
216-
* table */
216+
int64 recently_dead_tuples; /* # dead, but not yet removable */
217+
int64 missed_dead_tuples; /* # removable, but not removed */
217218
int64 num_tuples; /* total number of nonremovable tuples */
218219
int64 live_tuples; /* live tuples (reltuples estimate) */
219220
} LVRelState;
@@ -318,6 +319,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
318319
write_rate;
319320
bool aggressive,
320321
skipwithvm;
322+
bool frozenxid_updated,
323+
minmulti_updated;
321324
BlockNumber orig_rel_pages;
322325
char **indnames = NULL;
323326
TransactionId xidFullScanLimit;
@@ -539,17 +542,20 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
539542
{
540543
/* Cannot advance relfrozenxid/relminmxid */
541544
Assert(!aggressive);
545+
frozenxid_updated = minmulti_updated = false;
542546
vac_update_relstats(rel, new_rel_pages, new_live_tuples,
543547
new_rel_allvisible, vacrel->nindexes > 0,
544-
InvalidTransactionId, InvalidMultiXactId, false);
548+
InvalidTransactionId, InvalidMultiXactId,
549+
NULL, NULL, false);
545550
}
546551
else
547552
{
548553
Assert(vacrel->scanned_pages + vacrel->frozenskipped_pages ==
549554
orig_rel_pages);
550555
vac_update_relstats(rel, new_rel_pages, new_live_tuples,
551556
new_rel_allvisible, vacrel->nindexes > 0,
552-
FreezeLimit, MultiXactCutoff, false);
557+
FreezeLimit, MultiXactCutoff,
558+
&frozenxid_updated, &minmulti_updated, false);
553559
}
554560

555561
/*
@@ -565,7 +571,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
565571
pgstat_report_vacuum(RelationGetRelid(rel),
566572
rel->rd_rel->relisshared,
567573
Max(new_live_tuples, 0),
568-
vacrel->new_dead_tuples);
574+
vacrel->recently_dead_tuples +
575+
vacrel->missed_dead_tuples);
569576
pgstat_progress_end_command();
570577

571578
if (instrument)
@@ -578,6 +585,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
578585
{
579586
StringInfoData buf;
580587
char *msgfmt;
588+
int32 diff;
581589

582590
TimestampDifference(starttime, endtime, &secs, &usecs);
583591

@@ -629,16 +637,40 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
629637
vacrel->relnamespace,
630638
vacrel->relname,
631639
vacrel->num_index_scans);
632-
appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped frozen\n"),
640+
appendStringInfo(&buf, _("pages: %u removed, %u remain, %u scanned (%.2f%% of total)\n"),
633641
vacrel->removed_pages,
634642
vacrel->rel_pages,
635-
vacrel->frozenskipped_pages);
643+
vacrel->scanned_pages,
644+
orig_rel_pages == 0 ? 0 :
645+
100.0 * vacrel->scanned_pages / orig_rel_pages);
636646
appendStringInfo(&buf,
637-
_("tuples: %lld removed, %lld remain, %lld are dead but not yet removable, oldest xmin: %u\n"),
647+
_("tuples: %lld removed, %lld remain, %lld are dead but not yet removable\n"),
638648
(long long) vacrel->tuples_deleted,
639649
(long long) vacrel->new_rel_tuples,
640-
(long long) vacrel->new_dead_tuples,
641-
OldestXmin);
650+
(long long) vacrel->recently_dead_tuples);
651+
if (vacrel->missed_dead_tuples > 0)
652+
appendStringInfo(&buf,
653+
_("tuples missed: %lld dead from %u pages not removed due to cleanup lock contention\n"),
654+
(long long) vacrel->missed_dead_tuples,
655+
vacrel->missed_dead_pages);
656+
diff = (int32) (ReadNextTransactionId() - OldestXmin);
657+
appendStringInfo(&buf,
658+
_("removable cutoff: %u, older by %d xids when operation ended\n"),
659+
OldestXmin, diff);
660+
if (frozenxid_updated)
661+
{
662+
diff = (int32) (FreezeLimit - vacrel->relfrozenxid);
663+
appendStringInfo(&buf,
664+
_("new relfrozenxid: %u, which is %d xids ahead of previous value\n"),
665+
FreezeLimit, diff);
666+
}
667+
if (minmulti_updated)
668+
{
669+
diff = (int32) (MultiXactCutoff - vacrel->relminmxid);
670+
appendStringInfo(&buf,
671+
_("new relminmxid: %u, which is %d mxids ahead of previous value\n"),
672+
MultiXactCutoff, diff);
673+
}
642674
if (orig_rel_pages > 0)
643675
{
644676
if (vacrel->do_index_vacuuming)
@@ -779,13 +811,15 @@ lazy_scan_heap(LVRelState *vacrel, int nworkers)
779811
vacrel->frozenskipped_pages = 0;
780812
vacrel->removed_pages = 0;
781813
vacrel->lpdead_item_pages = 0;
814+
vacrel->missed_dead_pages = 0;
782815
vacrel->nonempty_pages = 0;
783816

784817
/* Initialize instrumentation counters */
785818
vacrel->num_index_scans = 0;
786819
vacrel->tuples_deleted = 0;
787820
vacrel->lpdead_items = 0;
788-
vacrel->new_dead_tuples = 0;
821+
vacrel->recently_dead_tuples = 0;
822+
vacrel->missed_dead_tuples = 0;
789823
vacrel->num_tuples = 0;
790824
vacrel->live_tuples = 0;
791825

@@ -1331,7 +1365,8 @@ lazy_scan_heap(LVRelState *vacrel, int nworkers)
13311365
* (unlikely) scenario that new_live_tuples is -1, take it as zero.
13321366
*/
13331367
vacrel->new_rel_tuples =
1334-
Max(vacrel->new_live_tuples, 0) + vacrel->new_dead_tuples;
1368+
Max(vacrel->new_live_tuples, 0) + vacrel->recently_dead_tuples +
1369+
vacrel->missed_dead_tuples;
13351370

13361371
/*
13371372
* Release any remaining pin on visibility map page.
@@ -1539,7 +1574,7 @@ lazy_scan_prune(LVRelState *vacrel,
15391574
HTSV_Result res;
15401575
int tuples_deleted,
15411576
lpdead_items,
1542-
new_dead_tuples,
1577+
recently_dead_tuples,
15431578
num_tuples,
15441579
live_tuples;
15451580
int nnewlpdead;
@@ -1556,7 +1591,7 @@ lazy_scan_prune(LVRelState *vacrel,
15561591
/* Initialize (or reset) page-level counters */
15571592
tuples_deleted = 0;
15581593
lpdead_items = 0;
1559-
new_dead_tuples = 0;
1594+
recently_dead_tuples = 0;
15601595
num_tuples = 0;
15611596
live_tuples = 0;
15621597

@@ -1715,11 +1750,11 @@ lazy_scan_prune(LVRelState *vacrel,
17151750
case HEAPTUPLE_RECENTLY_DEAD:
17161751

17171752
/*
1718-
* If tuple is recently deleted then we must not remove it
1719-
* from relation. (We only remove items that are LP_DEAD from
1753+
* If tuple is recently dead then we must not remove it from
1754+
* the relation. (We only remove items that are LP_DEAD from
17201755
* pruning.)
17211756
*/
1722-
new_dead_tuples++;
1757+
recently_dead_tuples++;
17231758
prunestate->all_visible = false;
17241759
break;
17251760
case HEAPTUPLE_INSERT_IN_PROGRESS:
@@ -1895,7 +1930,7 @@ lazy_scan_prune(LVRelState *vacrel,
18951930
/* Finally, add page-local counts to whole-VACUUM counts */
18961931
vacrel->tuples_deleted += tuples_deleted;
18971932
vacrel->lpdead_items += lpdead_items;
1898-
vacrel->new_dead_tuples += new_dead_tuples;
1933+
vacrel->recently_dead_tuples += recently_dead_tuples;
18991934
vacrel->num_tuples += num_tuples;
19001935
vacrel->live_tuples += live_tuples;
19011936
}
@@ -1932,7 +1967,8 @@ lazy_scan_noprune(LVRelState *vacrel,
19321967
int lpdead_items,
19331968
num_tuples,
19341969
live_tuples,
1935-
new_dead_tuples;
1970+
recently_dead_tuples,
1971+
missed_dead_tuples;
19361972
HeapTupleHeader tupleheader;
19371973
OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
19381974

@@ -1944,7 +1980,8 @@ lazy_scan_noprune(LVRelState *vacrel,
19441980
lpdead_items = 0;
19451981
num_tuples = 0;
19461982
live_tuples = 0;
1947-
new_dead_tuples = 0;
1983+
recently_dead_tuples = 0;
1984+
missed_dead_tuples = 0;
19481985

19491986
maxoff = PageGetMaxOffsetNumber(page);
19501987
for (offnum = FirstOffsetNumber;
@@ -2018,16 +2055,15 @@ lazy_scan_noprune(LVRelState *vacrel,
20182055
/*
20192056
* There is some useful work for pruning to do, that won't be
20202057
* done due to failure to get a cleanup lock.
2021-
*
2022-
* TODO Add dedicated instrumentation for this case
20232058
*/
2059+
missed_dead_tuples++;
20242060
break;
20252061
case HEAPTUPLE_RECENTLY_DEAD:
20262062

20272063
/*
2028-
* Count in new_dead_tuples, just like lazy_scan_prune
2064+
* Count in recently_dead_tuples, just like lazy_scan_prune
20292065
*/
2030-
new_dead_tuples++;
2066+
recently_dead_tuples++;
20312067
break;
20322068
case HEAPTUPLE_INSERT_IN_PROGRESS:
20332069

@@ -2063,7 +2099,7 @@ lazy_scan_noprune(LVRelState *vacrel,
20632099
*/
20642100
*hastup = true;
20652101
num_tuples += lpdead_items;
2066-
/* TODO HEAPTUPLE_DEAD style instrumentation needed here, too */
2102+
missed_dead_tuples += lpdead_items;
20672103
}
20682104

20692105
*recordfreespace = true;
@@ -2112,9 +2148,12 @@ lazy_scan_noprune(LVRelState *vacrel,
21122148
/*
21132149
* Finally, add relevant page-local counts to whole-VACUUM counts
21142150
*/
2115-
vacrel->new_dead_tuples += new_dead_tuples;
2151+
vacrel->recently_dead_tuples += recently_dead_tuples;
2152+
vacrel->missed_dead_tuples += missed_dead_tuples;
21162153
vacrel->num_tuples += num_tuples;
21172154
vacrel->live_tuples += live_tuples;
2155+
if (missed_dead_tuples > 0)
2156+
vacrel->missed_dead_pages++;
21182157

21192158
/* Caller won't need to call lazy_scan_prune with same page */
21202159
return true;
@@ -2193,8 +2232,8 @@ lazy_vacuum(LVRelState *vacrel)
21932232
* dead_items space is not CPU cache resident.
21942233
*
21952234
* We don't take any special steps to remember the LP_DEAD items (such
2196-
* as counting them in new_dead_tuples report to the stats collector)
2197-
* when the optimization is applied. Though the accounting used in
2235+
* as counting them in our final report to the stats collector) when
2236+
* the optimization is applied. Though the accounting used in
21982237
* analyze.c's acquire_sample_rows() will recognize the same LP_DEAD
21992238
* items as dead rows in its own stats collector report, that's okay.
22002239
* The discrepancy should be negligible. If this optimization is ever
@@ -3321,7 +3360,7 @@ update_index_statistics(LVRelState *vacrel)
33213360
false,
33223361
InvalidTransactionId,
33233362
InvalidMultiXactId,
3324-
false);
3363+
NULL, NULL, false);
33253364
}
33263365
}
33273366

src/backend/commands/analyze.c

+3
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
645645
hasindex,
646646
InvalidTransactionId,
647647
InvalidMultiXactId,
648+
NULL, NULL,
648649
in_outer_xact);
649650

650651
/* Same for indexes */
@@ -661,6 +662,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
661662
false,
662663
InvalidTransactionId,
663664
InvalidMultiXactId,
665+
NULL, NULL,
664666
in_outer_xact);
665667
}
666668
}
@@ -673,6 +675,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
673675
vac_update_relstats(onerel, -1, totalrows,
674676
0, hasindex, InvalidTransactionId,
675677
InvalidMultiXactId,
678+
NULL, NULL,
676679
in_outer_xact);
677680
}
678681

src/backend/commands/vacuum.c

+9
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,7 @@ vac_update_relstats(Relation relation,
13151315
BlockNumber num_all_visible_pages,
13161316
bool hasindex, TransactionId frozenxid,
13171317
MultiXactId minmulti,
1318+
bool *frozenxid_updated, bool *minmulti_updated,
13181319
bool in_outer_xact)
13191320
{
13201321
Oid relid = RelationGetRelid(relation);
@@ -1390,22 +1391,30 @@ vac_update_relstats(Relation relation,
13901391
* This should match vac_update_datfrozenxid() concerning what we consider
13911392
* to be "in the future".
13921393
*/
1394+
if (frozenxid_updated)
1395+
*frozenxid_updated = false;
13931396
if (TransactionIdIsNormal(frozenxid) &&
13941397
pgcform->relfrozenxid != frozenxid &&
13951398
(TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
13961399
TransactionIdPrecedes(ReadNextTransactionId(),
13971400
pgcform->relfrozenxid)))
13981401
{
1402+
if (frozenxid_updated)
1403+
*frozenxid_updated = true;
13991404
pgcform->relfrozenxid = frozenxid;
14001405
dirty = true;
14011406
}
14021407

14031408
/* Similarly for relminmxid */
1409+
if (minmulti_updated)
1410+
*minmulti_updated = false;
14041411
if (MultiXactIdIsValid(minmulti) &&
14051412
pgcform->relminmxid != minmulti &&
14061413
(MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
14071414
MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
14081415
{
1416+
if (minmulti_updated)
1417+
*minmulti_updated = true;
14091418
pgcform->relminmxid = minmulti;
14101419
dirty = true;
14111420
}

src/include/commands/vacuum.h

+2
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ extern void vac_update_relstats(Relation relation,
283283
bool hasindex,
284284
TransactionId frozenxid,
285285
MultiXactId minmulti,
286+
bool *frozenxid_updated,
287+
bool *minmulti_updated,
286288
bool in_outer_xact);
287289
extern void vacuum_set_xid_limits(Relation rel,
288290
int freeze_min_age, int freeze_table_age,

0 commit comments

Comments
 (0)