Age Owner Branch data TLA Line data Source code
1 : : /*
2 : : * brin_xlog.c
3 : : * XLog replay routines for BRIN indexes
4 : : *
5 : : * Portions Copyright (c) 1996-2024, 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
3433 heikki.linnakangas@i 24 :CBC 37 : brin_xlog_createidx(XLogReaderState *record)
25 : : {
26 : 37 : XLogRecPtr lsn = record->EndRecPtr;
3446 alvherre@alvh.no-ip. 27 : 37 : xl_brin_createidx *xlrec = (xl_brin_createidx *) XLogRecGetData(record);
28 : : Buffer buf;
29 : : Page page;
30 : :
31 : : /* create the index' metapage */
3433 heikki.linnakangas@i 32 : 37 : buf = XLogInitBufferForRedo(record, 0);
3446 alvherre@alvh.no-ip. 33 [ - + ]: 37 : Assert(BufferIsValid(buf));
2916 kgrittn@postgresql.o 34 : 37 : page = (Page) BufferGetPage(buf);
3446 alvherre@alvh.no-ip. 35 : 37 : brin_metapage_init(page, xlrec->pagesPerRange, xlrec->version);
36 : 37 : PageSetLSN(page, lsn);
37 : 37 : MarkBufferDirty(buf);
38 : 37 : UnlockReleaseBuffer(buf);
39 : 37 : }
40 : :
41 : : /*
42 : : * Common part of an insert or update. Inserts the new tuple and updates the
43 : : * revmap.
44 : : */
45 : : static void
3433 heikki.linnakangas@i 46 : 2127 : brin_xlog_insert_update(XLogReaderState *record,
47 : : xl_brin_insert *xlrec)
48 : : {
49 : 2127 : 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 [ + + ]: 2127 : if (XLogRecGetInfo(record) & XLOG_BRIN_INIT_PAGE)
60 : : {
61 : 63 : buffer = XLogInitBufferForRedo(record, 0);
2916 kgrittn@postgresql.o 62 : 63 : page = BufferGetPage(buffer);
3446 alvherre@alvh.no-ip. 63 : 63 : brin_page_init(page, BRIN_PAGETYPE_REGULAR);
64 : 63 : action = BLK_NEEDS_REDO;
65 : : }
66 : : else
67 : : {
3433 heikki.linnakangas@i 68 : 2064 : action = XLogReadBufferForRedo(record, 0, &buffer);
69 : : }
70 : :
71 : : /* need this page's blkno to store in revmap */
3215 alvherre@alvh.no-ip. 72 : 2127 : regpgno = BufferGetBlockNumber(buffer);
73 : :
74 : : /* insert the index item into the page */
3446 75 [ + + ]: 2127 : if (action == BLK_NEEDS_REDO)
76 : : {
77 : : OffsetNumber offnum;
78 : : BrinTuple *tuple;
79 : : Size tuplen;
80 : :
3433 heikki.linnakangas@i 81 : 2125 : tuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
82 : :
3446 alvherre@alvh.no-ip. 83 [ - + ]: 2125 : Assert(tuple->bt_blkno == xlrec->heapBlk);
84 : :
2916 kgrittn@postgresql.o 85 : 2125 : page = (Page) BufferGetPage(buffer);
3433 heikki.linnakangas@i 86 : 2125 : offnum = xlrec->offnum;
3446 alvherre@alvh.no-ip. 87 [ - + ]: 2125 : if (PageGetMaxOffsetNumber(page) + 1 < offnum)
3446 alvherre@alvh.no-ip. 88 [ # # ]:UBC 0 : elog(PANIC, "brin_xlog_insert_update: invalid max offset number");
89 : :
3433 heikki.linnakangas@i 90 :CBC 2125 : offnum = PageAddItem(page, (Item) tuple, tuplen, offnum, true, false);
3446 alvherre@alvh.no-ip. 91 [ - + ]: 2125 : if (offnum == InvalidOffsetNumber)
3446 alvherre@alvh.no-ip. 92 [ # # ]:UBC 0 : elog(PANIC, "brin_xlog_insert_update: failed to add tuple");
93 : :
3446 alvherre@alvh.no-ip. 94 :CBC 2125 : PageSetLSN(page, lsn);
95 : 2125 : MarkBufferDirty(buffer);
96 : : }
97 [ + - ]: 2127 : if (BufferIsValid(buffer))
98 : 2127 : UnlockReleaseBuffer(buffer);
99 : :
100 : : /* update the revmap */
3433 heikki.linnakangas@i 101 : 2127 : action = XLogReadBufferForRedo(record, 1, &buffer);
3446 alvherre@alvh.no-ip. 102 [ + + ]: 2127 : if (action == BLK_NEEDS_REDO)
103 : : {
104 : : ItemPointerData tid;
105 : :
3215 106 : 2125 : ItemPointerSet(&tid, regpgno, xlrec->offnum);
2916 kgrittn@postgresql.o 107 : 2125 : page = (Page) BufferGetPage(buffer);
108 : :
3446 alvherre@alvh.no-ip. 109 : 2125 : brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk,
110 : : tid);
111 : 2125 : PageSetLSN(page, lsn);
112 : 2125 : MarkBufferDirty(buffer);
113 : : }
114 [ + - ]: 2127 : if (BufferIsValid(buffer))
115 : 2127 : UnlockReleaseBuffer(buffer);
116 : :
117 : : /* XXX no FSM updates here ... */
118 : 2127 : }
119 : :
120 : : /*
121 : : * replay a BRIN index insertion
122 : : */
123 : : static void
3433 heikki.linnakangas@i 124 : 1828 : brin_xlog_insert(XLogReaderState *record)
125 : : {
3446 alvherre@alvh.no-ip. 126 : 1828 : xl_brin_insert *xlrec = (xl_brin_insert *) XLogRecGetData(record);
127 : :
3433 heikki.linnakangas@i 128 : 1828 : brin_xlog_insert_update(record, xlrec);
3446 alvherre@alvh.no-ip. 129 : 1828 : }
130 : :
131 : : /*
132 : : * replay a BRIN index update
133 : : */
134 : : static void
3433 heikki.linnakangas@i 135 : 299 : brin_xlog_update(XLogReaderState *record)
136 : : {
137 : 299 : XLogRecPtr lsn = record->EndRecPtr;
3446 alvherre@alvh.no-ip. 138 : 299 : xl_brin_update *xlrec = (xl_brin_update *) XLogRecGetData(record);
139 : : Buffer buffer;
140 : : XLogRedoAction action;
141 : :
142 : : /* First remove the old tuple */
3433 heikki.linnakangas@i 143 : 299 : action = XLogReadBufferForRedo(record, 2, &buffer);
3446 alvherre@alvh.no-ip. 144 [ + - ]: 299 : if (action == BLK_NEEDS_REDO)
145 : : {
146 : : Page page;
147 : : OffsetNumber offnum;
148 : :
2916 kgrittn@postgresql.o 149 : 299 : page = (Page) BufferGetPage(buffer);
150 : :
3433 heikki.linnakangas@i 151 : 299 : offnum = xlrec->oldOffnum;
152 : :
2774 tgl@sss.pgh.pa.us 153 : 299 : PageIndexTupleDeleteNoCompact(page, offnum);
154 : :
3446 alvherre@alvh.no-ip. 155 : 299 : PageSetLSN(page, lsn);
156 : 299 : MarkBufferDirty(buffer);
157 : : }
158 : :
159 : : /* Then insert the new tuple and update revmap, like in an insertion. */
3433 heikki.linnakangas@i 160 : 299 : brin_xlog_insert_update(record, &xlrec->insert);
161 : :
3446 alvherre@alvh.no-ip. 162 [ + - ]: 299 : if (BufferIsValid(buffer))
163 : 299 : UnlockReleaseBuffer(buffer);
164 : 299 : }
165 : :
166 : : /*
167 : : * Update a tuple on a single page.
168 : : */
169 : : static void
3433 heikki.linnakangas@i 170 : 2141 : brin_xlog_samepage_update(XLogReaderState *record)
171 : : {
172 : 2141 : XLogRecPtr lsn = record->EndRecPtr;
173 : : xl_brin_samepage_update *xlrec;
174 : : Buffer buffer;
175 : : XLogRedoAction action;
176 : :
3446 alvherre@alvh.no-ip. 177 : 2141 : xlrec = (xl_brin_samepage_update *) XLogRecGetData(record);
3433 heikki.linnakangas@i 178 : 2141 : action = XLogReadBufferForRedo(record, 0, &buffer);
3446 alvherre@alvh.no-ip. 179 [ + + ]: 2141 : if (action == BLK_NEEDS_REDO)
180 : : {
181 : : Size tuplen;
182 : : BrinTuple *brintuple;
183 : : Page page;
184 : : OffsetNumber offnum;
185 : :
3191 186 : 2140 : brintuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
187 : :
2916 kgrittn@postgresql.o 188 : 2140 : page = (Page) BufferGetPage(buffer);
189 : :
3433 heikki.linnakangas@i 190 : 2140 : offnum = xlrec->offnum;
191 : :
2774 tgl@sss.pgh.pa.us 192 [ - + ]: 2140 : if (!PageIndexTupleOverwrite(page, offnum, (Item) brintuple, tuplen))
2774 tgl@sss.pgh.pa.us 193 [ # # ]:UBC 0 : elog(PANIC, "brin_xlog_samepage_update: failed to replace tuple");
194 : :
3446 alvherre@alvh.no-ip. 195 :CBC 2140 : PageSetLSN(page, lsn);
196 : 2140 : MarkBufferDirty(buffer);
197 : : }
198 [ + - ]: 2141 : if (BufferIsValid(buffer))
199 : 2141 : UnlockReleaseBuffer(buffer);
200 : :
201 : : /* XXX no FSM updates here ... */
202 : 2141 : }
203 : :
204 : : /*
205 : : * Replay a revmap page extension
206 : : */
207 : : static void
3433 heikki.linnakangas@i 208 : 38 : brin_xlog_revmap_extend(XLogReaderState *record)
209 : : {
210 : 38 : 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 : :
3446 alvherre@alvh.no-ip. 218 : 38 : xlrec = (xl_brin_revmap_extend *) XLogRecGetData(record);
219 : :
3433 heikki.linnakangas@i 220 : 38 : XLogRecGetBlockTag(record, 1, NULL, NULL, &targetBlk);
221 [ - + ]: 38 : Assert(xlrec->targetBlk == targetBlk);
222 : :
223 : : /* Update the metapage */
224 : 38 : action = XLogReadBufferForRedo(record, 0, &metabuf);
3446 alvherre@alvh.no-ip. 225 [ + - ]: 38 : if (action == BLK_NEEDS_REDO)
226 : : {
227 : : Page metapg;
228 : : BrinMetaPageData *metadata;
229 : :
2916 kgrittn@postgresql.o 230 : 38 : metapg = BufferGetPage(metabuf);
3446 alvherre@alvh.no-ip. 231 : 38 : metadata = (BrinMetaPageData *) PageGetContents(metapg);
232 : :
233 [ - + ]: 38 : Assert(metadata->lastRevmapPage == xlrec->targetBlk - 1);
234 : 38 : metadata->lastRevmapPage = xlrec->targetBlk;
235 : :
236 : 38 : PageSetLSN(metapg, lsn);
237 : :
238 : : /*
239 : : * Set pd_lower just past the end of the metadata. This is essential,
240 : : * because without doing so, metadata will be lost if xlog.c
241 : : * compresses the page. (We must do this here because pre-v11
242 : : * versions of PG did not set the metapage's pd_lower correctly, so a
243 : : * pg_upgraded index might contain the wrong value.)
244 : : */
2355 tgl@sss.pgh.pa.us 245 : 38 : ((PageHeader) metapg)->pd_lower =
246 : 38 : ((char *) metadata + sizeof(BrinMetaPageData)) - (char *) metapg;
247 : :
3446 alvherre@alvh.no-ip. 248 : 38 : MarkBufferDirty(metabuf);
249 : : }
250 : :
251 : : /*
252 : : * Re-init the target block as a revmap page. There's never a full- page
253 : : * image here.
254 : : */
255 : :
3433 heikki.linnakangas@i 256 : 38 : buf = XLogInitBufferForRedo(record, 1);
2916 kgrittn@postgresql.o 257 : 38 : page = (Page) BufferGetPage(buf);
3446 alvherre@alvh.no-ip. 258 : 38 : brin_page_init(page, BRIN_PAGETYPE_REVMAP);
259 : :
260 : 38 : PageSetLSN(page, lsn);
261 : 38 : MarkBufferDirty(buf);
262 : :
263 : 38 : UnlockReleaseBuffer(buf);
264 [ + - ]: 38 : if (BufferIsValid(metabuf))
265 : 38 : UnlockReleaseBuffer(metabuf);
266 : 38 : }
267 : :
268 : : static void
2570 269 : 7 : brin_xlog_desummarize_page(XLogReaderState *record)
270 : : {
271 : 7 : XLogRecPtr lsn = record->EndRecPtr;
272 : : xl_brin_desummarize *xlrec;
273 : : Buffer buffer;
274 : : XLogRedoAction action;
275 : :
276 : 7 : xlrec = (xl_brin_desummarize *) XLogRecGetData(record);
277 : :
278 : : /* Update the revmap */
279 : 7 : action = XLogReadBufferForRedo(record, 0, &buffer);
280 [ + - ]: 7 : if (action == BLK_NEEDS_REDO)
281 : : {
282 : : ItemPointerData iptr;
283 : :
284 : 7 : ItemPointerSetInvalid(&iptr);
285 : 7 : brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk, iptr);
286 : :
287 : 7 : PageSetLSN(BufferGetPage(buffer), lsn);
288 : 7 : MarkBufferDirty(buffer);
289 : : }
290 [ + - ]: 7 : if (BufferIsValid(buffer))
291 : 7 : UnlockReleaseBuffer(buffer);
292 : :
293 : : /* remove the leftover entry from the regular page */
294 : 7 : action = XLogReadBufferForRedo(record, 1, &buffer);
295 [ + - ]: 7 : if (action == BLK_NEEDS_REDO)
296 : : {
2524 bruce@momjian.us 297 : 7 : Page regPg = BufferGetPage(buffer);
298 : :
2570 alvherre@alvh.no-ip. 299 : 7 : PageIndexTupleDeleteNoCompact(regPg, xlrec->regOffset);
300 : :
301 : 7 : PageSetLSN(regPg, lsn);
302 : 7 : MarkBufferDirty(buffer);
303 : : }
304 [ + - ]: 7 : if (BufferIsValid(buffer))
305 : 7 : UnlockReleaseBuffer(buffer);
306 : 7 : }
307 : :
308 : : void
3433 heikki.linnakangas@i 309 : 4350 : brin_redo(XLogReaderState *record)
310 : : {
311 : 4350 : uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
312 : :
3446 alvherre@alvh.no-ip. 313 [ + + + + : 4350 : switch (info & XLOG_BRIN_OPMASK)
+ + - ]
314 : : {
315 : 37 : case XLOG_BRIN_CREATE_INDEX:
3433 heikki.linnakangas@i 316 : 37 : brin_xlog_createidx(record);
3446 alvherre@alvh.no-ip. 317 : 37 : break;
318 : 1828 : case XLOG_BRIN_INSERT:
3433 heikki.linnakangas@i 319 : 1828 : brin_xlog_insert(record);
3446 alvherre@alvh.no-ip. 320 : 1828 : break;
321 : 299 : case XLOG_BRIN_UPDATE:
3433 heikki.linnakangas@i 322 : 299 : brin_xlog_update(record);
3446 alvherre@alvh.no-ip. 323 : 299 : break;
324 : 2141 : case XLOG_BRIN_SAMEPAGE_UPDATE:
3433 heikki.linnakangas@i 325 : 2141 : brin_xlog_samepage_update(record);
3446 alvherre@alvh.no-ip. 326 : 2141 : break;
327 : 38 : case XLOG_BRIN_REVMAP_EXTEND:
3433 heikki.linnakangas@i 328 : 38 : brin_xlog_revmap_extend(record);
3446 alvherre@alvh.no-ip. 329 : 38 : break;
2570 330 : 7 : case XLOG_BRIN_DESUMMARIZE:
331 : 7 : brin_xlog_desummarize_page(record);
332 : 7 : break;
3446 alvherre@alvh.no-ip. 333 :UBC 0 : default:
334 [ # # ]: 0 : elog(PANIC, "brin_redo: unknown op code %u", info);
335 : : }
3446 alvherre@alvh.no-ip. 336 :CBC 4350 : }
337 : :
338 : : /*
339 : : * Mask a BRIN page before doing consistency checks.
340 : : */
341 : : void
2622 rhaas@postgresql.org 342 : 10440 : brin_mask(char *pagedata, BlockNumber blkno)
343 : : {
344 : 10440 : Page page = (Page) pagedata;
2355 tgl@sss.pgh.pa.us 345 : 10440 : PageHeader pagehdr = (PageHeader) page;
346 : :
2396 rhaas@postgresql.org 347 : 10440 : mask_page_lsn_and_checksum(page);
348 : :
2622 349 : 10440 : mask_page_hint_bits(page);
350 : :
351 : : /*
352 : : * Regular brin pages contain unused space which needs to be masked.
353 : : * Similarly for meta pages, but mask it only if pd_lower appears to have
354 : : * been set correctly.
355 : : */
2355 tgl@sss.pgh.pa.us 356 [ + + ]: 10440 : if (BRIN_IS_REGULAR_PAGE(page) ||
357 [ + + + - ]: 3406 : (BRIN_IS_META_PAGE(page) && pagehdr->pd_lower > SizeOfPageHeaderData))
358 : : {
2622 rhaas@postgresql.org 359 : 7040 : mask_unused_space(page);
360 : : }
361 : :
362 : : /*
363 : : * BRIN_EVACUATE_PAGE is not WAL-logged, since it's of no use in recovery.
364 : : * Mask it. See brin_start_evacuating_page() for details.
365 : : */
618 alvherre@alvh.no-ip. 366 : 10440 : BrinPageFlags(page) &= ~BRIN_EVACUATE_PAGE;
2622 rhaas@postgresql.org 367 : 10440 : }
|