From: Melanie Plageman Date: Thu, 20 Nov 2025 15:30:43 +0000 (-0500) Subject: Refactor heap_page_prune_and_freeze() parameters into a struct X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=1937ed70621e203c99e651ce4430dd217743d150;p=postgresql.git 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 Reviewed-by: Kirill Reshke Discussion: https://postgr.es/m/yn4zp35kkdsjx6wf47zcfmxgexxt4h2og47pvnw2x5ifyrs3qc%407uw6jyyxuyf7 --- diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 231bea679c6..e9e14cb42b7 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -261,12 +261,18 @@ heap_page_prune_opt(Relation relation, Buffer buffer) PruneFreezeResult presult; /* - * For now, pass mark_unused_now as false regardless of whether or - * not the relation has indexes, since we cannot safely determine - * that during on-access pruning with the current implementation. + * We don't pass the HEAP_PAGE_PRUNE_MARK_UNUSED_NOW option + * regardless of whether or not the relation has indexes, since we + * cannot safely determine that during on-access pruning with the + * current implementation. */ - heap_page_prune_and_freeze(relation, buffer, vistest, 0, - NULL, &presult, PRUNE_ON_ACCESS, &dummy_off_loc, NULL, NULL); + PruneFreezeParams params = {.relation = relation,.buffer = buffer, + .reason = PRUNE_ON_ACCESS,.options = 0, + .vistest = vistest,.cutoffs = NULL + }; + + heap_page_prune_and_freeze(¶ms, &presult, &dummy_off_loc, + NULL, NULL); /* * 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 * array following array truncation by us. * - * If the HEAP_PRUNE_FREEZE option is set, we will also freeze tuples if it's - * required in order to advance relfrozenxid / relminmxid, or if it's - * considered advantageous for overall system performance to do so now. The - * '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 - * (see heap_prune_satisfies_vacuum). - * - * options: - * MARK_UNUSED_NOW indicates that dead items can be set LP_UNUSED during - * pruning. + * params contains the input parameters used to control freezing and pruning + * behavior. See the definition of PruneFreezeParams for more on what each + * parameter does. * - * FREEZE indicates that we will also freeze tuples, and will return - * 'all_visible', 'all_frozen' flags to the caller. - * - * 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. + * If the HEAP_PAGE_PRUNE_FREEZE option is set in params, we will freeze + * tuples if it's required in order to advance relfrozenxid / relminmxid, or + * if it's considered advantageous for overall system performance to do so + * now. The 'params.cutoffs', 'presult', 'new_relfrozen_xid' and + * 'new_relmin_mxid' arguments are required when freezing. When + * 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. + * They are always set to false when the HEAP_PAGE_PRUNE_FREEZE option is not + * passed, because at the moment only callers that also freeze need that + * information. * * 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. * heap_page_prune_and_freeze() is responsible for initializing it. Required * 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 * callback. * * 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 - * multi-XID seen on the relation so far. They will be updated with oldest - * values present on the page after pruning. After processing the whole - * relation, VACUUM can use these values as the new relfrozenxid/relminmxid - * for the relation. + * HEAP_PAGE_PRUNE_FREEZE option is set in params. On entry, they contain the + * oldest XID and multi-XID seen on the relation so far. They will be updated + * with oldest values present on the page after pruning. After processing the + * whole relation, VACUUM can use these values as the new + * relfrozenxid/relminmxid for the relation. */ void -heap_page_prune_and_freeze(Relation relation, Buffer buffer, - GlobalVisState *vistest, - int options, - struct VacuumCutoffs *cutoffs, +heap_page_prune_and_freeze(PruneFreezeParams *params, PruneFreezeResult *presult, - PruneReason reason, OffsetNumber *off_loc, TransactionId *new_relfrozen_xid, MultiXactId *new_relmin_mxid) { + Buffer buffer = params->buffer; Page page = BufferGetPage(buffer); BlockNumber blockno = BufferGetBlockNumber(buffer); OffsetNumber offnum, @@ -486,10 +476,11 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, 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.attempt_freeze = (options & HEAP_PAGE_PRUNE_FREEZE) != 0; - prstate.cutoffs = cutoffs; + prstate.vistest = params->vistest; + prstate.mark_unused_now = + (params->options & HEAP_PAGE_PRUNE_MARK_UNUSED_NOW) != 0; + 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, @@ -583,7 +574,7 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, prstate.visibility_cutoff_xid = InvalidTransactionId; 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 @@ -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 * 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, do_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 */ - if (RelationNeedsWAL(relation)) + if (RelationNeedsWAL(params->relation)) { /* * The snapshotConflictHorizon for the whole record should be the @@ -876,11 +867,11 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, else conflict_xid = prstate.latest_xid_removed; - log_heap_prune_and_freeze(relation, buffer, + log_heap_prune_and_freeze(params->relation, buffer, InvalidBuffer, /* vmbuffer */ 0, /* vmflags */ conflict_xid, - true, reason, + true, params->reason, prstate.frozen, prstate.nfrozen, prstate.redirected, prstate.nredirected, prstate.nowdead, prstate.ndead, diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index deb9a3dc0d1..c3fc1098e23 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -1965,7 +1965,10 @@ lazy_scan_prune(LVRelState *vacrel, { Relation rel = vacrel->rel; 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); @@ -1984,12 +1987,11 @@ lazy_scan_prune(LVRelState *vacrel, * tuples. Pruning will have determined whether or not the page is * all-visible. */ - prune_options = HEAP_PAGE_PRUNE_FREEZE; 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, - &vacrel->cutoffs, &presult, PRUNE_VACUUM_SCAN, + heap_page_prune_and_freeze(¶ms, + &presult, &vacrel->offnum, &vacrel->NewRelfrozenXid, &vacrel->NewRelminMxid); diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 909db73b7bb..632c4332a8c 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -221,6 +221,56 @@ typedef struct 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() */ @@ -264,13 +314,6 @@ typedef struct PruneFreezeResult OffsetNumber deadoffsets[MaxHeapTuplesPerPage]; } 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 @@ -367,12 +410,8 @@ extern TransactionId heap_index_delete_tuples(Relation rel, /* in heap/pruneheap.c */ extern void heap_page_prune_opt(Relation relation, Buffer buffer); -extern void heap_page_prune_and_freeze(Relation relation, Buffer buffer, - GlobalVisState *vistest, - int options, - struct VacuumCutoffs *cutoffs, +extern void heap_page_prune_and_freeze(PruneFreezeParams *params, PruneFreezeResult *presult, - PruneReason reason, OffsetNumber *off_loc, TransactionId *new_relfrozen_xid, MultiXactId *new_relmin_mxid); diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 57f2a9ccdc5..c751c25a04d 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2348,6 +2348,7 @@ ProjectionPath PromptInterruptContext ProtocolVersion PrsStorage +PruneFreezeParams PruneFreezeResult PruneReason PruneState