1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-24 00:23:06 +03:00

Refactor heap_page_prune_and_freeze() parameters into a struct

heap_page_prune_and_freeze() had accumulated an unwieldy number of input
parameters and upcoming work to handle VM updates in this function will
add even more.

Introduce a new PruneFreezeParams struct to group the function’s input
parameters, improving readability and maintainability.

Author: Melanie Plageman <melanieplageman@gmail.com>
Reviewed-by: Kirill Reshke <reshkekirill@gmail.com>
Discussion: https://postgr.es/m/yn4zp35kkdsjx6wf47zcfmxgexxt4h2og47pvnw2x5ifyrs3qc%407uw6jyyxuyf7
This commit is contained in:
Melanie Plageman
2025-11-20 10:30:43 -05:00
parent fa0ffa2877
commit 1937ed7062
4 changed files with 100 additions and 67 deletions

View File

@@ -261,12 +261,18 @@ heap_page_prune_opt(Relation relation, Buffer buffer)
PruneFreezeResult presult; PruneFreezeResult presult;
/* /*
* For now, pass mark_unused_now as false regardless of whether or * We don't pass the HEAP_PAGE_PRUNE_MARK_UNUSED_NOW option
* not the relation has indexes, since we cannot safely determine * regardless of whether or not the relation has indexes, since we
* that during on-access pruning with the current implementation. * cannot safely determine that during on-access pruning with the
* current implementation.
*/ */
heap_page_prune_and_freeze(relation, buffer, vistest, 0, PruneFreezeParams params = {.relation = relation,.buffer = buffer,
NULL, &presult, PRUNE_ON_ACCESS, &dummy_off_loc, NULL, NULL); .reason = PRUNE_ON_ACCESS,.options = 0,
.vistest = vistest,.cutoffs = NULL
};
heap_page_prune_and_freeze(&params, &presult, &dummy_off_loc,
NULL, NULL);
/* /*
* Report the number of tuples reclaimed to pgstats. This is * Report the number of tuples reclaimed to pgstats. This is
@@ -419,60 +425,44 @@ heap_page_will_freeze(Relation relation, Buffer buffer,
* also need to account for a reduction in the length of the line pointer * also need to account for a reduction in the length of the line pointer
* array following array truncation by us. * array following array truncation by us.
* *
* If the HEAP_PRUNE_FREEZE option is set, we will also freeze tuples if it's * params contains the input parameters used to control freezing and pruning
* required in order to advance relfrozenxid / relminmxid, or if it's * behavior. See the definition of PruneFreezeParams for more on what each
* considered advantageous for overall system performance to do so now. The * parameter does.
* 'cutoffs', 'presult', 'new_relfrozen_xid' and 'new_relmin_mxid' arguments
* are required when freezing. When HEAP_PRUNE_FREEZE option is set, we also
* set presult->all_visible and presult->all_frozen on exit, to indicate if
* the VM bits can be set. They are always set to false when the
* HEAP_PRUNE_FREEZE option is not set, because at the moment only callers
* that also freeze need that information.
* *
* vistest is used to distinguish whether tuples are DEAD or RECENTLY_DEAD * If the HEAP_PAGE_PRUNE_FREEZE option is set in params, we will freeze
* (see heap_prune_satisfies_vacuum). * tuples if it's required in order to advance relfrozenxid / relminmxid, or
* * if it's considered advantageous for overall system performance to do so
* options: * now. The 'params.cutoffs', 'presult', 'new_relfrozen_xid' and
* MARK_UNUSED_NOW indicates that dead items can be set LP_UNUSED during * 'new_relmin_mxid' arguments are required when freezing. When
* pruning. * HEAP_PAGE_PRUNE_FREEZE option is passed, we also set presult->all_visible
* * and presult->all_frozen on exit, to indicate if the VM bits can be set.
* FREEZE indicates that we will also freeze tuples, and will return * They are always set to false when the HEAP_PAGE_PRUNE_FREEZE option is not
* 'all_visible', 'all_frozen' flags to the caller. * passed, because at the moment only callers that also freeze need that
* * information.
* cutoffs contains the freeze cutoffs, established by VACUUM at the beginning
* of vacuuming the relation. Required if HEAP_PRUNE_FREEZE option is set.
* cutoffs->OldestXmin is also used to determine if dead tuples are
* HEAPTUPLE_RECENTLY_DEAD or HEAPTUPLE_DEAD.
* *
* presult contains output parameters needed by callers, such as the number of * presult contains output parameters needed by callers, such as the number of
* tuples removed and the offsets of dead items on the page after pruning. * tuples removed and the offsets of dead items on the page after pruning.
* heap_page_prune_and_freeze() is responsible for initializing it. Required * heap_page_prune_and_freeze() is responsible for initializing it. Required
* by all callers. * by all callers.
* *
* reason indicates why the pruning is performed. It is included in the WAL
* record for debugging and analysis purposes, but otherwise has no effect.
*
* off_loc is the offset location required by the caller to use in error * off_loc is the offset location required by the caller to use in error
* callback. * callback.
* *
* new_relfrozen_xid and new_relmin_mxid must provided by the caller if the * new_relfrozen_xid and new_relmin_mxid must provided by the caller if the
* HEAP_PRUNE_FREEZE option is set. On entry, they contain the oldest XID and * HEAP_PAGE_PRUNE_FREEZE option is set in params. On entry, they contain the
* multi-XID seen on the relation so far. They will be updated with oldest * oldest XID and multi-XID seen on the relation so far. They will be updated
* values present on the page after pruning. After processing the whole * with oldest values present on the page after pruning. After processing the
* relation, VACUUM can use these values as the new relfrozenxid/relminmxid * whole relation, VACUUM can use these values as the new
* for the relation. * relfrozenxid/relminmxid for the relation.
*/ */
void void
heap_page_prune_and_freeze(Relation relation, Buffer buffer, heap_page_prune_and_freeze(PruneFreezeParams *params,
GlobalVisState *vistest,
int options,
struct VacuumCutoffs *cutoffs,
PruneFreezeResult *presult, PruneFreezeResult *presult,
PruneReason reason,
OffsetNumber *off_loc, OffsetNumber *off_loc,
TransactionId *new_relfrozen_xid, TransactionId *new_relfrozen_xid,
MultiXactId *new_relmin_mxid) MultiXactId *new_relmin_mxid)
{ {
Buffer buffer = params->buffer;
Page page = BufferGetPage(buffer); Page page = BufferGetPage(buffer);
BlockNumber blockno = BufferGetBlockNumber(buffer); BlockNumber blockno = BufferGetBlockNumber(buffer);
OffsetNumber offnum, OffsetNumber offnum,
@@ -486,10 +476,11 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
int64 fpi_before = pgWalUsage.wal_fpi; int64 fpi_before = pgWalUsage.wal_fpi;
/* Copy parameters to prstate */ /* Copy parameters to prstate */
prstate.vistest = vistest; prstate.vistest = params->vistest;
prstate.mark_unused_now = (options & HEAP_PAGE_PRUNE_MARK_UNUSED_NOW) != 0; prstate.mark_unused_now =
prstate.attempt_freeze = (options & HEAP_PAGE_PRUNE_FREEZE) != 0; (params->options & HEAP_PAGE_PRUNE_MARK_UNUSED_NOW) != 0;
prstate.cutoffs = cutoffs; prstate.attempt_freeze = (params->options & HEAP_PAGE_PRUNE_FREEZE) != 0;
prstate.cutoffs = params->cutoffs;
/* /*
* Our strategy is to scan the page and make lists of items to change, * Our strategy is to scan the page and make lists of items to change,
@@ -583,7 +574,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
prstate.visibility_cutoff_xid = InvalidTransactionId; prstate.visibility_cutoff_xid = InvalidTransactionId;
maxoff = PageGetMaxOffsetNumber(page); maxoff = PageGetMaxOffsetNumber(page);
tup.t_tableOid = RelationGetRelid(relation); tup.t_tableOid = RelationGetRelid(params->relation);
/* /*
* Determine HTSV for all tuples, and queue them up for processing as HOT * Determine HTSV for all tuples, and queue them up for processing as HOT
@@ -786,7 +777,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
* Decide if we want to go ahead with freezing according to the freeze * Decide if we want to go ahead with freezing according to the freeze
* plans we prepared, or not. * plans we prepared, or not.
*/ */
do_freeze = heap_page_will_freeze(relation, buffer, do_freeze = heap_page_will_freeze(params->relation, buffer,
did_tuple_hint_fpi, did_tuple_hint_fpi,
do_prune, do_prune,
do_hint_prune, do_hint_prune,
@@ -838,7 +829,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
/* /*
* Emit a WAL XLOG_HEAP2_PRUNE* record showing what we did * Emit a WAL XLOG_HEAP2_PRUNE* record showing what we did
*/ */
if (RelationNeedsWAL(relation)) if (RelationNeedsWAL(params->relation))
{ {
/* /*
* The snapshotConflictHorizon for the whole record should be the * The snapshotConflictHorizon for the whole record should be the
@@ -876,11 +867,11 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer,
else else
conflict_xid = prstate.latest_xid_removed; conflict_xid = prstate.latest_xid_removed;
log_heap_prune_and_freeze(relation, buffer, log_heap_prune_and_freeze(params->relation, buffer,
InvalidBuffer, /* vmbuffer */ InvalidBuffer, /* vmbuffer */
0, /* vmflags */ 0, /* vmflags */
conflict_xid, conflict_xid,
true, reason, true, params->reason,
prstate.frozen, prstate.nfrozen, prstate.frozen, prstate.nfrozen,
prstate.redirected, prstate.nredirected, prstate.redirected, prstate.nredirected,
prstate.nowdead, prstate.ndead, prstate.nowdead, prstate.ndead,

View File

@@ -1965,7 +1965,10 @@ lazy_scan_prune(LVRelState *vacrel,
{ {
Relation rel = vacrel->rel; Relation rel = vacrel->rel;
PruneFreezeResult presult; PruneFreezeResult presult;
int prune_options = 0; PruneFreezeParams params = {.relation = rel,.buffer = buf,
.reason = PRUNE_VACUUM_SCAN,.options = HEAP_PAGE_PRUNE_FREEZE,
.vistest = vacrel->vistest,.cutoffs = &vacrel->cutoffs
};
Assert(BufferGetBlockNumber(buf) == blkno); Assert(BufferGetBlockNumber(buf) == blkno);
@@ -1984,12 +1987,11 @@ lazy_scan_prune(LVRelState *vacrel,
* tuples. Pruning will have determined whether or not the page is * tuples. Pruning will have determined whether or not the page is
* all-visible. * all-visible.
*/ */
prune_options = HEAP_PAGE_PRUNE_FREEZE;
if (vacrel->nindexes == 0) if (vacrel->nindexes == 0)
prune_options |= HEAP_PAGE_PRUNE_MARK_UNUSED_NOW; params.options |= HEAP_PAGE_PRUNE_MARK_UNUSED_NOW;
heap_page_prune_and_freeze(rel, buf, vacrel->vistest, prune_options, heap_page_prune_and_freeze(&params,
&vacrel->cutoffs, &presult, PRUNE_VACUUM_SCAN, &presult,
&vacrel->offnum, &vacrel->offnum,
&vacrel->NewRelfrozenXid, &vacrel->NewRelminMxid); &vacrel->NewRelfrozenXid, &vacrel->NewRelminMxid);

View File

@@ -221,6 +221,56 @@ typedef struct HeapPageFreeze
} HeapPageFreeze; } HeapPageFreeze;
/* 'reason' codes for heap_page_prune_and_freeze() */
typedef enum
{
PRUNE_ON_ACCESS, /* on-access pruning */
PRUNE_VACUUM_SCAN, /* VACUUM 1st heap pass */
PRUNE_VACUUM_CLEANUP, /* VACUUM 2nd heap pass */
} PruneReason;
/*
* Input parameters to heap_page_prune_and_freeze()
*/
typedef struct PruneFreezeParams
{
Relation relation; /* relation containing buffer to be pruned */
Buffer buffer; /* buffer to be pruned */
/*
* The reason pruning was performed. It is used to set the WAL record
* opcode which is used for debugging and analysis purposes.
*/
PruneReason reason;
/*
* Contains flag bits:
*
* HEAP_PAGE_PRUNE_MARK_UNUSED_NOW indicates that dead items can be set
* LP_UNUSED during pruning.
*
* HEAP_PAGE_PRUNE_FREEZE indicates that we will also freeze tuples, and
* will return 'all_visible', 'all_frozen' flags to the caller.
*/
int options;
/*
* vistest is used to distinguish whether tuples are DEAD or RECENTLY_DEAD
* (see heap_prune_satisfies_vacuum).
*/
GlobalVisState *vistest;
/*
* Contains the cutoffs used for freezing. They are required if the
* HEAP_PAGE_PRUNE_FREEZE option is set. cutoffs->OldestXmin is also used
* to determine if dead tuples are HEAPTUPLE_RECENTLY_DEAD or
* HEAPTUPLE_DEAD. Currently only vacuum passes in cutoffs. Vacuum
* calculates them once, at the beginning of vacuuming the relation.
*/
struct VacuumCutoffs *cutoffs;
} PruneFreezeParams;
/* /*
* Per-page state returned by heap_page_prune_and_freeze() * Per-page state returned by heap_page_prune_and_freeze()
*/ */
@@ -264,13 +314,6 @@ typedef struct PruneFreezeResult
OffsetNumber deadoffsets[MaxHeapTuplesPerPage]; OffsetNumber deadoffsets[MaxHeapTuplesPerPage];
} PruneFreezeResult; } PruneFreezeResult;
/* 'reason' codes for heap_page_prune_and_freeze() */
typedef enum
{
PRUNE_ON_ACCESS, /* on-access pruning */
PRUNE_VACUUM_SCAN, /* VACUUM 1st heap pass */
PRUNE_VACUUM_CLEANUP, /* VACUUM 2nd heap pass */
} PruneReason;
/* ---------------- /* ----------------
* function prototypes for heap access method * function prototypes for heap access method
@@ -367,12 +410,8 @@ extern TransactionId heap_index_delete_tuples(Relation rel,
/* in heap/pruneheap.c */ /* in heap/pruneheap.c */
extern void heap_page_prune_opt(Relation relation, Buffer buffer); extern void heap_page_prune_opt(Relation relation, Buffer buffer);
extern void heap_page_prune_and_freeze(Relation relation, Buffer buffer, extern void heap_page_prune_and_freeze(PruneFreezeParams *params,
GlobalVisState *vistest,
int options,
struct VacuumCutoffs *cutoffs,
PruneFreezeResult *presult, PruneFreezeResult *presult,
PruneReason reason,
OffsetNumber *off_loc, OffsetNumber *off_loc,
TransactionId *new_relfrozen_xid, TransactionId *new_relfrozen_xid,
MultiXactId *new_relmin_mxid); MultiXactId *new_relmin_mxid);

View File

@@ -2348,6 +2348,7 @@ ProjectionPath
PromptInterruptContext PromptInterruptContext
ProtocolVersion ProtocolVersion
PrsStorage PrsStorage
PruneFreezeParams
PruneFreezeResult PruneFreezeResult
PruneReason PruneReason
PruneState PruneState