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-2024, 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 
26 static 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  */
39 static 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  */
69 static 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))
119  GistMarkTuplesDeleted(page);
120  }
121 
122  /* Add new tuples if any */
123  if (data - begin < datalen)
124  {
125  OffsetNumber off = (PageIsEmpty(page)) ? FirstOffsetNumber :
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  */
171 static 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 
209  GistMarkTuplesDeleted(page);
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  */
222 static IndexTuple *
223 decodePageSplitRecord(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 
246 static void
248 {
249  XLogRecPtr lsn = record->EndRecPtr;
250  gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record);
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);
302  GistClearFollowRight(page);
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)
318  GistMarkFollowRight(page);
319  else
320  GistClearFollowRight(page);
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 */
341 static 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 
363  PageIndexTupleDelete(page, xldata->downlinkOffset);
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 
375 static 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 
396 void
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 
408  oldCxt = MemoryContextSwitchTo(opCtx);
409  switch (info)
410  {
412  gistRedoPageUpdateRecord(record);
413  break;
414  case XLOG_GIST_DELETE:
415  gistRedoDeleteRecord(record);
416  break;
418  gistRedoPageReuse(record);
419  break;
421  gistRedoPageSplitRecord(record);
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 
437 void
439 {
441 }
442 
443 void
445 {
447 }
448 
449 /*
450  * Mask a Gist page before running consistency checks on it.
451  */
452 void
453 gist_mask(char *pagedata, BlockNumber blkno)
454 {
455  Page page = (Page) pagedata;
456 
458 
459  mask_page_hint_bits(page);
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  */
466  GistPageSetNSN(page, (uint64) MASK_MARKER);
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  */
472  GistMarkFollowRight(page);
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  */
495 gistXLogSplit(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 
515  XLogBeginInsert();
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 
561  XLogBeginInsert();
562  XLogRegisterData((char *) &xlrec, SizeOfGistxlogPageDelete);
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  */
584  XLogBeginInsert();
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  */
593 void
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 
611  XLogBeginInsert();
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 
641  XLogBeginInsert();
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  */
670 gistXLogDelete(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 
680  XLogBeginInsert();
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:4867
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2474
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:404
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:355
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1161
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1405
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1052
static bool PageIsEmpty(Page page)
Definition: bufpage.h:220
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
unsigned short uint16
Definition: c.h:505
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:182
#define Assert(condition)
Definition: c.h:858
unsigned char uint8
Definition: c.h:504
uint32 TransactionId
Definition: c.h:652
size_t Size
Definition: c.h:605
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
MemoryContext createTempGistContext(void)
Definition: gist.c:122
#define GistMarkFollowRight(page)
Definition: gist.h:181
#define F_LEAF
Definition: gist.h:46
#define GistClearFollowRight(page)
Definition: gist.h:182
#define GistClearPageHasGarbage(page)
Definition: gist.h:178
#define GistPageIsLeaf(page)
Definition: gist.h:167
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:202
#define GistMarkTuplesDeleted(page)
Definition: gist.h:173
#define GistPageSetNSN(page, val)
Definition: gist.h:185
#define GistPageGetOpaque(page)
Definition: gist.h:165
XLogRecPtr GistNSN
Definition: gist.h:60
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:33
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:772
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:73
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 MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
void * palloc(Size size)
Definition: mcxt.c:1316
#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
const void size_t len
const void * data
MemoryContextSwitchTo(old_ctx)
#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:153
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:405
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:34
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1971
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2025
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:420
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
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:57
XLogRedoAction
Definition: xlogutils.h:70
@ BLK_RESTORED
Definition: xlogutils.h:73
@ BLK_NEEDS_REDO
Definition: xlogutils.h:71