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, 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)
 

Variables

static MemoryContext opCtx
 

Function Documentation

◆ decodePageSplitRecord()

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

Definition at line 230 of file gistxlog.c.

231 {
232  char *ptr;
233  int i = 0;
234  IndexTuple *tuples;
235 
236  /* extract the number of tuples */
237  memcpy(n, begin, sizeof(int));
238  ptr = begin + sizeof(int);
239 
240  tuples = palloc(*n * sizeof(IndexTuple));
241 
242  for (i = 0; i < *n; i++)
243  {
244  Assert(ptr - begin < len);
245  tuples[i] = (IndexTuple) ptr;
246  ptr += IndexTupleSize((IndexTuple) ptr);
247  }
248  Assert(ptr - begin == len);
249 
250  return tuples;
251 }
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:1210
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 459 of file gistxlog.c.

460 {
461  Page page = (Page) pagedata;
462 
464 
465  mask_page_hint_bits(page);
466  mask_unused_space(page);
467 
468  /*
469  * NSN is nothing but a special purpose LSN. Hence, mask it for the same
470  * reason as mask_page_lsn_and_checksum.
471  */
472  GistPageSetNSN(page, (uint64) MASK_MARKER);
473 
474  /*
475  * We update F_FOLLOW_RIGHT flag on the left child after writing WAL
476  * record. Hence, mask this flag. See gistplacetopage() for details.
477  */
478  GistMarkFollowRight(page);
479 
480  if (GistPageIsLeaf(page))
481  {
482  /*
483  * In gist leaf pages, it is possible to modify the LP_FLAGS without
484  * emitting any WAL record. Hence, mask the line pointer flags. See
485  * gistkillitems() for details.
486  */
487  mask_lp_flags(page);
488  }
489 
490  /*
491  * During gist redo, we never mark a page as garbage. Hence, mask it to
492  * ignore any differences.
493  */
495 }
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 403 of file gistxlog.c.

404 {
405  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
406  MemoryContext oldCxt;
407 
408  /*
409  * GiST indexes do not require any conflict processing. NB: If we ever
410  * implement a similar optimization we have in b-tree, and remove killed
411  * tuples outside VACUUM, we'll need to handle that here.
412  */
413 
414  oldCxt = MemoryContextSwitchTo(opCtx);
415  switch (info)
416  {
418  gistRedoPageUpdateRecord(record);
419  break;
420  case XLOG_GIST_DELETE:
421  gistRedoDeleteRecord(record);
422  break;
424  gistRedoPageReuse(record);
425  break;
427  gistRedoPageSplitRecord(record);
428  break;
430  gistRedoPageDelete(record);
431  break;
433  /* nop. See gistGetFakeLSN(). */
434  break;
435  default:
436  elog(PANIC, "gist_redo: unknown op code %u", info);
437  }
438 
439  MemoryContextSwitchTo(oldCxt);
441 }
unsigned char uint8
Definition: c.h:488
#define PANIC
Definition: elog.h:42
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:383
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:72
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:254
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:349
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:314
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409
#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 450 of file gistxlog.c.

451 {
453 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:387

References MemoryContextDelete(), and opCtx.

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 444 of file gistxlog.c.

445 {
447 }
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:4028
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1631
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:285
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:233
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 
181  /*
182  * If we have any conflict processing to do, it must happen before we
183  * update the page.
184  *
185  * GiST delete records can conflict with standby queries. You might think
186  * that vacuum records would conflict as well, but we've handled that
187  * already. XLOG_HEAP2_PRUNE records provide the highest xid cleaned by
188  * the vacuum of the heap and so we can resolve any conflicts just once
189  * when that arrives. After that we know that no conflicts exist from
190  * individual gist vacuum records on that index.
191  */
192  if (InHotStandby)
193  {
194  RelFileLocator rlocator;
195 
196  XLogRecGetBlockTag(record, 0, &rlocator, NULL, NULL);
197 
199  rlocator);
200  }
201 
202  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
203  {
204  page = (Page) BufferGetPage(buffer);
205 
207  {
208  OffsetNumber *todelete;
209 
210  todelete = (OffsetNumber *) ((char *) xldata + SizeOfGistxlogDelete);
211 
212  PageIndexMultiDelete(page, todelete, xldata->ntodelete);
213  }
214 
216  GistMarkTuplesDeleted(page);
217 
218  PageSetLSN(page, lsn);
219  MarkBufferDirty(buffer);
220  }
221 
222  if (BufferIsValid(buffer))
223  UnlockReleaseBuffer(buffer);
224 }
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1161
#define GistMarkTuplesDeleted(page)
Definition: gist.h:173
#define SizeOfGistxlogDelete
Definition: gistxlog.h:56
uint16 OffsetNumber
Definition: off.h:24
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, RelFileLocator locator)
Definition: standby.c:468
TransactionId snapshotConflictHorizon
Definition: gistxlog.h:50
uint16 ntodelete
Definition: gistxlog.h:51
void XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1961
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:415
#define XLogRecGetData(decoder)
Definition: xlogreader.h:414
#define InHotStandby
Definition: xlogutils.h:57

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

Referenced by gist_redo().

◆ gistRedoPageDelete()

static void gistRedoPageDelete ( XLogReaderState record)
static

Definition at line 349 of file gistxlog.c.

350 {
351  XLogRecPtr lsn = record->EndRecPtr;
353  Buffer parentBuffer;
354  Buffer leafBuffer;
355 
356  if (XLogReadBufferForRedo(record, 0, &leafBuffer) == BLK_NEEDS_REDO)
357  {
358  Page page = (Page) BufferGetPage(leafBuffer);
359 
360  GistPageSetDeleted(page, xldata->deleteXid);
361 
362  PageSetLSN(page, lsn);
363  MarkBufferDirty(leafBuffer);
364  }
365 
366  if (XLogReadBufferForRedo(record, 1, &parentBuffer) == BLK_NEEDS_REDO)
367  {
368  Page page = (Page) BufferGetPage(parentBuffer);
369 
370  PageIndexTupleDelete(page, xldata->downlinkOffset);
371 
372  PageSetLSN(page, lsn);
373  MarkBufferDirty(parentBuffer);
374  }
375 
376  if (BufferIsValid(parentBuffer))
377  UnlockReleaseBuffer(parentBuffer);
378  if (BufferIsValid(leafBuffer))
379  UnlockReleaseBuffer(leafBuffer);
380 }
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:83
OffsetNumber downlinkOffset
Definition: gistxlog.h:84

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 383 of file gistxlog.c.

384 {
386 
387  /*
388  * PAGE_REUSE records exist to provide a conflict point when we reuse
389  * pages in the index via the FSM. That's all they do though.
390  *
391  * snapshotConflictHorizon was the page's deleteXid. The
392  * GlobalVisCheckRemovableFullXid(deleteXid) test in gistPageRecyclable()
393  * conceptually mirrors the PGPROC->xmin > limitXmin test in
394  * GetConflictingVirtualXIDs(). Consequently, one XID value achieves the
395  * same exclusion effect on primary and standby.
396  */
397  if (InHotStandby)
399  xlrec->locator);
400 }
void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon, RelFileLocator locator)
Definition: standby.c:501
RelFileLocator locator
Definition: gistxlog.h:96
FullTransactionId snapshotConflictHorizon
Definition: gistxlog.h:98

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

Referenced by gist_redo().

◆ gistRedoPageSplitRecord()

static void gistRedoPageSplitRecord ( XLogReaderState record)
static

Definition at line 254 of file gistxlog.c.

255 {
256  XLogRecPtr lsn = record->EndRecPtr;
257  gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record);
258  Buffer firstbuffer = InvalidBuffer;
259  Buffer buffer;
260  Page page;
261  int i;
262  bool isrootsplit = false;
263 
264  /*
265  * We must hold lock on the first-listed page throughout the action,
266  * including while updating the left child page (if any). We can unlock
267  * remaining pages in the list as soon as they've been written, because
268  * there is no path for concurrent queries to reach those pages without
269  * first visiting the first-listed page.
270  */
271 
272  /* loop around all pages */
273  for (i = 0; i < xldata->npage; i++)
274  {
275  int flags;
276  char *data;
277  Size datalen;
278  int num;
279  BlockNumber blkno;
280  IndexTuple *tuples;
281 
282  XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
283  if (blkno == GIST_ROOT_BLKNO)
284  {
285  Assert(i == 0);
286  isrootsplit = true;
287  }
288 
289  buffer = XLogInitBufferForRedo(record, i + 1);
290  page = (Page) BufferGetPage(buffer);
291  data = XLogRecGetBlockData(record, i + 1, &datalen);
292 
293  tuples = decodePageSplitRecord(data, datalen, &num);
294 
295  /* ok, clear buffer */
296  if (xldata->origleaf && blkno != GIST_ROOT_BLKNO)
297  flags = F_LEAF;
298  else
299  flags = 0;
300  GISTInitBuffer(buffer, flags);
301 
302  /* and fill it */
303  gistfillbuffer(page, tuples, num, FirstOffsetNumber);
304 
305  if (blkno == GIST_ROOT_BLKNO)
306  {
307  GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
308  GistPageSetNSN(page, xldata->orignsn);
309  GistClearFollowRight(page);
310  }
311  else
312  {
313  if (i < xldata->npage - 1)
314  {
315  BlockNumber nextblkno;
316 
317  XLogRecGetBlockTag(record, i + 2, NULL, NULL, &nextblkno);
318  GistPageGetOpaque(page)->rightlink = nextblkno;
319  }
320  else
321  GistPageGetOpaque(page)->rightlink = xldata->origrlink;
322  GistPageSetNSN(page, xldata->orignsn);
323  if (i < xldata->npage - 1 && !isrootsplit &&
324  xldata->markfollowright)
325  GistMarkFollowRight(page);
326  else
327  GistClearFollowRight(page);
328  }
329 
330  PageSetLSN(page, lsn);
331  MarkBufferDirty(buffer);
332 
333  if (i == 0)
334  firstbuffer = buffer;
335  else
336  UnlockReleaseBuffer(buffer);
337  }
338 
339  /* Fix follow-right data on left child page, if any */
340  if (XLogRecHasBlockRef(record, 0))
341  gistRedoClearFollowRight(record, 0);
342 
343  /* Finally, release lock on the first page */
344  UnlockReleaseBuffer(firstbuffer);
345 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidBuffer
Definition: buf.h:25
size_t Size
Definition: c.h:589
#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:230
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:66
BlockNumber origrlink
Definition: gistxlog.h:65
bool markfollowright
Definition: gistxlog.h:70
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2015
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:419
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:166
#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 582 of file gistxlog.c.

583 {
584  int dummy = 0;
585 
586  /*
587  * Records other than SWITCH_WAL must have content. We use an integer 0 to
588  * follow the restriction.
589  */
590  XLogBeginInsert();
592  XLogRegisterData((char *) &dummy, sizeof(dummy));
593  return XLogInsert(RM_GIST_ID, XLOG_GIST_ASSIGN_LSN);
594 }
#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:451
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:433
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 
)

Definition at line 674 of file gistxlog.c.

676 {
677  gistxlogDelete xlrec;
678  XLogRecPtr recptr;
679 
680  xlrec.snapshotConflictHorizon = snapshotConflictHorizon;
681  xlrec.ntodelete = ntodelete;
682 
683  XLogBeginInsert();
684  XLogRegisterData((char *) &xlrec, SizeOfGistxlogDelete);
685 
686  /*
687  * We need the target-offsets array whether or not we store the whole
688  * buffer, to allow us to find the snapshotConflictHorizon on a standby
689  * server.
690  */
691  XLogRegisterData((char *) todelete, ntodelete * sizeof(OffsetNumber));
692 
694 
695  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_DELETE);
696 
697  return recptr;
698 }
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:243
#define REGBUF_STANDARD
Definition: xloginsert.h:34

References gistxlogDelete::ntodelete, REGBUF_STANDARD, 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 558 of file gistxlog.c.

560 {
561  gistxlogPageDelete xlrec;
562  XLogRecPtr recptr;
563 
564  xlrec.deleteXid = xid;
565  xlrec.downlinkOffset = downlinkOffset;
566 
567  XLogBeginInsert();
568  XLogRegisterData((char *) &xlrec, SizeOfGistxlogPageDelete);
569 
571  XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
572 
573  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
574 
575  return recptr;
576 }
#define SizeOfGistxlogPageDelete
Definition: gistxlog.h:88

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,
BlockNumber  blkno,
FullTransactionId  deleteXid 
)

Definition at line 600 of file gistxlog.c.

601 {
602  gistxlogPageReuse xlrec_reuse;
603 
604  /*
605  * Note that we don't register the buffer with the record, because this
606  * operation doesn't modify the page. This record only exists to provide a
607  * conflict point for Hot Standby.
608  */
609 
610  /* XLOG stuff */
611  xlrec_reuse.locator = rel->rd_locator;
612  xlrec_reuse.block = blkno;
613  xlrec_reuse.snapshotConflictHorizon = deleteXid;
614 
615  XLogBeginInsert();
616  XLogRegisterData((char *) &xlrec_reuse, SizeOfGistxlogPageReuse);
617 
618  XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
619 }
#define SizeOfGistxlogPageReuse
Definition: gistxlog.h:101
RelFileLocator rd_locator
Definition: rel.h:56
BlockNumber block
Definition: gistxlog.h:97

References gistxlogPageReuse::block, gistxlogPageReuse::locator, RelationData::rd_locator, 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 501 of file gistxlog.c.

505 {
506  gistxlogPageSplit xlrec;
507  SplitedPageLayout *ptr;
508  int npage = 0;
509  XLogRecPtr recptr;
510  int i;
511 
512  for (ptr = dist; ptr; ptr = ptr->next)
513  npage++;
514 
515  xlrec.origrlink = origrlink;
516  xlrec.orignsn = orignsn;
517  xlrec.origleaf = page_is_leaf;
518  xlrec.npage = (uint16) npage;
519  xlrec.markfollowright = markfollowright;
520 
521  XLogBeginInsert();
522 
523  /*
524  * Include a full page image of the child buf. (only necessary if a
525  * checkpoint happened since the child page was split)
526  */
527  if (BufferIsValid(leftchildbuf))
528  XLogRegisterBuffer(0, leftchildbuf, REGBUF_STANDARD);
529 
530  /*
531  * NOTE: We register a lot of data. The caller must've called
532  * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
533  * because we're already in a critical section. If you change the number
534  * of buffer or data registrations here, make sure you modify the
535  * XLogEnsureRecordSpace() calls accordingly!
536  */
537  XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageSplit));
538 
539  i = 1;
540  for (ptr = dist; ptr; ptr = ptr->next)
541  {
543  XLogRegisterBufData(i, (char *) &(ptr->block.num), sizeof(int));
544  XLogRegisterBufData(i, (char *) ptr->list, ptr->lenlist);
545  i++;
546  }
547 
548  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT);
549 
550  return recptr;
551 }
unsigned short uint16
Definition: c.h:489
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:389
#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 633 of file gistxlog.c.

637 {
638  gistxlogPageUpdate xlrec;
639  int i;
640  XLogRecPtr recptr;
641 
642  xlrec.ntodelete = ntodelete;
643  xlrec.ntoinsert = ituplen;
644 
645  XLogBeginInsert();
646  XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageUpdate));
647 
649  XLogRegisterBufData(0, (char *) todelete, sizeof(OffsetNumber) * ntodelete);
650 
651  /* new tuples */
652  for (i = 0; i < ituplen; i++)
653  XLogRegisterBufData(0, (char *) (itup[i]), IndexTupleSize(itup[i]));
654 
655  /*
656  * Include a full page image of the child buf. (only necessary if a
657  * checkpoint happened since the child page was split)
658  */
659  if (BufferIsValid(leftchildbuf))
660  XLogRegisterBuffer(1, leftchildbuf, REGBUF_STANDARD);
661 
662  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE);
663 
664  return recptr;
665 }

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().