PostgreSQL Source Code git master
gistxlog.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * gistxlog.c
4 * WAL replay logic for GiST.
5 *
6 *
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 * IDENTIFICATION
11 * src/backend/access/gist/gistxlog.c
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/bufmask.h"
17#include "access/gist_private.h"
18#include "access/gistxlog.h"
19#include "access/transam.h"
20#include "access/xloginsert.h"
21#include "access/xlogutils.h"
22#include "storage/standby.h"
23#include "utils/memutils.h"
24#include "utils/rel.h"
25
26static MemoryContext opCtx; /* working memory for operations */
27
28/*
29 * Replay the clearing of F_FOLLOW_RIGHT flag on a child page.
30 *
31 * Even if the WAL record includes a full-page image, we have to update the
32 * follow-right flag, because that change is not included in the full-page
33 * image. To be sure that the intermediate state with the wrong flag value is
34 * not visible to concurrent Hot Standby queries, this function handles
35 * restoring the full-page image as well as updating the flag. (Note that
36 * we never need to do anything else to the child page in the current WAL
37 * action.)
38 */
39static void
41{
42 XLogRecPtr lsn = record->EndRecPtr;
43 Buffer buffer;
44 Page page;
46
47 /*
48 * Note that we still update the page even if it was restored from a full
49 * page image, because the updated NSN is not included in the image.
50 */
51 action = XLogReadBufferForRedo(record, block_id, &buffer);
53 {
54 page = BufferGetPage(buffer);
55
56 GistPageSetNSN(page, lsn);
58
59 PageSetLSN(page, lsn);
60 MarkBufferDirty(buffer);
61 }
62 if (BufferIsValid(buffer))
63 UnlockReleaseBuffer(buffer);
64}
65
66/*
67 * redo any page update (except page split)
68 */
69static void
71{
72 XLogRecPtr lsn = record->EndRecPtr;
74 Buffer buffer;
75 Page page;
76
77 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
78 {
79 char *begin;
80 char *data;
81 Size datalen;
82 int ninserted PG_USED_FOR_ASSERTS_ONLY = 0;
83
84 data = begin = XLogRecGetBlockData(record, 0, &datalen);
85
86 page = (Page) BufferGetPage(buffer);
87
88 if (xldata->ntodelete == 1 && xldata->ntoinsert == 1)
89 {
90 /*
91 * When replacing one tuple with one other tuple, we must use
92 * PageIndexTupleOverwrite for consistency with gistplacetopage.
93 */
94 OffsetNumber offnum = *((OffsetNumber *) data);
95 IndexTuple itup;
96 Size itupsize;
97
98 data += sizeof(OffsetNumber);
99 itup = (IndexTuple) data;
100 itupsize = IndexTupleSize(itup);
101 if (!PageIndexTupleOverwrite(page, offnum, (Item) itup, itupsize))
102 elog(ERROR, "failed to add item to GiST index page, size %d bytes",
103 (int) itupsize);
104 data += itupsize;
105 /* should be nothing left after consuming 1 tuple */
106 Assert(data - begin == datalen);
107 /* update insertion count for assert check below */
108 ninserted++;
109 }
110 else if (xldata->ntodelete > 0)
111 {
112 /* Otherwise, delete old tuples if any */
113 OffsetNumber *todelete = (OffsetNumber *) data;
114
115 data += sizeof(OffsetNumber) * xldata->ntodelete;
116
117 PageIndexMultiDelete(page, todelete, xldata->ntodelete);
118 if (GistPageIsLeaf(page))
120 }
121
122 /* Add new tuples if any */
123 if (data - begin < datalen)
124 {
127
128 while (data - begin < datalen)
129 {
130 IndexTuple itup = (IndexTuple) data;
131 Size sz = IndexTupleSize(itup);
132 OffsetNumber l;
133
134 data += sz;
135
136 l = PageAddItem(page, (Item) itup, sz, off, false, false);
137 if (l == InvalidOffsetNumber)
138 elog(ERROR, "failed to add item to GiST index page, size %d bytes",
139 (int) sz);
140 off++;
141 ninserted++;
142 }
143 }
144
145 /* Check that XLOG record contained expected number of tuples */
146 Assert(ninserted == xldata->ntoinsert);
147
148 PageSetLSN(page, lsn);
149 MarkBufferDirty(buffer);
150 }
151
152 /*
153 * Fix follow-right data on left child page
154 *
155 * This must be done while still holding the lock on the target page. Note
156 * that even if the target page no longer exists, we still attempt to
157 * replay the change on the child page.
158 */
159 if (XLogRecHasBlockRef(record, 1))
160 gistRedoClearFollowRight(record, 1);
161
162 if (BufferIsValid(buffer))
163 UnlockReleaseBuffer(buffer);
164}
165
166
167/*
168 * redo delete on gist index page to remove tuples marked as DEAD during index
169 * tuple insertion
170 */
171static void
173{
174 XLogRecPtr lsn = record->EndRecPtr;
175 gistxlogDelete *xldata = (gistxlogDelete *) XLogRecGetData(record);
176 Buffer buffer;
177 Page page;
178 OffsetNumber *toDelete = xldata->offsets;
179
180 /*
181 * If we have any conflict processing to do, it must happen before we
182 * update the page.
183 *
184 * GiST delete records can conflict with standby queries. You might think
185 * that vacuum records would conflict as well, but we've handled that
186 * already. XLOG_HEAP2_PRUNE_VACUUM_SCAN records provide the highest xid
187 * cleaned by the vacuum of the heap and so we can resolve any conflicts
188 * just once when that arrives. After that we know that no conflicts
189 * exist from individual gist vacuum records on that index.
190 */
191 if (InHotStandby)
192 {
193 RelFileLocator rlocator;
194
195 XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
196
198 xldata->isCatalogRel,
199 rlocator);
200 }
201
202 if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
203 {
204 page = (Page) BufferGetPage(buffer);
205
206 PageIndexMultiDelete(page, toDelete, xldata->ntodelete);
207
210
211 PageSetLSN(page, lsn);
212 MarkBufferDirty(buffer);
213 }
214
215 if (BufferIsValid(buffer))
216 UnlockReleaseBuffer(buffer);
217}
218
219/*
220 * Returns an array of index pointers.
221 */
222static IndexTuple *
223decodePageSplitRecord(char *begin, int len, int *n)
224{
225 char *ptr;
226 int i = 0;
227 IndexTuple *tuples;
228
229 /* extract the number of tuples */
230 memcpy(n, begin, sizeof(int));
231 ptr = begin + sizeof(int);
232
233 tuples = palloc(*n * sizeof(IndexTuple));
234
235 for (i = 0; i < *n; i++)
236 {
237 Assert(ptr - begin < len);
238 tuples[i] = (IndexTuple) ptr;
239 ptr += IndexTupleSize((IndexTuple) ptr);
240 }
241 Assert(ptr - begin == len);
242
243 return tuples;
244}
245
246static void
248{
249 XLogRecPtr lsn = record->EndRecPtr;
251 Buffer firstbuffer = InvalidBuffer;
252 Buffer buffer;
253 Page page;
254 int i;
255 bool isrootsplit = false;
256
257 /*
258 * We must hold lock on the first-listed page throughout the action,
259 * including while updating the left child page (if any). We can unlock
260 * remaining pages in the list as soon as they've been written, because
261 * there is no path for concurrent queries to reach those pages without
262 * first visiting the first-listed page.
263 */
264
265 /* loop around all pages */
266 for (i = 0; i < xldata->npage; i++)
267 {
268 int flags;
269 char *data;
270 Size datalen;
271 int num;
272 BlockNumber blkno;
273 IndexTuple *tuples;
274
275 XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
276 if (blkno == GIST_ROOT_BLKNO)
277 {
278 Assert(i == 0);
279 isrootsplit = true;
280 }
281
282 buffer = XLogInitBufferForRedo(record, i + 1);
283 page = (Page) BufferGetPage(buffer);
284 data = XLogRecGetBlockData(record, i + 1, &datalen);
285
286 tuples = decodePageSplitRecord(data, datalen, &num);
287
288 /* ok, clear buffer */
289 if (xldata->origleaf && blkno != GIST_ROOT_BLKNO)
290 flags = F_LEAF;
291 else
292 flags = 0;
293 GISTInitBuffer(buffer, flags);
294
295 /* and fill it */
296 gistfillbuffer(page, tuples, num, FirstOffsetNumber);
297
298 if (blkno == GIST_ROOT_BLKNO)
299 {
300 GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
301 GistPageSetNSN(page, xldata->orignsn);
303 }
304 else
305 {
306 if (i < xldata->npage - 1)
307 {
308 BlockNumber nextblkno;
309
310 XLogRecGetBlockTag(record, i + 2, NULL, NULL, &nextblkno);
311 GistPageGetOpaque(page)->rightlink = nextblkno;
312 }
313 else
314 GistPageGetOpaque(page)->rightlink = xldata->origrlink;
315 GistPageSetNSN(page, xldata->orignsn);
316 if (i < xldata->npage - 1 && !isrootsplit &&
317 xldata->markfollowright)
319 else
321 }
322
323 PageSetLSN(page, lsn);
324 MarkBufferDirty(buffer);
325
326 if (i == 0)
327 firstbuffer = buffer;
328 else
329 UnlockReleaseBuffer(buffer);
330 }
331
332 /* Fix follow-right data on left child page, if any */
333 if (XLogRecHasBlockRef(record, 0))
334 gistRedoClearFollowRight(record, 0);
335
336 /* Finally, release lock on the first page */
337 UnlockReleaseBuffer(firstbuffer);
338}
339
340/* redo page deletion */
341static void
343{
344 XLogRecPtr lsn = record->EndRecPtr;
346 Buffer parentBuffer;
347 Buffer leafBuffer;
348
349 if (XLogReadBufferForRedo(record, 0, &leafBuffer) == BLK_NEEDS_REDO)
350 {
351 Page page = (Page) BufferGetPage(leafBuffer);
352
353 GistPageSetDeleted(page, xldata->deleteXid);
354
355 PageSetLSN(page, lsn);
356 MarkBufferDirty(leafBuffer);
357 }
358
359 if (XLogReadBufferForRedo(record, 1, &parentBuffer) == BLK_NEEDS_REDO)
360 {
361 Page page = (Page) BufferGetPage(parentBuffer);
362
364
365 PageSetLSN(page, lsn);
366 MarkBufferDirty(parentBuffer);
367 }
368
369 if (BufferIsValid(parentBuffer))
370 UnlockReleaseBuffer(parentBuffer);
371 if (BufferIsValid(leafBuffer))
372 UnlockReleaseBuffer(leafBuffer);
373}
374
375static void
377{
379
380 /*
381 * PAGE_REUSE records exist to provide a conflict point when we reuse
382 * pages in the index via the FSM. That's all they do though.
383 *
384 * snapshotConflictHorizon was the page's deleteXid. The
385 * GlobalVisCheckRemovableFullXid(deleteXid) test in gistPageRecyclable()
386 * conceptually mirrors the PGPROC->xmin > limitXmin test in
387 * GetConflictingVirtualXIDs(). Consequently, one XID value achieves the
388 * same exclusion effect on primary and standby.
389 */
390 if (InHotStandby)
392 xlrec->isCatalogRel,
393 xlrec->locator);
394}
395
396void
398{
399 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
400 MemoryContext oldCxt;
401
402 /*
403 * GiST indexes do not require any conflict processing. NB: If we ever
404 * implement a similar optimization we have in b-tree, and remove killed
405 * tuples outside VACUUM, we'll need to handle that here.
406 */
407
409 switch (info)
410 {
413 break;
414 case XLOG_GIST_DELETE:
415 gistRedoDeleteRecord(record);
416 break;
418 gistRedoPageReuse(record);
419 break;
422 break;
424 gistRedoPageDelete(record);
425 break;
427 /* nop. See gistGetFakeLSN(). */
428 break;
429 default:
430 elog(PANIC, "gist_redo: unknown op code %u", info);
431 }
432
433 MemoryContextSwitchTo(oldCxt);
435}
436
437void
439{
441}
442
443void
445{
447}
448
449/*
450 * Mask a Gist page before running consistency checks on it.
451 */
452void
453gist_mask(char *pagedata, BlockNumber blkno)
454{
455 Page page = (Page) pagedata;
456
458
460 mask_unused_space(page);
461
462 /*
463 * NSN is nothing but a special purpose LSN. Hence, mask it for the same
464 * reason as mask_page_lsn_and_checksum.
465 */
467
468 /*
469 * We update F_FOLLOW_RIGHT flag on the left child after writing WAL
470 * record. Hence, mask this flag. See gistplacetopage() for details.
471 */
473
474 if (GistPageIsLeaf(page))
475 {
476 /*
477 * In gist leaf pages, it is possible to modify the LP_FLAGS without
478 * emitting any WAL record. Hence, mask the line pointer flags. See
479 * gistkillitems() for details.
480 */
481 mask_lp_flags(page);
482 }
483
484 /*
485 * During gist redo, we never mark a page as garbage. Hence, mask it to
486 * ignore any differences.
487 */
489}
490
491/*
492 * Write WAL record of a page split.
493 */
495gistXLogSplit(bool page_is_leaf,
496 SplitPageLayout *dist,
497 BlockNumber origrlink, GistNSN orignsn,
498 Buffer leftchildbuf, bool markfollowright)
499{
500 gistxlogPageSplit xlrec;
501 SplitPageLayout *ptr;
502 int npage = 0;
503 XLogRecPtr recptr;
504 int i;
505
506 for (ptr = dist; ptr; ptr = ptr->next)
507 npage++;
508
509 xlrec.origrlink = origrlink;
510 xlrec.orignsn = orignsn;
511 xlrec.origleaf = page_is_leaf;
512 xlrec.npage = (uint16) npage;
513 xlrec.markfollowright = markfollowright;
514
516
517 /*
518 * Include a full page image of the child buf. (only necessary if a
519 * checkpoint happened since the child page was split)
520 */
521 if (BufferIsValid(leftchildbuf))
522 XLogRegisterBuffer(0, leftchildbuf, REGBUF_STANDARD);
523
524 /*
525 * NOTE: We register a lot of data. The caller must've called
526 * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
527 * because we're already in a critical section. If you change the number
528 * of buffer or data registrations here, make sure you modify the
529 * XLogEnsureRecordSpace() calls accordingly!
530 */
531 XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageSplit));
532
533 i = 1;
534 for (ptr = dist; ptr; ptr = ptr->next)
535 {
537 XLogRegisterBufData(i, (char *) &(ptr->block.num), sizeof(int));
538 XLogRegisterBufData(i, (char *) ptr->list, ptr->lenlist);
539 i++;
540 }
541
542 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT);
543
544 return recptr;
545}
546
547/*
548 * Write XLOG record describing a page deletion. This also includes removal of
549 * downlink from the parent page.
550 */
553 Buffer parentBuffer, OffsetNumber downlinkOffset)
554{
555 gistxlogPageDelete xlrec;
556 XLogRecPtr recptr;
557
558 xlrec.deleteXid = xid;
559 xlrec.downlinkOffset = downlinkOffset;
560
563
565 XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
566
567 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
568
569 return recptr;
570}
571
572/*
573 * Write an empty XLOG record to assign a distinct LSN.
574 */
577{
578 int dummy = 0;
579
580 /*
581 * Records other than XLOG_SWITCH must have content. We use an integer 0
582 * to follow the restriction.
583 */
586 XLogRegisterData((char *) &dummy, sizeof(dummy));
587 return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN);
588}
589
590/*
591 * Write XLOG record about reuse of a deleted page.
592 */
593void
595 BlockNumber blkno, FullTransactionId deleteXid)
596{
597 gistxlogPageReuse xlrec_reuse;
598
599 /*
600 * Note that we don't register the buffer with the record, because this
601 * operation doesn't modify the page. This record only exists to provide a
602 * conflict point for Hot Standby.
603 */
604
605 /* XLOG stuff */
607 xlrec_reuse.locator = rel->rd_locator;
608 xlrec_reuse.block = blkno;
609 xlrec_reuse.snapshotConflictHorizon = deleteXid;
610
612 XLogRegisterData((char *) &xlrec_reuse, SizeOfGistxlogPageReuse);
613
614 XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
615}
616
617/*
618 * Write XLOG record describing a page update. The update can include any
619 * number of deletions and/or insertions of tuples on a single index page.
620 *
621 * If this update inserts a downlink for a split page, also record that
622 * the F_FOLLOW_RIGHT flag on the child page is cleared and NSN set.
623 *
624 * Note that both the todelete array and the tuples are marked as belonging
625 * to the target buffer; they need not be stored in XLOG if XLogInsert decides
626 * to log the whole buffer contents instead.
627 */
630 OffsetNumber *todelete, int ntodelete,
631 IndexTuple *itup, int ituplen,
632 Buffer leftchildbuf)
633{
634 gistxlogPageUpdate xlrec;
635 int i;
636 XLogRecPtr recptr;
637
638 xlrec.ntodelete = ntodelete;
639 xlrec.ntoinsert = ituplen;
640
642 XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageUpdate));
643
645 XLogRegisterBufData(0, (char *) todelete, sizeof(OffsetNumber) * ntodelete);
646
647 /* new tuples */
648 for (i = 0; i < ituplen; i++)
649 XLogRegisterBufData(0, (char *) (itup[i]), IndexTupleSize(itup[i]));
650
651 /*
652 * Include a full page image of the child buf. (only necessary if a
653 * checkpoint happened since the child page was split)
654 */
655 if (BufferIsValid(leftchildbuf))
656 XLogRegisterBuffer(1, leftchildbuf, REGBUF_STANDARD);
657
658 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE);
659
660 return recptr;
661}
662
663/*
664 * Write XLOG record describing a delete of leaf index tuples marked as DEAD
665 * during new tuple insertion. One may think that this case is already covered
666 * by gistXLogUpdate(). But deletion of index tuples might conflict with
667 * standby queries and needs special handling.
668 */
670gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete,
671 TransactionId snapshotConflictHorizon, Relation heaprel)
672{
673 gistxlogDelete xlrec;
674 XLogRecPtr recptr;
675
677 xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
678 xlrec.ntodelete = ntodelete;
679
681 XLogRegisterData((char *) &xlrec, SizeOfGistxlogDelete);
682
683 /*
684 * We need the target-offsets array whether or not we store the whole
685 * buffer, to allow us to find the snapshotConflictHorizon on a standby
686 * server.
687 */
688 XLogRegisterData((char *) todelete, ntodelete * sizeof(OffsetNumber));
689
691
692 recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_DELETE);
693
694 return recptr;
695}
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
void mask_lp_flags(Page page)
Definition: bufmask.c:95
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31
void mask_unused_space(Page page)
Definition: bufmask.c:71
void mask_page_hint_bits(Page page)
Definition: bufmask.c:46
#define MASK_MARKER
Definition: bufmask.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4883
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:396
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:347
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1150
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1394
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1041
static bool PageIsEmpty(const PageData *page)
Definition: bufpage.h:224
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
PageData * Page
Definition: bufpage.h:82
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
Definition: bufpage.h:372
uint8_t uint8
Definition: c.h:486
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:204
#define Assert(condition)
Definition: c.h:815
uint64_t uint64
Definition: c.h:489
uint16_t uint16
Definition: c.h:487
uint32 TransactionId
Definition: c.h:609
size_t Size
Definition: c.h:562
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
MemoryContext createTempGistContext(void)
Definition: gist.c:123
#define GistMarkFollowRight(page)
Definition: gist.h:184
#define F_LEAF
Definition: gist.h:49
#define GistClearFollowRight(page)
Definition: gist.h:185
#define GistClearPageHasGarbage(page)
Definition: gist.h:181
#define GistPageIsLeaf(page)
Definition: gist.h:170
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:205
#define GistMarkTuplesDeleted(page)
Definition: gist.h:176
#define GistPageSetNSN(page, val)
Definition: gist.h:188
#define GistPageGetOpaque(page)
Definition: gist.h:168
XLogRecPtr GistNSN
Definition: gist.h:63
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:34
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:773
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:376
void gist_xlog_startup(void)
Definition: gistxlog.c:438
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:70
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:247
void gist_redo(XLogReaderState *record)
Definition: gistxlog.c:397
XLogRecPtr gistXLogAssignLSN(void)
Definition: gistxlog.c:576
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:342
XLogRecPtr gistXLogSplit(bool page_is_leaf, SplitPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
Definition: gistxlog.c:495
XLogRecPtr gistXLogPageDelete(Buffer buffer, FullTransactionId xid, Buffer parentBuffer, OffsetNumber downlinkOffset)
Definition: gistxlog.c:552
XLogRecPtr gistXLogDelete(Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId snapshotConflictHorizon, Relation heaprel)
Definition: gistxlog.c:670
static IndexTuple * decodePageSplitRecord(char *begin, int len, int *n)
Definition: gistxlog.c:223
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:172
void gistXLogPageReuse(Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
Definition: gistxlog.c:594
XLogRecPtr gistXLogUpdate(Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
Definition: gistxlog.c:629
void gist_xlog_cleanup(void)
Definition: gistxlog.c:444
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:40
static MemoryContext opCtx
Definition: gistxlog.c:26
void gist_mask(char *pagedata, BlockNumber blkno)
Definition: gistxlog.c:453
#define SizeOfGistxlogPageDelete
Definition: gistxlog.h:91
#define XLOG_GIST_ASSIGN_LSN
Definition: gistxlog.h:27
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
#define XLOG_GIST_PAGE_REUSE
Definition: gistxlog.h:22
#define XLOG_GIST_PAGE_DELETE
Definition: gistxlog.h:26
#define XLOG_GIST_DELETE
Definition: gistxlog.h:21
#define SizeOfGistxlogPageReuse
Definition: gistxlog.h:106
#define XLOG_GIST_PAGE_SPLIT
Definition: gistxlog.h:23
#define XLOG_GIST_PAGE_UPDATE
Definition: gistxlog.h:20
int i
Definition: isn.c:72
Pointer Item
Definition: item.h:17
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void * palloc(Size size)
Definition: mcxt.c:1317
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define InvalidOffsetNumber
Definition: off.h:26
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
const void size_t len
const void * data
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:511
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:467
RelFileLocator rd_locator
Definition: rel.h:57
gistxlogPage block
Definition: gist_private.h:193
struct SplitPageLayout * next
Definition: gist_private.h:200
IndexTupleData * list
Definition: gist_private.h:194
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
bool isCatalogRel
Definition: gistxlog.h:52
TransactionId snapshotConflictHorizon
Definition: gistxlog.h:50
OffsetNumber offsets[FLEXIBLE_ARRAY_MEMBER]
Definition: gistxlog.h:56
uint16 ntodelete
Definition: gistxlog.h:51
FullTransactionId deleteXid
Definition: gistxlog.h:86
OffsetNumber downlinkOffset
Definition: gistxlog.h:87
RelFileLocator locator
Definition: gistxlog.h:99
BlockNumber block
Definition: gistxlog.h:100
FullTransactionId snapshotConflictHorizon
Definition: gistxlog.h:101
GistNSN orignsn
Definition: gistxlog.h:69
BlockNumber origrlink
Definition: gistxlog.h:68
bool markfollowright
Definition: gistxlog.h:73
uint16 ntodelete
Definition: gistxlog.h:37
uint16 ntoinsert
Definition: gistxlog.h:38
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:155
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterBufData(uint8 block_id, const char *data, uint32 len)
Definition: xloginsert.c:405
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define REGBUF_WILL_INIT
Definition: xloginsert.h:34
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2025
void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1971
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:420
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:314
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:326
#define InHotStandby
Definition: xlogutils.h:60
XLogRedoAction
Definition: xlogutils.h:73
@ BLK_RESTORED
Definition: xlogutils.h:76
@ BLK_NEEDS_REDO
Definition: xlogutils.h:74