From 07e6620bc79878c1f6a2eed4dd6b338045cd9b40 Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Sun, 7 Jan 2024 16:53:45 -0500 Subject: [PATCH v3 09/17] Separate tuple pre freeze checks and invoke earlier When combining the prune and freeze records their critical sections will have to be combined. heap_freeze_execute_prepared() does a set of pre freeze validations before starting its critical section. Move these validations into a helper function, heap_pre_freeze_checks(), and invoke it in heap_page_prune() before the pruning critical section. Also move up the calculation of the freeze snapshot conflict horizon. --- src/backend/access/heap/heapam.c | 58 ++++++++++++++++------------- src/backend/access/heap/pruneheap.c | 8 +++- src/include/access/heapam.h | 3 ++ 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 7261c4988d7..16e3f2520a4 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6659,35 +6659,19 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, HeapTupleFreeze *frz) } /* - * heap_freeze_execute_prepared - * - * Executes freezing of one or more heap tuples on a page on behalf of caller. - * Caller passes an array of tuple plans from heap_prepare_freeze_tuple. - * Caller must set 'offset' in each plan for us. Note that we destructively - * sort caller's tuples array in-place, so caller had better be done with it. - * - * WAL-logs the changes so that VACUUM can advance the rel's relfrozenxid - * later on without any risk of unsafe pg_xact lookups, even following a hard - * crash (or when querying from a standby). We represent freezing by setting - * infomask bits in tuple headers, but this shouldn't be thought of as a hint. - * See section on buffer access rules in src/backend/storage/buffer/README. - */ +* Perform xmin/xmax XID status sanity checks before calling +* heap_freeze_execute_prepared(). +* +* heap_prepare_freeze_tuple doesn't perform these checks directly because +* pg_xact lookups are relatively expensive. They shouldn't be repeated +* by successive VACUUMs that each decide against freezing the same page. +*/ void -heap_freeze_execute_prepared(Relation rel, Buffer buffer, - TransactionId snapshotConflictHorizon, - HeapTupleFreeze *tuples, int ntuples) +heap_pre_freeze_checks(Buffer buffer, + HeapTupleFreeze *tuples, int ntuples) { Page page = BufferGetPage(buffer); - Assert(ntuples > 0); - - /* - * Perform xmin/xmax XID status sanity checks before critical section. - * - * heap_prepare_freeze_tuple doesn't perform these checks directly because - * pg_xact lookups are relatively expensive. They shouldn't be repeated - * by successive VACUUMs that each decide against freezing the same page. - */ for (int i = 0; i < ntuples; i++) { HeapTupleFreeze *frz = tuples + i; @@ -6726,6 +6710,30 @@ heap_freeze_execute_prepared(Relation rel, Buffer buffer, xmax))); } } +} + +/* + * heap_freeze_execute_prepared + * + * Executes freezing of one or more heap tuples on a page on behalf of caller. + * Caller passes an array of tuple plans from heap_prepare_freeze_tuple. + * Caller must set 'offset' in each plan for us. Note that we destructively + * sort caller's tuples array in-place, so caller had better be done with it. + * + * WAL-logs the changes so that VACUUM can advance the rel's relfrozenxid + * later on without any risk of unsafe pg_xact lookups, even following a hard + * crash (or when querying from a standby). We represent freezing by setting + * infomask bits in tuple headers, but this shouldn't be thought of as a hint. + * See section on buffer access rules in src/backend/storage/buffer/README. + */ +void +heap_freeze_execute_prepared(Relation rel, Buffer buffer, + TransactionId snapshotConflictHorizon, + HeapTupleFreeze *tuples, int ntuples) +{ + Page page = BufferGetPage(buffer); + + Assert(ntuples > 0); START_CRIT_SECTION(); diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index f164b7957ed..bc0a23da61b 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -523,6 +523,12 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, (pagefrz->freeze_required || (whole_page_freezable && presult->nfrozen > 0 && (prune_fpi || hint_bit_fpi))); + if (do_freeze) + { + heap_pre_freeze_checks(buffer, frozen, presult->nfrozen); + frz_conflict_horizon = heap_frz_conflict_horizon(presult, pagefrz); + } + /* Any error while applying the changes is critical */ START_CRIT_SECTION(); @@ -621,8 +627,6 @@ heap_page_prune_and_freeze(Relation relation, Buffer buffer, if (do_freeze) { - frz_conflict_horizon = heap_frz_conflict_horizon(presult, pagefrz); - /* Execute all freeze plans for page as a single atomic action */ heap_freeze_execute_prepared(relation, buffer, frz_conflict_horizon, diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 45c4ae22e6a..dffbbd3cd3e 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -314,6 +314,9 @@ extern TransactionId heap_frz_conflict_horizon(PruneFreezeResult *presult, extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, HeapPageFreeze *pagefrz, HeapTupleFreeze *frz, bool *totally_frozen); + +extern void heap_pre_freeze_checks(Buffer buffer, + HeapTupleFreeze *tuples, int ntuples); extern void heap_freeze_execute_prepared(Relation rel, Buffer buffer, TransactionId snapshotConflictHorizon, HeapTupleFreeze *tuples, int ntuples); -- 2.40.1