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/transam.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "storage/standby.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, SplitPageLayout *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 223 of file gistxlog.c.

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 }
#define Assert(condition)
Definition: c.h:812
int i
Definition: isn.c:72
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
void * palloc(Size size)
Definition: mcxt.c:1317
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 453 of file gistxlog.c.

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  */
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 }
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:81
uint64_t uint64
Definition: c.h:486
#define GistMarkFollowRight(page)
Definition: gist.h:183
#define GistClearPageHasGarbage(page)
Definition: gist.h:180
#define GistPageIsLeaf(page)
Definition: gist.h:169
#define GistPageSetNSN(page, val)
Definition: gist.h:187

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

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 }
uint8_t uint8
Definition: c.h:483
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:225
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:376
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:70
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:247
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:342
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:172
static MemoryContext opCtx
Definition: gistxlog.c:26
#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:383
MemoryContextSwitchTo(old_ctx)
#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 444 of file gistxlog.c.

445 {
447 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References MemoryContextDelete(), and opCtx.

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 438 of file gistxlog.c.

439 {
441 }
MemoryContext createTempGistContext(void)
Definition: gist.c:123

References createTempGistContext(), and opCtx.

◆ gistRedoClearFollowRight()

static void gistRedoClearFollowRight ( XLogReaderState record,
uint8  block_id 
)
static

Definition at line 40 of file gistxlog.c.

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 }
int Buffer
Definition: buf.h:23
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4941
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:400
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:351
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
#define GistClearFollowRight(page)
Definition: gist.h:184
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:314
XLogRedoAction
Definition: xlogutils.h:73
@ BLK_RESTORED
Definition: xlogutils.h:76
@ BLK_NEEDS_REDO
Definition: xlogutils.h:74

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

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 }
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:1150
#define GistMarkTuplesDeleted(page)
Definition: gist.h:175
uint16 OffsetNumber
Definition: off.h:24
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:467
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:1971
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define InHotStandby
Definition: xlogutils.h:60

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

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 }
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1041
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:204
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 376 of file gistxlog.c.

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 }
void ResolveRecoveryConflictWithSnapshotFullXid(FullTransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition: standby.c:511
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 247 of file gistxlog.c.

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 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
#define InvalidBuffer
Definition: buf.h:25
size_t Size
Definition: c.h:559
#define F_LEAF
Definition: gist.h:48
#define GistPageGetOpaque(page)
Definition: gist.h:167
#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:223
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:40
#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:2025
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:420
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:326

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

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 }
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1394
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:201
#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 576 of file gistxlog.c.

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 }
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:155
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:456
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogBeginInsert(void)
Definition: xloginsert.c:149

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

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 }
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
#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 552 of file gistxlog.c.

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 }
#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 594 of file gistxlog.c.

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 }
#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,
SplitPageLayout dist,
BlockNumber  origrlink,
GistNSN  orignsn,
Buffer  leftchildbuf,
bool  markfollowright 
)

Definition at line 495 of file gistxlog.c.

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

References SplitPageLayout::block, SplitPageLayout::buffer, BufferIsValid(), i, SplitPageLayout::lenlist, SplitPageLayout::list, gistxlogPageSplit::markfollowright, SplitPageLayout::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 629 of file gistxlog.c.

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 }

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

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