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)
 
void gistXLogPageReuse (Relation rel, BlockNumber blkno, FullTransactionId latestRemovedXid)
 
XLogRecPtr gistXLogUpdate (Buffer buffer, OffsetNumber *todelete, int ntodelete, IndexTuple *itup, int ituplen, Buffer leftchildbuf)
 
XLogRecPtr gistXLogDelete (Buffer buffer, OffsetNumber *todelete, int ntodelete, TransactionId latestRemovedXid)
 

Variables

static MemoryContext opCtx
 

Function Documentation

◆ decodePageSplitRecord()

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

Definition at line 229 of file gistxlog.c.

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

Referenced by gistRedoPageSplitRecord().

230 {
231  char *ptr;
232  int i = 0;
233  IndexTuple *tuples;
234 
235  /* extract the number of tuples */
236  memcpy(n, begin, sizeof(int));
237  ptr = begin + sizeof(int);
238 
239  tuples = palloc(*n * sizeof(IndexTuple));
240 
241  for (i = 0; i < *n; i++)
242  {
243  Assert(ptr - begin < len);
244  tuples[i] = (IndexTuple) ptr;
245  ptr += IndexTupleSize((IndexTuple) ptr);
246  }
247  Assert(ptr - begin == len);
248 
249  return tuples;
250 }
IndexTupleData * IndexTuple
Definition: itup.h:53
#define Assert(condition)
Definition: c.h:739
void * palloc(Size size)
Definition: mcxt.c:949
int i
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gist_mask()

void gist_mask ( char *  pagedata,
BlockNumber  blkno 
)

Definition at line 476 of file gistxlog.c.

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

477 {
478  Page page = (Page) pagedata;
479 
481 
482  mask_page_hint_bits(page);
483  mask_unused_space(page);
484 
485  /*
486  * NSN is nothing but a special purpose LSN. Hence, mask it for the same
487  * reason as mask_page_lsn_and_checksum.
488  */
489  GistPageSetNSN(page, (uint64) MASK_MARKER);
490 
491  /*
492  * We update F_FOLLOW_RIGHT flag on the left child after writing WAL
493  * record. Hence, mask this flag. See gistplacetopage() for details.
494  */
495  GistMarkFollowRight(page);
496 
497  if (GistPageIsLeaf(page))
498  {
499  /*
500  * In gist leaf pages, it is possible to modify the LP_FLAGS without
501  * emitting any WAL record. Hence, mask the line pointer flags. See
502  * gistkillitems() for details.
503  */
504  mask_lp_flags(page);
505  }
506 
507  /*
508  * During gist redo, we never mark a page as garbage. Hence, mask it to
509  * ignore any differences.
510  */
512 }
#define GistClearPageHasGarbage(page)
Definition: gist.h:151
void mask_page_hint_bits(Page page)
Definition: bufmask.c:46
#define GistPageSetNSN(page, val)
Definition: gist.h:158
void mask_unused_space(Page page)
Definition: bufmask.c:71
#define MASK_MARKER
Definition: bufmask.h:24
#define GistPageIsLeaf(page)
Definition: gist.h:140
void mask_page_lsn_and_checksum(Page page)
Definition: bufmask.c:31
#define GistMarkFollowRight(page)
Definition: gist.h:154
void mask_lp_flags(Page page)
Definition: bufmask.c:95
Pointer Page
Definition: bufpage.h:78

◆ gist_redo()

void gist_redo ( XLogReaderState record)

Definition at line 423 of file gistxlog.c.

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

424 {
425  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
426  MemoryContext oldCxt;
427 
428  /*
429  * GiST indexes do not require any conflict processing. NB: If we ever
430  * implement a similar optimization we have in b-tree, and remove killed
431  * tuples outside VACUUM, we'll need to handle that here.
432  */
433 
434  oldCxt = MemoryContextSwitchTo(opCtx);
435  switch (info)
436  {
438  gistRedoPageUpdateRecord(record);
439  break;
440  case XLOG_GIST_DELETE:
441  gistRedoDeleteRecord(record);
442  break;
444  gistRedoPageReuse(record);
445  break;
447  gistRedoPageSplitRecord(record);
448  break;
450  gistRedoPageDelete(record);
451  break;
452  default:
453  elog(PANIC, "gist_redo: unknown op code %u", info);
454  }
455 
456  MemoryContextSwitchTo(oldCxt);
458 }
static void gistRedoPageUpdateRecord(XLogReaderState *record)
Definition: gistxlog.c:72
static void gistRedoPageReuse(XLogReaderState *record)
Definition: gistxlog.c:382
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
unsigned char uint8
Definition: c.h:357
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:136
#define PANIC
Definition: elog.h:53
static void gistRedoPageDelete(XLogReaderState *record)
Definition: gistxlog.c:348
#define XLOG_GIST_PAGE_SPLIT
Definition: gistxlog.h:25
static void gistRedoPageSplitRecord(XLogReaderState *record)
Definition: gistxlog.c:253
#define XLOG_GIST_DELETE
Definition: gistxlog.h:21
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:279
#define XLOG_GIST_PAGE_REUSE
Definition: gistxlog.h:23
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_GIST_PAGE_DELETE
Definition: gistxlog.h:28
static void gistRedoDeleteRecord(XLogReaderState *record)
Definition: gistxlog.c:174
#define elog(elevel,...)
Definition: elog.h:228
static MemoryContext opCtx
Definition: gistxlog.c:28
#define XLOG_GIST_PAGE_UPDATE
Definition: gistxlog.h:20

◆ gist_xlog_cleanup()

void gist_xlog_cleanup ( void  )

Definition at line 467 of file gistxlog.c.

References MemoryContextDelete().

468 {
470 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static MemoryContext opCtx
Definition: gistxlog.c:28

◆ gist_xlog_startup()

void gist_xlog_startup ( void  )

Definition at line 461 of file gistxlog.c.

References createTempGistContext().

462 {
464 }
MemoryContext createTempGistContext(void)
Definition: gist.c:113
static MemoryContext opCtx
Definition: gistxlog.c:28

◆ gistRedoClearFollowRight()

static void gistRedoClearFollowRight ( XLogReaderState record,
uint8  block_id 
)
static

Definition at line 42 of file gistxlog.c.

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

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);
54  if (action == BLK_NEEDS_REDO || action == BLK_RESTORED)
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 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
#define GistPageSetNSN(page, val)
Definition: gist.h:158
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GistClearFollowRight(page)
Definition: gist.h:155
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:289
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRedoAction
Definition: xlogutils.h:27
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ gistRedoDeleteRecord()

static void gistRedoDeleteRecord ( XLogReaderState record)
static

Definition at line 174 of file gistxlog.c.

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

Referenced by gist_redo().

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_CLEANUP_INFO records provide the highest xid
188  * cleaned by the vacuum of the heap and so we can resolve any conflicts
189  * just once when that arrives. After that we know that no conflicts
190  * exist from individual gist vacuum records on that index.
191  */
192  if (InHotStandby)
193  {
194  RelFileNode rnode;
195 
196  XLogRecGetBlockTag(record, 0, &rnode, NULL, NULL);
197 
199  }
200 
201  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
202  {
203  page = (Page) BufferGetPage(buffer);
204 
206  {
207  OffsetNumber *todelete;
208 
209  todelete = (OffsetNumber *) ((char *) xldata + SizeOfGistxlogDelete);
210 
211  PageIndexMultiDelete(page, todelete, xldata->ntodelete);
212  }
213 
215  GistMarkTuplesDeleted(page);
216 
217  PageSetLSN(page, lsn);
218  MarkBufferDirty(buffer);
219  }
220 
221  if (BufferIsValid(buffer))
222  UnlockReleaseBuffer(buffer);
223 }
#define GistClearPageHasGarbage(page)
Definition: gist.h:151
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
#define GistMarkTuplesDeleted(page)
Definition: gist.h:146
#define InHotStandby
Definition: xlog.h:74
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
uint16 OffsetNumber
Definition: off.h:24
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define XLogRecGetDataLen(decoder)
Definition: xlogreader.h:284
uint16 ntodelete
Definition: gistxlog.h:52
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1460
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:289
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:835
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
TransactionId latestRemovedXid
Definition: gistxlog.h:51
void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node)
Definition: standby.c:294
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ gistRedoPageDelete()

static void gistRedoPageDelete ( XLogReaderState record)
static

Definition at line 348 of file gistxlog.c.

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

Referenced by gist_redo().

349 {
350  XLogRecPtr lsn = record->EndRecPtr;
352  Buffer parentBuffer;
353  Buffer leafBuffer;
354 
355  if (XLogReadBufferForRedo(record, 0, &leafBuffer) == BLK_NEEDS_REDO)
356  {
357  Page page = (Page) BufferGetPage(leafBuffer);
358 
359  GistPageSetDeleted(page, xldata->deleteXid);
360 
361  PageSetLSN(page, lsn);
362  MarkBufferDirty(leafBuffer);
363  }
364 
365  if (XLogReadBufferForRedo(record, 1, &parentBuffer) == BLK_NEEDS_REDO)
366  {
367  Page page = (Page) BufferGetPage(parentBuffer);
368 
369  PageIndexTupleDelete(page, xldata->downlinkOffset);
370 
371  PageSetLSN(page, lsn);
372  MarkBufferDirty(parentBuffer);
373  }
374 
375  if (BufferIsValid(parentBuffer))
376  UnlockReleaseBuffer(parentBuffer);
377  if (BufferIsValid(leafBuffer))
378  UnlockReleaseBuffer(leafBuffer);
379 }
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:726
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
FullTransactionId deleteXid
Definition: gistxlog.h:86
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
static void GistPageSetDeleted(Page page, FullTransactionId deletexid)
Definition: gist.h:175
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:289
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
OffsetNumber downlinkOffset
Definition: gistxlog.h:87

◆ gistRedoPageReuse()

static void gistRedoPageReuse ( XLogReaderState record)
static

Definition at line 382 of file gistxlog.c.

References InHotStandby, gistxlogPageReuse::latestRemovedFullXid, MaxTransactionId, gistxlogPageReuse::node, ReadNextFullTransactionId(), ResolveRecoveryConflictWithSnapshot(), U64FromFullTransactionId, XidFromFullTransactionId, and XLogRecGetData.

Referenced by gist_redo().

383 {
385 
386  /*
387  * PAGE_REUSE records exist to provide a conflict point when we reuse
388  * pages in the index via the FSM. That's all they do though.
389  *
390  * latestRemovedXid was the page's deleteXid. The deleteXid <
391  * RecentGlobalXmin test in gistPageRecyclable() conceptually mirrors the
392  * pgxact->xmin > limitXmin test in GetConflictingVirtualXIDs().
393  * Consequently, one XID value achieves the same exclusion effect on
394  * master and standby.
395  */
396  if (InHotStandby)
397  {
398  FullTransactionId latestRemovedFullXid = xlrec->latestRemovedFullXid;
400  uint64 diff;
401 
402  /*
403  * ResolveRecoveryConflictWithSnapshot operates on 32-bit
404  * TransactionIds, so truncate the logged FullTransactionId. If the
405  * logged value is very old, so that XID wrap-around already happened
406  * on it, there can't be any snapshots that still see it.
407  */
408  nextFullXid = ReadNextFullTransactionId();
409  diff = U64FromFullTransactionId(nextFullXid) -
410  U64FromFullTransactionId(latestRemovedFullXid);
411  if (diff < MaxTransactionId / 2)
412  {
413  TransactionId latestRemovedXid;
414 
415  latestRemovedXid = XidFromFullTransactionId(latestRemovedFullXid);
416  ResolveRecoveryConflictWithSnapshot(latestRemovedXid,
417  xlrec->node);
418  }
419  }
420 }
uint32 TransactionId
Definition: c.h:514
#define InHotStandby
Definition: xlog.h:74
RelFileNode node
Definition: gistxlog.h:99
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
FullTransactionId ReadNextFullTransactionId(void)
Definition: varsup.c:246
#define MaxTransactionId
Definition: transam.h:35
#define U64FromFullTransactionId(x)
Definition: transam.h:49
void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode node)
Definition: standby.c:294
FullTransactionId latestRemovedFullXid
Definition: gistxlog.h:101

◆ gistRedoPageSplitRecord()

static void gistRedoPageSplitRecord ( XLogReaderState record)
static

Definition at line 253 of file gistxlog.c.

References Assert, DataPageDeleteStack::blkno, BufferGetPage, 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().

254 {
255  XLogRecPtr lsn = record->EndRecPtr;
256  gistxlogPageSplit *xldata = (gistxlogPageSplit *) XLogRecGetData(record);
257  Buffer firstbuffer = InvalidBuffer;
258  Buffer buffer;
259  Page page;
260  int i;
261  bool isrootsplit = false;
262 
263  /*
264  * We must hold lock on the first-listed page throughout the action,
265  * including while updating the left child page (if any). We can unlock
266  * remaining pages in the list as soon as they've been written, because
267  * there is no path for concurrent queries to reach those pages without
268  * first visiting the first-listed page.
269  */
270 
271  /* loop around all pages */
272  for (i = 0; i < xldata->npage; i++)
273  {
274  int flags;
275  char *data;
276  Size datalen;
277  int num;
278  BlockNumber blkno;
279  IndexTuple *tuples;
280 
281  XLogRecGetBlockTag(record, i + 1, NULL, NULL, &blkno);
282  if (blkno == GIST_ROOT_BLKNO)
283  {
284  Assert(i == 0);
285  isrootsplit = true;
286  }
287 
288  buffer = XLogInitBufferForRedo(record, i + 1);
289  page = (Page) BufferGetPage(buffer);
290  data = XLogRecGetBlockData(record, i + 1, &datalen);
291 
292  tuples = decodePageSplitRecord(data, datalen, &num);
293 
294  /* ok, clear buffer */
295  if (xldata->origleaf && blkno != GIST_ROOT_BLKNO)
296  flags = F_LEAF;
297  else
298  flags = 0;
299  GISTInitBuffer(buffer, flags);
300 
301  /* and fill it */
302  gistfillbuffer(page, tuples, num, FirstOffsetNumber);
303 
304  if (blkno == GIST_ROOT_BLKNO)
305  {
306  GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
307  GistPageSetNSN(page, xldata->orignsn);
308  GistClearFollowRight(page);
309  }
310  else
311  {
312  if (i < xldata->npage - 1)
313  {
314  BlockNumber nextblkno;
315 
316  XLogRecGetBlockTag(record, i + 2, NULL, NULL, &nextblkno);
317  GistPageGetOpaque(page)->rightlink = nextblkno;
318  }
319  else
320  GistPageGetOpaque(page)->rightlink = xldata->origrlink;
321  GistPageSetNSN(page, xldata->orignsn);
322  if (i < xldata->npage - 1 && !isrootsplit &&
323  xldata->markfollowright)
324  GistMarkFollowRight(page);
325  else
326  GistClearFollowRight(page);
327  }
328 
329  PageSetLSN(page, lsn);
330  MarkBufferDirty(buffer);
331 
332  if (i == 0)
333  firstbuffer = buffer;
334  else
335  UnlockReleaseBuffer(buffer);
336  }
337 
338  /* Fix follow-right data on left child page, if any */
339  if (XLogRecHasBlockRef(record, 0))
340  gistRedoClearFollowRight(record, 0);
341 
342  /* Finally, release lock on the first page */
343  UnlockReleaseBuffer(firstbuffer);
344 }
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
bool markfollowright
Definition: gistxlog.h:73
void gistfillbuffer(Page page, IndexTuple *itup, int len, OffsetNumber off)
Definition: gistutil.c:33
#define GistPageSetNSN(page, val)
Definition: gist.h:158
#define InvalidBuffer
Definition: buf.h:25
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:286
uint32 BlockNumber
Definition: block.h:31
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:301
#define FirstOffsetNumber
Definition: off.h:27
static IndexTuple * decodePageSplitRecord(char *begin, int len, int *n)
Definition: gistxlog.c:229
BlockNumber origrlink
Definition: gistxlog.h:68
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
GistNSN orignsn
Definition: gistxlog.h:69
bool XLogRecGetBlockTag(XLogReaderState *record, uint8 block_id, RelFileNode *rnode, ForkNumber *forknum, BlockNumber *blknum)
Definition: xlogreader.c:1460
#define GistClearFollowRight(page)
Definition: gist.h:155
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:1484
#define GistPageGetOpaque(page)
Definition: gist.h:138
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:739
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:42
size_t Size
Definition: c.h:467
#define InvalidBlockNumber
Definition: block.h:33
#define GistMarkFollowRight(page)
Definition: gist.h:154
#define F_LEAF
Definition: gist.h:43
int i
#define GIST_ROOT_BLKNO
Definition: gist_private.h:262
void GISTInitBuffer(Buffer b, uint32 f)
Definition: gistutil.c:748
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ gistRedoPageUpdateRecord()

static void gistRedoPageUpdateRecord ( XLogReaderState record)
static

Definition at line 72 of file gistxlog.c.

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

Referenced by gist_redo().

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 = 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 }
#define PageIsEmpty(page)
Definition: bufpage.h:222
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1458
#define GistMarkTuplesDeleted(page)
Definition: gist.h:146
Pointer Item
Definition: item.h:17
#define XLogRecHasBlockRef(decoder, block_id)
Definition: xlogreader.h:286
uint16 ntoinsert
Definition: gistxlog.h:39
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:416
#define PageGetMaxOffsetNumber(page)
Definition: bufpage.h:357
uint16 ntodelete
Definition: gistxlog.h:38
XLogRecPtr EndRecPtr
Definition: xlogreader.h:132
uint16 OffsetNumber
Definition: off.h:24
#define XLogRecGetData(decoder)
Definition: xlogreader.h:283
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define ERROR
Definition: elog.h:43
bool PageIndexTupleOverwrite(Page page, OffsetNumber offnum, Item newtup, Size newsize)
Definition: bufpage.c:1065
#define FirstOffsetNumber
Definition: off.h:27
IndexTupleData * IndexTuple
Definition: itup.h:53
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GistPageIsLeaf(page)
Definition: gist.h:140
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:1484
#define InvalidOffsetNumber
Definition: off.h:26
XLogRedoAction XLogReadBufferForRedo(XLogReaderState *record, uint8 block_id, Buffer *buf)
Definition: xlogutils.c:289
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:739
static void gistRedoClearFollowRight(XLogReaderState *record, uint8 block_id)
Definition: gistxlog.c:42
void PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
Definition: bufpage.c:835
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52
size_t Size
Definition: c.h:467
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
#define elog(elevel,...)
Definition: elog.h:228
#define PageSetLSN(page, lsn)
Definition: bufpage.h:368
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78
#define IndexTupleSize(itup)
Definition: itup.h:71

◆ gistXLogDelete()

XLogRecPtr gistXLogDelete ( Buffer  buffer,
OffsetNumber todelete,
int  ntodelete,
TransactionId  latestRemovedXid 
)

Definition at line 673 of file gistxlog.c.

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

Referenced by gistprunepage().

675 {
676  gistxlogDelete xlrec;
677  XLogRecPtr recptr;
678 
679  xlrec.latestRemovedXid = latestRemovedXid;
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 latestRemovedXid on a standby server.
688  */
689  XLogRegisterData((char *) todelete, ntodelete * sizeof(OffsetNumber));
690 
692 
693  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_DELETE);
694 
695  return recptr;
696 }
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
uint16 OffsetNumber
Definition: off.h:24
uint16 ntodelete
Definition: gistxlog.h:52
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define XLOG_GIST_DELETE
Definition: gistxlog.h:21
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define SizeOfGistxlogDelete
Definition: gistxlog.h:59
TransactionId latestRemovedXid
Definition: gistxlog.h:51
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ gistXLogPageDelete()

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

Definition at line 575 of file gistxlog.c.

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

Referenced by gistdeletepage().

577 {
578  gistxlogPageDelete xlrec;
579  XLogRecPtr recptr;
580 
581  xlrec.deleteXid = xid;
582  xlrec.downlinkOffset = downlinkOffset;
583 
584  XLogBeginInsert();
585  XLogRegisterData((char *) &xlrec, SizeOfGistxlogPageDelete);
586 
588  XLogRegisterBuffer(1, parentBuffer, REGBUF_STANDARD);
589 
590  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_DELETE);
591 
592  return recptr;
593 }
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
FullTransactionId deleteXid
Definition: gistxlog.h:86
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define SizeOfGistxlogPageDelete
Definition: gistxlog.h:91
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_GIST_PAGE_DELETE
Definition: gistxlog.h:28
void XLogBeginInsert(void)
Definition: xloginsert.c:120
OffsetNumber downlinkOffset
Definition: gistxlog.h:87

◆ gistXLogPageReuse()

void gistXLogPageReuse ( Relation  rel,
BlockNumber  blkno,
FullTransactionId  latestRemovedXid 
)

Definition at line 599 of file gistxlog.c.

References DataPageDeleteStack::blkno, gistxlogPageReuse::block, gistxlogPageReuse::latestRemovedFullXid, gistxlogPageReuse::node, RelationData::rd_node, SizeOfGistxlogPageReuse, XLOG_GIST_PAGE_REUSE, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by gistNewBuffer().

600 {
601  gistxlogPageReuse xlrec_reuse;
602 
603  /*
604  * Note that we don't register the buffer with the record, because this
605  * operation doesn't modify the page. This record only exists to provide a
606  * conflict point for Hot Standby.
607  */
608 
609  /* XLOG stuff */
610  xlrec_reuse.node = rel->rd_node;
611  xlrec_reuse.block = blkno;
612  xlrec_reuse.latestRemovedFullXid = latestRemovedXid;
613 
614  XLogBeginInsert();
615  XLogRegisterData((char *) &xlrec_reuse, SizeOfGistxlogPageReuse);
616 
617  XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_REUSE);
618 }
BlockNumber block
Definition: gistxlog.h:100
RelFileNode node
Definition: gistxlog.h:99
#define SizeOfGistxlogPageReuse
Definition: gistxlog.h:104
#define XLOG_GIST_PAGE_REUSE
Definition: gistxlog.h:23
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
RelFileNode rd_node
Definition: rel.h:54
void XLogBeginInsert(void)
Definition: xloginsert.c:120
FullTransactionId latestRemovedFullXid
Definition: gistxlog.h:101

◆ gistXLogSplit()

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

Definition at line 518 of file gistxlog.c.

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

522 {
523  gistxlogPageSplit xlrec;
524  SplitedPageLayout *ptr;
525  int npage = 0;
526  XLogRecPtr recptr;
527  int i;
528 
529  for (ptr = dist; ptr; ptr = ptr->next)
530  npage++;
531 
532  xlrec.origrlink = origrlink;
533  xlrec.orignsn = orignsn;
534  xlrec.origleaf = page_is_leaf;
535  xlrec.npage = (uint16) npage;
536  xlrec.markfollowright = markfollowright;
537 
538  XLogBeginInsert();
539 
540  /*
541  * Include a full page image of the child buf. (only necessary if a
542  * checkpoint happened since the child page was split)
543  */
544  if (BufferIsValid(leftchildbuf))
545  XLogRegisterBuffer(0, leftchildbuf, REGBUF_STANDARD);
546 
547  /*
548  * NOTE: We register a lot of data. The caller must've called
549  * XLogEnsureRecordSpace() to prepare for that. We cannot do it here,
550  * because we're already in a critical section. If you change the number
551  * of buffer or data registrations here, make sure you modify the
552  * XLogEnsureRecordSpace() calls accordingly!
553  */
554  XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageSplit));
555 
556  i = 1;
557  for (ptr = dist; ptr; ptr = ptr->next)
558  {
560  XLogRegisterBufData(i, (char *) &(ptr->block.num), sizeof(int));
561  XLogRegisterBufData(i, (char *) ptr->list, ptr->lenlist);
562  i++;
563  }
564 
565  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT);
566 
567  return recptr;
568 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
bool markfollowright
Definition: gistxlog.h:73
#define REGBUF_WILL_INIT
Definition: xloginsert.h:33
IndexTupleData * list
Definition: gist_private.h:194
gistxlogPage block
Definition: gist_private.h:193
unsigned short uint16
Definition: c.h:358
#define XLOG_GIST_PAGE_SPLIT
Definition: gistxlog.h:25
#define REGBUF_STANDARD
Definition: xloginsert.h:35
BlockNumber origrlink
Definition: gistxlog.h:68
struct SplitedPageLayout * next
Definition: gist_private.h:200
GistNSN orignsn
Definition: gistxlog.h:69
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
int i
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ gistXLogUpdate()

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

Definition at line 632 of file gistxlog.c.

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

636 {
637  gistxlogPageUpdate xlrec;
638  int i;
639  XLogRecPtr recptr;
640 
641  xlrec.ntodelete = ntodelete;
642  xlrec.ntoinsert = ituplen;
643 
644  XLogBeginInsert();
645  XLogRegisterData((char *) &xlrec, sizeof(gistxlogPageUpdate));
646 
648  XLogRegisterBufData(0, (char *) todelete, sizeof(OffsetNumber) * ntodelete);
649 
650  /* new tuples */
651  for (i = 0; i < ituplen; i++)
652  XLogRegisterBufData(0, (char *) (itup[i]), IndexTupleSize(itup[i]));
653 
654  /*
655  * Include a full page image of the child buf. (only necessary if a
656  * checkpoint happened since the child page was split)
657  */
658  if (BufferIsValid(leftchildbuf))
659  XLogRegisterBuffer(1, leftchildbuf, REGBUF_STANDARD);
660 
661  recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_UPDATE);
662 
663  return recptr;
664 }
void XLogRegisterBufData(uint8 block_id, char *data, int len)
Definition: xloginsert.c:361
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
uint16 ntoinsert
Definition: gistxlog.h:39
uint16 ntodelete
Definition: gistxlog.h:38
uint16 OffsetNumber
Definition: off.h:24
#define REGBUF_STANDARD
Definition: xloginsert.h:35
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define BufferIsValid(bufnum)
Definition: bufmgr.h:113
int i
#define XLOG_GIST_PAGE_UPDATE
Definition: gistxlog.h:20
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define IndexTupleSize(itup)
Definition: itup.h:71

Variable Documentation

◆ opCtx

MemoryContext opCtx
static

Definition at line 28 of file gistxlog.c.