@ -43,7 +43,7 @@ typedef struct
/* whether or not dead items can be set LP_UNUSED during pruning */
bool mark_unused_now ;
/* whether to attempt freezing tuples */
bool freeze ;
bool attempt_ freeze;
struct VacuumCutoffs * cutoffs ;
/*-------------------------------------------------------
@ -177,6 +177,10 @@ static void heap_prune_record_unchanged_lp_redirect(PruneState *prstate, OffsetN
static void page_verify_redirects ( Page page ) ;
static bool heap_page_will_freeze ( Relation relation , Buffer buffer ,
bool did_tuple_hint_fpi , bool do_prune , bool do_hint_prune ,
PruneState * prstate ) ;
/*
* Optionally prune and repair fragmentation in the specified page .
@ -294,6 +298,117 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
}
}
/*
* Decide whether to proceed with freezing according to the freeze plans
* prepared for the given heap buffer . If freezing is chosen , this function
* performs several pre - freeze checks .
*
* The values of do_prune , do_hint_prune , and did_tuple_hint_fpi must be
* determined before calling this function .
*
* prstate is both an input and output parameter .
*
* Returns true if we should apply the freeze plans and freeze tuples on the
* page , and false otherwise .
*/
static bool
heap_page_will_freeze ( Relation relation , Buffer buffer ,
bool did_tuple_hint_fpi ,
bool do_prune ,
bool do_hint_prune ,
PruneState * prstate )
{
bool do_freeze = false ;
/*
* If the caller specified we should not attempt to freeze any tuples ,
* validate that everything is in the right state and return .
*/
if ( ! prstate - > attempt_freeze )
{
Assert ( ! prstate - > all_frozen & & prstate - > nfrozen = = 0 ) ;
Assert ( prstate - > lpdead_items = = 0 | | ! prstate - > all_visible ) ;
return false ;
}
if ( prstate - > pagefrz . freeze_required )
{
/*
* heap_prepare_freeze_tuple indicated that at least one XID / MXID from
* before FreezeLimit / MultiXactCutoff is present . Must freeze to
* advance relfrozenxid / relminmxid .
*/
do_freeze = true ;
}
else
{
/*
* Opportunistically freeze the page if we are generating an FPI
* anyway and if doing so means that we can set the page all - frozen
* afterwards ( might not happen until VACUUM ' s final heap pass ) .
*
* XXX : Previously , we knew if pruning emitted an FPI by checking
* pgWalUsage . wal_fpi before and after pruning . Once the freeze and
* prune records were combined , this heuristic couldn ' t be used
* anymore . The opportunistic freeze heuristic must be improved ;
* however , for now , try to approximate the old logic .
*/
if ( prstate - > all_visible & & prstate - > all_frozen & & prstate - > nfrozen > 0 )
{
/*
* Freezing would make the page all - frozen . Have already emitted
* an FPI or will do so anyway ?
*/
if ( RelationNeedsWAL ( relation ) )
{
if ( did_tuple_hint_fpi )
do_freeze = true ;
else if ( do_prune )
{
if ( XLogCheckBufferNeedsBackup ( buffer ) )
do_freeze = true ;
}
else if ( do_hint_prune )
{
if ( XLogHintBitIsNeeded ( ) & & XLogCheckBufferNeedsBackup ( buffer ) )
do_freeze = true ;
}
}
}
}
if ( do_freeze )
{
/*
* Validate the tuples we will be freezing before entering the
* critical section .
*/
heap_pre_freeze_checks ( buffer , prstate - > frozen , prstate - > nfrozen ) ;
}
else if ( prstate - > nfrozen > 0 )
{
/*
* The page contained some tuples that were not already frozen , and we
* chose not to freeze them now . The page won ' t be all - frozen then .
*/
Assert ( ! prstate - > pagefrz . freeze_required ) ;
prstate - > all_frozen = false ;
prstate - > nfrozen = 0 ; /* avoid miscounts in instrumentation */
}
else
{
/*
* We have no freeze plans to execute . The page might already be
* all - frozen ( perhaps only following pruning ) , though . Such pages
* can be marked all - frozen in the VM by our caller , even though none
* of its tuples were newly frozen here .
*/
}
return do_freeze ;
}
/*
* Prune and repair fragmentation and potentially freeze tuples on the
@ -366,14 +481,14 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
HeapTupleData tup ;
bool do_freeze ;
bool do_prune ;
bool do_hint ;
bool hint_bi t_fpi;
bool do_hint_prune ;
bool did_tuple_hin t_fpi;
int64 fpi_before = pgWalUsage . wal_fpi ;
/* Copy parameters to prstate */
prstate . vistest = vistest ;
prstate . mark_unused_now = ( options & HEAP_PAGE_PRUNE_MARK_UNUSED_NOW ) ! = 0 ;
prstate . freeze = ( options & HEAP_PAGE_PRUNE_FREEZE ) ! = 0 ;
prstate . attempt_ freeze = ( options & HEAP_PAGE_PRUNE_FREEZE ) ! = 0 ;
prstate . cutoffs = cutoffs ;
/*
@ -395,7 +510,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
/* initialize page freezing working state */
prstate . pagefrz . freeze_required = false ;
if ( prstate . freeze )
if ( prstate . attempt_ freeze)
{
Assert ( new_relfrozen_xid & & new_relmin_mxid ) ;
prstate . pagefrz . FreezePageRelfrozenXid = * new_relfrozen_xid ;
@ -442,7 +557,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
* function , when we return the value to the caller , so that the caller
* doesn ' t set the VM bit incorrectly .
*/
if ( prstate . freeze )
if ( prstate . attempt_ freeze)
{
prstate . all_visible = true ;
prstate . all_frozen = true ;
@ -556,7 +671,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
* If checksums are enabled , heap_prune_satisfies_vacuum ( ) may have caused
* an FPI to be emitted .
*/
hint_bi t_fpi = fpi_before ! = pgWalUsage . wal_fpi ;
did_tuple_hin t_fpi = fpi_before ! = pgWalUsage . wal_fpi ;
/*
* Process HOT chains .
@ -664,97 +779,23 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
* pd_prune_xid field or the page was marked full , we will update the hint
* bit .
*/
do_hint = ( ( PageHeader ) page ) - > pd_prune_xid ! = prstate . new_prune_xid | |
do_hint_prune = ( ( PageHeader ) page ) - > pd_prune_xid ! = prstate . new_prune_xid | |
PageIsFull ( page ) ;
/*
* Decide if we want to go ahead with freezing according to the freeze
* plans we prepared , or not .
*/
do_freeze = false ;
if ( prstate . freeze )
{
if ( prstate . pagefrz . freeze_required )
{
/*
* heap_prepare_freeze_tuple indicated that at least one XID / MXID
* from before FreezeLimit / MultiXactCutoff is present . Must
* freeze to advance relfrozenxid / relminmxid .
*/
do_freeze = true ;
}
else
{
/*
* Opportunistically freeze the page if we are generating an FPI
* anyway and if doing so means that we can set the page
* all - frozen afterwards ( might not happen until VACUUM ' s final
* heap pass ) .
*
* XXX : Previously , we knew if pruning emitted an FPI by checking
* pgWalUsage . wal_fpi before and after pruning . Once the freeze
* and prune records were combined , this heuristic couldn ' t be
* used anymore . The opportunistic freeze heuristic must be
* improved ; however , for now , try to approximate the old logic .
*/
if ( prstate . all_visible & & prstate . all_frozen & & prstate . nfrozen > 0 )
{
/*
* Freezing would make the page all - frozen . Have already
* emitted an FPI or will do so anyway ?
*/
if ( RelationNeedsWAL ( relation ) )
{
if ( hint_bit_fpi )
do_freeze = true ;
else if ( do_prune )
{
if ( XLogCheckBufferNeedsBackup ( buffer ) )
do_freeze = true ;
}
else if ( do_hint )
{
if ( XLogHintBitIsNeeded ( ) & & XLogCheckBufferNeedsBackup ( buffer ) )
do_freeze = true ;
}
}
}
}
}
if ( do_freeze )
{
/*
* Validate the tuples we will be freezing before entering the
* critical section .
*/
heap_pre_freeze_checks ( buffer , prstate . frozen , prstate . nfrozen ) ;
}
else if ( prstate . nfrozen > 0 )
{
/*
* The page contained some tuples that were not already frozen , and we
* chose not to freeze them now . The page won ' t be all - frozen then .
*/
Assert ( ! prstate . pagefrz . freeze_required ) ;
prstate . all_frozen = false ;
prstate . nfrozen = 0 ; /* avoid miscounts in instrumentation */
}
else
{
/*
* We have no freeze plans to execute . The page might already be
* all - frozen ( perhaps only following pruning ) , though . Such pages
* can be marked all - frozen in the VM by our caller , even though none
* of its tuples were newly frozen here .
*/
}
do_freeze = heap_page_will_freeze ( relation , buffer ,
did_tuple_hint_fpi ,
do_prune ,
do_hint_prune ,
& prstate ) ;
/* Any error while applying the changes is critical */
START_CRIT_SECTION ( ) ;
if ( do_hint )
if ( do_hint_prune )
{
/*
* Update the page ' s pd_prune_xid field to either zero , or the lowest
@ -897,7 +938,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
presult - > lpdead_items = prstate . lpdead_items ;
/* the presult->deadoffsets array was already filled in */
if ( prstate . freeze )
if ( prstate . attempt_ freeze)
{
if ( presult - > nfrozen > 0 )
{
@ -1479,7 +1520,7 @@ heap_prune_record_unchanged_lp_normal(Page page, PruneState *prstate, OffsetNumb
}
/* Consider freezing any normal tuples which will not be removed */
if ( prstate - > freeze )
if ( prstate - > attempt_ freeze)
{
bool totally_frozen ;