1 /*-------------------------------------------------------------------------
2  *
3  * bufmask.c
4  *	  Routines for buffer masking. Used to mask certain bits
5  *	  in a page which can be different when the WAL is generated
6  *	  and when the WAL is applied.
7  *
8  * Portions Copyright (c) 2016-2021, PostgreSQL Global Development Group
9  *
10  * Contains common routines required for masking a page.
11  *
12  * IDENTIFICATION
13  *	  src/backend/access/common/bufmask.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 
18 #include "postgres.h"
19 
20 #include "access/bufmask.h"
21 
22 /*
23  * mask_page_lsn_and_checksum
24  *
25  * In consistency checks, the LSN of the two pages compared will likely be
26  * different because of concurrent operations when the WAL is generated and
27  * the state of the page when WAL is applied. Also, mask out checksum as
28  * masking anything else on page means checksum is not going to match as well.
29  */
30 void
mask_page_lsn_and_checksum(Page page)31 mask_page_lsn_and_checksum(Page page)
32 {
33 	PageHeader	phdr = (PageHeader) page;
34 
35 	PageXLogRecPtrSet(phdr->pd_lsn, (uint64) MASK_MARKER);
36 	phdr->pd_checksum = MASK_MARKER;
37 }
38 
39 /*
40  * mask_page_hint_bits
41  *
42  * Mask hint bits in PageHeader. We want to ignore differences in hint bits,
43  * since they can be set without emitting any WAL.
44  */
45 void
mask_page_hint_bits(Page page)46 mask_page_hint_bits(Page page)
47 {
48 	PageHeader	phdr = (PageHeader) page;
49 
50 	/* Ignore prune_xid (it's like a hint-bit) */
51 	phdr->pd_prune_xid = MASK_MARKER;
52 
53 	/* Ignore PD_PAGE_FULL and PD_HAS_FREE_LINES flags, they are just hints. */
54 	PageClearFull(page);
55 	PageClearHasFreeLinePointers(page);
56 
57 	/*
58 	 * During replay, if the page LSN has advanced past our XLOG record's LSN,
59 	 * we don't mark the page all-visible. See heap_xlog_visible() for
60 	 * details.
61 	 */
62 	PageClearAllVisible(page);
63 }
64 
65 /*
66  * mask_unused_space
67  *
68  * Mask the unused space of a page between pd_lower and pd_upper.
69  */
70 void
mask_unused_space(Page page)71 mask_unused_space(Page page)
72 {
73 	int			pd_lower = ((PageHeader) page)->pd_lower;
74 	int			pd_upper = ((PageHeader) page)->pd_upper;
75 	int			pd_special = ((PageHeader) page)->pd_special;
76 
77 	/* Sanity check */
78 	if (pd_lower > pd_upper || pd_special < pd_upper ||
79 		pd_lower < SizeOfPageHeaderData || pd_special > BLCKSZ)
80 	{
81 		elog(ERROR, "invalid page pd_lower %u pd_upper %u pd_special %u\n",
82 			 pd_lower, pd_upper, pd_special);
83 	}
84 
85 	memset(page + pd_lower, MASK_MARKER, pd_upper - pd_lower);
86 }
87 
88 /*
89  * mask_lp_flags
90  *
91  * In some index AMs, line pointer flags can be modified on the primary
92  * without emitting any WAL record.
93  */
94 void
mask_lp_flags(Page page)95 mask_lp_flags(Page page)
96 {
97 	OffsetNumber offnum,
98 				maxoff;
99 
100 	maxoff = PageGetMaxOffsetNumber(page);
101 	for (offnum = FirstOffsetNumber;
102 		 offnum <= maxoff;
103 		 offnum = OffsetNumberNext(offnum))
104 	{
105 		ItemId		itemId = PageGetItemId(page, offnum);
106 
107 		if (ItemIdIsUsed(itemId))
108 			itemId->lp_flags = LP_UNUSED;
109 	}
110 }
111 
112 /*
113  * mask_page_content
114  *
115  * In some index AMs, the contents of deleted pages need to be almost
116  * completely ignored.
117  */
118 void
mask_page_content(Page page)119 mask_page_content(Page page)
120 {
121 	/* Mask Page Content */
122 	memset(page + SizeOfPageHeaderData, MASK_MARKER,
123 		   BLCKSZ - SizeOfPageHeaderData);
124 
125 	/* Mask pd_lower and pd_upper */
126 	memset(&((PageHeader) page)->pd_lower, MASK_MARKER,
127 		   sizeof(uint16));
128 	memset(&((PageHeader) page)->pd_upper, MASK_MARKER,
129 		   sizeof(uint16));
130 }
131