@ -17,9 +17,9 @@
* failsafe mechanism has triggered ( to avoid transaction ID wraparound ) ,
* vacuum may skip phases II and III .
*
* If the TID store fills up in phase I , vacuum suspends phase I , proceeds to
* phases II and II , cleaning up the dead tuples referenced in the current TID
* store . This empties the TID store resumes phase I .
* If the TID store fills up in phase I , vacuum suspends phase I and proceeds
* to phases II and I II, cleaning up the dead tuples referenced in the current
* TID store . This empties the TID store , allowing vacuum to resume phase I .
*
* In a way , the phases are more like states in a state machine , but they have
* been referred to colloquially as phases for so long that they are referred
@ -41,9 +41,53 @@
* to the end , skipping pages as permitted by their visibility status , vacuum
* options , and various other requirements .
*
* When page skipping is not disabled , a non - aggressive vacuum may scan pages
* that are marked all - visible ( and even all - frozen ) in the visibility map if
* the range of skippable pages is below SKIP_PAGES_THRESHOLD .
* Vacuums are either aggressive or normal . Aggressive vacuums must scan every
* unfrozen tuple in order to advance relfrozenxid and avoid transaction ID
* wraparound . Normal vacuums may scan otherwise skippable pages for one of
* two reasons :
*
* When page skipping is not disabled , a normal vacuum may scan pages that are
* marked all - visible ( and even all - frozen ) in the visibility map if the range
* of skippable pages is below SKIP_PAGES_THRESHOLD . This is primarily for the
* benefit of kernel readahead ( see comment in heap_vac_scan_next_block ( ) ) .
*
* A normal vacuum may also scan skippable pages in an effort to freeze them
* and decrease the backlog of all - visible but not all - frozen pages that have
* to be processed by the next aggressive vacuum . These are referred to as
* eagerly scanned pages . Pages scanned due to SKIP_PAGES_THRESHOLD do not
* count as eagerly scanned pages .
*
* Eagerly scanned pages that are set all - frozen in the VM are successful
* eager freezes and those not set all - frozen in the VM are failed eager
* freezes .
*
* Because we want to amortize the overhead of freezing pages over multiple
* vacuums , normal vacuums cap the number of successful eager freezes to
* MAX_EAGER_FREEZE_SUCCESS_RATE of the number of all - visible but not
* all - frozen pages at the beginning of the vacuum . Since eagerly frozen pages
* may be unfrozen before the next aggressive vacuum , capping the number of
* successful eager freezes also caps the downside of eager freezing :
* potentially wasted work .
*
* Once the success cap has been hit , eager scanning is disabled for the
* remainder of the vacuum of the relation .
*
* Success is capped globally because we don ' t want to limit our successes if
* old data happens to be concentrated in a particular part of the table . This
* is especially likely to happen for append - mostly workloads where the oldest
* data is at the beginning of the unfrozen portion of the relation .
*
* On the assumption that different regions of the table are likely to contain
* similarly aged data , normal vacuums use a localized eager freeze failure
* cap . The failure count is reset for each region of the table - - comprised
* of EAGER_SCAN_REGION_SIZE blocks . In each region , we tolerate
* vacuum_max_eager_freeze_failure_rate of EAGER_SCAN_REGION_SIZE failures
* before suspending eager scanning until the end of the region .
* vacuum_max_eager_freeze_failure_rate is configurable both globally and per
* table .
*
* Aggressive vacuums must examine every unfrozen tuple and thus are not
* subject to any of the limits imposed by the eager scanning algorithm .
*
* Once vacuum has decided to scan a given block , it must read the block and
* obtain a cleanup lock to prune tuples on the page . A non - aggressive vacuum
@ -100,6 +144,7 @@
# include "commands/progress.h"
# include "commands/vacuum.h"
# include "common/int.h"
# include "common/pg_prng.h"
# include "executor/instrument.h"
# include "miscadmin.h"
# include "pgstat.h"
@ -185,6 +230,24 @@ typedef enum
VACUUM_ERRCB_PHASE_TRUNCATE ,
} VacErrPhase ;
/*
* An eager scan of a page that is set all - frozen in the VM is considered
* " successful " . To spread out freezing overhead across multiple normal
* vacuums , we limit the number of successful eager page freezes . The maximum
* number of eager page freezes is calculated as a ratio of the all - visible
* but not all - frozen pages at the beginning of the vacuum .
*/
# define MAX_EAGER_FREEZE_SUCCESS_RATE 0.2
/*
* On the assumption that different regions of the table tend to have
* similarly aged data , once vacuum fails to freeze
* vacuum_max_eager_freeze_failure_rate of the blocks in a region of size
* EAGER_SCAN_REGION_SIZE , it suspends eager scanning until it has progressed
* to another region of the table with potentially older data .
*/
# define EAGER_SCAN_REGION_SIZE 4096
typedef struct LVRelState
{
/* Target heap relation and its indexes */
@ -241,6 +304,13 @@ typedef struct LVRelState
BlockNumber rel_pages ; /* total number of pages */
BlockNumber scanned_pages ; /* # pages examined (not skipped via VM) */
/*
* Count of all - visible blocks eagerly scanned ( for logging only ) . This
* does not include skippable blocks scanned due to SKIP_PAGES_THRESHOLD .
*/
BlockNumber eager_scanned_pages ;
BlockNumber removed_pages ; /* # pages removed by relation truncation */
BlockNumber new_frozen_tuple_pages ; /* # pages with newly frozen tuples */
@ -282,9 +352,57 @@ typedef struct LVRelState
BlockNumber current_block ; /* last block returned */
BlockNumber next_unskippable_block ; /* next unskippable block */
bool next_unskippable_allvis ; /* its visibility status */
bool next_unskippable_eager_scanned ; /* if it was eagerly scanned */
Buffer next_unskippable_vmbuffer ; /* buffer containing its VM bit */
/* State related to managing eager scanning of all-visible pages */
/*
* A normal vacuum that has failed to freeze too many eagerly scanned
* blocks in a region suspends eager scanning .
* next_eager_scan_region_start is the block number of the first block
* eligible for resumed eager scanning .
*
* When eager scanning is permanently disabled , either initially
* ( including for aggressive vacuum ) or due to hitting the success cap ,
* this is set to InvalidBlockNumber .
*/
BlockNumber next_eager_scan_region_start ;
/*
* The remaining number of blocks a normal vacuum will consider eager
* scanning when it is successful . When eager scanning is enabled , this is
* initialized to MAX_EAGER_FREEZE_SUCCESS_RATE of the total number of
* all - visible but not all - frozen pages . For each eager freeze success ,
* this is decremented . Once it hits 0 , eager scanning is permanently
* disabled . It is initialized to 0 if eager scanning starts out disabled
* ( including for aggressive vacuum ) .
*/
BlockNumber eager_scan_remaining_successes ;
/*
* The maximum number of blocks which may be eagerly scanned and not
* frozen before eager scanning is temporarily suspended . This is
* configurable both globally , via the
* vacuum_max_eager_freeze_failure_rate GUC , and per table , with a table
* storage parameter of the same name . It is calculated as
* vacuum_max_eager_freeze_failure_rate of EAGER_SCAN_REGION_SIZE blocks .
* It is 0 when eager scanning is disabled .
*/
BlockNumber eager_scan_max_fails_per_region ;
/*
* The number of eagerly scanned blocks vacuum failed to freeze ( due to
* age ) in the current eager scan region . Vacuum resets it to
* eager_scan_max_fails_per_region each time it enters a new region of the
* relation . If eager_scan_remaining_fails hits 0 , eager scanning is
* suspended until the next region . It is also 0 if eager scanning has
* been permanently disabled .
*/
BlockNumber eager_scan_remaining_fails ;
} LVRelState ;
/* Struct for saving and restoring vacuum error information. */
typedef struct LVSavedErrInfo
{
@ -296,8 +414,11 @@ typedef struct LVSavedErrInfo
/* non-export function prototypes */
static void lazy_scan_heap ( LVRelState * vacrel ) ;
static void heap_vacuum_eager_scan_setup ( LVRelState * vacrel ,
VacuumParams * params ) ;
static bool heap_vac_scan_next_block ( LVRelState * vacrel , BlockNumber * blkno ,
bool * all_visible_according_to_vm ) ;
bool * all_visible_according_to_vm ,
bool * was_eager_scanned ) ;
static void find_next_unskippable_block ( LVRelState * vacrel , bool * skipsallvis ) ;
static bool lazy_scan_new_or_empty ( LVRelState * vacrel , Buffer buf ,
BlockNumber blkno , Page page ,
@ -305,7 +426,7 @@ static bool lazy_scan_new_or_empty(LVRelState *vacrel, Buffer buf,
static void lazy_scan_prune ( LVRelState * vacrel , Buffer buf ,
BlockNumber blkno , Page page ,
Buffer vmbuffer , bool all_visible_according_to_vm ,
bool * has_lpdead_items ) ;
bool * has_lpdead_items , bool * vm_page_frozen ) ;
static bool lazy_scan_noprune ( LVRelState * vacrel , Buffer buf ,
BlockNumber blkno , Page page ,
bool * has_lpdead_items ) ;
@ -347,6 +468,130 @@ static void restore_vacuum_error_info(LVRelState *vacrel,
const LVSavedErrInfo * saved_vacrel ) ;
/*
* Helper to set up the eager scanning state for vacuuming a single relation .
* Initializes the eager scan management related members of the LVRelState .
*
* Caller provides whether or not an aggressive vacuum is required due to
* vacuum options or for relfrozenxid / relminmxid advancement .
*/
static void
heap_vacuum_eager_scan_setup ( LVRelState * vacrel , VacuumParams * params )
{
uint32 randseed ;
BlockNumber allvisible ;
BlockNumber allfrozen ;
float first_region_ratio ;
bool oldest_unfrozen_before_cutoff = false ;
/*
* Initialize eager scan management fields to their disabled values .
* Aggressive vacuums , normal vacuums of small tables , and normal vacuums
* of tables without sufficiently old tuples disable eager scanning .
*/
vacrel - > next_eager_scan_region_start = InvalidBlockNumber ;
vacrel - > eager_scan_max_fails_per_region = 0 ;
vacrel - > eager_scan_remaining_fails = 0 ;
vacrel - > eager_scan_remaining_successes = 0 ;
/* If eager scanning is explicitly disabled, just return. */
if ( params - > max_eager_freeze_failure_rate = = 0 )
return ;
/*
* The caller will have determined whether or not an aggressive vacuum is
* required by either the vacuum parameters or the relative age of the
* oldest unfrozen transaction IDs . An aggressive vacuum must scan every
* all - visible page to safely advance the relfrozenxid and / or relminmxid ,
* so scans of all - visible pages are not considered eager .
*/
if ( vacrel - > aggressive )
return ;
/*
* Aggressively vacuuming a small relation shouldn ' t take long , so it
* isn ' t worth amortizing . We use two times the region size as the size
* cutoff because the eager scan start block is a random spot somewhere in
* the first region , making the second region the first to be eager
* scanned normally .
*/
if ( vacrel - > rel_pages < 2 * EAGER_SCAN_REGION_SIZE )
return ;
/*
* We only want to enable eager scanning if we are likely to be able to
* freeze some of the pages in the relation .
*
* Tuples with XIDs older than OldestXmin or MXIDs older than OldestMxact
* are technically freezable , but we won ' t freeze them unless the criteria
* for opportunistic freezing is met . Only tuples with XIDs / MXIDs older
* than the the FreezeLimit / MultiXactCutoff are frozen in the common case .
*
* So , as a heuristic , we wait until the FreezeLimit has advanced past the
* relfrozenxid or the MultiXactCutoff has advanced past the relminmxid to
* enable eager scanning .
*/
if ( TransactionIdIsNormal ( vacrel - > cutoffs . relfrozenxid ) & &
TransactionIdPrecedes ( vacrel - > cutoffs . relfrozenxid ,
vacrel - > cutoffs . FreezeLimit ) )
oldest_unfrozen_before_cutoff = true ;
if ( ! oldest_unfrozen_before_cutoff & &
MultiXactIdIsValid ( vacrel - > cutoffs . relminmxid ) & &
MultiXactIdPrecedes ( vacrel - > cutoffs . relminmxid ,
vacrel - > cutoffs . MultiXactCutoff ) )
oldest_unfrozen_before_cutoff = true ;
if ( ! oldest_unfrozen_before_cutoff )
return ;
/* We have met the criteria to eagerly scan some pages. */
/*
* Our success cap is MAX_EAGER_FREEZE_SUCCESS_RATE of the number of
* all - visible but not all - frozen blocks in the relation .
*/
visibilitymap_count ( vacrel - > rel , & allvisible , & allfrozen ) ;
vacrel - > eager_scan_remaining_successes =
( BlockNumber ) ( MAX_EAGER_FREEZE_SUCCESS_RATE *
( allvisible - allfrozen ) ) ;
/* If every all-visible page is frozen, eager scanning is disabled. */
if ( vacrel - > eager_scan_remaining_successes = = 0 )
return ;
/*
* Now calculate the bounds of the first eager scan region . Its end block
* will be a random spot somewhere in the first EAGER_SCAN_REGION_SIZE
* blocks . This affects the bounds of all subsequent regions and avoids
* eager scanning and failing to freeze the same blocks each vacuum of the
* relation .
*/
randseed = pg_prng_uint32 ( & pg_global_prng_state ) ;
vacrel - > next_eager_scan_region_start = randseed % EAGER_SCAN_REGION_SIZE ;
Assert ( params - > max_eager_freeze_failure_rate > 0 & &
params - > max_eager_freeze_failure_rate < = 1 ) ;
vacrel - > eager_scan_max_fails_per_region =
params - > max_eager_freeze_failure_rate *
EAGER_SCAN_REGION_SIZE ;
/*
* The first region will be smaller than subsequent regions . As such ,
* adjust the eager freeze failures tolerated for this region .
*/
first_region_ratio = 1 - ( float ) vacrel - > next_eager_scan_region_start /
EAGER_SCAN_REGION_SIZE ;
vacrel - > eager_scan_remaining_fails =
vacrel - > eager_scan_max_fails_per_region *
first_region_ratio ;
}
/*
* heap_vacuum_rel ( ) - - perform VACUUM for one heap relation
*
@ -477,6 +722,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
/* Initialize page counters explicitly (be tidy) */
vacrel - > scanned_pages = 0 ;
vacrel - > eager_scanned_pages = 0 ;
vacrel - > removed_pages = 0 ;
vacrel - > new_frozen_tuple_pages = 0 ;
vacrel - > lpdead_item_pages = 0 ;
@ -502,6 +748,7 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
vacrel - > vm_new_visible_pages = 0 ;
vacrel - > vm_new_visible_frozen_pages = 0 ;
vacrel - > vm_new_frozen_pages = 0 ;
vacrel - > rel_pages = orig_rel_pages = RelationGetNumberOfBlocks ( rel ) ;
/*
* Get cutoffs that determine which deleted tuples are considered DEAD ,
@ -520,11 +767,16 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
* to increase the number of dead tuples it can prune away . )
*/
vacrel - > aggressive = vacuum_get_cutoffs ( rel , params , & vacrel - > cutoffs ) ;
vacrel - > rel_pages = orig_rel_pages = RelationGetNumberOfBlocks ( rel ) ;
vacrel - > vistest = GlobalVisTestFor ( rel ) ;
/* Initialize state used to track oldest extant XID/MXID */
vacrel - > NewRelfrozenXid = vacrel - > cutoffs . OldestXmin ;
vacrel - > NewRelminMxid = vacrel - > cutoffs . OldestMxact ;
/*
* Initialize state related to tracking all - visible page skipping . This is
* very important to determine whether or not it is safe to advance the
* relfrozenxid / relminmxid .
*/
vacrel - > skippedallvis = false ;
skipwithvm = true ;
if ( params - > options & VACOPT_DISABLE_PAGE_SKIPPING )
@ -539,6 +791,13 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
vacrel - > skipwithvm = skipwithvm ;
/*
* Set up eager scan tracking state . This must happen after determining
* whether or not the vacuum must be aggressive , because only normal
* vacuums use the eager scan algorithm .
*/
heap_vacuum_eager_scan_setup ( vacrel , params ) ;
if ( verbose )
{
if ( vacrel - > aggressive )
@ -734,12 +993,14 @@ heap_vacuum_rel(Relation rel, VacuumParams *params,
vacrel - > relnamespace ,
vacrel - > relname ,
vacrel - > num_index_scans ) ;
appendStringInfo ( & buf , _ ( " pages: %u removed, %u remain, %u scanned (%.2f%% of total) \n " ) ,
appendStringInfo ( & buf , _ ( " pages: %u removed, %u remain, %u scanned (%.2f%% of total), %u eagerly scanned \n " ) ,
vacrel - > removed_pages ,
new_rel_pages ,
vacrel - > scanned_pages ,
orig_rel_pages = = 0 ? 100.0 :
100.0 * vacrel - > scanned_pages / orig_rel_pages ) ;
100.0 * vacrel - > scanned_pages /
orig_rel_pages ,
vacrel - > eager_scanned_pages ) ;
appendStringInfo ( & buf ,
_ ( " tuples: %lld removed, %lld remain, %lld are dead but not yet removable \n " ) ,
( long long ) vacrel - > tuples_deleted ,
@ -910,8 +1171,10 @@ lazy_scan_heap(LVRelState *vacrel)
BlockNumber rel_pages = vacrel - > rel_pages ,
blkno ,
next_fsm_block_to_vacuum = 0 ;
bool all_visible_according_to_vm ;
bool all_visible_according_to_vm ,
was_eager_scanned = false ;
BlockNumber orig_eager_scan_success_limit =
vacrel - > eager_scan_remaining_successes ; /* for logging */
Buffer vmbuffer = InvalidBuffer ;
const int initprog_index [ ] = {
PROGRESS_VACUUM_PHASE ,
@ -930,16 +1193,21 @@ lazy_scan_heap(LVRelState *vacrel)
vacrel - > current_block = InvalidBlockNumber ;
vacrel - > next_unskippable_block = InvalidBlockNumber ;
vacrel - > next_unskippable_allvis = false ;
vacrel - > next_unskippable_eager_scanned = false ;
vacrel - > next_unskippable_vmbuffer = InvalidBuffer ;
while ( heap_vac_scan_next_block ( vacrel , & blkno , & all_visible_according_to_vm ) )
while ( heap_vac_scan_next_block ( vacrel , & blkno , & all_visible_according_to_vm ,
& was_eager_scanned ) )
{
Buffer buf ;
Page page ;
bool has_lpdead_items ;
bool vm_page_frozen = false ;
bool got_cleanup_lock = false ;
vacrel - > scanned_pages + + ;
if ( was_eager_scanned )
vacrel - > eager_scanned_pages + + ;
/* Report as block scanned, update error traceback information */
pgstat_progress_update_param ( PROGRESS_VACUUM_HEAP_BLKS_SCANNED , blkno ) ;
@ -1064,7 +1332,56 @@ lazy_scan_heap(LVRelState *vacrel)
if ( got_cleanup_lock )
lazy_scan_prune ( vacrel , buf , blkno , page ,
vmbuffer , all_visible_according_to_vm ,
& has_lpdead_items ) ;
& has_lpdead_items , & vm_page_frozen ) ;
/*
* Count an eagerly scanned page as a failure or a success .
*
* Only lazy_scan_prune ( ) freezes pages , so if we didn ' t get the
* cleanup lock , we won ' t have frozen the page . However , we only count
* pages that were too new to require freezing as eager freeze
* failures .
*
* We could gather more information from lazy_scan_noprune ( ) about
* whether or not there were tuples with XIDs or MXIDs older than the
* FreezeLimit or MultiXactCutoff . However , for simplicity , we simply
* exclude pages skipped due to cleanup lock contention from eager
* freeze algorithm caps .
*/
if ( got_cleanup_lock & & was_eager_scanned )
{
/* Aggressive vacuums do not eager scan. */
Assert ( ! vacrel - > aggressive ) ;
if ( vm_page_frozen )
{
Assert ( vacrel - > eager_scan_remaining_successes > 0 ) ;
vacrel - > eager_scan_remaining_successes - - ;
if ( vacrel - > eager_scan_remaining_successes = = 0 )
{
/*
* If we hit our success cap , permanently disable eager
* scanning by setting the other eager scan management
* fields to their disabled values .
*/
vacrel - > eager_scan_remaining_fails = 0 ;
vacrel - > next_eager_scan_region_start = InvalidBlockNumber ;
vacrel - > eager_scan_max_fails_per_region = 0 ;
ereport ( vacrel - > verbose ? INFO : DEBUG2 ,
( errmsg ( " disabling eager scanning after freezing %u eagerly scanned blocks of \" %s.%s.%s \" " ,
orig_eager_scan_success_limit ,
vacrel - > dbname , vacrel - > relnamespace ,
vacrel - > relname ) ) ) ;
}
}
else
{
Assert ( vacrel - > eager_scan_remaining_fails > 0 ) ;
vacrel - > eager_scan_remaining_fails - - ;
}
}
/*
* Now drop the buffer lock and , potentially , update the FSM .
@ -1164,7 +1481,9 @@ lazy_scan_heap(LVRelState *vacrel)
*
* The block number and visibility status of the next block to process are set
* in * blkno and * all_visible_according_to_vm . The return value is false if
* there are no further blocks to process .
* there are no further blocks to process . If the block is being eagerly
* scanned , was_eager_scanned is set so that the caller can count whether or
* not an eagerly scanned page is successfully frozen .
*
* vacrel is an in / out parameter here . Vacuum options and information about
* the relation are read . vacrel - > skippedallvis is set if we skip a block
@ -1174,13 +1493,16 @@ lazy_scan_heap(LVRelState *vacrel)
*/
static bool
heap_vac_scan_next_block ( LVRelState * vacrel , BlockNumber * blkno ,
bool * all_visible_according_to_vm )
bool * all_visible_according_to_vm ,
bool * was_eager_scanned )
{
BlockNumber next_block ;
/* relies on InvalidBlockNumber + 1 overflowing to 0 on first call */
next_block = vacrel - > current_block + 1 ;
* was_eager_scanned = false ;
/* Have we reached the end of the relation? */
if ( next_block > = vacrel - > rel_pages )
{
@ -1253,6 +1575,7 @@ heap_vac_scan_next_block(LVRelState *vacrel, BlockNumber *blkno,
* blkno = vacrel - > current_block = next_block ;
* all_visible_according_to_vm = vacrel - > next_unskippable_allvis ;
* was_eager_scanned = vacrel - > next_unskippable_eager_scanned ;
return true ;
}
}
@ -1276,11 +1599,12 @@ find_next_unskippable_block(LVRelState *vacrel, bool *skipsallvis)
BlockNumber rel_pages = vacrel - > rel_pages ;
BlockNumber next_unskippable_block = vacrel - > next_unskippable_block + 1 ;
Buffer next_unskippable_vmbuffer = vacrel - > next_unskippable_vmbuffer ;
bool next_unskippable_eager_scanned = false ;
bool next_unskippable_allvis ;
* skipsallvis = false ;
for ( ; ; )
for ( ; ; next_unskippable_block + + )
{
uint8 mapbits = visibilitymap_get_status ( vacrel - > rel ,
next_unskippable_block ,
@ -1288,6 +1612,19 @@ find_next_unskippable_block(LVRelState *vacrel, bool *skipsallvis)
next_unskippable_allvis = ( mapbits & VISIBILITYMAP_ALL_VISIBLE ) ! = 0 ;
/*
* At the start of each eager scan region , normal vacuums with eager
* scanning enabled reset the failure counter , allowing vacuum to
* resume eager scanning if it had been suspended in the previous
* region .
*/
if ( next_unskippable_block > = vacrel - > next_eager_scan_region_start )
{
vacrel - > eager_scan_remaining_fails =
vacrel - > eager_scan_max_fails_per_region ;
vacrel - > next_eager_scan_region_start + = EAGER_SCAN_REGION_SIZE ;
}
/*
* A block is unskippable if it is not all visible according to the
* visibility map .
@ -1316,28 +1653,41 @@ find_next_unskippable_block(LVRelState *vacrel, bool *skipsallvis)
break ;
/*
* Aggressive VACUUM caller can ' t skip pages just because they are
* all - visible . They may still skip all - frozen pages , which can ' t
* contain XIDs < OldestXmin ( XIDs that aren ' t already frozen by now ) .
* All - frozen pages cannot contain XIDs < OldestXmin ( XIDs that aren ' t
* already frozen by now ) , so this page can be skipped .
*/
if ( ( mapbits & VISIBILITYMAP_ALL_FROZEN ) ! = 0 )
continue ;
/*
* Aggressive vacuums cannot skip any all - visible pages that are not
* also all - frozen .
*/
if ( ( mapbits & VISIBILITYMAP_ALL_FROZEN ) = = 0 )
{
if ( vacrel - > aggressive )
break ;
/*
* All - visible block is safe to skip in non - aggressive case . But
* remember that the final range contains such a block for later .
* Normal vacuums with eager scanning enabled only skip all - visible
* but not all - frozen pages if they have hit the failure limit for the
* current eager scan region .
*/
* skipsallvis = true ;
if ( vacrel - > eager_scan_remaining_fails > 0 )
{
next_unskippable_eager_scanned = true ;
break ;
}
next_unskippable_block + + ;
/*
* All - visible blocks are safe to skip in a normal vacuum . But
* remember that the final range contains such a block for later .
*/
* skipsallvis = true ;
}
/* write the local variables back to vacrel */
vacrel - > next_unskippable_block = next_unskippable_block ;
vacrel - > next_unskippable_allvis = next_unskippable_allvis ;
vacrel - > next_unskippable_eager_scanned = next_unskippable_eager_scanned ;
vacrel - > next_unskippable_vmbuffer = next_unskippable_vmbuffer ;
}
@ -1368,6 +1718,12 @@ find_next_unskippable_block(LVRelState *vacrel, bool *skipsallvis)
* lazy_scan_prune ( or lazy_scan_noprune ) . Otherwise returns true , indicating
* that lazy_scan_heap is done processing the page , releasing lock on caller ' s
* behalf .
*
* No vm_page_frozen output parameter ( like that passed to lazy_scan_prune ( ) )
* is passed here because neither empty nor new pages can be eagerly frozen .
* New pages are never frozen . Empty pages are always set frozen in the VM at
* the same time that they are set all - visible , and we don ' t eagerly scan
* frozen pages .
*/
static bool
lazy_scan_new_or_empty ( LVRelState * vacrel , Buffer buf , BlockNumber blkno ,
@ -1507,6 +1863,10 @@ cmpOffsetNumbers(const void *a, const void *b)
*
* * has_lpdead_items is set to true or false depending on whether , upon return
* from this function , any LP_DEAD items are still present on the page .
*
* * vm_page_frozen is set to true if the page is newly set all - frozen in the
* VM . The caller currently only uses this for determining whether an eagerly
* scanned page was successfully set all - frozen .
*/
static void
lazy_scan_prune ( LVRelState * vacrel ,
@ -1515,7 +1875,8 @@ lazy_scan_prune(LVRelState *vacrel,
Page page ,
Buffer vmbuffer ,
bool all_visible_according_to_vm ,
bool * has_lpdead_items )
bool * has_lpdead_items ,
bool * vm_page_frozen )
{
Relation rel = vacrel - > rel ;
PruneFreezeResult presult ;
@ -1667,11 +2028,17 @@ lazy_scan_prune(LVRelState *vacrel,
{
vacrel - > vm_new_visible_pages + + ;
if ( presult . all_frozen )
{
vacrel - > vm_new_visible_frozen_pages + + ;
* vm_page_frozen = true ;
}
}
else if ( ( old_vmbits & VISIBILITYMAP_ALL_FROZEN ) = = 0 & &
presult . all_frozen )
{
vacrel - > vm_new_frozen_pages + + ;
* vm_page_frozen = true ;
}
}
/*
@ -1759,6 +2126,7 @@ lazy_scan_prune(LVRelState *vacrel,
{
vacrel - > vm_new_visible_pages + + ;
vacrel - > vm_new_visible_frozen_pages + + ;
* vm_page_frozen = true ;
}
/*
@ -1766,7 +2134,10 @@ lazy_scan_prune(LVRelState *vacrel,
* above , so we don ' t need to test the value of old_vmbits .
*/
else
{
vacrel - > vm_new_frozen_pages + + ;
* vm_page_frozen = true ;
}
}
}