Line data Source code
1 : /*
2 : * brin_xlog.c
3 : * XLog replay routines for BRIN indexes
4 : *
5 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
6 : * Portions Copyright (c) 1994, Regents of the University of California
7 : *
8 : * IDENTIFICATION
9 : * src/backend/access/brin/brin_xlog.c
10 : */
11 : #include "postgres.h"
12 :
13 : #include "access/brin_page.h"
14 : #include "access/brin_pageops.h"
15 : #include "access/brin_xlog.h"
16 : #include "access/bufmask.h"
17 : #include "access/xlogutils.h"
18 :
19 :
20 : /*
21 : * xlog replay routines
22 : */
23 : static void
24 0 : brin_xlog_createidx(XLogReaderState *record)
25 : {
26 0 : XLogRecPtr lsn = record->EndRecPtr;
27 0 : xl_brin_createidx *xlrec = (xl_brin_createidx *) XLogRecGetData(record);
28 : Buffer buf;
29 : Page page;
30 :
31 : /* create the index' metapage */
32 0 : buf = XLogInitBufferForRedo(record, 0);
33 0 : Assert(BufferIsValid(buf));
34 0 : page = (Page) BufferGetPage(buf);
35 0 : brin_metapage_init(page, xlrec->pagesPerRange, xlrec->version);
36 0 : PageSetLSN(page, lsn);
37 0 : MarkBufferDirty(buf);
38 0 : UnlockReleaseBuffer(buf);
39 0 : }
40 :
41 : /*
42 : * Common part of an insert or update. Inserts the new tuple and updates the
43 : * revmap.
44 : */
45 : static void
46 0 : brin_xlog_insert_update(XLogReaderState *record,
47 : xl_brin_insert *xlrec)
48 : {
49 0 : XLogRecPtr lsn = record->EndRecPtr;
50 : Buffer buffer;
51 : BlockNumber regpgno;
52 : Page page;
53 : XLogRedoAction action;
54 :
55 : /*
56 : * If we inserted the first and only tuple on the page, re-initialize the
57 : * page from scratch.
58 : */
59 0 : if (XLogRecGetInfo(record) & XLOG_BRIN_INIT_PAGE)
60 : {
61 0 : buffer = XLogInitBufferForRedo(record, 0);
62 0 : page = BufferGetPage(buffer);
63 0 : brin_page_init(page, BRIN_PAGETYPE_REGULAR);
64 0 : action = BLK_NEEDS_REDO;
65 : }
66 : else
67 : {
68 0 : action = XLogReadBufferForRedo(record, 0, &buffer);
69 : }
70 :
71 : /* need this page's blkno to store in revmap */
72 0 : regpgno = BufferGetBlockNumber(buffer);
73 :
74 : /* insert the index item into the page */
75 0 : if (action == BLK_NEEDS_REDO)
76 : {
77 : OffsetNumber offnum;
78 : BrinTuple *tuple;
79 : Size tuplen;
80 :
81 0 : tuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
82 :
83 0 : Assert(tuple->bt_blkno == xlrec->heapBlk);
84 :
85 0 : page = (Page) BufferGetPage(buffer);
86 0 : offnum = xlrec->offnum;
87 0 : if (PageGetMaxOffsetNumber(page) + 1 < offnum)
88 0 : elog(PANIC, "brin_xlog_insert_update: invalid max offset number");
89 :
90 0 : offnum = PageAddItem(page, (Item) tuple, tuplen, offnum, true, false);
91 0 : if (offnum == InvalidOffsetNumber)
92 0 : elog(PANIC, "brin_xlog_insert_update: failed to add tuple");
93 :
94 0 : PageSetLSN(page, lsn);
95 0 : MarkBufferDirty(buffer);
96 : }
97 0 : if (BufferIsValid(buffer))
98 0 : UnlockReleaseBuffer(buffer);
99 :
100 : /* update the revmap */
101 0 : action = XLogReadBufferForRedo(record, 1, &buffer);
102 0 : if (action == BLK_NEEDS_REDO)
103 : {
104 : ItemPointerData tid;
105 :
106 0 : ItemPointerSet(&tid, regpgno, xlrec->offnum);
107 0 : page = (Page) BufferGetPage(buffer);
108 :
109 0 : brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk,
110 : tid);
111 0 : PageSetLSN(page, lsn);
112 0 : MarkBufferDirty(buffer);
113 : }
114 0 : if (BufferIsValid(buffer))
115 0 : UnlockReleaseBuffer(buffer);
116 :
117 : /* XXX no FSM updates here ... */
118 0 : }
119 :
120 : /*
121 : * replay a BRIN index insertion
122 : */
123 : static void
124 0 : brin_xlog_insert(XLogReaderState *record)
125 : {
126 0 : xl_brin_insert *xlrec = (xl_brin_insert *) XLogRecGetData(record);
127 :
128 0 : brin_xlog_insert_update(record, xlrec);
129 0 : }
130 :
131 : /*
132 : * replay a BRIN index update
133 : */
134 : static void
135 0 : brin_xlog_update(XLogReaderState *record)
136 : {
137 0 : XLogRecPtr lsn = record->EndRecPtr;
138 0 : xl_brin_update *xlrec = (xl_brin_update *) XLogRecGetData(record);
139 : Buffer buffer;
140 : XLogRedoAction action;
141 :
142 : /* First remove the old tuple */
143 0 : action = XLogReadBufferForRedo(record, 2, &buffer);
144 0 : if (action == BLK_NEEDS_REDO)
145 : {
146 : Page page;
147 : OffsetNumber offnum;
148 :
149 0 : page = (Page) BufferGetPage(buffer);
150 :
151 0 : offnum = xlrec->oldOffnum;
152 :
153 0 : PageIndexTupleDeleteNoCompact(page, offnum);
154 :
155 0 : PageSetLSN(page, lsn);
156 0 : MarkBufferDirty(buffer);
157 : }
158 :
159 : /* Then insert the new tuple and update revmap, like in an insertion. */
160 0 : brin_xlog_insert_update(record, &xlrec->insert);
161 :
162 0 : if (BufferIsValid(buffer))
163 0 : UnlockReleaseBuffer(buffer);
164 0 : }
165 :
166 : /*
167 : * Update a tuple on a single page.
168 : */
169 : static void
170 0 : brin_xlog_samepage_update(XLogReaderState *record)
171 : {
172 0 : XLogRecPtr lsn = record->EndRecPtr;
173 : xl_brin_samepage_update *xlrec;
174 : Buffer buffer;
175 : XLogRedoAction action;
176 :
177 0 : xlrec = (xl_brin_samepage_update *) XLogRecGetData(record);
178 0 : action = XLogReadBufferForRedo(record, 0, &buffer);
179 0 : if (action == BLK_NEEDS_REDO)
180 : {
181 : Size tuplen;
182 : BrinTuple *brintuple;
183 : Page page;
184 : OffsetNumber offnum;
185 :
186 0 : brintuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
187 :
188 0 : page = (Page) BufferGetPage(buffer);
189 :
190 0 : offnum = xlrec->offnum;
191 :
192 0 : if (!PageIndexTupleOverwrite(page, offnum, (Item) brintuple, tuplen))
193 0 : elog(PANIC, "brin_xlog_samepage_update: failed to replace tuple");
194 :
195 0 : PageSetLSN(page, lsn);
196 0 : MarkBufferDirty(buffer);
197 : }
198 0 : if (BufferIsValid(buffer))
199 0 : UnlockReleaseBuffer(buffer);
200 :
201 : /* XXX no FSM updates here ... */
202 0 : }
203 :
204 : /*
205 : * Replay a revmap page extension
206 : */
207 : static void
208 0 : brin_xlog_revmap_extend(XLogReaderState *record)
209 : {
210 0 : XLogRecPtr lsn = record->EndRecPtr;
211 : xl_brin_revmap_extend *xlrec;
212 : Buffer metabuf;
213 : Buffer buf;
214 : Page page;
215 : BlockNumber targetBlk;
216 : XLogRedoAction action;
217 :
218 0 : xlrec = (xl_brin_revmap_extend *) XLogRecGetData(record);
219 :
220 0 : XLogRecGetBlockTag(record, 1, NULL, NULL, &targetBlk);
221 0 : Assert(xlrec->targetBlk == targetBlk);
222 :
223 : /* Update the metapage */
224 0 : action = XLogReadBufferForRedo(record, 0, &metabuf);
225 0 : if (action == BLK_NEEDS_REDO)
226 : {
227 : Page metapg;
228 : BrinMetaPageData *metadata;
229 :
230 0 : metapg = BufferGetPage(metabuf);
231 0 : metadata = (BrinMetaPageData *) PageGetContents(metapg);
232 :
233 0 : Assert(metadata->lastRevmapPage == xlrec->targetBlk - 1);
234 0 : metadata->lastRevmapPage = xlrec->targetBlk;
235 :
236 0 : PageSetLSN(metapg, lsn);
237 0 : MarkBufferDirty(metabuf);
238 : }
239 :
240 : /*
241 : * Re-init the target block as a revmap page. There's never a full- page
242 : * image here.
243 : */
244 :
245 0 : buf = XLogInitBufferForRedo(record, 1);
246 0 : page = (Page) BufferGetPage(buf);
247 0 : brin_page_init(page, BRIN_PAGETYPE_REVMAP);
248 :
249 0 : PageSetLSN(page, lsn);
250 0 : MarkBufferDirty(buf);
251 :
252 0 : UnlockReleaseBuffer(buf);
253 0 : if (BufferIsValid(metabuf))
254 0 : UnlockReleaseBuffer(metabuf);
255 0 : }
256 :
257 : static void
258 0 : brin_xlog_desummarize_page(XLogReaderState *record)
259 : {
260 0 : XLogRecPtr lsn = record->EndRecPtr;
261 : xl_brin_desummarize *xlrec;
262 : Buffer buffer;
263 : XLogRedoAction action;
264 :
265 0 : xlrec = (xl_brin_desummarize *) XLogRecGetData(record);
266 :
267 : /* Update the revmap */
268 0 : action = XLogReadBufferForRedo(record, 0, &buffer);
269 0 : if (action == BLK_NEEDS_REDO)
270 : {
271 : ItemPointerData iptr;
272 :
273 0 : ItemPointerSetInvalid(&iptr);
274 0 : brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk, iptr);
275 :
276 0 : PageSetLSN(BufferGetPage(buffer), lsn);
277 0 : MarkBufferDirty(buffer);
278 : }
279 0 : if (BufferIsValid(buffer))
280 0 : UnlockReleaseBuffer(buffer);
281 :
282 : /* remove the leftover entry from the regular page */
283 0 : action = XLogReadBufferForRedo(record, 1, &buffer);
284 0 : if (action == BLK_NEEDS_REDO)
285 : {
286 0 : Page regPg = BufferGetPage(buffer);
287 :
288 0 : PageIndexTupleDeleteNoCompact(regPg, xlrec->regOffset);
289 :
290 0 : PageSetLSN(regPg, lsn);
291 0 : MarkBufferDirty(buffer);
292 : }
293 0 : if (BufferIsValid(buffer))
294 0 : UnlockReleaseBuffer(buffer);
295 0 : }
296 :
297 : void
298 0 : brin_redo(XLogReaderState *record)
299 : {
300 0 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
301 :
302 0 : switch (info & XLOG_BRIN_OPMASK)
303 : {
304 : case XLOG_BRIN_CREATE_INDEX:
305 0 : brin_xlog_createidx(record);
306 0 : break;
307 : case XLOG_BRIN_INSERT:
308 0 : brin_xlog_insert(record);
309 0 : break;
310 : case XLOG_BRIN_UPDATE:
311 0 : brin_xlog_update(record);
312 0 : break;
313 : case XLOG_BRIN_SAMEPAGE_UPDATE:
314 0 : brin_xlog_samepage_update(record);
315 0 : break;
316 : case XLOG_BRIN_REVMAP_EXTEND:
317 0 : brin_xlog_revmap_extend(record);
318 0 : break;
319 : case XLOG_BRIN_DESUMMARIZE:
320 0 : brin_xlog_desummarize_page(record);
321 0 : break;
322 : default:
323 0 : elog(PANIC, "brin_redo: unknown op code %u", info);
324 : }
325 0 : }
326 :
327 : /*
328 : * Mask a BRIN page before doing consistency checks.
329 : */
330 : void
331 0 : brin_mask(char *pagedata, BlockNumber blkno)
332 : {
333 0 : Page page = (Page) pagedata;
334 :
335 0 : mask_page_lsn(page);
336 :
337 0 : mask_page_hint_bits(page);
338 :
339 0 : if (BRIN_IS_REGULAR_PAGE(page))
340 : {
341 : /* Regular brin pages contain unused space which needs to be masked. */
342 0 : mask_unused_space(page);
343 : }
344 0 : }
|