@ -171,10 +171,11 @@ typedef struct LVRelState
/* 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 .
@ -237,9 +238,6 @@ typedef struct LVSavedErrInfo
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 ,
@ -299,6 +297,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
BufferAccessStrategy bstrategy )
{
LVRelState * vacrel ;
bool verbose ,
instrument ;
PGRUsage ru0 ;
TimestampTz starttime = 0 ;
WalUsage walusage_start = pgWalUsage ;
@ -324,8 +324,10 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
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 ( ) ;
@ -336,11 +338,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
}
}
if ( params - > options & VACOPT_VERBOSE )
elevel = INFO ;
else
elevel = DEBUG2 ;
pgstat_progress_start_command ( PROGRESS_COMMAND_VACUUM ,
RelationGetRelid ( rel ) ) ;
@ -365,14 +362,54 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
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
@ -386,6 +423,8 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
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 ) ;
@ -416,37 +455,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
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 )
@ -477,11 +485,6 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
*/
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 ) ;
@ -544,12 +547,11 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
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 ) )
{
@ -572,12 +574,17 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
( 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
@ -676,7 +683,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
( 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 ) ;
}
@ -688,7 +695,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
if ( vacrel - > indstats [ i ] )
pfree ( vacrel - > indstats [ i ] ) ;
if ( indnames & & indnames [ i ] )
if ( instrument )
pfree ( indnames [ i ] ) ;
}
}
@ -738,10 +745,8 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
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 ,
@ -750,19 +755,6 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
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 ;
@ -1453,52 +1445,6 @@ lazy_scan_heap(LVRelState *vacrel, VacuumParams *params, bool aggressive)
/* 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 ) ;
}
/*
@ -1995,11 +1941,6 @@ lazy_vacuum(LVRelState *vacrel)
* 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 ) )
{
@ -2142,7 +2083,6 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
{
int index ;
BlockNumber vacuumed_pages ;
PGRUsage ru0 ;
Buffer vmbuffer = InvalidBuffer ;
LVSavedErrInfo saved_err_info ;
@ -2159,7 +2099,6 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
VACUUM_ERRCB_PHASE_VACUUM_HEAP ,
InvalidBlockNumber , InvalidOffsetNumber ) ;
pg_rusage_init ( & ru0 ) ;
vacuumed_pages = 0 ;
index = 0 ;
@ -2206,10 +2145,9 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
( 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 ) ;
@ -2519,7 +2457,7 @@ lazy_vacuum_one_index(Relation indrel, IndexBulkDeleteResult *istat,
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 ;
@ -2567,7 +2505,7 @@ lazy_cleanup_one_index(Relation indrel, IndexBulkDeleteResult *istat,
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 ;
@ -2653,10 +2591,6 @@ lazy_truncate_heap(LVRelState *vacrel)
*/
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
@ -2684,7 +2618,7 @@ lazy_truncate_heap(LVRelState *vacrel)
* 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 ;
@ -2754,12 +2688,10 @@ lazy_truncate_heap(LVRelState *vacrel)
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 ) ;
}
@ -2818,7 +2750,7 @@ count_nondeletable_pages(LVRelState *vacrel, bool *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 ) ) ) ;
@ -2985,7 +2917,8 @@ dead_items_alloc(LVRelState *vacrel, int nworkers)
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 */