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-2019, 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
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 */
30void
31mask_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 */
45void
46mask_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 */
70void
71mask_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 in master without
92 * emitting any WAL record.
93 */
94void
95mask_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 */
118void
119mask_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