On Sun, Jan 26, 2020 at 12:29:38PM -0800, Andres Freund wrote:
> > postgres=# SET client_min_messages=debug;SET statement_timeout=99; VACUUM
> > (VERBOSE, PARALLEL 0) t;
> > INFO: vacuuming "public.t"
> > DEBUG: "t_a_idx": vacuuming index
> > 2020-01-20 15:47:36.338 CST [20139] ERROR: canceling statement due to
> > statement timeout
> > 2020-01-20 15:47:36.338 CST [20139] CONTEXT: while vacuuming relation
> > "public.t_a_idx"
> > 2020-01-20 15:47:36.338 CST [20139] STATEMENT: VACUUM (VERBOSE, PARALLEL
> > 0) t;
> > ERROR: canceling statement due to statement timeout
> > CONTEXT: while vacuuming relation "public.t_a_idx"
>
> It'd be a bit nicer if it said index "public.t_a_idx" for relation "public.t".
I think that tips the scale in favour of making vacrelstats a global.
I added that as a 1st patch, and squished the callback patches into one.
Also, it seems to me we shouldn't repeat the namespace of the index *and* its
table. I tried looking for consistency here:
grep -r '\\"%s.%s\\"' --incl='*.c' |grep '\\"%s\\"'
src/backend/commands/cluster.c: (errmsg("clustering
\"%s.%s\" using index scan on \"%s\"",
src/backend/access/heap/vacuumlazy.c: errcontext(_("while vacuuming
index \"%s\" on table \"%s.%s\""),
grep -r 'index \\".* table \\"' --incl='*.c'
src/backend/catalog/index.c: (errmsg("building index
\"%s\" on table \"%s\" serially",
src/backend/catalog/index.c:
(errmsg_plural("building index \"%s\" on table \"%s\" with request for %d
parallel worker",
src/backend/catalog/index.c:
"building index \"%s\" on table \"%s\" with request for %d parallel workers",
src/backend/catalog/catalog.c: errmsg("index \"%s\"
does not belong to table \"%s\"",
src/backend/commands/indexcmds.c: (errmsg("%s %s
will create implicit index \"%s\" for table \"%s\"",
src/backend/commands/tablecmds.c: errmsg("index
\"%s\" for table \"%s\" does not exist",
src/backend/commands/tablecmds.c: errmsg("index
\"%s\" for table \"%s\" does not exist",
src/backend/commands/tablecmds.c:
errdetail("The index \"%s\" belongs to a constraint in table \"%s\" but no
constraint exists for index \"%s\".",
src/backend/commands/cluster.c:
errmsg("index \"%s\" for table \"%s\" does not exist",
src/backend/parser/parse_utilcmd.c:
errmsg("index \"%s\" does not belong to table \"%s\"",
>From 8ee9ffc1325118438309ee25e9b33c61cccd022f Mon Sep 17 00:00:00 2001
From: Justin Pryzby <[email protected]>
Date: Sun, 26 Jan 2020 22:38:10 -0600
Subject: [PATCH v14 1/3] make vacrelstats a global
---
src/backend/access/heap/vacuumlazy.c | 276 +++++++++++++++++------------------
1 file changed, 136 insertions(+), 140 deletions(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 8ce5011..114428b 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -302,16 +302,17 @@ static MultiXactId MultiXactCutoff;
static BufferAccessStrategy vac_strategy;
+LVRelStats vacrelstats = {0};
/* non-export function prototypes */
static void lazy_scan_heap(Relation onerel, VacuumParams *params,
- LVRelStats *vacrelstats, Relation *Irel, int nindexes,
+ Relation *Irel, int nindexes,
bool aggressive);
-static void lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats);
+static void lazy_vacuum_heap(Relation onerel);
static bool lazy_check_needs_freeze(Buffer buf, bool *hastup);
static void lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes);
static void lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
LVDeadTuples *dead_tuples, double reltuples);
@@ -319,13 +320,11 @@ static void lazy_cleanup_index(Relation indrel,
IndexBulkDeleteResult **stats,
double reltuples, bool estimated_count);
static int lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
- int tupindex, LVRelStats *vacrelstats, Buffer *vmbuffer);
-static bool should_attempt_truncation(VacuumParams *params,
- LVRelStats *vacrelstats);
-static void lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats);
-static BlockNumber count_nondeletable_pages(Relation onerel,
- LVRelStats *vacrelstats);
-static void lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks);
+ int tupindex, Buffer *vmbuffer);
+static bool should_attempt_truncation(VacuumParams *params);
+static void lazy_truncate_heap(Relation onerel);
+static BlockNumber count_nondeletable_pages(Relation onerel);
+static void lazy_space_alloc(BlockNumber relblocks);
static void lazy_record_dead_tuple(LVDeadTuples *dead_tuples,
ItemPointer itemptr);
static bool lazy_tid_reaped(ItemPointer itemptr, void *state);
@@ -333,19 +332,19 @@ static int vac_cmp_itemptr(const void *left, const void *right);
static bool heap_page_is_all_visible(Relation rel, Buffer buf,
TransactionId *visibility_cutoff_xid, bool *all_frozen);
static void lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes);
static void parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVDeadTuples *dead_tuples,
int nindexes);
static void vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes);
static void vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
LVShared *lvshared, LVSharedIndStats *shared_indstats,
LVDeadTuples *dead_tuples);
static void lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes);
static long compute_max_dead_tuples(BlockNumber relblocks, bool hasindex);
static int compute_parallel_vacuum_workers(Relation *Irel, int nindexes, int nrequested,
@@ -355,7 +354,7 @@ static void prepare_index_statistics(LVShared *lvshared, bool *can_parallel_vacu
static void update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats,
int nindexes);
static LVParallelState *begin_parallel_vacuum(Oid relid, Relation *Irel,
- LVRelStats *vacrelstats, BlockNumber nblocks,
+ BlockNumber nblocks,
int nindexes, int nrequested);
static void end_parallel_vacuum(Relation *Irel, IndexBulkDeleteResult **stats,
LVParallelState *lps, int nindexes);
@@ -376,7 +375,6 @@ void
heap_vacuum_rel(Relation onerel, VacuumParams *params,
BufferAccessStrategy bstrategy)
{
- LVRelStats *vacrelstats;
Relation *Irel;
int nindexes;
PGRUsage ru0;
@@ -458,21 +456,20 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
return;
}
- vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
-
- vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
- vacrelstats->old_live_tuples = onerel->rd_rel->reltuples;
- vacrelstats->num_index_scans = 0;
- vacrelstats->pages_removed = 0;
- vacrelstats->lock_waiter_detected = false;
+ memset(&vacrelstats, 0, sizeof(vacrelstats));
+ vacrelstats.old_rel_pages = onerel->rd_rel->relpages;
+ vacrelstats.old_live_tuples = onerel->rd_rel->reltuples;
+ // vacrelstats.num_index_scans = 0;
+ // vacrelstats.pages_removed = 0;
+ // vacrelstats.lock_waiter_detected = false;
/* Open all indexes of the relation */
vac_open_indexes(onerel, RowExclusiveLock, &nindexes, &Irel);
- vacrelstats->useindex = (nindexes > 0 &&
+ vacrelstats.useindex = (nindexes > 0 &&
params->index_cleanup == VACOPT_TERNARY_ENABLED);
/* Do the vacuuming */
- lazy_scan_heap(onerel, params, vacrelstats, Irel, nindexes, aggressive);
+ lazy_scan_heap(onerel, params, Irel, nindexes, aggressive);
/* Done with indexes */
vac_close_indexes(nindexes, Irel, NoLock);
@@ -484,8 +481,8 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
* NB: We need to check this before truncating the relation, because that
* will change ->rel_pages.
*/
- if ((vacrelstats->scanned_pages + vacrelstats->frozenskipped_pages)
- < vacrelstats->rel_pages)
+ if ((vacrelstats.scanned_pages + vacrelstats.frozenskipped_pages)
+ < vacrelstats.rel_pages)
{
Assert(!aggressive);
scanned_all_unfrozen = false;
@@ -496,8 +493,8 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
/*
* Optionally truncate the relation.
*/
- if (should_attempt_truncation(params, vacrelstats))
- lazy_truncate_heap(onerel, vacrelstats);
+ if (should_attempt_truncation(params))
+ lazy_truncate_heap(onerel);
/* Report that we are now doing final cleanup */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
@@ -524,12 +521,12 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
* Also, don't change relfrozenxid/relminmxid if we skipped any pages,
* since then we don't know for certain that all tuples have a newer xmin.
*/
- new_rel_pages = vacrelstats->rel_pages;
- new_live_tuples = vacrelstats->new_live_tuples;
- if (vacrelstats->tupcount_pages == 0 && new_rel_pages > 0)
+ new_rel_pages = vacrelstats.rel_pages;
+ new_live_tuples = vacrelstats.new_live_tuples;
+ if (vacrelstats.tupcount_pages == 0 && new_rel_pages > 0)
{
- new_rel_pages = vacrelstats->old_rel_pages;
- new_live_tuples = vacrelstats->old_live_tuples;
+ new_rel_pages = vacrelstats.old_rel_pages;
+ new_live_tuples = vacrelstats.old_live_tuples;
}
visibilitymap_count(onerel, &new_rel_allvisible, NULL);
@@ -552,7 +549,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
pgstat_report_vacuum(RelationGetRelid(onerel),
onerel->rd_rel->relisshared,
new_live_tuples,
- vacrelstats->new_dead_tuples);
+ vacrelstats.new_dead_tuples);
pgstat_progress_end_command();
/* and log the action if appropriate */
@@ -601,17 +598,17 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
get_database_name(MyDatabaseId),
get_namespace_name(RelationGetNamespace(onerel)),
RelationGetRelationName(onerel),
- vacrelstats->num_index_scans);
+ vacrelstats.num_index_scans);
appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
- vacrelstats->pages_removed,
- vacrelstats->rel_pages,
- vacrelstats->pinskipped_pages,
- vacrelstats->frozenskipped_pages);
+ vacrelstats.pages_removed,
+ vacrelstats.rel_pages,
+ vacrelstats.pinskipped_pages,
+ vacrelstats.frozenskipped_pages);
appendStringInfo(&buf,
_("tuples: %.0f removed, %.0f remain, %.0f are dead but not yet removable, oldest xmin: %u\n"),
- vacrelstats->tuples_deleted,
- vacrelstats->new_rel_tuples,
- vacrelstats->new_dead_tuples,
+ vacrelstats.tuples_deleted,
+ vacrelstats.new_rel_tuples,
+ vacrelstats.new_dead_tuples,
OldestXmin);
appendStringInfo(&buf,
_("buffer usage: %d hits, %d misses, %d dirtied\n"),
@@ -646,7 +643,7 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
* which would be after the rows have become inaccessible.
*/
static void
-vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
+vacuum_log_cleanup_info(Relation rel)
{
/*
* Skip this for relations for which no WAL is to be written, or if we're
@@ -658,8 +655,8 @@ vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
/*
* No need to write the record at all unless it contains a valid value
*/
- if (TransactionIdIsValid(vacrelstats->latestRemovedXid))
- (void) log_heap_cleanup_info(rel->rd_node, vacrelstats->latestRemovedXid);
+ if (TransactionIdIsValid(vacrelstats.latestRemovedXid))
+ (void) log_heap_cleanup_info(rel->rd_node, vacrelstats.latestRemovedXid);
}
/*
@@ -691,7 +688,7 @@ vacuum_log_cleanup_info(Relation rel, LVRelStats *vacrelstats)
* reference them have been killed.
*/
static void
-lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
+lazy_scan_heap(Relation onerel, VacuumParams *params,
Relation *Irel, int nindexes, bool aggressive)
{
LVParallelState *lps = NULL;
@@ -747,18 +744,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
palloc0(nindexes * sizeof(IndexBulkDeleteResult *));
nblocks = RelationGetNumberOfBlocks(onerel);
- vacrelstats->rel_pages = nblocks;
- vacrelstats->scanned_pages = 0;
- vacrelstats->tupcount_pages = 0;
- vacrelstats->nonempty_pages = 0;
- vacrelstats->latestRemovedXid = InvalidTransactionId;
+ vacrelstats.rel_pages = nblocks;
+ vacrelstats.scanned_pages = 0;
+ vacrelstats.tupcount_pages = 0;
+ vacrelstats.nonempty_pages = 0;
+ vacrelstats.latestRemovedXid = InvalidTransactionId;
/*
* Initialize the state for a parallel vacuum. As of now, only one worker
* can be used for an index, so we invoke parallelism only if there are at
* least two indexes on a table.
*/
- if (params->nworkers >= 0 && vacrelstats->useindex && nindexes > 1)
+ if (params->nworkers >= 0 && vacrelstats.useindex && nindexes > 1)
{
/*
* Since parallel workers cannot access data in temporary tables, we
@@ -777,7 +774,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
}
else
lps = begin_parallel_vacuum(RelationGetRelid(onerel), Irel,
- vacrelstats, nblocks, nindexes,
+ nblocks, nindexes,
params->nworkers);
}
@@ -786,9 +783,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* initialized.
*/
if (!ParallelVacuumIsActive(lps))
- lazy_space_alloc(vacrelstats, nblocks);
+ lazy_space_alloc(nblocks);
- dead_tuples = vacrelstats->dead_tuples;
+ dead_tuples = vacrelstats.dead_tuples;
frozen = palloc(sizeof(xl_heap_freeze_tuple) * MaxHeapTuplesPerPage);
/* Report that we're scanning the heap, advertising total # of blocks */
@@ -889,7 +886,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
/* see note above about forcing scanning of last page */
#define FORCE_CHECK_PAGE() \
- (blkno == nblocks - 1 && should_attempt_truncation(params, vacrelstats))
+ (blkno == nblocks - 1 && should_attempt_truncation(params))
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_SCANNED, blkno);
@@ -960,7 +957,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* in this case an approximate answer is OK.
*/
if (aggressive || VM_ALL_FROZEN(onerel, blkno, &vmbuffer))
- vacrelstats->frozenskipped_pages++;
+ vacrelstats.frozenskipped_pages++;
continue;
}
all_visible_according_to_vm = true;
@@ -989,10 +986,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
/* Work on all the indexes, then the heap */
lazy_vacuum_all_indexes(onerel, Irel, indstats,
- vacrelstats, lps, nindexes);
-
+ lps, nindexes);
/* Remove tuples from heap */
- lazy_vacuum_heap(onerel, vacrelstats);
+ lazy_vacuum_heap(onerel);
/*
* Forget the now-vacuumed tuples, and press on, but be careful
@@ -1039,7 +1035,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
if (!aggressive && !FORCE_CHECK_PAGE())
{
ReleaseBuffer(buf);
- vacrelstats->pinskipped_pages++;
+ vacrelstats.pinskipped_pages++;
continue;
}
@@ -1063,10 +1059,10 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
if (!lazy_check_needs_freeze(buf, &hastup))
{
UnlockReleaseBuffer(buf);
- vacrelstats->scanned_pages++;
- vacrelstats->pinskipped_pages++;
+ vacrelstats.scanned_pages++;
+ vacrelstats.pinskipped_pages++;
if (hastup)
- vacrelstats->nonempty_pages = blkno + 1;
+ vacrelstats.nonempty_pages = blkno + 1;
continue;
}
if (!aggressive)
@@ -1076,9 +1072,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* to claiming that the page contains no freezable tuples.
*/
UnlockReleaseBuffer(buf);
- vacrelstats->pinskipped_pages++;
+ vacrelstats.pinskipped_pages++;
if (hastup)
- vacrelstats->nonempty_pages = blkno + 1;
+ vacrelstats.nonempty_pages = blkno + 1;
continue;
}
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
@@ -1086,8 +1082,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
/* drop through to normal processing */
}
- vacrelstats->scanned_pages++;
- vacrelstats->tupcount_pages++;
+ vacrelstats.scanned_pages++;
+ vacrelstats.tupcount_pages++;
page = BufferGetPage(buf);
@@ -1184,7 +1180,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* We count tuples removed by the pruning step as removed by VACUUM.
*/
tups_vacuumed += heap_page_prune(onerel, buf, OldestXmin, false,
- &vacrelstats->latestRemovedXid);
+ &vacrelstats.latestRemovedXid);
/*
* Now scan the page to collect vacuumable items and check for tuples
@@ -1381,7 +1377,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
{
lazy_record_dead_tuple(dead_tuples, &(tuple.t_self));
HeapTupleHeaderAdvanceLatestRemovedXid(tuple.t_data,
- &vacrelstats->latestRemovedXid);
+ &vacrelstats.latestRemovedXid);
tups_vacuumed += 1;
has_dead_tuples = true;
}
@@ -1449,12 +1445,12 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* doing a second scan. Also we don't do that but forget dead tuples
* when index cleanup is disabled.
*/
- if (!vacrelstats->useindex && dead_tuples->num_tuples > 0)
+ if (!vacrelstats.useindex && dead_tuples->num_tuples > 0)
{
if (nindexes == 0)
{
/* Remove tuples from heap if the table has no index */
- lazy_vacuum_page(onerel, blkno, buf, 0, vacrelstats, &vmbuffer);
+ lazy_vacuum_page(onerel, blkno, buf, 0, &vmbuffer);
vacuumed_pages++;
has_dead_tuples = false;
}
@@ -1465,7 +1461,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* Instead of vacuuming the dead tuples on the heap, we just
* forget them.
*
- * Note that vacrelstats->dead_tuples could have tuples which
+ * Note that vacrelstats.dead_tuples could have tuples which
* became dead after HOT-pruning but are not marked dead yet.
* We do not process them because it's a very rare condition,
* and the next vacuum will process them anyway.
@@ -1584,7 +1580,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
/* Remember the location of the last page with nonremovable tuples */
if (hastup)
- vacrelstats->nonempty_pages = blkno + 1;
+ vacrelstats.nonempty_pages = blkno + 1;
/*
* If we remembered any tuples for deletion, then the page will be
@@ -1603,18 +1599,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pfree(frozen);
/* save stats for use later */
- vacrelstats->tuples_deleted = tups_vacuumed;
- vacrelstats->new_dead_tuples = nkeep;
+ vacrelstats.tuples_deleted = tups_vacuumed;
+ vacrelstats.new_dead_tuples = nkeep;
/* now we can compute the new value for pg_class.reltuples */
- vacrelstats->new_live_tuples = vac_estimate_reltuples(onerel,
+ vacrelstats.new_live_tuples = vac_estimate_reltuples(onerel,
nblocks,
- vacrelstats->tupcount_pages,
+ vacrelstats.tupcount_pages,
live_tuples);
/* also compute total number of surviving heap entries */
- vacrelstats->new_rel_tuples =
- vacrelstats->new_live_tuples + vacrelstats->new_dead_tuples;
+ vacrelstats.new_rel_tuples =
+ vacrelstats.new_live_tuples + vacrelstats.new_dead_tuples;
/*
* Release any remaining pin on visibility map page.
@@ -1630,11 +1626,11 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
if (dead_tuples->num_tuples > 0)
{
/* Work on all the indexes, and then the heap */
- lazy_vacuum_all_indexes(onerel, Irel, indstats, vacrelstats,
+ lazy_vacuum_all_indexes(onerel, Irel, indstats,
lps, nindexes);
/* Remove tuples from heap */
- lazy_vacuum_heap(onerel, vacrelstats);
+ lazy_vacuum_heap(onerel);
}
/*
@@ -1648,8 +1644,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_VACUUMED, blkno);
/* Do post-vacuum cleanup */
- if (vacrelstats->useindex)
- lazy_cleanup_all_indexes(Irel, indstats, vacrelstats, lps, nindexes);
+ if (vacrelstats.useindex)
+ lazy_cleanup_all_indexes(Irel, indstats, lps, nindexes);
/*
* End parallel mode before updating index statistics as we cannot write
@@ -1680,12 +1676,12 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
nunused);
appendStringInfo(&buf, ngettext("Skipped %u page due to buffer pins, ",
"Skipped %u pages due to buffer pins, ",
- vacrelstats->pinskipped_pages),
- vacrelstats->pinskipped_pages);
+ vacrelstats.pinskipped_pages),
+ vacrelstats.pinskipped_pages);
appendStringInfo(&buf, ngettext("%u frozen page.\n",
"%u frozen pages.\n",
- vacrelstats->frozenskipped_pages),
- vacrelstats->frozenskipped_pages);
+ vacrelstats.frozenskipped_pages),
+ vacrelstats.frozenskipped_pages);
appendStringInfo(&buf, ngettext("%u page is entirely empty.\n",
"%u pages are entirely empty.\n",
empty_pages),
@@ -1696,7 +1692,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
(errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u out of %u pages",
RelationGetRelationName(onerel),
tups_vacuumed, num_tuples,
- vacrelstats->scanned_pages, nblocks),
+ vacrelstats.scanned_pages, nblocks),
errdetail_internal("%s", buf.data)));
pfree(buf.data);
}
@@ -1709,14 +1705,14 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
static void
lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes)
{
Assert(!IsParallelWorker());
Assert(nindexes > 0);
/* Log cleanup info before we touch indexes */
- vacuum_log_cleanup_info(onerel, vacrelstats);
+ vacuum_log_cleanup_info(onerel);
/* Report that we are now vacuuming indexes */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
@@ -1733,24 +1729,24 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
* We can only provide an approximate value of num_heap_tuples in
* vacuum cases.
*/
- lps->lvshared->reltuples = vacrelstats->old_live_tuples;
+ lps->lvshared->reltuples = vacrelstats.old_live_tuples;
lps->lvshared->estimated_count = true;
- lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes);
+ lazy_parallel_vacuum_indexes(Irel, stats, lps, nindexes);
}
else
{
int idx;
for (idx = 0; idx < nindexes; idx++)
- lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats->dead_tuples,
- vacrelstats->old_live_tuples);
+ lazy_vacuum_index(Irel[idx], &stats[idx], vacrelstats.dead_tuples,
+ vacrelstats.old_live_tuples);
}
/* Increase and report the number of index scans */
- vacrelstats->num_index_scans++;
+ vacrelstats.num_index_scans++;
pgstat_progress_update_param(PROGRESS_VACUUM_NUM_INDEX_VACUUMS,
- vacrelstats->num_index_scans);
+ vacrelstats.num_index_scans);
}
@@ -1766,7 +1762,7 @@ lazy_vacuum_all_indexes(Relation onerel, Relation *Irel,
* process index entry removal in batches as large as possible.
*/
static void
-lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
+lazy_vacuum_heap(Relation onerel)
{
int tupindex;
int npages;
@@ -1781,7 +1777,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
npages = 0;
tupindex = 0;
- while (tupindex < vacrelstats->dead_tuples->num_tuples)
+ while (tupindex < vacrelstats.dead_tuples->num_tuples)
{
BlockNumber tblk;
Buffer buf;
@@ -1790,7 +1786,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
vacuum_delay_point();
- tblk = ItemPointerGetBlockNumber(&vacrelstats->dead_tuples->itemptrs[tupindex]);
+ tblk = ItemPointerGetBlockNumber(&vacrelstats.dead_tuples->itemptrs[tupindex]);
buf = ReadBufferExtended(onerel, MAIN_FORKNUM, tblk, RBM_NORMAL,
vac_strategy);
if (!ConditionalLockBufferForCleanup(buf))
@@ -1799,7 +1795,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
++tupindex;
continue;
}
- tupindex = lazy_vacuum_page(onerel, tblk, buf, tupindex, vacrelstats,
+ tupindex = lazy_vacuum_page(onerel, tblk, buf, tupindex,
&vmbuffer);
/* Now that we've compacted the page, record its available space */
@@ -1836,9 +1832,9 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
*/
static int
lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
- int tupindex, LVRelStats *vacrelstats, Buffer *vmbuffer)
+ int tupindex, Buffer *vmbuffer)
{
- LVDeadTuples *dead_tuples = vacrelstats->dead_tuples;
+ LVDeadTuples *dead_tuples = vacrelstats.dead_tuples;
Page page = BufferGetPage(buffer);
OffsetNumber unused[MaxOffsetNumber];
int uncnt = 0;
@@ -1879,7 +1875,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
recptr = log_heap_clean(onerel, buffer,
NULL, 0, NULL, 0,
unused, uncnt,
- vacrelstats->latestRemovedXid);
+ vacrelstats.latestRemovedXid);
PageSetLSN(page, recptr);
}
@@ -1987,7 +1983,7 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup)
*/
static void
lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes)
{
int nworkers;
@@ -2021,7 +2017,7 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
/* Setup the shared cost-based vacuum delay and launch workers */
if (nworkers > 0)
{
- if (vacrelstats->num_index_scans > 0)
+ if (vacrelstats.num_index_scans > 0)
{
/* Reset the parallel index processing counter */
pg_atomic_write_u32(&(lps->lvshared->idx), 0);
@@ -2076,14 +2072,14 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
}
/* Process the indexes that can be processed by only leader process */
- vacuum_indexes_leader(Irel, stats, vacrelstats, lps, nindexes);
+ vacuum_indexes_leader(Irel, stats, lps, nindexes);
/*
* Join as a parallel worker. The leader process alone processes all the
* indexes in the case where no workers are launched.
*/
parallel_vacuum_index(Irel, stats, lps->lvshared,
- vacrelstats->dead_tuples, nindexes);
+ vacrelstats.dead_tuples, nindexes);
/* Wait for all vacuum workers to finish */
WaitForParallelWorkersToFinish(lps->pcxt);
@@ -2157,7 +2153,7 @@ parallel_vacuum_index(Relation *Irel, IndexBulkDeleteResult **stats,
*/
static void
vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes)
{
int i;
@@ -2180,7 +2176,7 @@ vacuum_indexes_leader(Relation *Irel, IndexBulkDeleteResult **stats,
if (shared_indstats == NULL ||
skip_parallel_vacuum_index(Irel[i], lps->lvshared))
vacuum_one_index(Irel[i], &(stats[i]), lps->lvshared,
- shared_indstats, vacrelstats->dead_tuples);
+ shared_indstats, vacrelstats.dead_tuples);
}
/*
@@ -2259,7 +2255,7 @@ vacuum_one_index(Relation indrel, IndexBulkDeleteResult **stats,
*/
static void
lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
- LVRelStats *vacrelstats, LVParallelState *lps,
+ LVParallelState *lps,
int nindexes)
{
int idx;
@@ -2280,25 +2276,25 @@ lazy_cleanup_all_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
/* Tell parallel workers to do index cleanup */
lps->lvshared->for_cleanup = true;
lps->lvshared->first_time =
- (vacrelstats->num_index_scans == 0);
+ (vacrelstats.num_index_scans == 0);
/*
* Now we can provide a better estimate of total number of surviving
* tuples (we assume indexes are more interested in that than in the
* number of nominally live tuples).
*/
- lps->lvshared->reltuples = vacrelstats->new_rel_tuples;
+ lps->lvshared->reltuples = vacrelstats.new_rel_tuples;
lps->lvshared->estimated_count =
- (vacrelstats->tupcount_pages < vacrelstats->rel_pages);
+ (vacrelstats.tupcount_pages < vacrelstats.rel_pages);
- lazy_parallel_vacuum_indexes(Irel, stats, vacrelstats, lps, nindexes);
+ lazy_parallel_vacuum_indexes(Irel, stats, lps, nindexes);
}
else
{
for (idx = 0; idx < nindexes; idx++)
lazy_cleanup_index(Irel[idx], &stats[idx],
- vacrelstats->new_rel_tuples,
- vacrelstats->tupcount_pages < vacrelstats->rel_pages);
+ vacrelstats.new_rel_tuples,
+ vacrelstats.tupcount_pages < vacrelstats.rel_pages);
}
}
@@ -2414,17 +2410,17 @@ lazy_cleanup_index(Relation indrel,
* careful to depend only on fields that lazy_scan_heap updates on-the-fly.
*/
static bool
-should_attempt_truncation(VacuumParams *params, LVRelStats *vacrelstats)
+should_attempt_truncation(VacuumParams *params)
{
BlockNumber possibly_freeable;
if (params->truncate == VACOPT_TERNARY_DISABLED)
return false;
- possibly_freeable = vacrelstats->rel_pages - vacrelstats->nonempty_pages;
+ possibly_freeable = vacrelstats.rel_pages - vacrelstats.nonempty_pages;
if (possibly_freeable > 0 &&
(possibly_freeable >= REL_TRUNCATE_MINIMUM ||
- possibly_freeable >= vacrelstats->rel_pages / REL_TRUNCATE_FRACTION) &&
+ possibly_freeable >= vacrelstats.rel_pages / REL_TRUNCATE_FRACTION) &&
old_snapshot_threshold < 0)
return true;
else
@@ -2435,9 +2431,9 @@ should_attempt_truncation(VacuumParams *params, LVRelStats *vacrelstats)
* lazy_truncate_heap - try to truncate off any empty pages at the end
*/
static void
-lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
+lazy_truncate_heap(Relation onerel)
{
- BlockNumber old_rel_pages = vacrelstats->rel_pages;
+ BlockNumber old_rel_pages = vacrelstats.rel_pages;
BlockNumber new_rel_pages;
PGRUsage ru0;
int lock_retry;
@@ -2460,7 +2456,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* (which is quite possible considering we already hold a lower-grade
* lock).
*/
- vacrelstats->lock_waiter_detected = false;
+ vacrelstats.lock_waiter_detected = false;
lock_retry = 0;
while (true)
{
@@ -2480,7 +2476,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* We failed to establish the lock in the specified number of
* retries. This means we give up truncating.
*/
- vacrelstats->lock_waiter_detected = true;
+ vacrelstats.lock_waiter_detected = true;
ereport(elevel,
(errmsg("\"%s\": stopping truncate due to conflicting lock request",
RelationGetRelationName(onerel))));
@@ -2499,7 +2495,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
if (new_rel_pages != old_rel_pages)
{
/*
- * Note: we intentionally don't update vacrelstats->rel_pages with
+ * Note: we intentionally don't update vacrelstats.rel_pages with
* the new rel size here. If we did, it would amount to assuming
* that the new pages are empty, which is unlikely. Leaving the
* numbers alone amounts to assuming that the new pages have the
@@ -2515,7 +2511,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* other backends could have added tuples to these pages whilst we
* were vacuuming.
*/
- new_rel_pages = count_nondeletable_pages(onerel, vacrelstats);
+ new_rel_pages = count_nondeletable_pages(onerel);
if (new_rel_pages >= old_rel_pages)
{
@@ -2543,8 +2539,8 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* without also touching reltuples, since the tuple count wasn't
* changed by the truncation.
*/
- vacrelstats->pages_removed += old_rel_pages - new_rel_pages;
- vacrelstats->rel_pages = new_rel_pages;
+ vacrelstats.pages_removed += old_rel_pages - new_rel_pages;
+ vacrelstats.rel_pages = new_rel_pages;
ereport(elevel,
(errmsg("\"%s\": truncated %u to %u pages",
@@ -2553,8 +2549,8 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
errdetail_internal("%s",
pg_rusage_show(&ru0))));
old_rel_pages = new_rel_pages;
- } while (new_rel_pages > vacrelstats->nonempty_pages &&
- vacrelstats->lock_waiter_detected);
+ } while (new_rel_pages > vacrelstats.nonempty_pages &&
+ vacrelstats.lock_waiter_detected);
}
/*
@@ -2563,7 +2559,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats)
* Returns number of nondeletable pages (last nonempty page + 1).
*/
static BlockNumber
-count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
+count_nondeletable_pages(Relation onerel)
{
BlockNumber blkno;
BlockNumber prefetchedUntil;
@@ -2578,11 +2574,11 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
* unsigned.) To make the scan faster, we prefetch a few blocks at a time
* in forward direction, so that OS-level readahead can kick in.
*/
- blkno = vacrelstats->rel_pages;
+ blkno = vacrelstats.rel_pages;
StaticAssertStmt((PREFETCH_SIZE & (PREFETCH_SIZE - 1)) == 0,
"prefetch size must be power of 2");
prefetchedUntil = InvalidBlockNumber;
- while (blkno > vacrelstats->nonempty_pages)
+ while (blkno > vacrelstats.nonempty_pages)
{
Buffer buf;
Page page;
@@ -2615,7 +2611,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
(errmsg("\"%s\": suspending truncate due to conflicting lock request",
RelationGetRelationName(onerel))));
- vacrelstats->lock_waiter_detected = true;
+ vacrelstats.lock_waiter_detected = true;
return blkno;
}
starttime = currenttime;
@@ -2695,7 +2691,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats)
* pages still are; we need not bother to look at the last known-nonempty
* page.
*/
- return vacrelstats->nonempty_pages;
+ return vacrelstats.nonempty_pages;
}
/*
@@ -2734,18 +2730,18 @@ compute_max_dead_tuples(BlockNumber relblocks, bool useindex)
* See the comments at the head of this file for rationale.
*/
static void
-lazy_space_alloc(LVRelStats *vacrelstats, BlockNumber relblocks)
+lazy_space_alloc(BlockNumber relblocks)
{
LVDeadTuples *dead_tuples = NULL;
long maxtuples;
- maxtuples = compute_max_dead_tuples(relblocks, vacrelstats->useindex);
+ maxtuples = compute_max_dead_tuples(relblocks, vacrelstats.useindex);
dead_tuples = (LVDeadTuples *) palloc(SizeOfDeadTuples(maxtuples));
dead_tuples->num_tuples = 0;
dead_tuples->max_tuples = (int) maxtuples;
- vacrelstats->dead_tuples = dead_tuples;
+ vacrelstats.dead_tuples = dead_tuples;
}
/*
@@ -3063,7 +3059,7 @@ update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats,
* create a parallel context, and then initialize the DSM segment.
*/
static LVParallelState *
-begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
+begin_parallel_vacuum(Oid relid, Relation *Irel,
BlockNumber nblocks, int nindexes, int nrequested)
{
LVParallelState *lps = NULL;
@@ -3185,7 +3181,7 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
dead_tuples->num_tuples = 0;
MemSet(dead_tuples->itemptrs, 0, sizeof(ItemPointerData) * maxtuples);
shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_DEAD_TUPLES, dead_tuples);
- vacrelstats->dead_tuples = dead_tuples;
+ vacrelstats.dead_tuples = dead_tuples;
/* Store query string for workers */
sharedquery = (char *) shm_toc_allocate(pcxt->toc, querylen + 1);
--
2.7.4
>From 592a77554f99b5ff9035c55bf19a79a1443ae59e Mon Sep 17 00:00:00 2001
From: Justin Pryzby <[email protected]>
Date: Thu, 12 Dec 2019 20:54:37 -0600
Subject: [PATCH v14 2/3] vacuum errcontext to show block being processed
As requested here.
https://www.postgresql.org/message-id/20190807235154.erbmr4o4bo6vgnjv%40alap3.anarazel.de
---
src/backend/access/heap/vacuumlazy.c | 85 +++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 114428b..a62dc79 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -290,8 +290,14 @@ typedef struct LVRelStats
int num_index_scans;
TransactionId latestRemovedXid;
bool lock_waiter_detected;
-} LVRelStats;
+ /* Used by the error callback */
+ char *relname;
+ char *relnamespace;
+ BlockNumber blkno;
+ char *indname;
+ int stage; /* 0: scan heap; 1: vacuum heap; 2: vacuum index */
+} LVRelStats;
/* A few variables that don't seem worth passing around as parameters */
static int elevel = -1;
@@ -360,6 +366,7 @@ static void end_parallel_vacuum(Relation *Irel, IndexBulkDeleteResult **stats,
LVParallelState *lps, int nindexes);
static LVSharedIndStats *get_indstats(LVShared *lvshared, int n);
static bool skip_parallel_vacuum_index(Relation indrel, LVShared *lvshared);
+static void vacuum_error_callback(void *arg);
/*
@@ -721,6 +728,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
PROGRESS_VACUUM_MAX_DEAD_TUPLES
};
int64 initprog_val[3];
+ ErrorContextCallback errcallback;
pg_rusage_init(&ru0);
@@ -867,6 +875,17 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
else
skipping_blocks = false;
+ /* Setup error traceback support for ereport() */
+ vacrelstats.relnamespace = get_namespace_name(RelationGetNamespace(onerel));
+ vacrelstats.relname = relname;
+ vacrelstats.blkno = InvalidBlockNumber; /* Not known yet */
+ vacrelstats.stage = 0;
+
+ errcallback.callback = vacuum_error_callback;
+ errcallback.arg = (void *) &vacrelstats;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+
for (blkno = 0; blkno < nblocks; blkno++)
{
Buffer buf;
@@ -888,6 +907,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
#define FORCE_CHECK_PAGE() \
(blkno == nblocks - 1 && should_attempt_truncation(params))
+ vacrelstats.blkno = blkno;
+
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_SCANNED, blkno);
if (blkno == next_unskippable_block)
@@ -984,12 +1005,18 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
vmbuffer = InvalidBuffer;
}
+ /* Pop the error context stack */
+ error_context_stack = errcallback.previous;
+
/* Work on all the indexes, then the heap */
lazy_vacuum_all_indexes(onerel, Irel, indstats,
lps, nindexes);
/* Remove tuples from heap */
lazy_vacuum_heap(onerel);
+ /* Replace error context while continuing heap scan */
+ error_context_stack = &errcallback;
+
/*
* Forget the now-vacuumed tuples, and press on, but be careful
* not to reset latestRemovedXid since we want that value to be
@@ -1593,6 +1620,9 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
RecordPageWithFreeSpace(onerel, blkno, freespace);
}
+ /* Pop the error context stack */
+ error_context_stack = errcallback.previous;
+
/* report that everything is scanned and vacuumed */
pgstat_progress_update_param(PROGRESS_VACUUM_HEAP_BLKS_SCANNED, blkno);
@@ -1768,11 +1798,24 @@ lazy_vacuum_heap(Relation onerel)
int npages;
PGRUsage ru0;
Buffer vmbuffer = InvalidBuffer;
+ ErrorContextCallback errcallback;
/* Report that we are now vacuuming the heap */
pgstat_progress_update_param(PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_PHASE_VACUUM_HEAP);
+ /*
+ * Setup error traceback support for ereport()
+ * ->relnamespace and ->relname are already set
+ */
+ vacrelstats.blkno = InvalidBlockNumber; /* Not known yet */
+ vacrelstats.stage = 1;
+
+ errcallback.callback = vacuum_error_callback;
+ errcallback.arg = (void *) &vacrelstats;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+
pg_rusage_init(&ru0);
npages = 0;
@@ -1787,6 +1830,7 @@ lazy_vacuum_heap(Relation onerel)
vacuum_delay_point();
tblk = ItemPointerGetBlockNumber(&vacrelstats.dead_tuples->itemptrs[tupindex]);
+ vacrelstats.blkno = tblk;
buf = ReadBufferExtended(onerel, MAIN_FORKNUM, tblk, RBM_NORMAL,
vac_strategy);
if (!ConditionalLockBufferForCleanup(buf))
@@ -1807,6 +1851,9 @@ lazy_vacuum_heap(Relation onerel)
npages++;
}
+ /* Pop the error context stack */
+ error_context_stack = errcallback.previous;
+
if (BufferIsValid(vmbuffer))
{
ReleaseBuffer(vmbuffer);
@@ -2314,6 +2361,8 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
IndexVacuumInfo ivinfo;
const char *msg;
PGRUsage ru0;
+ ErrorContextCallback errcallback;
+ LVRelStats errcbarg; /* Used for error callback, only */
pg_rusage_init(&ru0);
@@ -2325,10 +2374,24 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
ivinfo.num_heap_tuples = reltuples;
ivinfo.strategy = vac_strategy;
+ /* Setup error traceback support for ereport() */
+ errcbarg.relnamespace = get_namespace_name(RelationGetNamespace(indrel));
+ errcbarg.indname = RelationGetRelationName(indrel);
+ errcbarg.relname = vacrelstats.relname;
+ errcbarg.stage = 2;
+
+ errcallback.callback = vacuum_error_callback;
+ errcallback.arg = (void *) &errcbarg;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+
/* Do bulk deletion */
*stats = index_bulk_delete(&ivinfo, *stats,
lazy_tid_reaped, (void *) dead_tuples);
+ /* Pop the error context stack */
+ error_context_stack = errcallback.previous;
+
if (IsParallelWorker())
msg = gettext_noop("scanned index \"%s\" to remove %d row versions by parallel vacuum worker");
else
@@ -3371,3 +3434,23 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
table_close(onerel, ShareUpdateExclusiveLock);
pfree(stats);
}
+
+/*
+ * Error context callback for errors occurring during vacuum.
+ */
+static void
+vacuum_error_callback(void *arg)
+{
+ LVRelStats *cbarg = arg;
+
+ if (cbarg->stage == 0)
+ errcontext(_("while scanning block %u of relation \"%s.%s\""),
+ cbarg->blkno, cbarg->relnamespace, cbarg->relname);
+ else if (cbarg->stage == 1)
+ errcontext(_("while vacuuming block %u of relation \"%s.%s\""),
+ cbarg->blkno, cbarg->relnamespace, cbarg->relname);
+ else if (cbarg->stage == 2)
+ errcontext(_("while vacuuming index \"%s\" on table \"%s.%s\""),
+ cbarg->indname, cbarg->relnamespace, cbarg->relname);
+
+}
--
2.7.4
>From 7c76861addf213b3b417d783b04b12112fc468f1 Mon Sep 17 00:00:00 2001
From: Justin Pryzby <[email protected]>
Date: Mon, 20 Jan 2020 15:26:39 -0600
Subject: [PATCH v14 3/3] Avoid extra calls like GetRelationName
---
src/backend/access/heap/vacuumlazy.c | 75 ++++++++++++++++++------------------
1 file changed, 37 insertions(+), 38 deletions(-)
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index a62dc79..1841e7c 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -270,6 +270,9 @@ typedef struct LVParallelState
typedef struct LVRelStats
{
+ char *relname;
+ char *relnamespace;
+
/* useindex = true means two-pass strategy; false means one-pass */
bool useindex;
/* Overall statistics about rel */
@@ -292,8 +295,6 @@ typedef struct LVRelStats
bool lock_waiter_detected;
/* Used by the error callback */
- char *relname;
- char *relnamespace;
BlockNumber blkno;
char *indname;
int stage; /* 0: scan heap; 1: vacuum heap; 2: vacuum index */
@@ -603,8 +604,8 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
}
appendStringInfo(&buf, msgfmt,
get_database_name(MyDatabaseId),
- get_namespace_name(RelationGetNamespace(onerel)),
- RelationGetRelationName(onerel),
+ vacrelstats.relnamespace,
+ vacrelstats.relname,
vacrelstats.num_index_scans);
appendStringInfo(&buf, _("pages: %u removed, %u remain, %u skipped due to pins, %u skipped frozen\n"),
vacrelstats.pages_removed,
@@ -703,7 +704,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
BlockNumber nblocks,
blkno;
HeapTupleData tuple;
- char *relname;
TransactionId relfrozenxid = onerel->rd_rel->relfrozenxid;
TransactionId relminmxid = onerel->rd_rel->relminmxid;
BlockNumber empty_pages,
@@ -732,18 +732,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
pg_rusage_init(&ru0);
- relname = RelationGetRelationName(onerel);
- if (aggressive)
- ereport(elevel,
- (errmsg("aggressively vacuuming \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(onerel)),
- relname)));
- else
- ereport(elevel,
- (errmsg("vacuuming \"%s.%s\"",
- get_namespace_name(RelationGetNamespace(onerel)),
- relname)));
-
empty_pages = vacuumed_pages = 0;
next_fsm_block_to_vacuum = (BlockNumber) 0;
num_tuples = live_tuples = tups_vacuumed = nkeep = nunused = 0;
@@ -758,6 +746,28 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
vacrelstats.nonempty_pages = 0;
vacrelstats.latestRemovedXid = InvalidTransactionId;
+ vacrelstats.relnamespace = get_namespace_name(RelationGetNamespace(onerel));
+ vacrelstats.relname = RelationGetRelationName(onerel);
+ vacrelstats.blkno = InvalidBlockNumber; /* Not known yet */
+ vacrelstats.stage = 0;
+
+ if (aggressive)
+ ereport(elevel,
+ (errmsg("aggressively vacuuming \"%s.%s\"",
+ vacrelstats.relnamespace,
+ vacrelstats.relname)));
+ else
+ ereport(elevel,
+ (errmsg("vacuuming \"%s.%s\"",
+ vacrelstats.relnamespace,
+ vacrelstats.relname)));
+
+ /* Setup error traceback support for ereport() */
+ errcallback.callback = vacuum_error_callback;
+ errcallback.arg = (void *) &vacrelstats;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+
/*
* Initialize the state for a parallel vacuum. As of now, only one worker
* can be used for an index, so we invoke parallelism only if there are at
@@ -778,7 +788,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
if (params->nworkers > 0)
ereport(WARNING,
(errmsg("disabling parallel option of vacuum on \"%s\" --- cannot vacuum temporary tables in parallel",
- RelationGetRelationName(onerel))));
+ vacrelstats.relname)));
}
else
lps = begin_parallel_vacuum(RelationGetRelid(onerel), Irel,
@@ -875,17 +885,6 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
else
skipping_blocks = false;
- /* Setup error traceback support for ereport() */
- vacrelstats.relnamespace = get_namespace_name(RelationGetNamespace(onerel));
- vacrelstats.relname = relname;
- vacrelstats.blkno = InvalidBlockNumber; /* Not known yet */
- vacrelstats.stage = 0;
-
- errcallback.callback = vacuum_error_callback;
- errcallback.arg = (void *) &vacrelstats;
- errcallback.previous = error_context_stack;
- error_context_stack = &errcallback;
-
for (blkno = 0; blkno < nblocks; blkno++)
{
Buffer buf;
@@ -1557,7 +1556,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
&& VM_ALL_VISIBLE(onerel, blkno, &vmbuffer))
{
elog(WARNING, "page is not marked all-visible but visibility map bit is set in relation \"%s\" page %u",
- relname, blkno);
+ vacrelstats.relname, blkno);
visibilitymap_clear(onerel, blkno, vmbuffer,
VISIBILITYMAP_VALID_BITS);
}
@@ -1578,7 +1577,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
else if (PageIsAllVisible(page) && has_dead_tuples)
{
elog(WARNING, "page containing dead tuples is marked as all-visible in relation \"%s\" page %u",
- relname, blkno);
+ vacrelstats.relname, blkno);
PageClearAllVisible(page);
MarkBufferDirty(buf);
visibilitymap_clear(onerel, blkno, vmbuffer,
@@ -1691,7 +1690,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
if (vacuumed_pages)
ereport(elevel,
(errmsg("\"%s\": removed %.0f row versions in %u pages",
- RelationGetRelationName(onerel),
+ vacrelstats.relname,
tups_vacuumed, vacuumed_pages)));
/*
@@ -1720,7 +1719,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params,
ereport(elevel,
(errmsg("\"%s\": found %.0f removable, %.0f nonremovable row versions in %u out of %u pages",
- RelationGetRelationName(onerel),
+ vacrelstats.relname,
tups_vacuumed, num_tuples,
vacrelstats.scanned_pages, nblocks),
errdetail_internal("%s", buf.data)));
@@ -1862,7 +1861,7 @@ lazy_vacuum_heap(Relation onerel)
ereport(elevel,
(errmsg("\"%s\": removed %d row versions in %d pages",
- RelationGetRelationName(onerel),
+ vacrelstats.relname,
tupindex, npages),
errdetail_internal("%s", pg_rusage_show(&ru0))));
}
@@ -2399,7 +2398,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
ereport(elevel,
(errmsg(msg,
- RelationGetRelationName(indrel),
+ vacrelstats.relname,
dead_tuples->num_tuples),
errdetail_internal("%s", pg_rusage_show(&ru0))));
}
@@ -2542,7 +2541,7 @@ lazy_truncate_heap(Relation onerel)
vacrelstats.lock_waiter_detected = true;
ereport(elevel,
(errmsg("\"%s\": stopping truncate due to conflicting lock request",
- RelationGetRelationName(onerel))));
+ vacrelstats.relname)));
return;
}
@@ -2607,7 +2606,7 @@ lazy_truncate_heap(Relation onerel)
ereport(elevel,
(errmsg("\"%s\": truncated %u to %u pages",
- RelationGetRelationName(onerel),
+ vacrelstats.relname,
old_rel_pages, new_rel_pages),
errdetail_internal("%s",
pg_rusage_show(&ru0))));
@@ -2672,7 +2671,7 @@ count_nondeletable_pages(Relation onerel)
{
ereport(elevel,
(errmsg("\"%s\": suspending truncate due to conflicting lock request",
- RelationGetRelationName(onerel))));
+ vacrelstats.relname)));
vacrelstats.lock_waiter_detected = true;
return blkno;
--
2.7.4