aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/heap/vacuumlazy.c97
-rw-r--r--src/backend/commands/analyze.c3
-rw-r--r--src/backend/commands/vacuum.c9
-rw-r--r--src/include/commands/vacuum.h2
4 files changed, 82 insertions, 29 deletions
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index e676969ed1c..fed25f49294 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -199,6 +199,7 @@ typedef struct LVRelState
BlockNumber frozenskipped_pages; /* # frozen pages skipped via VM */
BlockNumber removed_pages; /* # pages removed by relation truncation */
BlockNumber lpdead_item_pages; /* # pages with LP_DEAD items */
+ BlockNumber missed_dead_pages; /* # pages with missed dead tuples */
BlockNumber nonempty_pages; /* actually, last nonempty page + 1 */
/* Statistics output by us, for table */
@@ -212,8 +213,8 @@ typedef struct LVRelState
/* Counters that follow are only for scanned_pages */
int64 tuples_deleted; /* # deleted from table */
int64 lpdead_items; /* # deleted from indexes */
- int64 new_dead_tuples; /* new estimated total # of dead items in
- * table */
+ int64 recently_dead_tuples; /* # dead, but not yet removable */
+ int64 missed_dead_tuples; /* # removable, but not removed */
int64 num_tuples; /* total number of nonremovable tuples */
int64 live_tuples; /* live tuples (reltuples estimate) */
} LVRelState;
@@ -318,6 +319,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
write_rate;
bool aggressive,
skipwithvm;
+ bool frozenxid_updated,
+ minmulti_updated;
BlockNumber orig_rel_pages;
char **indnames = NULL;
TransactionId xidFullScanLimit;
@@ -539,9 +542,11 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
{
/* Cannot advance relfrozenxid/relminmxid */
Assert(!aggressive);
+ frozenxid_updated = minmulti_updated = false;
vac_update_relstats(rel, new_rel_pages, new_live_tuples,
new_rel_allvisible, vacrel->nindexes > 0,
- InvalidTransactionId, InvalidMultiXactId, false);
+ InvalidTransactionId, InvalidMultiXactId,
+ NULL, NULL, false);
}
else
{
@@ -549,7 +554,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
orig_rel_pages);
vac_update_relstats(rel, new_rel_pages, new_live_tuples,
new_rel_allvisible, vacrel->nindexes > 0,
- FreezeLimit, MultiXactCutoff, false);
+ FreezeLimit, MultiXactCutoff,
+ &frozenxid_updated, &minmulti_updated, false);
}
/*
@@ -565,7 +571,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
pgstat_report_vacuum(RelationGetRelid(rel),
rel->rd_rel->relisshared,
Max(new_live_tuples, 0),
- vacrel->new_dead_tuples);
+ vacrel->recently_dead_tuples +
+ vacrel->missed_dead_tuples);
pgstat_progress_end_command();
if (instrument)
@@ -578,6 +585,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
{
StringInfoData buf;
char *msgfmt;
+ int32 diff;
TimestampDifference(starttime, endtime, &secs, &usecs);
@@ -629,16 +637,40 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
vacrel->relnamespace,
vacrel->relname,
vacrel->num_index_scans);
- appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped frozen\n"),
+ appendStringInfo(&buf, _("pages: %u removed, %u remain, %u scanned (%.2f%% of total)\n"),
vacrel->removed_pages,
vacrel->rel_pages,
- vacrel->frozenskipped_pages);
+ vacrel->scanned_pages,
+ orig_rel_pages == 0 ? 0 :
+ 100.0 * vacrel->scanned_pages / orig_rel_pages);
appendStringInfo(&buf,
- _("tuples: %lld removed, %lld remain, %lld are dead but not yet removable, oldest xmin: %u\n"),
+ _("tuples: %lld removed, %lld remain, %lld are dead but not yet removable\n"),
(long long) vacrel->tuples_deleted,
(long long) vacrel->new_rel_tuples,
- (long long) vacrel->new_dead_tuples,
- OldestXmin);
+ (long long) vacrel->recently_dead_tuples);
+ if (vacrel->missed_dead_tuples > 0)
+ appendStringInfo(&buf,
+ _("tuples missed: %lld dead from %u pages not removed due to cleanup lock contention\n"),
+ (long long) vacrel->missed_dead_tuples,
+ vacrel->missed_dead_pages);
+ diff = (int32) (ReadNextTransactionId() - OldestXmin);
+ appendStringInfo(&buf,
+ _("removable cutoff: %u, older by %d xids when operation ended\n"),
+ OldestXmin, diff);
+ if (frozenxid_updated)
+ {
+ diff = (int32) (FreezeLimit - vacrel->relfrozenxid);
+ appendStringInfo(&buf,
+ _("new relfrozenxid: %u, which is %d xids ahead of previous value\n"),
+ FreezeLimit, diff);
+ }
+ if (minmulti_updated)
+ {
+ diff = (int32) (MultiXactCutoff - vacrel->relminmxid);
+ appendStringInfo(&buf,
+ _("new relminmxid: %u, which is %d mxids ahead of previous value\n"),
+ MultiXactCutoff, diff);
+ }
if (orig_rel_pages > 0)
{
if (vacrel->do_index_vacuuming)
@@ -779,13 +811,15 @@ lazy_scan_heap(LVRelState *vacrel, int nworkers)
vacrel->frozenskipped_pages = 0;
vacrel->removed_pages = 0;
vacrel->lpdead_item_pages = 0;
+ vacrel->missed_dead_pages = 0;
vacrel->nonempty_pages = 0;
/* Initialize instrumentation counters */
vacrel->num_index_scans = 0;
vacrel->tuples_deleted = 0;
vacrel->lpdead_items = 0;
- vacrel->new_dead_tuples = 0;
+ vacrel->recently_dead_tuples = 0;
+ vacrel->missed_dead_tuples = 0;
vacrel->num_tuples = 0;
vacrel->live_tuples = 0;
@@ -1331,7 +1365,8 @@ lazy_scan_heap(LVRelState *vacrel, int nworkers)
* (unlikely) scenario that new_live_tuples is -1, take it as zero.
*/
vacrel->new_rel_tuples =
- Max(vacrel->new_live_tuples, 0) + vacrel->new_dead_tuples;
+ Max(vacrel->new_live_tuples, 0) + vacrel->recently_dead_tuples +
+ vacrel->missed_dead_tuples;
/*
* Release any remaining pin on visibility map page.
@@ -1539,7 +1574,7 @@ lazy_scan_prune(LVRelState *vacrel,
HTSV_Result res;
int tuples_deleted,
lpdead_items,
- new_dead_tuples,
+ recently_dead_tuples,
num_tuples,
live_tuples;
int nnewlpdead;
@@ -1556,7 +1591,7 @@ retry:
/* Initialize (or reset) page-level counters */
tuples_deleted = 0;
lpdead_items = 0;
- new_dead_tuples = 0;
+ recently_dead_tuples = 0;
num_tuples = 0;
live_tuples = 0;
@@ -1715,11 +1750,11 @@ retry:
case HEAPTUPLE_RECENTLY_DEAD:
/*
- * If tuple is recently deleted then we must not remove it
- * from relation. (We only remove items that are LP_DEAD from
+ * If tuple is recently dead then we must not remove it from
+ * the relation. (We only remove items that are LP_DEAD from
* pruning.)
*/
- new_dead_tuples++;
+ recently_dead_tuples++;
prunestate->all_visible = false;
break;
case HEAPTUPLE_INSERT_IN_PROGRESS:
@@ -1895,7 +1930,7 @@ retry:
/* Finally, add page-local counts to whole-VACUUM counts */
vacrel->tuples_deleted += tuples_deleted;
vacrel->lpdead_items += lpdead_items;
- vacrel->new_dead_tuples += new_dead_tuples;
+ vacrel->recently_dead_tuples += recently_dead_tuples;
vacrel->num_tuples += num_tuples;
vacrel->live_tuples += live_tuples;
}
@@ -1932,7 +1967,8 @@ lazy_scan_noprune(LVRelState *vacrel,
int lpdead_items,
num_tuples,
live_tuples,
- new_dead_tuples;
+ recently_dead_tuples,
+ missed_dead_tuples;
HeapTupleHeader tupleheader;
OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
@@ -1944,7 +1980,8 @@ lazy_scan_noprune(LVRelState *vacrel,
lpdead_items = 0;
num_tuples = 0;
live_tuples = 0;
- new_dead_tuples = 0;
+ recently_dead_tuples = 0;
+ missed_dead_tuples = 0;
maxoff = PageGetMaxOffsetNumber(page);
for (offnum = FirstOffsetNumber;
@@ -2018,16 +2055,15 @@ lazy_scan_noprune(LVRelState *vacrel,
/*
* There is some useful work for pruning to do, that won't be
* done due to failure to get a cleanup lock.
- *
- * TODO Add dedicated instrumentation for this case
*/
+ missed_dead_tuples++;
break;
case HEAPTUPLE_RECENTLY_DEAD:
/*
- * Count in new_dead_tuples, just like lazy_scan_prune
+ * Count in recently_dead_tuples, just like lazy_scan_prune
*/
- new_dead_tuples++;
+ recently_dead_tuples++;
break;
case HEAPTUPLE_INSERT_IN_PROGRESS:
@@ -2063,7 +2099,7 @@ lazy_scan_noprune(LVRelState *vacrel,
*/
*hastup = true;
num_tuples += lpdead_items;
- /* TODO HEAPTUPLE_DEAD style instrumentation needed here, too */
+ missed_dead_tuples += lpdead_items;
}
*recordfreespace = true;
@@ -2112,9 +2148,12 @@ lazy_scan_noprune(LVRelState *vacrel,
/*
* Finally, add relevant page-local counts to whole-VACUUM counts
*/
- vacrel->new_dead_tuples += new_dead_tuples;
+ vacrel->recently_dead_tuples += recently_dead_tuples;
+ vacrel->missed_dead_tuples += missed_dead_tuples;
vacrel->num_tuples += num_tuples;
vacrel->live_tuples += live_tuples;
+ if (missed_dead_tuples > 0)
+ vacrel->missed_dead_pages++;
/* Caller won't need to call lazy_scan_prune with same page */
return true;
@@ -2193,8 +2232,8 @@ lazy_vacuum(LVRelState *vacrel)
* dead_items space is not CPU cache resident.
*
* We don't take any special steps to remember the LP_DEAD items (such
- * as counting them in new_dead_tuples report to the stats collector)
- * when the optimization is applied. Though the accounting used in
+ * as counting them in our final report to the stats collector) when
+ * the optimization is applied. Though the accounting used in
* analyze.c's acquire_sample_rows() will recognize the same LP_DEAD
* items as dead rows in its own stats collector report, that's okay.
* The discrepancy should be negligible. If this optimization is ever
@@ -3321,7 +3360,7 @@ update_index_statistics(LVRelState *vacrel)
false,
InvalidTransactionId,
InvalidMultiXactId,
- false);
+ NULL, NULL, false);
}
}
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index a0da998c2ea..736479295ad 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -645,6 +645,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
hasindex,
InvalidTransactionId,
InvalidMultiXactId,
+ NULL, NULL,
in_outer_xact);
/* Same for indexes */
@@ -661,6 +662,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
false,
InvalidTransactionId,
InvalidMultiXactId,
+ NULL, NULL,
in_outer_xact);
}
}
@@ -673,6 +675,7 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
vac_update_relstats(onerel, -1, totalrows,
0, hasindex, InvalidTransactionId,
InvalidMultiXactId,
+ NULL, NULL,
in_outer_xact);
}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index d1dadc54e47..37413dd43e9 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1315,6 +1315,7 @@ vac_update_relstats(Relation relation,
BlockNumber num_all_visible_pages,
bool hasindex, TransactionId frozenxid,
MultiXactId minmulti,
+ bool *frozenxid_updated, bool *minmulti_updated,
bool in_outer_xact)
{
Oid relid = RelationGetRelid(relation);
@@ -1390,22 +1391,30 @@ vac_update_relstats(Relation relation,
* This should match vac_update_datfrozenxid() concerning what we consider
* to be "in the future".
*/
+ if (frozenxid_updated)
+ *frozenxid_updated = false;
if (TransactionIdIsNormal(frozenxid) &&
pgcform->relfrozenxid != frozenxid &&
(TransactionIdPrecedes(pgcform->relfrozenxid, frozenxid) ||
TransactionIdPrecedes(ReadNextTransactionId(),
pgcform->relfrozenxid)))
{
+ if (frozenxid_updated)
+ *frozenxid_updated = true;
pgcform->relfrozenxid = frozenxid;
dirty = true;
}
/* Similarly for relminmxid */
+ if (minmulti_updated)
+ *minmulti_updated = false;
if (MultiXactIdIsValid(minmulti) &&
pgcform->relminmxid != minmulti &&
(MultiXactIdPrecedes(pgcform->relminmxid, minmulti) ||
MultiXactIdPrecedes(ReadNextMultiXactId(), pgcform->relminmxid)))
{
+ if (minmulti_updated)
+ *minmulti_updated = true;
pgcform->relminmxid = minmulti;
dirty = true;
}
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 5d0bdfa4279..e5e548d6b9a 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -283,6 +283,8 @@ extern void vac_update_relstats(Relation relation,
bool hasindex,
TransactionId frozenxid,
MultiXactId minmulti,
+ bool *frozenxid_updated,
+ bool *minmulti_updated,
bool in_outer_xact);
extern void vacuum_set_xid_limits(Relation rel,
int freeze_min_age, int freeze_table_age,