1 /*-------------------------------------------------------------------------
4 * POSTGRES heap access XLOG definitions.
7 * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/include/access/heapam_xlog.h
12 *-------------------------------------------------------------------------
17 #include "access/htup.h"
18 #include "access/xlogreader.h"
19 #include "lib/stringinfo.h"
20 #include "storage/buf.h"
21 #include "storage/bufpage.h"
22 #include "storage/relfilenode.h"
23 #include "utils/relcache.h"
27 * WAL record definitions for heapam.c's WAL operations
29 * XLOG allows to store some information in high 4 bits of log
30 * record xl_info field. We use 3 for opcode and one for init bit.
32 #define XLOG_HEAP_INSERT 0x00
33 #define XLOG_HEAP_DELETE 0x10
34 #define XLOG_HEAP_UPDATE 0x20
35 #define XLOG_HEAP_TRUNCATE 0x30
36 #define XLOG_HEAP_HOT_UPDATE 0x40
37 #define XLOG_HEAP_CONFIRM 0x50
38 #define XLOG_HEAP_LOCK 0x60
39 #define XLOG_HEAP_INPLACE 0x70
41 #define XLOG_HEAP_OPMASK 0x70
43 * When we insert 1st item on new page in INSERT, UPDATE, HOT_UPDATE,
44 * or MULTI_INSERT, we can (and we do) restore entire page in redo
46 #define XLOG_HEAP_INIT_PAGE 0x80
48 * We ran out of opcodes, so heapam.c now has a second RmgrId. These opcodes
49 * are associated with RM_HEAP2_ID, but are not logically different from
50 * the ones above associated with RM_HEAP_ID. XLOG_HEAP_OPMASK applies to
53 #define XLOG_HEAP2_REWRITE 0x00
54 #define XLOG_HEAP2_PRUNE 0x10
55 #define XLOG_HEAP2_VACUUM 0x20
56 #define XLOG_HEAP2_FREEZE_PAGE 0x30
57 #define XLOG_HEAP2_VISIBLE 0x40
58 #define XLOG_HEAP2_MULTI_INSERT 0x50
59 #define XLOG_HEAP2_LOCK_UPDATED 0x60
60 #define XLOG_HEAP2_NEW_CID 0x70
63 * xl_heap_insert/xl_heap_multi_insert flag values, 8 bits are available.
65 /* PD_ALL_VISIBLE was cleared */
66 #define XLH_INSERT_ALL_VISIBLE_CLEARED (1<<0)
67 #define XLH_INSERT_LAST_IN_MULTI (1<<1)
68 #define XLH_INSERT_IS_SPECULATIVE (1<<2)
69 #define XLH_INSERT_CONTAINS_NEW_TUPLE (1<<3)
70 #define XLH_INSERT_ON_TOAST_RELATION (1<<4)
72 /* all_frozen_set always implies all_visible_set */
73 #define XLH_INSERT_ALL_FROZEN_SET (1<<5)
76 * xl_heap_update flag values, 8 bits are available.
78 /* PD_ALL_VISIBLE was cleared */
79 #define XLH_UPDATE_OLD_ALL_VISIBLE_CLEARED (1<<0)
80 /* PD_ALL_VISIBLE was cleared in the 2nd page */
81 #define XLH_UPDATE_NEW_ALL_VISIBLE_CLEARED (1<<1)
82 #define XLH_UPDATE_CONTAINS_OLD_TUPLE (1<<2)
83 #define XLH_UPDATE_CONTAINS_OLD_KEY (1<<3)
84 #define XLH_UPDATE_CONTAINS_NEW_TUPLE (1<<4)
85 #define XLH_UPDATE_PREFIX_FROM_OLD (1<<5)
86 #define XLH_UPDATE_SUFFIX_FROM_OLD (1<<6)
88 /* convenience macro for checking whether any form of old tuple was logged */
89 #define XLH_UPDATE_CONTAINS_OLD \
90 (XLH_UPDATE_CONTAINS_OLD_TUPLE | XLH_UPDATE_CONTAINS_OLD_KEY)
93 * xl_heap_delete flag values, 8 bits are available.
95 /* PD_ALL_VISIBLE was cleared */
96 #define XLH_DELETE_ALL_VISIBLE_CLEARED (1<<0)
97 #define XLH_DELETE_CONTAINS_OLD_TUPLE (1<<1)
98 #define XLH_DELETE_CONTAINS_OLD_KEY (1<<2)
99 #define XLH_DELETE_IS_SUPER (1<<3)
100 #define XLH_DELETE_IS_PARTITION_MOVE (1<<4)
102 /* convenience macro for checking whether any form of old tuple was logged */
103 #define XLH_DELETE_CONTAINS_OLD \
104 (XLH_DELETE_CONTAINS_OLD_TUPLE | XLH_DELETE_CONTAINS_OLD_KEY)
106 /* This is what we need to know about delete */
107 typedef struct xl_heap_delete
109 TransactionId xmax
; /* xmax of the deleted tuple */
110 OffsetNumber offnum
; /* deleted tuple's offset */
111 uint8 infobits_set
; /* infomask bits */
115 #define SizeOfHeapDelete (offsetof(xl_heap_delete, flags) + sizeof(uint8))
118 * xl_heap_truncate flag values, 8 bits are available.
120 #define XLH_TRUNCATE_CASCADE (1<<0)
121 #define XLH_TRUNCATE_RESTART_SEQS (1<<1)
124 * For truncate we list all truncated relids in an array, followed by all
125 * sequence relids that need to be restarted, if any.
126 * All rels are always within the same database, so we just list dbid once.
128 typedef struct xl_heap_truncate
133 Oid relids
[FLEXIBLE_ARRAY_MEMBER
];
136 #define SizeOfHeapTruncate (offsetof(xl_heap_truncate, relids))
139 * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted
140 * or updated tuple in WAL; we can save a few bytes by reconstructing the
141 * fields that are available elsewhere in the WAL record, or perhaps just
142 * plain needn't be reconstructed. These are the fields we must store.
144 typedef struct xl_heap_header
151 #define SizeOfHeapHeader (offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
153 /* This is what we need to know about insert */
154 typedef struct xl_heap_insert
156 OffsetNumber offnum
; /* inserted tuple's offset */
159 /* xl_heap_header & TUPLE DATA in backup block 0 */
162 #define SizeOfHeapInsert (offsetof(xl_heap_insert, flags) + sizeof(uint8))
165 * This is what we need to know about a multi-insert.
167 * The main data of the record consists of this xl_heap_multi_insert header.
168 * 'offsets' array is omitted if the whole page is reinitialized
169 * (XLOG_HEAP_INIT_PAGE).
171 * In block 0's data portion, there is an xl_multi_insert_tuple struct,
172 * followed by the tuple data for each tuple. There is padding to align
173 * each xl_multi_insert_tuple struct.
175 typedef struct xl_heap_multi_insert
179 OffsetNumber offsets
[FLEXIBLE_ARRAY_MEMBER
];
180 } xl_heap_multi_insert
;
182 #define SizeOfHeapMultiInsert offsetof(xl_heap_multi_insert, offsets)
184 typedef struct xl_multi_insert_tuple
186 uint16 datalen
; /* size of tuple data that follows */
190 /* TUPLE DATA FOLLOWS AT END OF STRUCT */
191 } xl_multi_insert_tuple
;
193 #define SizeOfMultiInsertTuple (offsetof(xl_multi_insert_tuple, t_hoff) + sizeof(uint8))
196 * This is what we need to know about update|hot_update
198 * Backup blk 0: new page
200 * If XLH_UPDATE_PREFIX_FROM_OLD or XLH_UPDATE_SUFFIX_FROM_OLD flags are set,
201 * the prefix and/or suffix come first, as one or two uint16s.
203 * After that, xl_heap_header and new tuple data follow. The new tuple
204 * data doesn't include the prefix and suffix, which are copied from the
205 * old tuple on replay.
207 * If XLH_UPDATE_CONTAINS_NEW_TUPLE flag is given, the tuple data is
208 * included even if a full-page image was taken.
210 * Backup blk 1: old page, if different. (no data, just a reference to the blk)
212 typedef struct xl_heap_update
214 TransactionId old_xmax
; /* xmax of the old tuple */
215 OffsetNumber old_offnum
; /* old tuple's offset */
216 uint8 old_infobits_set
; /* infomask bits to set on old tuple */
218 TransactionId new_xmax
; /* xmax of the new tuple */
219 OffsetNumber new_offnum
; /* new tuple's offset */
222 * If XLH_UPDATE_CONTAINS_OLD_TUPLE or XLH_UPDATE_CONTAINS_OLD_KEY flags
223 * are set, xl_heap_header and tuple data for the old tuple follow.
227 #define SizeOfHeapUpdate (offsetof(xl_heap_update, new_offnum) + sizeof(OffsetNumber))
230 * This is what we need to know about page pruning (both during VACUUM and
231 * during opportunistic pruning)
233 * The array of OffsetNumbers following the fixed part of the record contains:
234 * * for each redirected item: the item offset, then the offset redirected to
235 * * for each now-dead item: the item offset
236 * * for each now-unused item: the item offset
237 * The total number of OffsetNumbers is therefore 2*nredirected+ndead+nunused.
238 * Note that nunused is not explicitly stored, but may be found by reference
239 * to the total record length.
241 * Requires a super-exclusive lock.
243 typedef struct xl_heap_prune
245 TransactionId latestRemovedXid
;
248 /* OFFSET NUMBERS are in the block reference 0 */
251 #define SizeOfHeapPrune (offsetof(xl_heap_prune, ndead) + sizeof(uint16))
254 * The vacuum page record is similar to the prune record, but can only mark
255 * already dead items as unused
257 * Used by heap vacuuming only. Does not require a super-exclusive lock.
259 typedef struct xl_heap_vacuum
262 /* OFFSET NUMBERS are in the block reference 0 */
265 #define SizeOfHeapVacuum (offsetof(xl_heap_vacuum, nunused) + sizeof(uint16))
267 /* flags for infobits_set */
268 #define XLHL_XMAX_IS_MULTI 0x01
269 #define XLHL_XMAX_LOCK_ONLY 0x02
270 #define XLHL_XMAX_EXCL_LOCK 0x04
271 #define XLHL_XMAX_KEYSHR_LOCK 0x08
272 #define XLHL_KEYS_UPDATED 0x10
274 /* flag bits for xl_heap_lock / xl_heap_lock_updated's flag field */
275 #define XLH_LOCK_ALL_FROZEN_CLEARED 0x01
277 /* This is what we need to know about lock */
278 typedef struct xl_heap_lock
280 TransactionId locking_xid
; /* might be a MultiXactId not xid */
281 OffsetNumber offnum
; /* locked tuple's offset on page */
282 int8 infobits_set
; /* infomask and infomask2 bits to set */
283 uint8 flags
; /* XLH_LOCK_* flag bits */
286 #define SizeOfHeapLock (offsetof(xl_heap_lock, flags) + sizeof(int8))
288 /* This is what we need to know about locking an updated version of a row */
289 typedef struct xl_heap_lock_updated
295 } xl_heap_lock_updated
;
297 #define SizeOfHeapLockUpdated (offsetof(xl_heap_lock_updated, flags) + sizeof(uint8))
299 /* This is what we need to know about confirmation of speculative insertion */
300 typedef struct xl_heap_confirm
302 OffsetNumber offnum
; /* confirmed tuple's offset on page */
305 #define SizeOfHeapConfirm (offsetof(xl_heap_confirm, offnum) + sizeof(OffsetNumber))
307 /* This is what we need to know about in-place update */
308 typedef struct xl_heap_inplace
310 OffsetNumber offnum
; /* updated tuple's offset on page */
311 /* TUPLE DATA FOLLOWS AT END OF STRUCT */
314 #define SizeOfHeapInplace (offsetof(xl_heap_inplace, offnum) + sizeof(OffsetNumber))
317 * This struct represents a 'freeze plan', which is what we need to know about
318 * a single tuple being frozen during vacuum.
320 /* 0x01 was XLH_FREEZE_XMIN */
321 #define XLH_FREEZE_XVAC 0x02
322 #define XLH_INVALID_XVAC 0x04
324 typedef struct xl_heap_freeze_tuple
331 } xl_heap_freeze_tuple
;
334 * This is what we need to know about a block being frozen during vacuum
336 * Backup block 0's data contains an array of xl_heap_freeze_tuple structs,
337 * one for each tuple.
339 typedef struct xl_heap_freeze_page
341 TransactionId cutoff_xid
;
343 } xl_heap_freeze_page
;
345 #define SizeOfHeapFreezePage (offsetof(xl_heap_freeze_page, ntuples) + sizeof(uint16))
348 * This is what we need to know about setting a visibility map bit
350 * Backup blk 0: visibility map buffer
351 * Backup blk 1: heap buffer
353 typedef struct xl_heap_visible
355 TransactionId cutoff_xid
;
359 #define SizeOfHeapVisible (offsetof(xl_heap_visible, flags) + sizeof(uint8))
361 typedef struct xl_heap_new_cid
364 * store toplevel xid so we don't have to merge cids from different
367 TransactionId top_xid
;
370 CommandId combocid
; /* just for debugging */
373 * Store the relfilenode/ctid pair to facilitate lookups.
375 RelFileNode target_node
;
376 ItemPointerData target_tid
;
379 #define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target_tid) + sizeof(ItemPointerData))
381 /* logical rewrite xlog record header */
382 typedef struct xl_heap_rewrite_mapping
384 TransactionId mapped_xid
; /* xid that might need to see the row */
385 Oid mapped_db
; /* DbOid or InvalidOid for shared rels */
386 Oid mapped_rel
; /* Oid of the mapped relation */
387 off_t offset
; /* How far have we written so far */
388 uint32 num_mappings
; /* Number of in-memory mappings */
389 XLogRecPtr start_lsn
; /* Insert LSN at begin of rewrite */
390 } xl_heap_rewrite_mapping
;
392 extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple
,
393 TransactionId
*latestRemovedXid
);
395 extern void heap_redo(XLogReaderState
*record
);
396 extern void heap_desc(StringInfo buf
, XLogReaderState
*record
);
397 extern const char *heap_identify(uint8 info
);
398 extern void heap_mask(char *pagedata
, BlockNumber blkno
);
399 extern void heap2_redo(XLogReaderState
*record
);
400 extern void heap2_desc(StringInfo buf
, XLogReaderState
*record
);
401 extern const char *heap2_identify(uint8 info
);
402 extern void heap_xlog_logical_rewrite(XLogReaderState
*r
);
404 extern XLogRecPtr
log_heap_freeze(Relation reln
, Buffer buffer
,
405 TransactionId cutoff_xid
, xl_heap_freeze_tuple
*tuples
,
407 extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple
,
408 TransactionId relfrozenxid
,
409 TransactionId relminmxid
,
410 TransactionId cutoff_xid
,
411 TransactionId cutoff_multi
,
412 xl_heap_freeze_tuple
*frz
,
413 bool *totally_frozen
);
414 extern void heap_execute_freeze_tuple(HeapTupleHeader tuple
,
415 xl_heap_freeze_tuple
*xlrec_tp
);
416 extern XLogRecPtr
log_heap_visible(RelFileNode rnode
, Buffer heap_buffer
,
417 Buffer vm_buffer
, TransactionId cutoff_xid
, uint8 flags
);
419 #endif /* HEAPAM_XLOG_H */