PostgreSQL Source Code  git master
gistxlog.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/gist_private.h"
#include "access/gistxlog.h"
#include "access/heapam_xlog.h"
#include "access/transam.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "storage/procarray.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistxlog.c:

Go to the source code of this file.

Functions

static void gistRedoClearFollowRight (XLogReaderState *record, uint8 block_id)
 
static void gistRedoPageUpdateRecord (XLogReaderState *record)
 
static void gistRedoDeleteRecord (XLogReaderState *record)
 
static IndexTupledecodePageSplitRecord (char *begin, int len, int *n)
 
static void gistRedoPageSplitRecord (XLogReaderState *record)
 
static void gistRedoPageDelete (XLogReaderState *record)
 
static void gistRedoPageReuse (XLogReaderState *record)
 
void gist_redo (XLogReaderState *record)
 
void gist_xlog_startup (void)
 
void gist_xlog_cleanup (void)
 
void gist_mask (char *pagedata, BlockNumber blkno)
 
XLogRecPtr gistXLogSplit (bool page_is_leaf, SplitedPageLayout *dist, BlockNumber origrlink, GistNSN orignsn, Buffer leftchildbuf, bool markfollowright)
 
XLogRecPtr gistXLogPageDelete (Buffer buffer, FullTransactionId xid, Buffer parentBuffer, OffsetNumber downlinkOffset)
 
XLogRecPtr gistXLogAssignLSN (void)
 
void gistXLogPageReuse (Relation rel, Relation heaprel, BlockNumber blkno, FullTransactionId deleteXid)
 
XLogRecPtr gistXLogUpdate (Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
 
XLogRecPtr gistXLogDelete (Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId snapshotConflictHorizon, Relation heaprel)
 

Variables

static MemoryContext opCtx
 

Function Documentation

◆ decodePageSplitRecord()

static IndexTuple* decodePageSplitRecord ( char *  begin,
int  len,
int *  n 
)
static

Definition at line 225 of file gistxlog.c.

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 }
int i
Definition: isn.c:73
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
Assert(fmt[strlen(fmt) - 1] !='\n')
void * palloc(Size size)
Definition: mcxt.c:1226
const void size_t len

References Assert(), i, IndexTupleSize, len, and palloc().

Referenced by gistRedoPageSplitRecord().

◆ gist_mask()

void gist_mask ( char *  pagedata,
BlockNumber  blkno 
)

Definition at line 455 of file gistxlog.c.

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 }
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
Pointer Page
Definition: bufpage.h:78
#define GistMarkFollowRight(page)
Definition: gist.h:181
#define GistClearPageHasGarbage(page)
Definition: gist.h:178
#define GistPageIsLeaf(page)
Definition: gist.h:167
#define GistPageSetNSN(page, val)
Definition: gist.h:185

References GistClearPageHasGarbage, GistMarkFollowRight, GistPageIsLeaf, GistPageSetNSN, mask_lp_flags(), MASK_MARKER, mask_page_hint_bits(), mask_page_lsn_and_checksum(), and mask_unused_space().

◆ gist_redo()

void gist_redo ( XLogReaderState record)

Definition at line 399 of file gistxlog.c.

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 }
unsigned char uint8
Definition: c.h:493
#define PANIC
Definition: elog.h:42
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:378
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:72
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:249
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:344
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:174
static MemoryContext opCtx
Definition: gistxlog.c:28
#define XLOG_GIST_ASSIGN_LSN
Definition: gistxlog.h:27
#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 XLOG_GIST_PAGE_SPLIT
Definition: gistxlog.h:23
#define XLOG_GIST_PAGE_UPDATE
Definition: gistxlog.h:20
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:330
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

References elog(), gistRedoDeleteRecord(), gistRedoPageDelete(), gistRedoPageReuse(), gistRedoPageSplitRecord(), gistRedoPageUpdateRecord(), MemoryContextReset(), MemoryContextSwitchTo(), opCtx, PANIC, XLOG_GIST_ASSIGN_LSN, XLOG_GIST_DELETE, XLOG_GIST_PAGE_DELETE, XLOG_GIST_PAGE_REUSE, XLOG_GIST_PAGE_SPLIT, XLOG_GIST_PAGE_UPDATE, XLogRecGetInfo, and XLR_INFO_MASK.

◆ gist_xlog_cleanup()

void gist_xlog_cleanup ( void  )

Definition at line 446 of file gistxlog.c.

447 {
449 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403

References MemoryContextDelete(), and opCtx.

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 440 of file gistxlog.c.

441 {
443 }
MemoryContext createTempGistContext(void)
Definition: gist.c:121

References createTempGistContext(), and opCtx.

◆ gistRedoClearFollowRight()

static void gistRedoClearFollowRight ( XLogReaderState record,
uint8  block_id 
)
static

Definition at line 42 of file gistxlog.c.

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 }
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4497
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2111
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
#define GistClearFollowRight(page)
Definition: gist.h:182
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:317
XLogRedoAction
Definition: xlogutils.h:70
@ BLK_RESTORED
Definition: xlogutils.h:73
@ BLK_NEEDS_REDO
Definition: xlogutils.h:71

References generate_unaccent_rules::action, BLK_NEEDS_REDO, BLK_RESTORED, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, GistClearFollowRight, GistPageSetNSN, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), and XLogReadBufferForRedo().

Referenced by gistRedoPageSplitRecord(), and gistRedoPageUpdateRecord().

◆ gistRedoDeleteRecord()

static void gistRedoDeleteRecord ( XLogReaderState record)
static

Definition at line 174 of file gistxlog.c.

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 }
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1161
#define GistMarkTuplesDeleted(page)
Definition: gist.h:173
uint16 OffsetNumber
Definition: off.h:24
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:468
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
void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1979
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define InHotStandby
Definition: xlogutils.h:57

References BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, GistClearPageHasGarbage, GistMarkTuplesDeleted, InHotStandby, gistxlogDelete::isCatalogRel, MarkBufferDirty(), gistxlogDelete::ntodelete, gistxlogDelete::offsets, PageIndexMultiDelete(), PageSetLSN(), ResolveRecoveryConflictWithSnapshot(), gistxlogDelete::snapshotConflictHorizon, UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockTag(), and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageDelete()

static void gistRedoPageDelete ( XLogReaderState record)
static

Definition at line 344 of file gistxlog.c.

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 }
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1052
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:202
FullTransactionId deleteXid
Definition: gistxlog.h:86
OffsetNumber downlinkOffset
Definition: gistxlog.h:87

References BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), gistxlogPageDelete::deleteXid, gistxlogPageDelete::downlinkOffset, XLogReaderState::EndRecPtr, GistPageSetDeleted(), MarkBufferDirty(), PageIndexTupleDelete(), PageSetLSN(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageReuse()

static void gistRedoPageReuse ( XLogReaderState record)
static

Definition at line 378 of file gistxlog.c.

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 }
void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:512
RelFileLocator locator
Definition: gistxlog.h:99
FullTransactionId snapshotConflictHorizon
Definition: gistxlog.h:101

References InHotStandby, gistxlogPageReuse::isCatalogRel, gistxlogPageReuse::locator, ResolveRecoveryConflictWithSnapshotFullXid(), gistxlogPageReuse::snapshotConflictHorizon, and XLogRecGetData.

Referenced by gist_redo().

◆ gistRedoPageSplitRecord()

static void gistRedoPageSplitRecord ( XLogReaderState record)
static

Definition at line 249 of file gistxlog.c.

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 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidBuffer
Definition: buf.h:25
size_t Size
Definition: c.h:594
#define F_LEAF
Definition: gist.h:46
#define GistPageGetOpaque(page)
Definition: gist.h:165
#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 IndexTuple * decodePageSplitRecord(char *begin, int len, int *n)
Definition: gistxlog.c:225
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:42
#define FirstOffsetNumber
Definition: off.h:27
const void * data
GistNSN orignsn
Definition: gistxlog.h:69
BlockNumber origrlink
Definition: gistxlog.h:68
bool markfollowright
Definition: gistxlog.h:73
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2033
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:420
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:329

References Assert(), BufferGetPage(), data, decodePageSplitRecord(), XLogReaderState::EndRecPtr, F_LEAF, FirstOffsetNumber, GIST_ROOT_BLKNO, GistClearFollowRight, gistfillbuffer(), GISTInitBuffer(), GistMarkFollowRight, GistPageGetOpaque, GistPageSetNSN, gistRedoClearFollowRight(), i, InvalidBlockNumber, InvalidBuffer, MarkBufferDirty(), gistxlogPageSplit::markfollowright, gistxlogPageSplit::npage, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), XLogRecGetBlockData(), XLogRecGetBlockTag(), XLogRecGetData, and XLogRecHasBlockRef.

Referenced by gist_redo().

◆ gistRedoPageUpdateRecord()

static void gistRedoPageUpdateRecord ( XLogReaderState record)
static

Definition at line 72 of file gistxlog.c.

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 }
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1405
static bool PageIsEmpty(Page page)
Definition: bufpage.h:220
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:369
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:468
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:171
#define ERROR
Definition: elog.h:39
Pointer Item
Definition: item.h:17
#define InvalidOffsetNumber
Definition: off.h:26
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
uint16 ntodelete
Definition: gistxlog.h:37
uint16 ntoinsert
Definition: gistxlog.h:38

References Assert(), BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), data, elog(), XLogReaderState::EndRecPtr, ERROR, FirstOffsetNumber, GistMarkTuplesDeleted, GistPageIsLeaf, gistRedoClearFollowRight(), IndexTupleSize, InvalidOffsetNumber, MarkBufferDirty(), gistxlogPageUpdate::ntodelete, gistxlogPageUpdate::ntoinsert, OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber(), PageIndexMultiDelete(), PageIndexTupleOverwrite(), PageIsEmpty(), PageSetLSN(), PG_USED_FOR_ASSERTS_ONLY, UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockData(), XLogRecGetData, and XLogRecHasBlockRef.

Referenced by gist_redo().

◆ gistXLogAssignLSN()

XLogRecPtr gistXLogAssignLSN ( void  )

Definition at line 578 of file gistxlog.c.

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 }
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:150
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:351
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:461
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:443
void XLogBeginInsert(void)
Definition: xloginsert.c:150

References XLOG_GIST_ASSIGN_LSN, XLOG_MARK_UNIMPORTANT, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by gistGetFakeLSN().

◆ gistXLogDelete()

XLogRecPtr gistXLogDelete ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
TransactionId  snapshotConflictHorizon,
Relation  heaprel 
)

Definition at line 672 of file gistxlog.c.

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 }
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:685
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
#define REGBUF_STANDARD
Definition: xloginsert.h:34

References gistxlogDelete::isCatalogRel, gistxlogDelete::ntodelete, REGBUF_STANDARD, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogDelete, gistxlogDelete::snapshotConflictHorizon, XLOG_GIST_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistprunepage().

◆ gistXLogPageDelete()

XLogRecPtr gistXLogPageDelete ( Buffer  buffer,
FullTransactionId  xid,
Buffer  parentBuffer,
OffsetNumber  downlinkOffset 
)

Definition at line 554 of file gistxlog.c.

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 }
#define SizeOfGistxlogPageDelete
Definition: gistxlog.h:91

References gistxlogPageDelete::deleteXid, gistxlogPageDelete::downlinkOffset, REGBUF_STANDARD, SizeOfGistxlogPageDelete, XLOG_GIST_PAGE_DELETE, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistdeletepage().

◆ gistXLogPageReuse()

void gistXLogPageReuse ( Relation  rel,
Relation  heaprel,
BlockNumber  blkno,
FullTransactionId  deleteXid 
)

Definition at line 596 of file gistxlog.c.

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 }
#define SizeOfGistxlogPageReuse
Definition: gistxlog.h:106
RelFileLocator rd_locator
Definition: rel.h:57
BlockNumber block
Definition: gistxlog.h:100

References gistxlogPageReuse::block, gistxlogPageReuse::isCatalogRel, gistxlogPageReuse::locator, RelationData::rd_locator, RelationIsAccessibleInLogicalDecoding, SizeOfGistxlogPageReuse, gistxlogPageReuse::snapshotConflictHorizon, XLOG_GIST_PAGE_REUSE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by gistNewBuffer().

◆ gistXLogSplit()

XLogRecPtr gistXLogSplit ( bool  page_is_leaf,
SplitedPageLayout dist,
BlockNumber  origrlink,
GistNSN  orignsn,
Buffer  leftchildbuf,
bool  markfollowright 
)

Definition at line 497 of file gistxlog.c.

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 }
unsigned short uint16
Definition: c.h:494
gistxlogPage block
Definition: gist_private.h:193
IndexTupleData * list
Definition: gist_private.h:194
struct SplitedPageLayout * next
Definition: gist_private.h:200
void XLogRegisterBufData(uint8 block_id, char *data, uint32 len)
Definition: xloginsert.c:392
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33

References SplitedPageLayout::block, SplitedPageLayout::buffer, BufferIsValid(), i, SplitedPageLayout::lenlist, SplitedPageLayout::list, gistxlogPageSplit::markfollowright, SplitedPageLayout::next, gistxlogPageSplit::npage, gistxlogPage::num, gistxlogPageSplit::origleaf, gistxlogPageSplit::orignsn, gistxlogPageSplit::origrlink, REGBUF_STANDARD, REGBUF_WILL_INIT, XLOG_GIST_PAGE_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage().

◆ gistXLogUpdate()

XLogRecPtr gistXLogUpdate ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
IndexTuple itup,
int  ituplen,
Buffer  leftchildbuf 
)

Definition at line 631 of file gistxlog.c.

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 }

References BufferIsValid(), i, IndexTupleSize, gistxlogPageUpdate::ntodelete, gistxlogPageUpdate::ntoinsert, REGBUF_STANDARD, XLOG_GIST_PAGE_UPDATE, XLogBeginInsert(), XLogInsert(), XLogRegisterBufData(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by gistplacetopage(), and gistvacuumpage().

Variable Documentation

◆ opCtx

MemoryContext opCtx
static

Definition at line 28 of file gistxlog.c.

Referenced by gist_redo(), gist_xlog_cleanup(), and gist_xlog_startup().