/* Error reporting state */
char *relnamespace;
char *relname;
- char *indname;
+ char *indname; /* Current index name */
BlockNumber blkno; /* used only for heap operations */
OffsetNumber offnum; /* used only for heap operations */
VacErrPhase phase;
+ bool verbose; /* VACUUM VERBOSE? */
/*
* State managed by lazy_scan_heap() follows.
VacErrPhase phase;
} LVSavedErrInfo;
-/* elevel controls whole VACUUM's verbosity */
-static int elevel = -1;
-
/* non-export function prototypes */
static void lazy_scan_heap(LVRelState *vacrel, VacuumParams *params,
BufferAccessStrategy bstrategy)
{
LVRelState *vacrel;
+ bool verbose,
+ instrument;
PGRUsage ru0;
TimestampTz starttime = 0;
WalUsage walusage_start = pgWalUsage;
TransactionId FreezeLimit;
MultiXactId MultiXactCutoff;
- /* measure elapsed time iff autovacuum logging requires it */
- if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
+ verbose = (params->options & VACOPT_VERBOSE) != 0;
+ instrument = (verbose || (IsAutoVacuumWorkerProcess() &&
+ params->log_min_duration >= 0));
+ if (instrument)
{
pg_rusage_init(&ru0);
starttime = GetCurrentTimestamp();
}
}
- if (params->options & VACOPT_VERBOSE)
- elevel = INFO;
- else
- elevel = DEBUG2;
-
pgstat_progress_start_command(PROGRESS_COMMAND_VACUUM,
RelationGetRelid(rel));
if (params->options & VACOPT_DISABLE_PAGE_SKIPPING)
aggressive = true;
+ /*
+ * Setup error traceback support for ereport() first. The idea is to set
+ * up an error context callback to display additional information on any
+ * error during a vacuum. During different phases of vacuum, we update
+ * the state so that the error context callback always display current
+ * information.
+ *
+ * Copy the names of heap rel into local memory for error reporting
+ * purposes, too. It isn't always safe to assume that we can get the name
+ * of each rel. It's convenient for code in lazy_scan_heap to always use
+ * these temp copies.
+ */
vacrel = (LVRelState *) palloc0(sizeof(LVRelState));
+ vacrel->relnamespace = get_namespace_name(RelationGetNamespace(rel));
+ vacrel->relname = pstrdup(RelationGetRelationName(rel));
+ vacrel->indname = NULL;
+ vacrel->phase = VACUUM_ERRCB_PHASE_UNKNOWN;
+ vacrel->verbose = verbose;
+ errcallback.callback = vacuum_error_callback;
+ errcallback.arg = vacrel;
+ errcallback.previous = error_context_stack;
+ error_context_stack = &errcallback;
+ if (verbose)
+ {
+ Assert(!IsAutoVacuumWorkerProcess());
+ if (aggressive)
+ ereport(INFO,
+ (errmsg("aggressively vacuuming \"%s.%s.%s\"",
+ get_database_name(MyDatabaseId),
+ vacrel->relnamespace, vacrel->relname)));
+ else
+ ereport(INFO,
+ (errmsg("vacuuming \"%s.%s.%s\"",
+ get_database_name(MyDatabaseId),
+ vacrel->relnamespace, vacrel->relname)));
+ }
- /* Set up high level stuff about rel */
+ /* Set up high level stuff about rel and its indexes */
vacrel->rel = rel;
vac_open_indexes(vacrel->rel, RowExclusiveLock, &vacrel->nindexes,
&vacrel->indrels);
- vacrel->failsafe_active = false;
- vacrel->consider_bypass_optimization = true;
+ if (instrument && vacrel->nindexes > 0)
+ {
+ /* Copy index names used by instrumentation (not error reporting) */
+ indnames = palloc(sizeof(char *) * vacrel->nindexes);
+ for (int i = 0; i < vacrel->nindexes; i++)
+ indnames[i] = pstrdup(RelationGetRelationName(vacrel->indrels[i]));
+ }
/*
* The index_cleanup param either disables index vacuuming and cleanup or
Assert(params->index_cleanup != VACOPTVALUE_UNSPECIFIED);
Assert(params->truncate != VACOPTVALUE_UNSPECIFIED &&
params->truncate != VACOPTVALUE_AUTO);
+ vacrel->failsafe_active = false;
+ vacrel->consider_bypass_optimization = true;
vacrel->do_index_vacuuming = true;
vacrel->do_index_cleanup = true;
vacrel->do_rel_truncate = (params->truncate != VACOPTVALUE_DISABLED);
vacrel->FreezeLimit = FreezeLimit;
vacrel->MultiXactCutoff = MultiXactCutoff;
- vacrel->relnamespace = get_namespace_name(RelationGetNamespace(rel));
- vacrel->relname = pstrdup(RelationGetRelationName(rel));
- vacrel->indname = NULL;
- vacrel->phase = VACUUM_ERRCB_PHASE_UNKNOWN;
-
- /* Save index names iff autovacuum logging requires it */
- if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0 &&
- vacrel->nindexes > 0)
- {
- indnames = palloc(sizeof(char *) * vacrel->nindexes);
- for (int i = 0; i < vacrel->nindexes; i++)
- indnames[i] =
- pstrdup(RelationGetRelationName(vacrel->indrels[i]));
- }
-
- /*
- * Setup error traceback support for ereport(). The idea is to set up an
- * error context callback to display additional information on any error
- * during a vacuum. During different phases of vacuum (heap scan, heap
- * vacuum, index vacuum, index clean up, heap truncate), we update the
- * error context callback to display appropriate information.
- *
- * Note that the index vacuum and heap vacuum phases may be called
- * multiple times in the middle of the heap scan phase. So the old phase
- * information is restored at the end of those phases.
- */
- errcallback.callback = vacuum_error_callback;
- errcallback.arg = vacrel;
- errcallback.previous = error_context_stack;
- error_context_stack = &errcallback;
-
/*
* Call lazy_scan_heap to perform all required heap pruning, index
* vacuuming, and heap vacuuming (plus related processing)
*/
if (should_attempt_truncation(vacrel))
{
- /*
- * Update error traceback information. This is the last phase during
- * which we add context information to errors, so we don't need to
- * revert to the previous phase.
- */
update_vacuum_error_info(vacrel, NULL, VACUUM_ERRCB_PHASE_TRUNCATE,
vacrel->nonempty_pages,
InvalidOffsetNumber);
vacrel->new_dead_tuples);
pgstat_progress_end_command();
- /* and log the action if appropriate */
- if (IsAutoVacuumWorkerProcess() && params->log_min_duration >= 0)
+ if (instrument)
{
TimestampTz endtime = GetCurrentTimestamp();
- if (params->log_min_duration == 0 ||
+ if (verbose || params->log_min_duration == 0 ||
TimestampDifferenceExceeds(starttime, endtime,
params->log_min_duration))
{
(secs + usecs / 1000000.0);
}
- /*
- * This is pretty messy, but we split it up so that we can skip
- * emitting individual parts of the message when not applicable.
- */
initStringInfo(&buf);
- if (params->is_wraparound)
+ if (verbose)
+ {
+ /*
+ * Aggressiveness already reported earlier, in dedicated
+ * VACUUM VERBOSE ereport
+ */
+ Assert(!params->is_wraparound);
+ msgfmt = _("finished vacuuming \"%s.%s.%s\": index scans: %d\n");
+ }
+ else if (params->is_wraparound)
{
/*
* While it's possible for a VACUUM to be both is_wraparound
(unsigned long long) walusage.wal_bytes);
appendStringInfo(&buf, _("system usage: %s"), pg_rusage_show(&ru0));
- ereport(LOG,
+ ereport(verbose ? INFO : LOG,
(errmsg_internal("%s", buf.data)));
pfree(buf.data);
}
if (vacrel->indstats[i])
pfree(vacrel->indstats[i]);
- if (indnames && indnames[i])
+ if (instrument)
pfree(indnames[i]);
}
}
next_unskippable_block,
next_failsafe_block,
next_fsm_block_to_vacuum;
- PGRUsage ru0;
Buffer vmbuffer = InvalidBuffer;
bool skipping_blocks;
- StringInfoData buf;
const int initprog_index[] = {
PROGRESS_VACUUM_PHASE,
PROGRESS_VACUUM_TOTAL_HEAP_BLKS,
int64 initprog_val[3];
GlobalVisState *vistest;
- pg_rusage_init(&ru0);
-
- if (aggressive)
- ereport(elevel,
- (errmsg("aggressively vacuuming \"%s.%s\"",
- vacrel->relnamespace,
- vacrel->relname)));
- else
- ereport(elevel,
- (errmsg("vacuuming \"%s.%s\"",
- vacrel->relnamespace,
- vacrel->relname)));
-
nblocks = RelationGetNumberOfBlocks(vacrel->rel);
next_unskippable_block = 0;
next_failsafe_block = 0;
/* Update index statistics */
if (vacrel->nindexes > 0 && vacrel->do_index_cleanup)
update_index_statistics(vacrel);
-
- /*
- * When the table has no indexes (i.e. in the one-pass strategy case),
- * make log report that lazy_vacuum_heap_rel would've made had there been
- * indexes. (As in the two-pass strategy case, only make this report when
- * there were LP_DEAD line pointers vacuumed in lazy_vacuum_heap_page.)
- */
- if (vacrel->nindexes == 0 && vacrel->lpdead_item_pages > 0)
- ereport(elevel,
- (errmsg("table \"%s\": removed %lld dead item identifiers in %u pages",
- vacrel->relname, (long long) vacrel->lpdead_items,
- vacrel->lpdead_item_pages)));
-
- /*
- * Make a log report summarizing pruning and freezing.
- *
- * The autovacuum specific logging in heap_vacuum_rel summarizes an entire
- * VACUUM operation, whereas each VACUUM VERBOSE log report generally
- * summarizes a single round of index/heap vacuuming (or rel truncation).
- * It wouldn't make sense to report on pruning or freezing while following
- * that convention, though. You can think of this log report as a summary
- * of our first pass over the heap.
- */
- initStringInfo(&buf);
- appendStringInfo(&buf,
- _("%lld dead row versions cannot be removed yet, oldest xmin: %u\n"),
- (long long) vacrel->new_dead_tuples, vacrel->OldestXmin);
- appendStringInfo(&buf, ngettext("Skipped %u page due to buffer pins, ",
- "Skipped %u pages due to buffer pins, ",
- vacrel->pinskipped_pages),
- vacrel->pinskipped_pages);
- appendStringInfo(&buf, ngettext("%u frozen page.\n",
- "%u frozen pages.\n",
- vacrel->frozenskipped_pages),
- vacrel->frozenskipped_pages);
- appendStringInfo(&buf, _("%s."), pg_rusage_show(&ru0));
-
- ereport(elevel,
- (errmsg("table \"%s.%s\": found %lld removable, %lld nonremovable row versions in %u out of %u pages",
- vacrel->relnamespace,
- vacrel->relname,
- (long long) vacrel->tuples_deleted,
- (long long) vacrel->num_tuples, vacrel->scanned_pages,
- nblocks),
- errdetail_internal("%s", buf.data)));
- pfree(buf.data);
}
/*
* calls.)
*/
vacrel->do_index_vacuuming = false;
- ereport(elevel,
- (errmsg("table \"%s\": index scan bypassed: %u pages from table (%.2f%% of total) have %lld dead item identifiers",
- vacrel->relname, vacrel->lpdead_item_pages,
- 100.0 * vacrel->lpdead_item_pages / vacrel->rel_pages,
- (long long) vacrel->lpdead_items)));
}
else if (lazy_vacuum_all_indexes(vacrel))
{
{
int index;
BlockNumber vacuumed_pages;
- PGRUsage ru0;
Buffer vmbuffer = InvalidBuffer;
LVSavedErrInfo saved_err_info;
VACUUM_ERRCB_PHASE_VACUUM_HEAP,
InvalidBlockNumber, InvalidOffsetNumber);
- pg_rusage_init(&ru0);
vacuumed_pages = 0;
index = 0;
(index == vacrel->lpdead_items &&
vacuumed_pages == vacrel->lpdead_item_pages));
- ereport(elevel,
+ ereport(DEBUG2,
(errmsg("table \"%s\": removed %lld dead item identifiers in %u pages",
- vacrel->relname, (long long) index, vacuumed_pages),
- errdetail_internal("%s", pg_rusage_show(&ru0))));
+ vacrel->relname, (long long) index, vacuumed_pages)));
/* Revert to the previous phase information for error traceback */
restore_vacuum_error_info(vacrel, &saved_err_info);
ivinfo.analyze_only = false;
ivinfo.report_progress = false;
ivinfo.estimated_count = true;
- ivinfo.message_level = elevel;
+ ivinfo.message_level = DEBUG2;
ivinfo.num_heap_tuples = reltuples;
ivinfo.strategy = vacrel->bstrategy;
ivinfo.analyze_only = false;
ivinfo.report_progress = false;
ivinfo.estimated_count = estimated_count;
- ivinfo.message_level = elevel;
+ ivinfo.message_level = DEBUG2;
ivinfo.num_heap_tuples = reltuples;
ivinfo.strategy = vacrel->bstrategy;
*/
do
{
- PGRUsage ru0;
-
- pg_rusage_init(&ru0);
-
/*
* We need full exclusive lock on the relation in order to do
* truncation. If we can't get it, give up rather than waiting --- we
* We failed to establish the lock in the specified number of
* retries. This means we give up truncating.
*/
- ereport(elevel,
+ ereport(vacrel->verbose ? INFO : DEBUG2,
(errmsg("\"%s\": stopping truncate due to conflicting lock request",
vacrel->relname)));
return;
vacrel->pages_removed += orig_rel_pages - new_rel_pages;
vacrel->rel_pages = new_rel_pages;
- ereport(elevel,
+ ereport(vacrel->verbose ? INFO : DEBUG2,
(errmsg("table \"%s\": truncated %u to %u pages",
vacrel->relname,
- orig_rel_pages, new_rel_pages),
- errdetail_internal("%s",
- pg_rusage_show(&ru0))));
+ orig_rel_pages, new_rel_pages)));
orig_rel_pages = new_rel_pages;
} while (new_rel_pages > vacrel->nonempty_pages && lock_waiter_detected);
}
{
if (LockHasWaitersRelation(vacrel->rel, AccessExclusiveLock))
{
- ereport(elevel,
+ ereport(vacrel->verbose ? INFO : DEBUG2,
(errmsg("table \"%s\": suspending truncate due to conflicting lock request",
vacrel->relname)));
else
vacrel->pvs = parallel_vacuum_init(vacrel->rel, vacrel->indrels,
vacrel->nindexes, nworkers,
- max_items, elevel,
+ max_items,
+ vacrel->verbose ? INFO : DEBUG2,
vacrel->bstrategy);
/* If parallel mode started, dead_items space is allocated in DSM */