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