diff options
Diffstat (limited to 'src/include/access/heapam.h')
-rw-r--r-- | src/include/access/heapam.h | 91 |
1 files changed, 83 insertions, 8 deletions
diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 53eb011766b..09a1993f4d7 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -113,6 +113,82 @@ typedef struct HeapTupleFreeze OffsetNumber offset; } HeapTupleFreeze; +/* + * State used by VACUUM to track the details of freezing all eligible tuples + * on a given heap page. + * + * VACUUM prepares freeze plans for each page via heap_prepare_freeze_tuple + * calls (every tuple with storage gets its own call). This page-level freeze + * state is updated across each call, which ultimately determines whether or + * not freezing the page is required. + * + * Aside from the basic question of whether or not freezing will go ahead, the + * state also tracks the oldest extant XID/MXID in the table as a whole, for + * the purposes of advancing relfrozenxid/relminmxid values in pg_class later + * on. Each heap_prepare_freeze_tuple call pushes NewRelfrozenXid and/or + * NewRelminMxid back as required to avoid unsafe final pg_class values. Any + * and all unfrozen XIDs or MXIDs that remain after VACUUM finishes _must_ + * have values >= the final relfrozenxid/relminmxid values in pg_class. This + * includes XIDs that remain as MultiXact members from any tuple's xmax. + * + * When 'freeze_required' flag isn't set after all tuples are examined, the + * final choice on freezing is made by vacuumlazy.c. It can decide to trigger + * freezing based on whatever criteria it deems appropriate. However, it is + * recommended that vacuumlazy.c avoid early freezing when freezing does not + * enable setting the target page all-frozen in the visibility map afterwards. + */ +typedef struct HeapPageFreeze +{ + /* Is heap_prepare_freeze_tuple caller required to freeze page? */ + bool freeze_required; + + /* + * "Freeze" NewRelfrozenXid/NewRelminMxid trackers. + * + * Trackers used when heap_freeze_execute_prepared freezes the page, and + * when page is "nominally frozen", which happens with pages where every + * call to heap_prepare_freeze_tuple produced no usable freeze plan. + * + * "Nominal freezing" enables vacuumlazy.c's approach of setting a page + * all-frozen in the visibility map when every tuple's 'totally_frozen' + * result is true. That always works in the same way, independent of the + * need to freeze tuples, and without complicating the general rule around + * 'totally_frozen' results (which is that 'totally_frozen' results are + * only to be trusted with a page that goes on to be frozen by caller). + * + * When we freeze a page, we generally freeze all XIDs < OldestXmin, only + * leaving behind XIDs that are ineligible for freezing, if any. And so + * you might wonder why these trackers are necessary at all; why should + * _any_ page that VACUUM freezes _ever_ be left with XIDs/MXIDs that + * ratchet back the top-level NewRelfrozenXid/NewRelminMxid trackers? + * + * It is useful to use a definition of "freeze the page" that does not + * overspecify how MultiXacts are affected. heap_prepare_freeze_tuple + * generally prefers to remove Multis eagerly, but lazy processing is used + * in cases where laziness allows VACUUM to avoid allocating a new Multi. + * The "freeze the page" trackers enable this flexibility. + */ + TransactionId FreezePageRelfrozenXid; + MultiXactId FreezePageRelminMxid; + + /* + * "No freeze" NewRelfrozenXid/NewRelminMxid trackers. + * + * These trackers are maintained in the same way as the trackers used when + * VACUUM scans a page that isn't cleanup locked. Both code paths are + * based on the same general idea (do less work for this page during the + * ongoing VACUUM, at the cost of having to accept older final values). + * + * When vacuumlazy.c caller decides to do "no freeze" processing, it must + * not go on to set the page all-frozen (setting the page all-visible + * could still be okay). heap_prepare_freeze_tuple's 'totally_frozen' + * results can only be used on a page that also gets frozen as instructed. + */ + TransactionId NoFreezePageRelfrozenXid; + MultiXactId NoFreezePageRelminMxid; + +} HeapPageFreeze; + /* ---------------- * function prototypes for heap access method * @@ -180,19 +256,18 @@ extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple, extern void heap_inplace_update(Relation relation, HeapTuple tuple); extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, const struct VacuumCutoffs *cutoffs, - HeapTupleFreeze *frz, bool *totally_frozen, - TransactionId *relfrozenxid_out, - MultiXactId *relminmxid_out); + HeapPageFreeze *pagefrz, + HeapTupleFreeze *frz, bool *totally_frozen); extern void heap_freeze_execute_prepared(Relation rel, Buffer buffer, - TransactionId FreezeLimit, + TransactionId snapshotConflictHorizon, HeapTupleFreeze *tuples, int ntuples); extern bool heap_freeze_tuple(HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId FreezeLimit, TransactionId MultiXactCutoff); -extern bool heap_tuple_would_freeze(HeapTupleHeader tuple, - const struct VacuumCutoffs *cutoffs, - TransactionId *relfrozenxid_out, - MultiXactId *relminmxid_out); +extern bool heap_tuple_should_freeze(HeapTupleHeader tuple, + const struct VacuumCutoffs *cutoffs, + TransactionId *NoFreezePageRelfrozenXid, + MultiXactId *NoFreezePageRelminMxid); extern bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple); extern void simple_heap_insert(Relation relation, HeapTuple tup); |