1 /*-------------------------------------------------------------------------
2  *
3  * heapam_xlog.h
4  *	  POSTGRES heap access XLOG definitions.
5  *
6  *
7  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * src/include/access/heapam_xlog.h
11  *
12  *-------------------------------------------------------------------------
13  */
14 #ifndef HEAPAM_XLOG_H
15 #define HEAPAM_XLOG_H
16 
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"
24 
25 
26 /*
27  * WAL record definitions for heapam.c's WAL operations
28  *
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.
31  */
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
40 
41 #define XLOG_HEAP_OPMASK		0x70
42 /*
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
45  */
46 #define XLOG_HEAP_INIT_PAGE		0x80
47 /*
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
51  * these, too.
52  */
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
61 
62 /*
63  * xl_heap_insert/xl_heap_multi_insert flag values, 8 bits are available.
64  */
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)
71 
72 /* all_frozen_set always implies all_visible_set */
73 #define XLH_INSERT_ALL_FROZEN_SET				(1<<5)
74 
75 /*
76  * xl_heap_update flag values, 8 bits are available.
77  */
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)
87 
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)
91 
92 /*
93  * xl_heap_delete flag values, 8 bits are available.
94  */
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)
101 
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)
105 
106 /* This is what we need to know about delete */
107 typedef struct xl_heap_delete
108 {
109 	TransactionId xmax;			/* xmax of the deleted tuple */
110 	OffsetNumber offnum;		/* deleted tuple's offset */
111 	uint8		infobits_set;	/* infomask bits */
112 	uint8		flags;
113 } xl_heap_delete;
114 
115 #define SizeOfHeapDelete	(offsetof(xl_heap_delete, flags) + sizeof(uint8))
116 
117 /*
118  * xl_heap_truncate flag values, 8 bits are available.
119  */
120 #define XLH_TRUNCATE_CASCADE					(1<<0)
121 #define XLH_TRUNCATE_RESTART_SEQS				(1<<1)
122 
123 /*
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.
127  */
128 typedef struct xl_heap_truncate
129 {
130 	Oid			dbId;
131 	uint32		nrelids;
132 	uint8		flags;
133 	Oid			relids[FLEXIBLE_ARRAY_MEMBER];
134 } xl_heap_truncate;
135 
136 #define SizeOfHeapTruncate	(offsetof(xl_heap_truncate, relids))
137 
138 /*
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.
143  */
144 typedef struct xl_heap_header
145 {
146 	uint16		t_infomask2;
147 	uint16		t_infomask;
148 	uint8		t_hoff;
149 } xl_heap_header;
150 
151 #define SizeOfHeapHeader	(offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
152 
153 /* This is what we need to know about insert */
154 typedef struct xl_heap_insert
155 {
156 	OffsetNumber offnum;		/* inserted tuple's offset */
157 	uint8		flags;
158 
159 	/* xl_heap_header & TUPLE DATA in backup block 0 */
160 } xl_heap_insert;
161 
162 #define SizeOfHeapInsert	(offsetof(xl_heap_insert, flags) + sizeof(uint8))
163 
164 /*
165  * This is what we need to know about a multi-insert.
166  *
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).
170  *
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.
174  */
175 typedef struct xl_heap_multi_insert
176 {
177 	uint8		flags;
178 	uint16		ntuples;
179 	OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
180 } xl_heap_multi_insert;
181 
182 #define SizeOfHeapMultiInsert	offsetof(xl_heap_multi_insert, offsets)
183 
184 typedef struct xl_multi_insert_tuple
185 {
186 	uint16		datalen;		/* size of tuple data that follows */
187 	uint16		t_infomask2;
188 	uint16		t_infomask;
189 	uint8		t_hoff;
190 	/* TUPLE DATA FOLLOWS AT END OF STRUCT */
191 } xl_multi_insert_tuple;
192 
193 #define SizeOfMultiInsertTuple	(offsetof(xl_multi_insert_tuple, t_hoff) + sizeof(uint8))
194 
195 /*
196  * This is what we need to know about update|hot_update
197  *
198  * Backup blk 0: new page
199  *
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.
202  *
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.
206  *
207  * If XLH_UPDATE_CONTAINS_NEW_TUPLE flag is given, the tuple data is
208  * included even if a full-page image was taken.
209  *
210  * Backup blk 1: old page, if different. (no data, just a reference to the blk)
211  */
212 typedef struct xl_heap_update
213 {
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 */
217 	uint8		flags;
218 	TransactionId new_xmax;		/* xmax of the new tuple */
219 	OffsetNumber new_offnum;	/* new tuple's offset */
220 
221 	/*
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.
224 	 */
225 } xl_heap_update;
226 
227 #define SizeOfHeapUpdate	(offsetof(xl_heap_update, new_offnum) + sizeof(OffsetNumber))
228 
229 /*
230  * This is what we need to know about page pruning (both during VACUUM and
231  * during opportunistic pruning)
232  *
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.
240  *
241  * Requires a super-exclusive lock.
242  */
243 typedef struct xl_heap_prune
244 {
245 	TransactionId latestRemovedXid;
246 	uint16		nredirected;
247 	uint16		ndead;
248 	/* OFFSET NUMBERS are in the block reference 0 */
249 } xl_heap_prune;
250 
251 #define SizeOfHeapPrune (offsetof(xl_heap_prune, ndead) + sizeof(uint16))
252 
253 /*
254  * The vacuum page record is similar to the prune record, but can only mark
255  * already dead items as unused
256  *
257  * Used by heap vacuuming only.  Does not require a super-exclusive lock.
258  */
259 typedef struct xl_heap_vacuum
260 {
261 	uint16		nunused;
262 	/* OFFSET NUMBERS are in the block reference 0 */
263 } xl_heap_vacuum;
264 
265 #define SizeOfHeapVacuum (offsetof(xl_heap_vacuum, nunused) + sizeof(uint16))
266 
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
273 
274 /* flag bits for xl_heap_lock / xl_heap_lock_updated's flag field */
275 #define XLH_LOCK_ALL_FROZEN_CLEARED		0x01
276 
277 /* This is what we need to know about lock */
278 typedef struct xl_heap_lock
279 {
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 */
284 } xl_heap_lock;
285 
286 #define SizeOfHeapLock	(offsetof(xl_heap_lock, flags) + sizeof(int8))
287 
288 /* This is what we need to know about locking an updated version of a row */
289 typedef struct xl_heap_lock_updated
290 {
291 	TransactionId xmax;
292 	OffsetNumber offnum;
293 	uint8		infobits_set;
294 	uint8		flags;
295 } xl_heap_lock_updated;
296 
297 #define SizeOfHeapLockUpdated	(offsetof(xl_heap_lock_updated, flags) + sizeof(uint8))
298 
299 /* This is what we need to know about confirmation of speculative insertion */
300 typedef struct xl_heap_confirm
301 {
302 	OffsetNumber offnum;		/* confirmed tuple's offset on page */
303 } xl_heap_confirm;
304 
305 #define SizeOfHeapConfirm	(offsetof(xl_heap_confirm, offnum) + sizeof(OffsetNumber))
306 
307 /* This is what we need to know about in-place update */
308 typedef struct xl_heap_inplace
309 {
310 	OffsetNumber offnum;		/* updated tuple's offset on page */
311 	/* TUPLE DATA FOLLOWS AT END OF STRUCT */
312 } xl_heap_inplace;
313 
314 #define SizeOfHeapInplace	(offsetof(xl_heap_inplace, offnum) + sizeof(OffsetNumber))
315 
316 /*
317  * This struct represents a 'freeze plan', which is what we need to know about
318  * a single tuple being frozen during vacuum.
319  */
320 /* 0x01 was XLH_FREEZE_XMIN */
321 #define		XLH_FREEZE_XVAC		0x02
322 #define		XLH_INVALID_XVAC	0x04
323 
324 typedef struct xl_heap_freeze_tuple
325 {
326 	TransactionId xmax;
327 	OffsetNumber offset;
328 	uint16		t_infomask2;
329 	uint16		t_infomask;
330 	uint8		frzflags;
331 } xl_heap_freeze_tuple;
332 
333 /*
334  * This is what we need to know about a block being frozen during vacuum
335  *
336  * Backup block 0's data contains an array of xl_heap_freeze_tuple structs,
337  * one for each tuple.
338  */
339 typedef struct xl_heap_freeze_page
340 {
341 	TransactionId cutoff_xid;
342 	uint16		ntuples;
343 } xl_heap_freeze_page;
344 
345 #define SizeOfHeapFreezePage (offsetof(xl_heap_freeze_page, ntuples) + sizeof(uint16))
346 
347 /*
348  * This is what we need to know about setting a visibility map bit
349  *
350  * Backup blk 0: visibility map buffer
351  * Backup blk 1: heap buffer
352  */
353 typedef struct xl_heap_visible
354 {
355 	TransactionId cutoff_xid;
356 	uint8		flags;
357 } xl_heap_visible;
358 
359 #define SizeOfHeapVisible (offsetof(xl_heap_visible, flags) + sizeof(uint8))
360 
361 typedef struct xl_heap_new_cid
362 {
363 	/*
364 	 * store toplevel xid so we don't have to merge cids from different
365 	 * transactions
366 	 */
367 	TransactionId top_xid;
368 	CommandId	cmin;
369 	CommandId	cmax;
370 	CommandId	combocid;		/* just for debugging */
371 
372 	/*
373 	 * Store the relfilenode/ctid pair to facilitate lookups.
374 	 */
375 	RelFileNode target_node;
376 	ItemPointerData target_tid;
377 } xl_heap_new_cid;
378 
379 #define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target_tid) + sizeof(ItemPointerData))
380 
381 /* logical rewrite xlog record header */
382 typedef struct xl_heap_rewrite_mapping
383 {
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;
391 
392 extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
393 												   TransactionId *latestRemovedXid);
394 
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);
403 
404 extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
405 								  TransactionId cutoff_xid, xl_heap_freeze_tuple *tuples,
406 								  int ntuples);
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);
418 
419 #endif							/* HEAPAM_XLOG_H */
420