/
githubmirror
/
postgres
Обзор
Документация
Войти
/
githubmirror
/
postgres
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/include/access/heapam.h
547 строк
20 KB
Peter Geoghegan
heapam: Track heap block in IndexFetchHeapData.
04 апр 2026, 18:45
04 апр 2026, 18:45
c7d0959
Код
Авторство
О чём код?
/*------------------------------------------------------------------------- * * heapam.h * POSTGRES heap access method definitions. * * * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/heapam.h * *------------------------------------------------------------------------- */ #ifndef HEAPAM_H #define HEAPAM_H #include "access/heapam_xlog.h" #include "access/relation.h" /* for backward compatibility */ #include "access/relscan.h" #include "access/sdir.h" #include "access/skey.h" #include "access/table.h" /* for backward compatibility */ #include "access/tableam.h" #include "nodes/lockoptions.h" #include "nodes/primnodes.h" #include "storage/bufpage.h" #include "storage/dsm.h" #include "storage/lockdefs.h" #include "storage/read_stream.h" #include "storage/shm_toc.h" #include "utils/relcache.h" #include "utils/snapshot.h" /* "options" flag bits for heap_insert */ #define HEAP_INSERT_SKIP_FSM TABLE_INSERT_SKIP_FSM #define HEAP_INSERT_FROZEN TABLE_INSERT_FROZEN #define HEAP_INSERT_NO_LOGICAL TABLE_INSERT_NO_LOGICAL #define HEAP_INSERT_SPECULATIVE 0x0010 /* "options" flag bits for heap_page_prune_and_freeze */ #define HEAP_PAGE_PRUNE_MARK_UNUSED_NOW (1 << 0) #define HEAP_PAGE_PRUNE_FREEZE (1 << 1) #define HEAP_PAGE_PRUNE_ALLOW_FAST_PATH (1 << 2) #define HEAP_PAGE_PRUNE_SET_VM (1 << 3) typedef struct BulkInsertStateData *BulkInsertState; typedef struct GlobalVisState GlobalVisState; typedef struct TupleTableSlot TupleTableSlot; typedef struct VacuumCutoffs VacuumCutoffs; typedef struct VacuumParams VacuumParams; #define MaxLockTupleMode LockTupleExclusive /* * Descriptor for heap table scans. */ typedef struct HeapScanDescData { TableScanDescData rs_base; /* AM independent part of the descriptor */ /* state set up at initscan time */ BlockNumber rs_nblocks; /* total number of blocks in rel */ BlockNumber rs_startblock; /* block # to start at */ BlockNumber rs_numblocks; /* max number of blocks to scan */ /* rs_numblocks is usually InvalidBlockNumber, meaning "scan whole rel" */ /* scan current state */ bool rs_inited; /* false = scan not init'd yet */ OffsetNumber rs_coffset; /* current offset # in non-page-at-a-time mode */ BlockNumber rs_cblock; /* current block # in scan, if any */ Buffer rs_cbuf; /* current buffer in scan, if any */ /* NB: if rs_cbuf is not InvalidBuffer, we hold a pin on that buffer */ BufferAccessStrategy rs_strategy; /* access strategy for reads */ HeapTupleData rs_ctup; /* current tuple in scan, if any */ /* For scans that stream reads */ ReadStream *rs_read_stream; /* * For sequential scans and TID range scans to stream reads. The read * stream is allocated at the beginning of the scan and reset on rescan or * when the scan direction changes. The scan direction is saved each time * a new page is requested. If the scan direction changes from one page to * the next, the read stream releases all previously pinned buffers and * resets the prefetch block. */ ScanDirection rs_dir; BlockNumber rs_prefetch_block; /* * For parallel scans to store page allocation data. NULL when not * performing a parallel scan. */ ParallelBlockTableScanWorkerData *rs_parallelworkerdata; /* Current heap block's corresponding page in the visibility map */ Buffer rs_vmbuffer; /* these fields only used in page-at-a-time mode and for bitmap scans */ uint32 rs_cindex; /* current tuple's index in vistuples */ uint32 rs_ntuples; /* number of visible tuples on page */ OffsetNumber rs_vistuples[MaxHeapTuplesPerPage]; /* their offsets */ } HeapScanDescData; typedef struct HeapScanDescData *HeapScanDesc; typedef struct BitmapHeapScanDescData { HeapScanDescData rs_heap_base; /* Holds no data */ } BitmapHeapScanDescData; typedef struct BitmapHeapScanDescData *BitmapHeapScanDesc; /* * Descriptor for fetches from heap via an index. */ typedef struct IndexFetchHeapData { IndexFetchTableData xs_base; /* AM independent part of the descriptor */ /* * Current heap buffer in scan (and its block number), if any. NB: if * xs_blk is not InvalidBlockNumber, we hold a pin in xs_cbuf. */ Buffer xs_cbuf; BlockNumber xs_blk; /* Current heap block's corresponding page in the visibility map */ Buffer xs_vmbuffer; } IndexFetchHeapData; /* Result codes for HeapTupleSatisfiesVacuum */ typedef enum { HEAPTUPLE_DEAD, /* tuple is dead and deletable */ HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ HEAPTUPLE_DELETE_IN_PROGRESS, /* deleting xact is still in progress */ } HTSV_Result; /* * heap_prepare_freeze_tuple may request that heap_freeze_execute_prepared * check any tuple's to-be-frozen xmin and/or xmax status using pg_xact */ #define HEAP_FREEZE_CHECK_XMIN_COMMITTED 0x01 #define HEAP_FREEZE_CHECK_XMAX_ABORTED 0x02 /* heap_prepare_freeze_tuple state describing how to freeze a tuple */ typedef struct HeapTupleFreeze { /* Fields describing how to process tuple */ TransactionId xmax; uint16 t_infomask2; uint16 t_infomask; uint8 frzflags; /* xmin/xmax check flags */ uint8 checkflags; /* Page offset number for tuple */ 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, or when there * are zero freeze plans for a page. It is always valid for vacuumlazy.c * to freeze any page, by definition. This even includes pages that have * no tuples with storage to consider in the first place. That way the * 'totally_frozen' results from heap_prepare_freeze_tuple can always be * used in the same way, even when no freeze plans need to be executed to * "freeze the page". Only the "freeze" path needs to consider the need * to set pages all-frozen in the visibility map under this scheme. * * 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; /* * Newest XID that this page's freeze actions will remove from tuple * visibility metadata (currently xmin and/or xvac). It is used to derive * the snapshot conflict horizon for a WAL record that freezes tuples. On * a standby, we must not replay that change while any snapshot could * still treat that XID as running. * * It's only used if we execute freeze plans for this page, so there is no * corresponding "no freeze" tracker. */ TransactionId FreezePageConflictXid; /* * "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). */ TransactionId NoFreezePageRelfrozenXid; MultiXactId NoFreezePageRelminMxid; } 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 */ /* * Callers should provide a pinned vmbuffer corresponding to the heap * block in buffer. We will check for and repair any corruption in the VM * and set the VM after pruning if the page is all-visible/all-frozen. */ Buffer vmbuffer; /* * 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. */ 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. */ VacuumCutoffs *cutoffs; } PruneFreezeParams; /* * Per-page state returned by heap_page_prune_and_freeze() */ typedef struct PruneFreezeResult { int ndeleted; /* Number of tuples deleted from the page */ int nnewlpdead; /* Number of newly LP_DEAD items */ int nfrozen; /* Number of tuples we froze */ /* Number of live and recently dead tuples on the page, after pruning */ int live_tuples; int recently_dead_tuples; /* * Whether or not the page was newly set all-visible and all-frozen during * phase I of vacuuming. */ bool newly_all_visible; bool newly_all_visible_frozen; bool newly_all_frozen; /* * Whether or not the page makes rel truncation unsafe. This is set to * 'true', even if the page contains LP_DEAD items. VACUUM will remove * them before attempting to truncate. */ bool hastup; /* * LP_DEAD items on the page after pruning. Includes existing LP_DEAD * items. */ int lpdead_items; OffsetNumber deadoffsets[MaxHeapTuplesPerPage]; } PruneFreezeResult; /* ---------------- * function prototypes for heap access method * * heap_create, heap_create_with_catalog, and heap_drop_with_catalog * are declared in catalog/heap.h * ---------------- */ extern TableScanDesc heap_beginscan(Relation relation, Snapshot snapshot, int nkeys, ScanKey key, ParallelTableScanDesc parallel_scan, uint32 flags); extern void heap_setscanlimits(TableScanDesc sscan, BlockNumber startBlk, BlockNumber numBlks); extern void heap_prepare_pagescan(TableScanDesc sscan); extern void heap_rescan(TableScanDesc sscan, ScanKey key, bool set_params, bool allow_strat, bool allow_sync, bool allow_pagemode); extern void heap_endscan(TableScanDesc sscan); extern HeapTuple heap_getnext(TableScanDesc sscan, ScanDirection direction); extern bool heap_getnextslot(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot); extern void heap_set_tidrange(TableScanDesc sscan, ItemPointer mintid, ItemPointer maxtid); extern bool heap_getnextslot_tidrange(TableScanDesc sscan, ScanDirection direction, TupleTableSlot *slot); extern bool heap_fetch(Relation relation, Snapshot snapshot, HeapTuple tuple, Buffer *userbuf, bool keep_buf); extern void heap_get_latest_tid(TableScanDesc sscan, ItemPointer tid); extern BulkInsertState GetBulkInsertState(void); extern void FreeBulkInsertState(BulkInsertState); extern void ReleaseBulkInsertStatePin(BulkInsertState bistate); extern void heap_insert(Relation relation, HeapTuple tup, CommandId cid, uint32 options, BulkInsertState bistate); extern void heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples, CommandId cid, uint32 options, BulkInsertState bistate); extern TM_Result heap_delete(Relation relation, const ItemPointerData *tid, CommandId cid, uint32 options, Snapshot crosscheck, bool wait, TM_FailureData *tmfd); extern void heap_finish_speculative(Relation relation, const ItemPointerData *tid); extern void heap_abort_speculative(Relation relation, const ItemPointerData *tid); extern TM_Result heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, CommandId cid, uint32 options, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes); extern TM_Result heap_lock_tuple(Relation relation, HeapTuple tuple, CommandId cid, LockTupleMode mode, LockWaitPolicy wait_policy, bool follow_updates, Buffer *buffer, TM_FailureData *tmfd); extern bool heap_inplace_lock(Relation relation, HeapTuple oldtup_ptr, Buffer buffer, void (*release_callback) (void *), void *arg); extern void heap_inplace_update_and_unlock(Relation relation, HeapTuple oldtup, HeapTuple tuple, Buffer buffer); extern void heap_inplace_unlock(Relation relation, HeapTuple oldtup, Buffer buffer); extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple, const VacuumCutoffs *cutoffs, HeapPageFreeze *pagefrz, HeapTupleFreeze *frz, bool *totally_frozen); extern void heap_pre_freeze_checks(Buffer buffer, HeapTupleFreeze *tuples, int ntuples); extern void heap_freeze_prepared_tuples(Buffer buffer, HeapTupleFreeze *tuples, int ntuples); extern bool heap_freeze_tuple(HeapTupleHeader tuple, TransactionId relfrozenxid, TransactionId relminmxid, TransactionId FreezeLimit, TransactionId MultiXactCutoff); extern bool heap_tuple_should_freeze(HeapTupleHeader tuple, const VacuumCutoffs *cutoffs, TransactionId *NoFreezePageRelfrozenXid, MultiXactId *NoFreezePageRelminMxid); extern bool heap_tuple_needs_eventual_freeze(HeapTupleHeader tuple); extern void simple_heap_insert(Relation relation, HeapTuple tup); extern void simple_heap_delete(Relation relation, const ItemPointerData *tid); extern void simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tup, TU_UpdateIndexes *update_indexes); extern TransactionId heap_index_delete_tuples(Relation rel, TM_IndexDeleteOp *delstate); /* in heap/heapam_indexscan.c */ extern IndexFetchTableData *heapam_index_fetch_begin(Relation rel, uint32 flags); extern void heapam_index_fetch_reset(IndexFetchTableData *scan); extern void heapam_index_fetch_end(IndexFetchTableData *scan); extern bool heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, Snapshot snapshot, HeapTuple heapTuple, bool *all_dead, bool first_call); extern bool heapam_index_fetch_tuple(struct IndexFetchTableData *scan, ItemPointer tid, Snapshot snapshot, TupleTableSlot *slot, bool *heap_continue, bool *all_dead); /* in heap/pruneheap.c */ extern void heap_page_prune_opt(Relation relation, Buffer buffer, Buffer *vmbuffer, bool rel_read_only); extern void heap_page_prune_and_freeze(PruneFreezeParams *params, PruneFreezeResult *presult, OffsetNumber *off_loc, TransactionId *new_relfrozen_xid, MultiXactId *new_relmin_mxid); extern void heap_page_prune_execute(Buffer buffer, bool lp_truncate_only, OffsetNumber *redirected, int nredirected, OffsetNumber *nowdead, int ndead, OffsetNumber *nowunused, int nunused); extern void heap_get_root_tuples(Page page, OffsetNumber *root_offsets); extern void log_heap_prune_and_freeze(Relation relation, Buffer buffer, Buffer vmbuffer, uint8 vmflags, TransactionId conflict_xid, bool cleanup_lock, PruneReason reason, HeapTupleFreeze *frozen, int nfrozen, OffsetNumber *redirected, int nredirected, OffsetNumber *dead, int ndead, OffsetNumber *unused, int nunused); /* in heap/vacuumlazy.c */ extern void heap_vacuum_rel(Relation rel, const VacuumParams *params, BufferAccessStrategy bstrategy); #ifdef USE_ASSERT_CHECKING extern bool heap_page_is_all_visible(Relation rel, Buffer buf, GlobalVisState *vistest, bool *all_frozen, TransactionId *newest_live_xid, OffsetNumber *logging_offnum); #endif /* in heap/heapam_visibility.c */ extern bool HeapTupleSatisfiesVisibility(HeapTuple htup, Snapshot snapshot, Buffer buffer); extern TM_Result HeapTupleSatisfiesUpdate(HeapTuple htup, CommandId curcid, Buffer buffer); extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTuple htup, TransactionId OldestXmin, Buffer buffer); extern HTSV_Result HeapTupleSatisfiesVacuumHorizon(HeapTuple htup, Buffer buffer, TransactionId *dead_after); extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer, uint16 infomask, TransactionId xid); extern bool HeapTupleHeaderIsOnlyLocked(HeapTupleHeader tuple); extern bool HeapTupleIsSurelyDead(HeapTuple htup, GlobalVisState *vistest); /* * Some of the input/output to/from HeapTupleSatisfiesMVCCBatch() is passed * via this struct, as otherwise the increased number of arguments to * HeapTupleSatisfiesMVCCBatch() leads to on-stack argument passing on x86-64, * which causes a small regression. */ typedef struct BatchMVCCState { HeapTupleData tuples[MaxHeapTuplesPerPage]; bool visible[MaxHeapTuplesPerPage]; } BatchMVCCState; extern int HeapTupleSatisfiesMVCCBatch(Snapshot snapshot, Buffer buffer, int ntups, BatchMVCCState *batchmvcc, OffsetNumber *vistuples_dense); /* * To avoid leaking too much knowledge about reorderbuffer implementation * details this is implemented in reorderbuffer.c not heapam_visibility.c */ struct HTAB; extern bool ResolveCminCmaxDuringDecoding(struct HTAB *tuplecid_data, Snapshot snapshot, HeapTuple htup, Buffer buffer, CommandId *cmin, CommandId *cmax); extern void HeapCheckForSerializableConflictOut(bool visible, Relation relation, HeapTuple tuple, Buffer buffer, Snapshot snapshot); /* * heap_execute_freeze_tuple * Execute the prepared freezing of a tuple with caller's freeze plan. * * Caller is responsible for ensuring that no other backend can access the * storage underlying this tuple, either by holding an exclusive lock on the * buffer containing it (which is what lazy VACUUM does), or by having it be * in private storage (which is what CLUSTER and friends do). */ static inline void heap_execute_freeze_tuple(HeapTupleHeader tuple, HeapTupleFreeze *frz) { HeapTupleHeaderSetXmax(tuple, frz->xmax); if (frz->frzflags & XLH_FREEZE_XVAC) HeapTupleHeaderSetXvac(tuple, FrozenTransactionId); if (frz->frzflags & XLH_INVALID_XVAC) HeapTupleHeaderSetXvac(tuple, InvalidTransactionId); tuple->t_infomask = frz->t_infomask; tuple->t_infomask2 = frz->t_infomask2; } #endif /* HEAPAM_H */