1 /*
2 * brin_xlog.c
3 * XLog replay routines for BRIN indexes
4 *
5 * Portions Copyright (c) 1996-2016, 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/xlogutils.h"
17
18
19 /*
20 * xlog replay routines
21 */
22 static void
brin_xlog_createidx(XLogReaderState * record)23 brin_xlog_createidx(XLogReaderState *record)
24 {
25 XLogRecPtr lsn = record->EndRecPtr;
26 xl_brin_createidx *xlrec = (xl_brin_createidx *) XLogRecGetData(record);
27 Buffer buf;
28 Page page;
29
30 /* create the index' metapage */
31 buf = XLogInitBufferForRedo(record, 0);
32 Assert(BufferIsValid(buf));
33 page = (Page) BufferGetPage(buf);
34 brin_metapage_init(page, xlrec->pagesPerRange, xlrec->version);
35 PageSetLSN(page, lsn);
36 MarkBufferDirty(buf);
37 UnlockReleaseBuffer(buf);
38 }
39
40 /*
41 * Common part of an insert or update. Inserts the new tuple and updates the
42 * revmap.
43 */
44 static void
brin_xlog_insert_update(XLogReaderState * record,xl_brin_insert * xlrec)45 brin_xlog_insert_update(XLogReaderState *record,
46 xl_brin_insert *xlrec)
47 {
48 XLogRecPtr lsn = record->EndRecPtr;
49 Buffer buffer;
50 BlockNumber regpgno;
51 Page page;
52 XLogRedoAction action;
53
54 /*
55 * If we inserted the first and only tuple on the page, re-initialize the
56 * page from scratch.
57 */
58 if (XLogRecGetInfo(record) & XLOG_BRIN_INIT_PAGE)
59 {
60 buffer = XLogInitBufferForRedo(record, 0);
61 page = BufferGetPage(buffer);
62 brin_page_init(page, BRIN_PAGETYPE_REGULAR);
63 action = BLK_NEEDS_REDO;
64 }
65 else
66 {
67 action = XLogReadBufferForRedo(record, 0, &buffer);
68 }
69
70 /* need this page's blkno to store in revmap */
71 regpgno = BufferGetBlockNumber(buffer);
72
73 /* insert the index item into the page */
74 if (action == BLK_NEEDS_REDO)
75 {
76 OffsetNumber offnum;
77 BrinTuple *tuple;
78 Size tuplen;
79
80 tuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
81
82 Assert(tuple->bt_blkno == xlrec->heapBlk);
83
84 page = (Page) BufferGetPage(buffer);
85 offnum = xlrec->offnum;
86 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
87 elog(PANIC, "brin_xlog_insert_update: invalid max offset number");
88
89 offnum = PageAddItem(page, (Item) tuple, tuplen, offnum, true, false);
90 if (offnum == InvalidOffsetNumber)
91 elog(PANIC, "brin_xlog_insert_update: failed to add tuple");
92
93 PageSetLSN(page, lsn);
94 MarkBufferDirty(buffer);
95 }
96 if (BufferIsValid(buffer))
97 UnlockReleaseBuffer(buffer);
98
99 /* update the revmap */
100 action = XLogReadBufferForRedo(record, 1, &buffer);
101 if (action == BLK_NEEDS_REDO)
102 {
103 ItemPointerData tid;
104
105 ItemPointerSet(&tid, regpgno, xlrec->offnum);
106 page = (Page) BufferGetPage(buffer);
107
108 brinSetHeapBlockItemptr(buffer, xlrec->pagesPerRange, xlrec->heapBlk,
109 tid);
110 PageSetLSN(page, lsn);
111 MarkBufferDirty(buffer);
112 }
113 if (BufferIsValid(buffer))
114 UnlockReleaseBuffer(buffer);
115
116 /* XXX no FSM updates here ... */
117 }
118
119 /*
120 * replay a BRIN index insertion
121 */
122 static void
brin_xlog_insert(XLogReaderState * record)123 brin_xlog_insert(XLogReaderState *record)
124 {
125 xl_brin_insert *xlrec = (xl_brin_insert *) XLogRecGetData(record);
126
127 brin_xlog_insert_update(record, xlrec);
128 }
129
130 /*
131 * replay a BRIN index update
132 */
133 static void
brin_xlog_update(XLogReaderState * record)134 brin_xlog_update(XLogReaderState *record)
135 {
136 XLogRecPtr lsn = record->EndRecPtr;
137 xl_brin_update *xlrec = (xl_brin_update *) XLogRecGetData(record);
138 Buffer buffer;
139 XLogRedoAction action;
140
141 /* First remove the old tuple */
142 action = XLogReadBufferForRedo(record, 2, &buffer);
143 if (action == BLK_NEEDS_REDO)
144 {
145 Page page;
146 OffsetNumber offnum;
147
148 page = (Page) BufferGetPage(buffer);
149
150 offnum = xlrec->oldOffnum;
151 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
152 elog(PANIC, "brin_xlog_update: invalid max offset number");
153
154 PageIndexDeleteNoCompact(page, &offnum, 1);
155
156 PageSetLSN(page, lsn);
157 MarkBufferDirty(buffer);
158 }
159
160 /* Then insert the new tuple and update revmap, like in an insertion. */
161 brin_xlog_insert_update(record, &xlrec->insert);
162
163 if (BufferIsValid(buffer))
164 UnlockReleaseBuffer(buffer);
165 }
166
167 /*
168 * Update a tuple on a single page.
169 */
170 static void
brin_xlog_samepage_update(XLogReaderState * record)171 brin_xlog_samepage_update(XLogReaderState *record)
172 {
173 XLogRecPtr lsn = record->EndRecPtr;
174 xl_brin_samepage_update *xlrec;
175 Buffer buffer;
176 XLogRedoAction action;
177
178 xlrec = (xl_brin_samepage_update *) XLogRecGetData(record);
179 action = XLogReadBufferForRedo(record, 0, &buffer);
180 if (action == BLK_NEEDS_REDO)
181 {
182 Size tuplen;
183 BrinTuple *brintuple;
184 Page page;
185 OffsetNumber offnum;
186
187 brintuple = (BrinTuple *) XLogRecGetBlockData(record, 0, &tuplen);
188
189 page = (Page) BufferGetPage(buffer);
190
191 offnum = xlrec->offnum;
192 if (PageGetMaxOffsetNumber(page) + 1 < offnum)
193 elog(PANIC, "brin_xlog_samepage_update: invalid max offset number");
194
195 PageIndexDeleteNoCompact(page, &offnum, 1);
196 offnum = PageAddItemExtended(page, (Item) brintuple, tuplen, offnum,
197 PAI_OVERWRITE | PAI_ALLOW_FAR_OFFSET);
198 if (offnum == InvalidOffsetNumber)
199 elog(PANIC, "brin_xlog_samepage_update: failed to add tuple");
200
201 PageSetLSN(page, lsn);
202 MarkBufferDirty(buffer);
203 }
204 if (BufferIsValid(buffer))
205 UnlockReleaseBuffer(buffer);
206
207 /* XXX no FSM updates here ... */
208 }
209
210 /*
211 * Replay a revmap page extension
212 */
213 static void
brin_xlog_revmap_extend(XLogReaderState * record)214 brin_xlog_revmap_extend(XLogReaderState *record)
215 {
216 XLogRecPtr lsn = record->EndRecPtr;
217 xl_brin_revmap_extend *xlrec;
218 Buffer metabuf;
219 Buffer buf;
220 Page page;
221 BlockNumber targetBlk;
222 XLogRedoAction action;
223
224 xlrec = (xl_brin_revmap_extend *) XLogRecGetData(record);
225
226 XLogRecGetBlockTag(record, 1, NULL, NULL, &targetBlk);
227 Assert(xlrec->targetBlk == targetBlk);
228
229 /* Update the metapage */
230 action = XLogReadBufferForRedo(record, 0, &metabuf);
231 if (action == BLK_NEEDS_REDO)
232 {
233 Page metapg;
234 BrinMetaPageData *metadata;
235
236 metapg = BufferGetPage(metabuf);
237 metadata = (BrinMetaPageData *) PageGetContents(metapg);
238
239 Assert(metadata->lastRevmapPage == xlrec->targetBlk - 1);
240 metadata->lastRevmapPage = xlrec->targetBlk;
241
242 PageSetLSN(metapg, lsn);
243 MarkBufferDirty(metabuf);
244 }
245
246 /*
247 * Re-init the target block as a revmap page. There's never a full- page
248 * image here.
249 */
250
251 buf = XLogInitBufferForRedo(record, 1);
252 page = (Page) BufferGetPage(buf);
253 brin_page_init(page, BRIN_PAGETYPE_REVMAP);
254
255 PageSetLSN(page, lsn);
256 MarkBufferDirty(buf);
257
258 UnlockReleaseBuffer(buf);
259 if (BufferIsValid(metabuf))
260 UnlockReleaseBuffer(metabuf);
261 }
262
263 void
brin_redo(XLogReaderState * record)264 brin_redo(XLogReaderState *record)
265 {
266 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
267
268 switch (info & XLOG_BRIN_OPMASK)
269 {
270 case XLOG_BRIN_CREATE_INDEX:
271 brin_xlog_createidx(record);
272 break;
273 case XLOG_BRIN_INSERT:
274 brin_xlog_insert(record);
275 break;
276 case XLOG_BRIN_UPDATE:
277 brin_xlog_update(record);
278 break;
279 case XLOG_BRIN_SAMEPAGE_UPDATE:
280 brin_xlog_samepage_update(record);
281 break;
282 case XLOG_BRIN_REVMAP_EXTEND:
283 brin_xlog_revmap_extend(record);
284 break;
285 default:
286 elog(PANIC, "brin_redo: unknown op code %u", info);
287 }
288 }
289