1 /*-------------------------------------------------------------------------
2  *
3  * heapam_xlog.h
4  *	  POSTGRES heap access XLOG definitions.
5  *
6  *
7  * Portions Copyright (c) 1996-2017, 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 /* 0x030 is free, was XLOG_HEAP_MOVE */
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_CLEAN		0x10
55 #define XLOG_HEAP2_FREEZE_PAGE	0x20
56 #define XLOG_HEAP2_CLEANUP_INFO 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 
71 /*
72  * xl_heap_update flag values, 8 bits are available.
73  */
74 /* PD_ALL_VISIBLE was cleared */
75 #define XLH_UPDATE_OLD_ALL_VISIBLE_CLEARED		(1<<0)
76 /* PD_ALL_VISIBLE was cleared in the 2nd page */
77 #define XLH_UPDATE_NEW_ALL_VISIBLE_CLEARED		(1<<1)
78 #define XLH_UPDATE_CONTAINS_OLD_TUPLE			(1<<2)
79 #define XLH_UPDATE_CONTAINS_OLD_KEY				(1<<3)
80 #define XLH_UPDATE_CONTAINS_NEW_TUPLE			(1<<4)
81 #define XLH_UPDATE_PREFIX_FROM_OLD				(1<<5)
82 #define XLH_UPDATE_SUFFIX_FROM_OLD				(1<<6)
83 
84 /* convenience macro for checking whether any form of old tuple was logged */
85 #define XLH_UPDATE_CONTAINS_OLD						\
86 	(XLH_UPDATE_CONTAINS_OLD_TUPLE | XLH_UPDATE_CONTAINS_OLD_KEY)
87 
88 /*
89  * xl_heap_delete flag values, 8 bits are available.
90  */
91 /* PD_ALL_VISIBLE was cleared */
92 #define XLH_DELETE_ALL_VISIBLE_CLEARED			(1<<0)
93 #define XLH_DELETE_CONTAINS_OLD_TUPLE			(1<<1)
94 #define XLH_DELETE_CONTAINS_OLD_KEY				(1<<2)
95 #define XLH_DELETE_IS_SUPER						(1<<3)
96 
97 /* convenience macro for checking whether any form of old tuple was logged */
98 #define XLH_DELETE_CONTAINS_OLD						\
99 	(XLH_DELETE_CONTAINS_OLD_TUPLE | XLH_DELETE_CONTAINS_OLD_KEY)
100 
101 /* This is what we need to know about delete */
102 typedef struct xl_heap_delete
103 {
104 	TransactionId xmax;			/* xmax of the deleted tuple */
105 	OffsetNumber offnum;		/* deleted tuple's offset */
106 	uint8		infobits_set;	/* infomask bits */
107 	uint8		flags;
108 } xl_heap_delete;
109 
110 #define SizeOfHeapDelete	(offsetof(xl_heap_delete, flags) + sizeof(uint8))
111 
112 /*
113  * We don't store the whole fixed part (HeapTupleHeaderData) of an inserted
114  * or updated tuple in WAL; we can save a few bytes by reconstructing the
115  * fields that are available elsewhere in the WAL record, or perhaps just
116  * plain needn't be reconstructed.  These are the fields we must store.
117  */
118 typedef struct xl_heap_header
119 {
120 	uint16		t_infomask2;
121 	uint16		t_infomask;
122 	uint8		t_hoff;
123 } xl_heap_header;
124 
125 #define SizeOfHeapHeader	(offsetof(xl_heap_header, t_hoff) + sizeof(uint8))
126 
127 /* This is what we need to know about insert */
128 typedef struct xl_heap_insert
129 {
130 	OffsetNumber offnum;		/* inserted tuple's offset */
131 	uint8		flags;
132 
133 	/* xl_heap_header & TUPLE DATA in backup block 0 */
134 } xl_heap_insert;
135 
136 #define SizeOfHeapInsert	(offsetof(xl_heap_insert, flags) + sizeof(uint8))
137 
138 /*
139  * This is what we need to know about a multi-insert.
140  *
141  * The main data of the record consists of this xl_heap_multi_insert header.
142  * 'offsets' array is omitted if the whole page is reinitialized
143  * (XLOG_HEAP_INIT_PAGE).
144  *
145  * In block 0's data portion, there is an xl_multi_insert_tuple struct,
146  * followed by the tuple data for each tuple. There is padding to align
147  * each xl_multi_insert struct.
148  */
149 typedef struct xl_heap_multi_insert
150 {
151 	uint8		flags;
152 	uint16		ntuples;
153 	OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER];
154 } xl_heap_multi_insert;
155 
156 #define SizeOfHeapMultiInsert	offsetof(xl_heap_multi_insert, offsets)
157 
158 typedef struct xl_multi_insert_tuple
159 {
160 	uint16		datalen;		/* size of tuple data that follows */
161 	uint16		t_infomask2;
162 	uint16		t_infomask;
163 	uint8		t_hoff;
164 	/* TUPLE DATA FOLLOWS AT END OF STRUCT */
165 } xl_multi_insert_tuple;
166 
167 #define SizeOfMultiInsertTuple	(offsetof(xl_multi_insert_tuple, t_hoff) + sizeof(uint8))
168 
169 /*
170  * This is what we need to know about update|hot_update
171  *
172  * Backup blk 0: new page
173  *
174  * If XLOG_HEAP_PREFIX_FROM_OLD or XLOG_HEAP_SUFFIX_FROM_OLD flags are set,
175  * the prefix and/or suffix come first, as one or two uint16s.
176  *
177  * After that, xl_heap_header and new tuple data follow.  The new tuple
178  * data doesn't include the prefix and suffix, which are copied from the
179  * old tuple on replay.
180  *
181  * If HEAP_CONTAINS_NEW_TUPLE_DATA flag is given, the tuple data is
182  * included even if a full-page image was taken.
183  *
184  * Backup blk 1: old page, if different. (no data, just a reference to the blk)
185  */
186 typedef struct xl_heap_update
187 {
188 	TransactionId old_xmax;		/* xmax of the old tuple */
189 	OffsetNumber old_offnum;	/* old tuple's offset */
190 	uint8		old_infobits_set;	/* infomask bits to set on old tuple */
191 	uint8		flags;
192 	TransactionId new_xmax;		/* xmax of the new tuple */
193 	OffsetNumber new_offnum;	/* new tuple's offset */
194 
195 	/*
196 	 * If XLOG_HEAP_CONTAINS_OLD_TUPLE or XLOG_HEAP_CONTAINS_OLD_KEY flags are
197 	 * set, a xl_heap_header struct and tuple data for the old tuple follows.
198 	 */
199 } xl_heap_update;
200 
201 #define SizeOfHeapUpdate	(offsetof(xl_heap_update, new_offnum) + sizeof(OffsetNumber))
202 
203 /*
204  * This is what we need to know about vacuum page cleanup/redirect
205  *
206  * The array of OffsetNumbers following the fixed part of the record contains:
207  *	* for each redirected item: the item offset, then the offset redirected to
208  *	* for each now-dead item: the item offset
209  *	* for each now-unused item: the item offset
210  * The total number of OffsetNumbers is therefore 2*nredirected+ndead+nunused.
211  * Note that nunused is not explicitly stored, but may be found by reference
212  * to the total record length.
213  */
214 typedef struct xl_heap_clean
215 {
216 	TransactionId latestRemovedXid;
217 	uint16		nredirected;
218 	uint16		ndead;
219 	/* OFFSET NUMBERS are in the block reference 0 */
220 } xl_heap_clean;
221 
222 #define SizeOfHeapClean (offsetof(xl_heap_clean, ndead) + sizeof(uint16))
223 
224 /*
225  * Cleanup_info is required in some cases during a lazy VACUUM.
226  * Used for reporting the results of HeapTupleHeaderAdvanceLatestRemovedXid()
227  * see vacuumlazy.c for full explanation
228  */
229 typedef struct xl_heap_cleanup_info
230 {
231 	RelFileNode node;
232 	TransactionId latestRemovedXid;
233 } xl_heap_cleanup_info;
234 
235 #define SizeOfHeapCleanupInfo (sizeof(xl_heap_cleanup_info))
236 
237 /* flags for infobits_set */
238 #define XLHL_XMAX_IS_MULTI		0x01
239 #define XLHL_XMAX_LOCK_ONLY		0x02
240 #define XLHL_XMAX_EXCL_LOCK		0x04
241 #define XLHL_XMAX_KEYSHR_LOCK	0x08
242 #define XLHL_KEYS_UPDATED		0x10
243 
244 /* flag bits for xl_heap_lock / xl_heap_lock_updated's flag field */
245 #define XLH_LOCK_ALL_FROZEN_CLEARED		0x01
246 
247 /* This is what we need to know about lock */
248 typedef struct xl_heap_lock
249 {
250 	TransactionId locking_xid;	/* might be a MultiXactId not xid */
251 	OffsetNumber offnum;		/* locked tuple's offset on page */
252 	int8		infobits_set;	/* infomask and infomask2 bits to set */
253 	uint8		flags;			/* XLH_LOCK_* flag bits */
254 } xl_heap_lock;
255 
256 #define SizeOfHeapLock	(offsetof(xl_heap_lock, flags) + sizeof(int8))
257 
258 /* This is what we need to know about locking an updated version of a row */
259 typedef struct xl_heap_lock_updated
260 {
261 	TransactionId xmax;
262 	OffsetNumber offnum;
263 	uint8		infobits_set;
264 	uint8		flags;
265 } xl_heap_lock_updated;
266 
267 #define SizeOfHeapLockUpdated	(offsetof(xl_heap_lock_updated, flags) + sizeof(uint8))
268 
269 /* This is what we need to know about confirmation of speculative insertion */
270 typedef struct xl_heap_confirm
271 {
272 	OffsetNumber offnum;		/* confirmed tuple's offset on page */
273 } xl_heap_confirm;
274 
275 #define SizeOfHeapConfirm	(offsetof(xl_heap_confirm, offnum) + sizeof(OffsetNumber))
276 
277 /* This is what we need to know about in-place update */
278 typedef struct xl_heap_inplace
279 {
280 	OffsetNumber offnum;		/* updated tuple's offset on page */
281 	/* TUPLE DATA FOLLOWS AT END OF STRUCT */
282 } xl_heap_inplace;
283 
284 #define SizeOfHeapInplace	(offsetof(xl_heap_inplace, offnum) + sizeof(OffsetNumber))
285 
286 /*
287  * This struct represents a 'freeze plan', which is what we need to know about
288  * a single tuple being frozen during vacuum.
289  */
290 /* 0x01 was XLH_FREEZE_XMIN */
291 #define		XLH_FREEZE_XVAC		0x02
292 #define		XLH_INVALID_XVAC	0x04
293 
294 typedef struct xl_heap_freeze_tuple
295 {
296 	TransactionId xmax;
297 	OffsetNumber offset;
298 	uint16		t_infomask2;
299 	uint16		t_infomask;
300 	uint8		frzflags;
301 } xl_heap_freeze_tuple;
302 
303 /*
304  * This is what we need to know about a block being frozen during vacuum
305  *
306  * Backup block 0's data contains an array of xl_heap_freeze_tuple structs,
307  * one for each tuple.
308  */
309 typedef struct xl_heap_freeze_page
310 {
311 	TransactionId cutoff_xid;
312 	uint16		ntuples;
313 } xl_heap_freeze_page;
314 
315 #define SizeOfHeapFreezePage (offsetof(xl_heap_freeze_page, ntuples) + sizeof(uint16))
316 
317 /*
318  * This is what we need to know about setting a visibility map bit
319  *
320  * Backup blk 0: visibility map buffer
321  * Backup blk 1: heap buffer
322  */
323 typedef struct xl_heap_visible
324 {
325 	TransactionId cutoff_xid;
326 	uint8		flags;
327 } xl_heap_visible;
328 
329 #define SizeOfHeapVisible (offsetof(xl_heap_visible, flags) + sizeof(uint8))
330 
331 typedef struct xl_heap_new_cid
332 {
333 	/*
334 	 * store toplevel xid so we don't have to merge cids from different
335 	 * transactions
336 	 */
337 	TransactionId top_xid;
338 	CommandId	cmin;
339 	CommandId	cmax;
340 	CommandId	combocid;		/* just for debugging */
341 
342 	/*
343 	 * Store the relfilenode/ctid pair to facilitate lookups.
344 	 */
345 	RelFileNode target_node;
346 	ItemPointerData target_tid;
347 } xl_heap_new_cid;
348 
349 #define SizeOfHeapNewCid (offsetof(xl_heap_new_cid, target_tid) + sizeof(ItemPointerData))
350 
351 /* logical rewrite xlog record header */
352 typedef struct xl_heap_rewrite_mapping
353 {
354 	TransactionId mapped_xid;	/* xid that might need to see the row */
355 	Oid			mapped_db;		/* DbOid or InvalidOid for shared rels */
356 	Oid			mapped_rel;		/* Oid of the mapped relation */
357 	off_t		offset;			/* How far have we written so far */
358 	uint32		num_mappings;	/* Number of in-memory mappings */
359 	XLogRecPtr	start_lsn;		/* Insert LSN at begin of rewrite */
360 } xl_heap_rewrite_mapping;
361 
362 extern void HeapTupleHeaderAdvanceLatestRemovedXid(HeapTupleHeader tuple,
363 									   TransactionId *latestRemovedXid);
364 
365 extern void heap_redo(XLogReaderState *record);
366 extern void heap_desc(StringInfo buf, XLogReaderState *record);
367 extern const char *heap_identify(uint8 info);
368 extern void heap_mask(char *pagedata, BlockNumber blkno);
369 extern void heap2_redo(XLogReaderState *record);
370 extern void heap2_desc(StringInfo buf, XLogReaderState *record);
371 extern const char *heap2_identify(uint8 info);
372 extern void heap_xlog_logical_rewrite(XLogReaderState *r);
373 
374 extern XLogRecPtr log_heap_cleanup_info(RelFileNode rnode,
375 					  TransactionId latestRemovedXid);
376 extern XLogRecPtr log_heap_clean(Relation reln, Buffer buffer,
377 			   OffsetNumber *redirected, int nredirected,
378 			   OffsetNumber *nowdead, int ndead,
379 			   OffsetNumber *nowunused, int nunused,
380 			   TransactionId latestRemovedXid);
381 extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
382 				TransactionId cutoff_xid, xl_heap_freeze_tuple *tuples,
383 				int ntuples);
384 extern bool heap_prepare_freeze_tuple(HeapTupleHeader tuple,
385 						  TransactionId relfrozenxid,
386 						  TransactionId relminmxid,
387 						  TransactionId cutoff_xid,
388 						  TransactionId cutoff_multi,
389 						  xl_heap_freeze_tuple *frz,
390 						  bool *totally_frozen);
391 extern void heap_execute_freeze_tuple(HeapTupleHeader tuple,
392 						  xl_heap_freeze_tuple *xlrec_tp);
393 extern XLogRecPtr log_heap_visible(RelFileNode rnode, Buffer heap_buffer,
394 				 Buffer vm_buffer, TransactionId cutoff_xid, uint8 flags);
395 
396 #endif							/* HEAPAM_XLOG_H */
397