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 | */ |
30 | void |
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 |
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 |
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 in master without |
92 | * emitting any WAL record. |
93 | */ |
94 | void |
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 |
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 | |