@ -316,6 +316,7 @@ typedef struct LVRelStats
/* Used for error callback */
/* Used for error callback */
char * indname ;
char * indname ;
BlockNumber blkno ; /* used only for heap operations */
BlockNumber blkno ; /* used only for heap operations */
OffsetNumber offnum ; /* used only for heap operations */
VacErrPhase phase ;
VacErrPhase phase ;
} LVRelStats ;
} LVRelStats ;
@ -323,6 +324,7 @@ typedef struct LVRelStats
typedef struct LVSavedErrInfo
typedef struct LVSavedErrInfo
{
{
BlockNumber blkno ;
BlockNumber blkno ;
OffsetNumber offnum ;
VacErrPhase phase ;
VacErrPhase phase ;
} LVSavedErrInfo ;
} LVSavedErrInfo ;
@ -341,7 +343,8 @@ static void lazy_scan_heap(Relation onerel, VacuumParams *params,
LVRelStats * vacrelstats , Relation * Irel , int nindexes ,
LVRelStats * vacrelstats , Relation * Irel , int nindexes ,
bool aggressive ) ;
bool aggressive ) ;
static void lazy_vacuum_heap ( Relation onerel , LVRelStats * vacrelstats ) ;
static void lazy_vacuum_heap ( Relation onerel , LVRelStats * vacrelstats ) ;
static bool lazy_check_needs_freeze ( Buffer buf , bool * hastup ) ;
static bool lazy_check_needs_freeze ( Buffer buf , bool * hastup ,
LVRelStats * vacrelstats ) ;
static void lazy_vacuum_all_indexes ( Relation onerel , Relation * Irel ,
static void lazy_vacuum_all_indexes ( Relation onerel , Relation * Irel ,
IndexBulkDeleteResult * * stats ,
IndexBulkDeleteResult * * stats ,
LVRelStats * vacrelstats , LVParallelState * lps ,
LVRelStats * vacrelstats , LVParallelState * lps ,
@ -364,6 +367,7 @@ static void lazy_record_dead_tuple(LVDeadTuples *dead_tuples,
static bool lazy_tid_reaped ( ItemPointer itemptr , void * state ) ;
static bool lazy_tid_reaped ( ItemPointer itemptr , void * state ) ;
static int vac_cmp_itemptr ( const void * left , const void * right ) ;
static int vac_cmp_itemptr ( const void * left , const void * right ) ;
static bool heap_page_is_all_visible ( Relation rel , Buffer buf ,
static bool heap_page_is_all_visible ( Relation rel , Buffer buf ,
LVRelStats * vacrelstats ,
TransactionId * visibility_cutoff_xid , bool * all_frozen ) ;
TransactionId * visibility_cutoff_xid , bool * all_frozen ) ;
static void lazy_parallel_vacuum_indexes ( Relation * Irel , IndexBulkDeleteResult * * stats ,
static void lazy_parallel_vacuum_indexes ( Relation * Irel , IndexBulkDeleteResult * * stats ,
LVRelStats * vacrelstats , LVParallelState * lps ,
LVRelStats * vacrelstats , LVParallelState * lps ,
@ -396,7 +400,8 @@ static LVSharedIndStats *get_indstats(LVShared *lvshared, int n);
static bool skip_parallel_vacuum_index ( Relation indrel , LVShared * lvshared ) ;
static bool skip_parallel_vacuum_index ( Relation indrel , LVShared * lvshared ) ;
static void vacuum_error_callback ( void * arg ) ;
static void vacuum_error_callback ( void * arg ) ;
static void update_vacuum_error_info ( LVRelStats * errinfo , LVSavedErrInfo * saved_err_info ,
static void update_vacuum_error_info ( LVRelStats * errinfo , LVSavedErrInfo * saved_err_info ,
int phase , BlockNumber blkno ) ;
int phase , BlockNumber blkno ,
OffsetNumber offnum ) ;
static void restore_vacuum_error_info ( LVRelStats * errinfo , const LVSavedErrInfo * saved_err_info ) ;
static void restore_vacuum_error_info ( LVRelStats * errinfo , const LVSavedErrInfo * saved_err_info ) ;
@ -547,7 +552,8 @@ heap_vacuum_rel(Relation onerel, VacuumParams *params,
* revert to the previous phase .
* revert to the previous phase .
*/
*/
update_vacuum_error_info ( vacrelstats , NULL , VACUUM_ERRCB_PHASE_TRUNCATE ,
update_vacuum_error_info ( vacrelstats , NULL , VACUUM_ERRCB_PHASE_TRUNCATE ,
vacrelstats - > nonempty_pages ) ;
vacrelstats - > nonempty_pages ,
InvalidOffsetNumber ) ;
lazy_truncate_heap ( onerel , vacrelstats ) ;
lazy_truncate_heap ( onerel , vacrelstats ) ;
}
}
@ -960,7 +966,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
pgstat_progress_update_param ( PROGRESS_VACUUM_HEAP_BLKS_SCANNED , blkno ) ;
pgstat_progress_update_param ( PROGRESS_VACUUM_HEAP_BLKS_SCANNED , blkno ) ;
update_vacuum_error_info ( vacrelstats , NULL , VACUUM_ERRCB_PHASE_SCAN_HEAP ,
update_vacuum_error_info ( vacrelstats , NULL , VACUUM_ERRCB_PHASE_SCAN_HEAP ,
blkno ) ;
blkno , InvalidOffsetNumber ) ;
if ( blkno = = next_unskippable_block )
if ( blkno = = next_unskippable_block )
{
{
@ -1129,7 +1135,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
* to use lazy_check_needs_freeze ( ) for both situations , though .
* to use lazy_check_needs_freeze ( ) for both situations , though .
*/
*/
LockBuffer ( buf , BUFFER_LOCK_SHARE ) ;
LockBuffer ( buf , BUFFER_LOCK_SHARE ) ;
if ( ! lazy_check_needs_freeze ( buf , & hastup ) )
if ( ! lazy_check_needs_freeze ( buf , & hastup , vacrelstats ) )
{
{
UnlockReleaseBuffer ( buf ) ;
UnlockReleaseBuffer ( buf ) ;
vacrelstats - > scanned_pages + + ;
vacrelstats - > scanned_pages + + ;
@ -1244,7 +1250,8 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
*/
*/
tups_vacuumed + = heap_page_prune ( onerel , buf , vistest , false ,
tups_vacuumed + = heap_page_prune ( onerel , buf , vistest , false ,
InvalidTransactionId , 0 ,
InvalidTransactionId , 0 ,
& vacrelstats - > latestRemovedXid ) ;
& vacrelstats - > latestRemovedXid ,
& vacrelstats - > offnum ) ;
/*
/*
* Now scan the page to collect vacuumable items and check for tuples
* Now scan the page to collect vacuumable items and check for tuples
@ -1267,6 +1274,11 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
{
{
ItemId itemid ;
ItemId itemid ;
/*
* Set the offset number so that we can display it along with any
* error that occurred while processing this tuple .
*/
vacrelstats - > offnum = offnum ;
itemid = PageGetItemId ( page , offnum ) ;
itemid = PageGetItemId ( page , offnum ) ;
/* Unused items require no processing, but we count 'em */
/* Unused items require no processing, but we count 'em */
@ -1468,6 +1480,12 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
}
}
} /* scan along page */
} /* scan along page */
/*
* Clear the offset information once we have processed all the tuples
* on the page .
*/
vacrelstats - > offnum = InvalidOffsetNumber ;
/*
/*
* If we froze any tuples , mark the buffer dirty , and write a WAL
* If we froze any tuples , mark the buffer dirty , and write a WAL
* record recording the changes . We must log the changes to be
* record recording the changes . We must log the changes to be
@ -1845,7 +1863,7 @@ lazy_vacuum_heap(Relation onerel, LVRelStats *vacrelstats)
/* Update error traceback information */
/* Update error traceback information */
update_vacuum_error_info ( vacrelstats , & saved_err_info , VACUUM_ERRCB_PHASE_VACUUM_HEAP ,
update_vacuum_error_info ( vacrelstats , & saved_err_info , VACUUM_ERRCB_PHASE_VACUUM_HEAP ,
InvalidBlockNumber ) ;
InvalidBlockNumber , InvalidOffsetNumber ) ;
pg_rusage_init ( & ru0 ) ;
pg_rusage_init ( & ru0 ) ;
npages = 0 ;
npages = 0 ;
@ -1927,7 +1945,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
/* Update error traceback information */
/* Update error traceback information */
update_vacuum_error_info ( vacrelstats , & saved_err_info , VACUUM_ERRCB_PHASE_VACUUM_HEAP ,
update_vacuum_error_info ( vacrelstats , & saved_err_info , VACUUM_ERRCB_PHASE_VACUUM_HEAP ,
blkno ) ;
blkno , InvalidOffsetNumber ) ;
START_CRIT_SECTION ( ) ;
START_CRIT_SECTION ( ) ;
@ -1979,7 +1997,8 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
* dirty , exclusively locked , and , if needed , a full page image has been
* dirty , exclusively locked , and , if needed , a full page image has been
* emitted in the log_heap_clean ( ) above .
* emitted in the log_heap_clean ( ) above .
*/
*/
if ( heap_page_is_all_visible ( onerel , buffer , & visibility_cutoff_xid ,
if ( heap_page_is_all_visible ( onerel , buffer , vacrelstats ,
& visibility_cutoff_xid ,
& all_frozen ) )
& all_frozen ) )
PageSetAllVisible ( page ) ;
PageSetAllVisible ( page ) ;
@ -2018,7 +2037,7 @@ lazy_vacuum_page(Relation onerel, BlockNumber blkno, Buffer buffer,
* Also returns a flag indicating whether page contains any tuples at all .
* Also returns a flag indicating whether page contains any tuples at all .
*/
*/
static bool
static bool
lazy_check_needs_freeze ( Buffer buf , bool * hastup )
lazy_check_needs_freeze ( Buffer buf , bool * hastup , LVRelStats * vacrelstats )
{
{
Page page = BufferGetPage ( buf ) ;
Page page = BufferGetPage ( buf ) ;
OffsetNumber offnum ,
OffsetNumber offnum ,
@ -2043,6 +2062,11 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup)
{
{
ItemId itemid ;
ItemId itemid ;
/*
* Set the offset number so that we can display it along with any
* error that occurred while processing this tuple .
*/
vacrelstats - > offnum = offnum ;
itemid = PageGetItemId ( page , offnum ) ;
itemid = PageGetItemId ( page , offnum ) ;
/* this should match hastup test in count_nondeletable_pages() */
/* this should match hastup test in count_nondeletable_pages() */
@ -2057,10 +2081,13 @@ lazy_check_needs_freeze(Buffer buf, bool *hastup)
if ( heap_tuple_needs_freeze ( tupleheader , FreezeLimit ,
if ( heap_tuple_needs_freeze ( tupleheader , FreezeLimit ,
MultiXactCutoff , buf ) )
MultiXactCutoff , buf ) )
return t ru e;
b reak ;
} /* scan along page */
} /* scan along page */
return false ;
/* Clear the offset information once we have processed the given page. */
vacrelstats - > offnum = InvalidOffsetNumber ;
return ( offnum < = maxoff ) ;
}
}
/*
/*
@ -2438,7 +2465,7 @@ lazy_vacuum_index(Relation indrel, IndexBulkDeleteResult **stats,
vacrelstats - > indname = pstrdup ( RelationGetRelationName ( indrel ) ) ;
vacrelstats - > indname = pstrdup ( RelationGetRelationName ( indrel ) ) ;
update_vacuum_error_info ( vacrelstats , & saved_err_info ,
update_vacuum_error_info ( vacrelstats , & saved_err_info ,
VACUUM_ERRCB_PHASE_VACUUM_INDEX ,
VACUUM_ERRCB_PHASE_VACUUM_INDEX ,
InvalidBlockNumber ) ;
InvalidBlockNumber , InvalidOffsetNumber ) ;
/* Do bulk deletion */
/* Do bulk deletion */
* stats = index_bulk_delete ( & ivinfo , * stats ,
* stats = index_bulk_delete ( & ivinfo , * stats ,
@ -2498,7 +2525,7 @@ lazy_cleanup_index(Relation indrel,
vacrelstats - > indname = pstrdup ( RelationGetRelationName ( indrel ) ) ;
vacrelstats - > indname = pstrdup ( RelationGetRelationName ( indrel ) ) ;
update_vacuum_error_info ( vacrelstats , & saved_err_info ,
update_vacuum_error_info ( vacrelstats , & saved_err_info ,
VACUUM_ERRCB_PHASE_INDEX_CLEANUP ,
VACUUM_ERRCB_PHASE_INDEX_CLEANUP ,
InvalidBlockNumber ) ;
InvalidBlockNumber , InvalidOffsetNumber ) ;
* stats = index_vacuum_cleanup ( & ivinfo , * stats ) ;
* stats = index_vacuum_cleanup ( & ivinfo , * stats ) ;
@ -2522,7 +2549,7 @@ lazy_cleanup_index(Relation indrel,
pg_rusage_show ( & ru0 ) ) ) ) ;
pg_rusage_show ( & ru0 ) ) ) ) ;
}
}
/* Revert back to the old phase information for error traceback */
/* Revert to the previous phase information for error traceback */
restore_vacuum_error_info ( vacrelstats , & saved_err_info ) ;
restore_vacuum_error_info ( vacrelstats , & saved_err_info ) ;
pfree ( vacrelstats - > indname ) ;
pfree ( vacrelstats - > indname ) ;
vacrelstats - > indname = NULL ;
vacrelstats - > indname = NULL ;
@ -2964,6 +2991,7 @@ vac_cmp_itemptr(const void *left, const void *right)
*/
*/
static bool
static bool
heap_page_is_all_visible ( Relation rel , Buffer buf ,
heap_page_is_all_visible ( Relation rel , Buffer buf ,
LVRelStats * vacrelstats ,
TransactionId * visibility_cutoff_xid ,
TransactionId * visibility_cutoff_xid ,
bool * all_frozen )
bool * all_frozen )
{
{
@ -2988,6 +3016,11 @@ heap_page_is_all_visible(Relation rel, Buffer buf,
ItemId itemid ;
ItemId itemid ;
HeapTupleData tuple ;
HeapTupleData tuple ;
/*
* Set the offset number so that we can display it along with any
* error that occurred while processing this tuple .
*/
vacrelstats - > offnum = offnum ;
itemid = PageGetItemId ( page , offnum ) ;
itemid = PageGetItemId ( page , offnum ) ;
/* Unused or redirect line pointers are of no interest */
/* Unused or redirect line pointers are of no interest */
@ -3065,6 +3098,9 @@ heap_page_is_all_visible(Relation rel, Buffer buf,
}
}
} /* scan along page */
} /* scan along page */
/* Clear the offset information once we have processed the given page. */
vacrelstats - > offnum = InvalidOffsetNumber ;
return all_visible ;
return all_visible ;
}
}
@ -3586,8 +3622,14 @@ vacuum_error_callback(void *arg)
{
{
case VACUUM_ERRCB_PHASE_SCAN_HEAP :
case VACUUM_ERRCB_PHASE_SCAN_HEAP :
if ( BlockNumberIsValid ( errinfo - > blkno ) )
if ( BlockNumberIsValid ( errinfo - > blkno ) )
{
if ( OffsetNumberIsValid ( errinfo - > offnum ) )
errcontext ( " while scanning block %u and offset %u of relation \" %s.%s \" " ,
errinfo - > blkno , errinfo - > offnum , errinfo - > relnamespace , errinfo - > relname ) ;
else
errcontext ( " while scanning block %u of relation \" %s.%s \" " ,
errcontext ( " while scanning block %u of relation \" %s.%s \" " ,
errinfo - > blkno , errinfo - > relnamespace , errinfo - > relname ) ;
errinfo - > blkno , errinfo - > relnamespace , errinfo - > relname ) ;
}
else
else
errcontext ( " while scanning relation \" %s.%s \" " ,
errcontext ( " while scanning relation \" %s.%s \" " ,
errinfo - > relnamespace , errinfo - > relname ) ;
errinfo - > relnamespace , errinfo - > relname ) ;
@ -3595,8 +3637,14 @@ vacuum_error_callback(void *arg)
case VACUUM_ERRCB_PHASE_VACUUM_HEAP :
case VACUUM_ERRCB_PHASE_VACUUM_HEAP :
if ( BlockNumberIsValid ( errinfo - > blkno ) )
if ( BlockNumberIsValid ( errinfo - > blkno ) )
{
if ( OffsetNumberIsValid ( errinfo - > offnum ) )
errcontext ( " while vacuuming block %u and offset %u of relation \" %s.%s \" " ,
errinfo - > blkno , errinfo - > offnum , errinfo - > relnamespace , errinfo - > relname ) ;
else
errcontext ( " while vacuuming block %u of relation \" %s.%s \" " ,
errcontext ( " while vacuuming block %u of relation \" %s.%s \" " ,
errinfo - > blkno , errinfo - > relnamespace , errinfo - > relname ) ;
errinfo - > blkno , errinfo - > relnamespace , errinfo - > relname ) ;
}
else
else
errcontext ( " while vacuuming relation \" %s.%s \" " ,
errcontext ( " while vacuuming relation \" %s.%s \" " ,
errinfo - > relnamespace , errinfo - > relname ) ;
errinfo - > relnamespace , errinfo - > relname ) ;
@ -3631,15 +3679,17 @@ vacuum_error_callback(void *arg)
*/
*/
static void
static void
update_vacuum_error_info ( LVRelStats * errinfo , LVSavedErrInfo * saved_err_info , int phase ,
update_vacuum_error_info ( LVRelStats * errinfo , LVSavedErrInfo * saved_err_info , int phase ,
BlockNumber blkno )
BlockNumber blkno , OffsetNumber offnum )
{
{
if ( saved_err_info )
if ( saved_err_info )
{
{
saved_err_info - > offnum = errinfo - > offnum ;
saved_err_info - > blkno = errinfo - > blkno ;
saved_err_info - > blkno = errinfo - > blkno ;
saved_err_info - > phase = errinfo - > phase ;
saved_err_info - > phase = errinfo - > phase ;
}
}
errinfo - > blkno = blkno ;
errinfo - > blkno = blkno ;
errinfo - > offnum = offnum ;
errinfo - > phase = phase ;
errinfo - > phase = phase ;
}
}
@ -3650,5 +3700,6 @@ static void
restore_vacuum_error_info ( LVRelStats * errinfo , const LVSavedErrInfo * saved_err_info )
restore_vacuum_error_info ( LVRelStats * errinfo , const LVSavedErrInfo * saved_err_info )
{
{
errinfo - > blkno = saved_err_info - > blkno ;
errinfo - > blkno = saved_err_info - > blkno ;
errinfo - > offnum = saved_err_info - > offnum ;
errinfo - > phase = saved_err_info - > phase ;
errinfo - > phase = saved_err_info - > phase ;
}
}