PostgreSQL Source Code  git master
ginxlog.c File Reference
#include "postgres.h"
#include "access/bufmask.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xlogutils.h"
#include "utils/memutils.h"
Include dependency graph for ginxlog.c:

Go to the source code of this file.

Functions

static void ginRedoClearIncompleteSplit (XLogReaderState *record, uint8 block_id)
 
static void ginRedoCreatePTree (XLogReaderState *record)
 
static void ginRedoInsertEntry (Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
 
static void ginRedoRecompress (Page page, ginxlogRecompressDataLeaf *data)
 
static void ginRedoInsertData (Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
 
static void ginRedoInsert (XLogReaderState *record)
 
static void ginRedoSplit (XLogReaderState *record)
 
static void ginRedoVacuumPage (XLogReaderState *record)
 
static void ginRedoVacuumDataLeafPage (XLogReaderState *record)
 
static void ginRedoDeletePage (XLogReaderState *record)
 
static void ginRedoUpdateMetapage (XLogReaderState *record)
 
static void ginRedoInsertListPage (XLogReaderState *record)
 
static void ginRedoDeleteListPages (XLogReaderState *record)
 
void gin_redo (XLogReaderState *record)
 
void gin_xlog_startup (void)
 
void gin_xlog_cleanup (void)
 
void gin_mask (char *pagedata, BlockNumber blkno)
 

Variables

static MemoryContext opCtx
 

Function Documentation

◆ gin_mask()

void gin_mask ( char *  pagedata,
BlockNumber  blkno 
)

Definition at line 793 of file ginxlog.c.

794 {
795  Page page = (Page) pagedata;
796  PageHeader pagehdr = (PageHeader) page;
797  GinPageOpaque opaque;
798 
800  opaque = GinPageGetOpaque(page);
801 
802  mask_page_hint_bits(page);
803 
804  /*
805  * For a GIN_DELETED page, the page is initialized to empty. Hence, mask
806  * the whole page content. For other pages, mask the hole if pd_lower
807  * appears to have been set correctly.
808  */
809  if (opaque->flags & GIN_DELETED)
810  mask_page_content(page);
811  else if (pagehdr->pd_lower > SizeOfPageHeaderData)
812  mask_unused_space(page);
813 }
void mask_page_content(Page page)
Definition: bufmask.c:119
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
PageHeaderData * PageHeader
Definition: bufpage.h:173
Pointer Page
Definition: bufpage.h:81
#define SizeOfPageHeaderData
Definition: bufpage.h:216
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GIN_DELETED
Definition: ginblock.h:43
LocationIndex pd_lower
Definition: bufpage.h:165

References GinPageOpaqueData::flags, GIN_DELETED, GinPageGetOpaque, mask_page_content(), mask_page_hint_bits(), mask_page_lsn_and_checksum(), mask_unused_space(), PageHeaderData::pd_lower, and SizeOfPageHeaderData.

◆ gin_redo()

void gin_redo ( XLogReaderState record)

Definition at line 726 of file ginxlog.c.

727 {
728  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
729  MemoryContext oldCtx;
730 
731  /*
732  * GIN indexes do not require any conflict processing. NB: If we ever
733  * implement a similar optimization as we have in b-tree, and remove
734  * killed tuples outside VACUUM, we'll need to handle that here.
735  */
736 
737  oldCtx = MemoryContextSwitchTo(opCtx);
738  switch (info)
739  {
741  ginRedoCreatePTree(record);
742  break;
743  case XLOG_GIN_INSERT:
744  ginRedoInsert(record);
745  break;
746  case XLOG_GIN_SPLIT:
747  ginRedoSplit(record);
748  break;
750  ginRedoVacuumPage(record);
751  break;
754  break;
756  ginRedoDeletePage(record);
757  break;
759  ginRedoUpdateMetapage(record);
760  break;
762  ginRedoInsertListPage(record);
763  break;
765  ginRedoDeleteListPages(record);
766  break;
767  default:
768  elog(PANIC, "gin_redo: unknown op code %u", info);
769  }
770  MemoryContextSwitchTo(oldCtx);
772 }
uint8_t uint8
Definition: c.h:483
#define PANIC
Definition: elog.h:42
#define elog(elevel,...)
Definition: elog.h:225
static void ginRedoInsert(XLogReaderState *record)
Definition: ginxlog.c:347
static void ginRedoSplit(XLogReaderState *record)
Definition: ginxlog.c:402
static void ginRedoDeletePage(XLogReaderState *record)
Definition: ginxlog.c:477
static void ginRedoVacuumDataLeafPage(XLogReaderState *record)
Definition: ginxlog.c:452
static void ginRedoDeleteListPages(XLogReaderState *record)
Definition: ginxlog.c:675
static void ginRedoUpdateMetapage(XLogReaderState *record)
Definition: ginxlog.c:528
static void ginRedoInsertListPage(XLogReaderState *record)
Definition: ginxlog.c:620
static MemoryContext opCtx
Definition: ginxlog.c:22
static void ginRedoCreatePTree(XLogReaderState *record)
Definition: ginxlog.c:44
static void ginRedoVacuumPage(XLogReaderState *record)
Definition: ginxlog.c:440
#define XLOG_GIN_UPDATE_META_PAGE
Definition: ginxlog.h:162
#define XLOG_GIN_INSERT
Definition: ginxlog.h:35
#define XLOG_GIN_CREATE_PTREE
Definition: ginxlog.h:19
#define XLOG_GIN_VACUUM_PAGE
Definition: ginxlog.h:135
#define XLOG_GIN_DELETE_PAGE
Definition: ginxlog.h:153
#define XLOG_GIN_INSERT_LISTPAGE
Definition: ginxlog.h:180
#define XLOG_GIN_VACUUM_DATA_LEAF_PAGE
Definition: ginxlog.h:141
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:109
#define XLOG_GIN_DELETE_LISTPAGE
Definition: ginxlog.h:194
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, ginRedoCreatePTree(), ginRedoDeleteListPages(), ginRedoDeletePage(), ginRedoInsert(), ginRedoInsertListPage(), ginRedoSplit(), ginRedoUpdateMetapage(), ginRedoVacuumDataLeafPage(), ginRedoVacuumPage(), MemoryContextReset(), MemoryContextSwitchTo(), opCtx, PANIC, XLOG_GIN_CREATE_PTREE, XLOG_GIN_DELETE_LISTPAGE, XLOG_GIN_DELETE_PAGE, XLOG_GIN_INSERT, XLOG_GIN_INSERT_LISTPAGE, XLOG_GIN_SPLIT, XLOG_GIN_UPDATE_META_PAGE, XLOG_GIN_VACUUM_DATA_LEAF_PAGE, XLOG_GIN_VACUUM_PAGE, XLogRecGetInfo, and XLR_INFO_MASK.

◆ gin_xlog_cleanup()

void gin_xlog_cleanup ( void  )

Definition at line 783 of file ginxlog.c.

784 {
786  opCtx = NULL;
787 }
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454

References MemoryContextDelete(), and opCtx.

◆ gin_xlog_startup()

void gin_xlog_startup ( void  )

Definition at line 775 of file ginxlog.c.

776 {
778  "GIN recovery temporary context",
780 }
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CurrentMemoryContext, and opCtx.

◆ ginRedoClearIncompleteSplit()

static void ginRedoClearIncompleteSplit ( XLogReaderState record,
uint8  block_id 
)
static

Definition at line 25 of file ginxlog.c.

26 {
27  XLogRecPtr lsn = record->EndRecPtr;
28  Buffer buffer;
29  Page page;
30 
31  if (XLogReadBufferForRedo(record, block_id, &buffer) == BLK_NEEDS_REDO)
32  {
33  page = (Page) BufferGetPage(buffer);
34  GinPageGetOpaque(page)->flags &= ~GIN_INCOMPLETE_SPLIT;
35 
36  PageSetLSN(page, lsn);
37  MarkBufferDirty(buffer);
38  }
39  if (BufferIsValid(buffer))
40  UnlockReleaseBuffer(buffer);
41 }
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 GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:47
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
@ BLK_NEEDS_REDO
Definition: xlogutils.h:74

References BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), XLogReaderState::EndRecPtr, GIN_INCOMPLETE_SPLIT, GinPageGetOpaque, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), and XLogReadBufferForRedo().

Referenced by ginRedoInsert(), and ginRedoSplit().

◆ ginRedoCreatePTree()

static void ginRedoCreatePTree ( XLogReaderState record)
static

Definition at line 44 of file ginxlog.c.

45 {
46  XLogRecPtr lsn = record->EndRecPtr;
48  char *ptr;
49  Buffer buffer;
50  Page page;
51 
52  buffer = XLogInitBufferForRedo(record, 0);
53  page = (Page) BufferGetPage(buffer);
54 
56 
57  ptr = XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree);
58 
59  /* Place page data */
60  memcpy(GinDataLeafPageGetPostingList(page), ptr, data->size);
61 
62  GinDataPageSetDataSize(page, data->size);
63 
64  PageSetLSN(page, lsn);
65 
66  MarkBufferDirty(buffer);
67  UnlockReleaseBuffer(buffer);
68 }
#define GIN_DATA
Definition: ginblock.h:41
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GIN_LEAF
Definition: ginblock.h:42
#define GinDataPageSetDataSize(page, size)
Definition: ginblock.h:309
#define GinDataLeafPageGetPostingList(page)
Definition: ginblock.h:278
void GinInitBuffer(Buffer b, uint32 f)
Definition: ginutil.c:351
struct ginxlogCreatePostingTree ginxlogCreatePostingTree
const void * data
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
Buffer XLogInitBufferForRedo(XLogReaderState *record, uint8 block_id)
Definition: xlogutils.c:326

References BufferGetPage(), data, XLogReaderState::EndRecPtr, GIN_COMPRESSED, GIN_DATA, GIN_LEAF, GinDataLeafPageGetPostingList, GinDataPageSetDataSize, GinInitBuffer(), MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoDeleteListPages()

static void ginRedoDeleteListPages ( XLogReaderState record)
static

Definition at line 675 of file ginxlog.c.

676 {
677  XLogRecPtr lsn = record->EndRecPtr;
679  Buffer metabuffer;
680  Page metapage;
681  int i;
682 
683  metabuffer = XLogInitBufferForRedo(record, 0);
685  metapage = BufferGetPage(metabuffer);
686 
687  GinInitMetabuffer(metabuffer);
688 
689  memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
690  PageSetLSN(metapage, lsn);
691  MarkBufferDirty(metabuffer);
692 
693  /*
694  * In normal operation, shiftList() takes exclusive lock on all the
695  * pages-to-be-deleted simultaneously. During replay, however, it should
696  * be all right to lock them one at a time. This is dependent on the fact
697  * that we are deleting pages from the head of the list, and that readers
698  * share-lock the next page before releasing the one they are on. So we
699  * cannot get past a reader that is on, or due to visit, any page we are
700  * going to delete. New incoming readers will block behind our metapage
701  * lock and then see a fully updated page list.
702  *
703  * No full-page images are taken of the deleted pages. Instead, they are
704  * re-initialized as empty, deleted pages. Their right-links don't need to
705  * be preserved, because no new readers can see the pages, as explained
706  * above.
707  */
708  for (i = 0; i < data->ndeleted; i++)
709  {
710  Buffer buffer;
711  Page page;
712 
713  buffer = XLogInitBufferForRedo(record, i + 1);
714  page = BufferGetPage(buffer);
715  GinInitBuffer(buffer, GIN_DELETED);
716 
717  PageSetLSN(page, lsn);
718  MarkBufferDirty(buffer);
719 
720  UnlockReleaseBuffer(buffer);
721  }
722  UnlockReleaseBuffer(metabuffer);
723 }
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3724
#define Assert(condition)
Definition: c.h:812
#define GIN_METAPAGE_BLKNO
Definition: ginblock.h:51
#define GinPageGetMeta(p)
Definition: ginblock.h:104
void GinInitMetabuffer(Buffer b)
Definition: ginutil.c:357
int i
Definition: isn.c:72

References Assert, BufferGetBlockNumber(), BufferGetPage(), data, XLogReaderState::EndRecPtr, GIN_DELETED, GIN_METAPAGE_BLKNO, GinInitBuffer(), GinInitMetabuffer(), GinPageGetMeta, i, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoDeletePage()

static void ginRedoDeletePage ( XLogReaderState record)
static

Definition at line 477 of file ginxlog.c.

478 {
479  XLogRecPtr lsn = record->EndRecPtr;
481  Buffer dbuffer;
482  Buffer pbuffer;
483  Buffer lbuffer;
484  Page page;
485 
486  /*
487  * Lock left page first in order to prevent possible deadlock with
488  * ginStepRight().
489  */
490  if (XLogReadBufferForRedo(record, 2, &lbuffer) == BLK_NEEDS_REDO)
491  {
492  page = BufferGetPage(lbuffer);
493  Assert(GinPageIsData(page));
494  GinPageGetOpaque(page)->rightlink = data->rightLink;
495  PageSetLSN(page, lsn);
496  MarkBufferDirty(lbuffer);
497  }
498 
499  if (XLogReadBufferForRedo(record, 0, &dbuffer) == BLK_NEEDS_REDO)
500  {
501  page = BufferGetPage(dbuffer);
502  Assert(GinPageIsData(page));
503  GinPageSetDeleted(page);
504  GinPageSetDeleteXid(page, data->deleteXid);
505  PageSetLSN(page, lsn);
506  MarkBufferDirty(dbuffer);
507  }
508 
509  if (XLogReadBufferForRedo(record, 1, &pbuffer) == BLK_NEEDS_REDO)
510  {
511  page = BufferGetPage(pbuffer);
512  Assert(GinPageIsData(page));
513  Assert(!GinPageIsLeaf(page));
514  GinPageDeletePostingItem(page, data->parentOffset);
515  PageSetLSN(page, lsn);
516  MarkBufferDirty(pbuffer);
517  }
518 
519  if (BufferIsValid(lbuffer))
520  UnlockReleaseBuffer(lbuffer);
521  if (BufferIsValid(pbuffer))
522  UnlockReleaseBuffer(pbuffer);
523  if (BufferIsValid(dbuffer))
524  UnlockReleaseBuffer(dbuffer);
525 }
#define GinPageSetDeleteXid(page, xid)
Definition: ginblock.h:136
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageSetDeleted(page)
Definition: ginblock.h:125
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
void GinPageDeletePostingItem(Page page, OffsetNumber offset)
Definition: gindatapage.c:417

References Assert, BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), data, XLogReaderState::EndRecPtr, GinPageDeletePostingItem(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GinPageSetDeleted, GinPageSetDeleteXid, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoInsert()

static void ginRedoInsert ( XLogReaderState record)
static

Definition at line 347 of file ginxlog.c.

348 {
349  XLogRecPtr lsn = record->EndRecPtr;
351  Buffer buffer;
352 #ifdef NOT_USED
353  BlockNumber leftChildBlkno = InvalidBlockNumber;
354 #endif
355  BlockNumber rightChildBlkno = InvalidBlockNumber;
356  bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
357 
358  /*
359  * First clear incomplete-split flag on child page if this finishes a
360  * split.
361  */
362  if (!isLeaf)
363  {
364  char *payload = XLogRecGetData(record) + sizeof(ginxlogInsert);
365 
366 #ifdef NOT_USED
367  leftChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
368 #endif
369  payload += sizeof(BlockIdData);
370  rightChildBlkno = BlockIdGetBlockNumber((BlockId) payload);
371  payload += sizeof(BlockIdData);
372 
373  ginRedoClearIncompleteSplit(record, 1);
374  }
375 
376  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
377  {
378  Page page = BufferGetPage(buffer);
379  Size len;
380  char *payload = XLogRecGetBlockData(record, 0, &len);
381 
382  /* How to insert the payload is tree-type specific */
383  if (data->flags & GIN_INSERT_ISDATA)
384  {
385  Assert(GinPageIsData(page));
386  ginRedoInsertData(buffer, isLeaf, rightChildBlkno, payload);
387  }
388  else
389  {
390  Assert(!GinPageIsData(page));
391  ginRedoInsertEntry(buffer, isLeaf, rightChildBlkno, payload);
392  }
393 
394  PageSetLSN(page, lsn);
395  MarkBufferDirty(buffer);
396  }
397  if (BufferIsValid(buffer))
398  UnlockReleaseBuffer(buffer);
399 }
uint32 BlockNumber
Definition: block.h:31
struct BlockIdData BlockIdData
#define InvalidBlockNumber
Definition: block.h:33
static BlockNumber BlockIdGetBlockNumber(const BlockIdData *blockId)
Definition: block.h:103
size_t Size
Definition: c.h:559
static void ginRedoInsertEntry(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
Definition: ginxlog.c:71
static void ginRedoClearIncompleteSplit(XLogReaderState *record, uint8 block_id)
Definition: ginxlog.c:25
static void ginRedoInsertData(Buffer buffer, bool isLeaf, BlockNumber rightblkno, void *rdata)
Definition: ginxlog.c:319
#define GIN_INSERT_ISDATA
Definition: ginxlog.h:124
#define GIN_INSERT_ISLEAF
Definition: ginxlog.h:125
const void size_t len
char * XLogRecGetBlockData(XLogReaderState *record, uint8 block_id, Size *len)
Definition: xlogreader.c:2025

References Assert, BLK_NEEDS_REDO, BlockIdGetBlockNumber(), BufferGetPage(), BufferIsValid(), data, XLogReaderState::EndRecPtr, GIN_INSERT_ISDATA, GIN_INSERT_ISLEAF, GinPageIsData, ginRedoClearIncompleteSplit(), ginRedoInsertData(), ginRedoInsertEntry(), InvalidBlockNumber, len, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), XLogRecGetBlockData(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoInsertData()

static void ginRedoInsertData ( Buffer  buffer,
bool  isLeaf,
BlockNumber  rightblkno,
void *  rdata 
)
static

Definition at line 319 of file ginxlog.c.

320 {
321  Page page = BufferGetPage(buffer);
322 
323  if (isLeaf)
324  {
326 
327  Assert(GinPageIsLeaf(page));
328 
329  ginRedoRecompress(page, data);
330  }
331  else
332  {
334  PostingItem *oldpitem;
335 
336  Assert(!GinPageIsLeaf(page));
337 
338  /* update link to right page after split */
339  oldpitem = GinDataPageGetPostingItem(page, data->offset);
340  PostingItemSetBlockNumber(oldpitem, rightblkno);
341 
342  GinDataPageAddPostingItem(page, &data->newitem, data->offset);
343  }
344 }
#define GinDataPageGetPostingItem(page, i)
Definition: ginblock.h:298
#define PostingItemSetBlockNumber(pointer, blockNumber)
Definition: ginblock.h:192
void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset)
Definition: gindatapage.c:380
static void ginRedoRecompress(Page page, ginxlogRecompressDataLeaf *data)
Definition: ginxlog.c:117

References Assert, BufferGetPage(), data, GinDataPageAddPostingItem(), GinDataPageGetPostingItem, GinPageIsLeaf, ginRedoRecompress(), and PostingItemSetBlockNumber.

Referenced by ginRedoInsert().

◆ ginRedoInsertEntry()

static void ginRedoInsertEntry ( Buffer  buffer,
bool  isLeaf,
BlockNumber  rightblkno,
void *  rdata 
)
static

Definition at line 71 of file ginxlog.c.

72 {
73  Page page = BufferGetPage(buffer);
75  OffsetNumber offset = data->offset;
76  IndexTuple itup;
77 
78  if (rightblkno != InvalidBlockNumber)
79  {
80  /* update link to right page after split */
81  Assert(!GinPageIsLeaf(page));
82  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
83  itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, offset));
84  GinSetDownlink(itup, rightblkno);
85  }
86 
87  if (data->isDelete)
88  {
89  Assert(GinPageIsLeaf(page));
90  Assert(offset >= FirstOffsetNumber && offset <= PageGetMaxOffsetNumber(page));
91  PageIndexTupleDelete(page, offset);
92  }
93 
94  itup = &data->tuple;
95 
96  if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), offset, false, false) == InvalidOffsetNumber)
97  {
98  RelFileLocator locator;
99  ForkNumber forknum;
100  BlockNumber blknum;
101 
102  BufferGetTag(buffer, &locator, &forknum, &blknum);
103  elog(ERROR, "failed to add item to index page in %u/%u/%u",
104  locator.spcOid, locator.dbOid, locator.relNumber);
105  }
106 }
void BufferGetTag(Buffer buffer, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum)
Definition: bufmgr.c:3745
void PageIndexTupleDelete(Page page, OffsetNumber offnum)
Definition: bufpage.c:1041
static Item PageGetItem(Page page, ItemId itemId)
Definition: bufpage.h:354
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
Definition: bufpage.h:243
static OffsetNumber PageGetMaxOffsetNumber(Page page)
Definition: bufpage.h:372
#define PageAddItem(page, item, size, offsetNumber, overwrite, is_heap)
Definition: bufpage.h:471
#define ERROR
Definition: elog.h:39
#define GinSetDownlink(itup, blkno)
Definition: ginblock.h:258
Pointer Item
Definition: item.h:17
IndexTupleData * IndexTuple
Definition: itup.h:53
#define IndexTupleSize(itup)
Definition: itup.h:70
#define InvalidOffsetNumber
Definition: off.h:26
uint16 OffsetNumber
Definition: off.h:24
#define FirstOffsetNumber
Definition: off.h:27
ForkNumber
Definition: relpath.h:56
RelFileNumber relNumber

References Assert, BufferGetPage(), BufferGetTag(), data, RelFileLocator::dbOid, elog, ERROR, FirstOffsetNumber, GinPageIsLeaf, GinSetDownlink, IndexTupleSize, InvalidBlockNumber, InvalidOffsetNumber, PageAddItem, PageGetItem(), PageGetItemId(), PageGetMaxOffsetNumber(), PageIndexTupleDelete(), RelFileLocator::relNumber, and RelFileLocator::spcOid.

Referenced by ginRedoInsert().

◆ ginRedoInsertListPage()

static void ginRedoInsertListPage ( XLogReaderState record)
static

Definition at line 620 of file ginxlog.c.

621 {
622  XLogRecPtr lsn = record->EndRecPtr;
624  Buffer buffer;
625  Page page;
626  OffsetNumber l,
627  off = FirstOffsetNumber;
628  int i,
629  tupsize;
630  char *payload;
631  IndexTuple tuples;
632  Size totaltupsize;
633 
634  /* We always re-initialize the page. */
635  buffer = XLogInitBufferForRedo(record, 0);
636  page = BufferGetPage(buffer);
637 
638  GinInitBuffer(buffer, GIN_LIST);
639  GinPageGetOpaque(page)->rightlink = data->rightlink;
640  if (data->rightlink == InvalidBlockNumber)
641  {
642  /* tail of sublist */
643  GinPageSetFullRow(page);
644  GinPageGetOpaque(page)->maxoff = 1;
645  }
646  else
647  {
648  GinPageGetOpaque(page)->maxoff = 0;
649  }
650 
651  payload = XLogRecGetBlockData(record, 0, &totaltupsize);
652 
653  tuples = (IndexTuple) payload;
654  for (i = 0; i < data->ntuples; i++)
655  {
656  tupsize = IndexTupleSize(tuples);
657 
658  l = PageAddItem(page, (Item) tuples, tupsize, off, false, false);
659 
660  if (l == InvalidOffsetNumber)
661  elog(ERROR, "failed to add item to index page");
662 
663  tuples = (IndexTuple) (((char *) tuples) + tupsize);
664  off++;
665  }
666  Assert((char *) tuples == payload + totaltupsize);
667 
668  PageSetLSN(page, lsn);
669  MarkBufferDirty(buffer);
670 
671  UnlockReleaseBuffer(buffer);
672 }
#define GIN_LIST
Definition: ginblock.h:45
#define GinPageSetFullRow(page)
Definition: ginblock.h:120

References Assert, BufferGetPage(), data, elog, XLogReaderState::EndRecPtr, ERROR, FirstOffsetNumber, GIN_LIST, GinInitBuffer(), GinPageGetOpaque, GinPageSetFullRow, i, IndexTupleSize, InvalidBlockNumber, InvalidOffsetNumber, MarkBufferDirty(), PageAddItem, PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), XLogRecGetBlockData(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoRecompress()

static void ginRedoRecompress ( Page  page,
ginxlogRecompressDataLeaf data 
)
static

Definition at line 117 of file ginxlog.c.

118 {
119  int actionno;
120  int segno;
121  GinPostingList *oldseg;
122  Pointer segmentend;
123  char *walbuf;
124  int totalsize;
125  Pointer tailCopy = NULL;
126  Pointer writePtr;
127  Pointer segptr;
128 
129  /*
130  * If the page is in pre-9.4 format, convert to new format first.
131  */
132  if (!GinPageIsCompressed(page))
133  {
134  ItemPointer uncompressed = (ItemPointer) GinDataPageGetData(page);
135  int nuncompressed = GinPageGetOpaque(page)->maxoff;
136  int npacked;
137 
138  /*
139  * Empty leaf pages are deleted as part of vacuum, but leftmost and
140  * rightmost pages are never deleted. So, pg_upgrade'd from pre-9.4
141  * instances might contain empty leaf pages, and we need to handle
142  * them correctly.
143  */
144  if (nuncompressed > 0)
145  {
146  GinPostingList *plist;
147 
148  plist = ginCompressPostingList(uncompressed, nuncompressed,
149  BLCKSZ, &npacked);
150  totalsize = SizeOfGinPostingList(plist);
151 
152  Assert(npacked == nuncompressed);
153 
154  memcpy(GinDataLeafPageGetPostingList(page), plist, totalsize);
155  }
156  else
157  {
158  totalsize = 0;
159  }
160 
161  GinDataPageSetDataSize(page, totalsize);
162  GinPageSetCompressed(page);
163  GinPageGetOpaque(page)->maxoff = InvalidOffsetNumber;
164  }
165 
166  oldseg = GinDataLeafPageGetPostingList(page);
167  writePtr = (Pointer) oldseg;
168  segmentend = (Pointer) oldseg + GinDataLeafPageGetPostingListSize(page);
169  segno = 0;
170 
171  walbuf = ((char *) data) + sizeof(ginxlogRecompressDataLeaf);
172  for (actionno = 0; actionno < data->nactions; actionno++)
173  {
174  uint8 a_segno = *((uint8 *) (walbuf++));
175  uint8 a_action = *((uint8 *) (walbuf++));
176  GinPostingList *newseg = NULL;
177  int newsegsize = 0;
178  ItemPointerData *items = NULL;
179  uint16 nitems = 0;
180  ItemPointerData *olditems;
181  int nolditems;
182  ItemPointerData *newitems;
183  int nnewitems;
184  int segsize;
185 
186  /* Extract all the information we need from the WAL record */
187  if (a_action == GIN_SEGMENT_INSERT ||
188  a_action == GIN_SEGMENT_REPLACE)
189  {
190  newseg = (GinPostingList *) walbuf;
191  newsegsize = SizeOfGinPostingList(newseg);
192  walbuf += SHORTALIGN(newsegsize);
193  }
194 
195  if (a_action == GIN_SEGMENT_ADDITEMS)
196  {
197  memcpy(&nitems, walbuf, sizeof(uint16));
198  walbuf += sizeof(uint16);
199  items = (ItemPointerData *) walbuf;
200  walbuf += nitems * sizeof(ItemPointerData);
201  }
202 
203  /* Skip to the segment that this action concerns */
204  Assert(segno <= a_segno);
205  while (segno < a_segno)
206  {
207  /*
208  * Once modification is started and page tail is copied, we've to
209  * copy unmodified segments.
210  */
211  segsize = SizeOfGinPostingList(oldseg);
212  if (tailCopy)
213  {
214  Assert(writePtr + segsize < PageGetSpecialPointer(page));
215  memcpy(writePtr, (Pointer) oldseg, segsize);
216  }
217  writePtr += segsize;
218  oldseg = GinNextPostingListSegment(oldseg);
219  segno++;
220  }
221 
222  /*
223  * ADDITEMS action is handled like REPLACE, but the new segment to
224  * replace the old one is reconstructed using the old segment from
225  * disk and the new items from the WAL record.
226  */
227  if (a_action == GIN_SEGMENT_ADDITEMS)
228  {
229  int npacked;
230 
231  olditems = ginPostingListDecode(oldseg, &nolditems);
232 
233  newitems = ginMergeItemPointers(items, nitems,
234  olditems, nolditems,
235  &nnewitems);
236  Assert(nnewitems == nolditems + nitems);
237 
238  newseg = ginCompressPostingList(newitems, nnewitems,
239  BLCKSZ, &npacked);
240  Assert(npacked == nnewitems);
241 
242  newsegsize = SizeOfGinPostingList(newseg);
243  a_action = GIN_SEGMENT_REPLACE;
244  }
245 
246  segptr = (Pointer) oldseg;
247  if (segptr != segmentend)
248  segsize = SizeOfGinPostingList(oldseg);
249  else
250  {
251  /*
252  * Positioned after the last existing segment. Only INSERTs
253  * expected here.
254  */
255  Assert(a_action == GIN_SEGMENT_INSERT);
256  segsize = 0;
257  }
258 
259  /*
260  * We're about to start modification of the page. So, copy tail of
261  * the page if it's not done already.
262  */
263  if (!tailCopy && segptr != segmentend)
264  {
265  int tailSize = segmentend - segptr;
266 
267  tailCopy = (Pointer) palloc(tailSize);
268  memcpy(tailCopy, segptr, tailSize);
269  segptr = tailCopy;
270  oldseg = (GinPostingList *) segptr;
271  segmentend = segptr + tailSize;
272  }
273 
274  switch (a_action)
275  {
276  case GIN_SEGMENT_DELETE:
277  segptr += segsize;
278  segno++;
279  break;
280 
281  case GIN_SEGMENT_INSERT:
282  /* copy the new segment in place */
283  Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
284  memcpy(writePtr, newseg, newsegsize);
285  writePtr += newsegsize;
286  break;
287 
288  case GIN_SEGMENT_REPLACE:
289  /* copy the new version of segment in place */
290  Assert(writePtr + newsegsize <= PageGetSpecialPointer(page));
291  memcpy(writePtr, newseg, newsegsize);
292  writePtr += newsegsize;
293  segptr += segsize;
294  segno++;
295  break;
296 
297  default:
298  elog(ERROR, "unexpected GIN leaf action: %u", a_action);
299  }
300  oldseg = (GinPostingList *) segptr;
301  }
302 
303  /* Copy the rest of unmodified segments if any. */
304  segptr = (Pointer) oldseg;
305  if (segptr != segmentend && tailCopy)
306  {
307  int restSize = segmentend - segptr;
308 
309  Assert(writePtr + restSize <= PageGetSpecialPointer(page));
310  memcpy(writePtr, segptr, restSize);
311  writePtr += restSize;
312  }
313 
314  totalsize = writePtr - (Pointer) GinDataLeafPageGetPostingList(page);
315  GinDataPageSetDataSize(page, totalsize);
316 }
static char * PageGetSpecialPointer(Page page)
Definition: bufpage.h:339
char * Pointer
Definition: c.h:476
#define SHORTALIGN(LEN)
Definition: c.h:761
uint16_t uint16
Definition: c.h:484
#define SizeOfGinPostingList(plist)
Definition: ginblock.h:342
#define GinDataLeafPageGetPostingListSize(page)
Definition: ginblock.h:280
#define GinPageSetCompressed(page)
Definition: ginblock.h:122
#define GinNextPostingListSegment(cur)
Definition: ginblock.h:343
#define GinDataPageGetData(page)
Definition: ginblock.h:295
#define GinPageIsCompressed(page)
Definition: ginblock.h:121
GinPostingList * ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, int *nwritten)
ItemPointer ginPostingListDecode(GinPostingList *plist, int *ndecoded_out)
ItemPointer ginMergeItemPointers(ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb, int *nmerged)
#define GIN_SEGMENT_ADDITEMS
Definition: ginxlog.h:95
#define GIN_SEGMENT_DELETE
Definition: ginxlog.h:92
#define GIN_SEGMENT_INSERT
Definition: ginxlog.h:93
#define GIN_SEGMENT_REPLACE
Definition: ginxlog.h:94
#define nitems(x)
Definition: indent.h:31
ItemPointerData * ItemPointer
Definition: itemptr.h:49
struct ItemPointerData ItemPointerData
void * palloc(Size size)
Definition: mcxt.c:1317
static ItemArray items
Definition: test_tidstore.c:48

References Assert, data, elog, ERROR, GIN_SEGMENT_ADDITEMS, GIN_SEGMENT_DELETE, GIN_SEGMENT_INSERT, GIN_SEGMENT_REPLACE, ginCompressPostingList(), GinDataLeafPageGetPostingList, GinDataLeafPageGetPostingListSize, GinDataPageGetData, GinDataPageSetDataSize, ginMergeItemPointers(), GinNextPostingListSegment, GinPageGetOpaque, GinPageIsCompressed, GinPageSetCompressed, ginPostingListDecode(), InvalidOffsetNumber, items, nitems, PageGetSpecialPointer(), palloc(), SHORTALIGN, and SizeOfGinPostingList.

Referenced by ginRedoInsertData(), and ginRedoVacuumDataLeafPage().

◆ ginRedoSplit()

static void ginRedoSplit ( XLogReaderState record)
static

Definition at line 402 of file ginxlog.c.

403 {
405  Buffer lbuffer,
406  rbuffer,
407  rootbuf;
408  bool isLeaf = (data->flags & GIN_INSERT_ISLEAF) != 0;
409  bool isRoot = (data->flags & GIN_SPLIT_ROOT) != 0;
410 
411  /*
412  * First clear incomplete-split flag on child page if this finishes a
413  * split
414  */
415  if (!isLeaf)
416  ginRedoClearIncompleteSplit(record, 3);
417 
418  if (XLogReadBufferForRedo(record, 0, &lbuffer) != BLK_RESTORED)
419  elog(ERROR, "GIN split record did not contain a full-page image of left page");
420 
421  if (XLogReadBufferForRedo(record, 1, &rbuffer) != BLK_RESTORED)
422  elog(ERROR, "GIN split record did not contain a full-page image of right page");
423 
424  if (isRoot)
425  {
426  if (XLogReadBufferForRedo(record, 2, &rootbuf) != BLK_RESTORED)
427  elog(ERROR, "GIN split record did not contain a full-page image of root page");
428  UnlockReleaseBuffer(rootbuf);
429  }
430 
431  UnlockReleaseBuffer(rbuffer);
432  UnlockReleaseBuffer(lbuffer);
433 }
#define GIN_SPLIT_ROOT
Definition: ginxlog.h:126
@ BLK_RESTORED
Definition: xlogutils.h:76

References BLK_RESTORED, data, elog, ERROR, GIN_INSERT_ISLEAF, GIN_SPLIT_ROOT, ginRedoClearIncompleteSplit(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoUpdateMetapage()

static void ginRedoUpdateMetapage ( XLogReaderState record)
static

Definition at line 528 of file ginxlog.c.

529 {
530  XLogRecPtr lsn = record->EndRecPtr;
532  Buffer metabuffer;
533  Page metapage;
534  Buffer buffer;
535 
536  /*
537  * Restore the metapage. This is essentially the same as a full-page
538  * image, so restore the metapage unconditionally without looking at the
539  * LSN, to avoid torn page hazards.
540  */
541  metabuffer = XLogInitBufferForRedo(record, 0);
543  metapage = BufferGetPage(metabuffer);
544 
545  GinInitMetabuffer(metabuffer);
546  memcpy(GinPageGetMeta(metapage), &data->metadata, sizeof(GinMetaPageData));
547  PageSetLSN(metapage, lsn);
548  MarkBufferDirty(metabuffer);
549 
550  if (data->ntuples > 0)
551  {
552  /*
553  * insert into tail page
554  */
555  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
556  {
557  Page page = BufferGetPage(buffer);
558  OffsetNumber off;
559  int i;
560  Size tupsize;
561  char *payload;
562  IndexTuple tuples;
563  Size totaltupsize;
564 
565  payload = XLogRecGetBlockData(record, 1, &totaltupsize);
566  tuples = (IndexTuple) payload;
567 
568  if (PageIsEmpty(page))
569  off = FirstOffsetNumber;
570  else
572 
573  for (i = 0; i < data->ntuples; i++)
574  {
575  tupsize = IndexTupleSize(tuples);
576 
577  if (PageAddItem(page, (Item) tuples, tupsize, off,
578  false, false) == InvalidOffsetNumber)
579  elog(ERROR, "failed to add item to index page");
580 
581  tuples = (IndexTuple) (((char *) tuples) + tupsize);
582 
583  off++;
584  }
585  Assert(payload + totaltupsize == (char *) tuples);
586 
587  /*
588  * Increase counter of heap tuples
589  */
590  GinPageGetOpaque(page)->maxoff++;
591 
592  PageSetLSN(page, lsn);
593  MarkBufferDirty(buffer);
594  }
595  if (BufferIsValid(buffer))
596  UnlockReleaseBuffer(buffer);
597  }
598  else if (data->prevTail != InvalidBlockNumber)
599  {
600  /*
601  * New tail
602  */
603  if (XLogReadBufferForRedo(record, 1, &buffer) == BLK_NEEDS_REDO)
604  {
605  Page page = BufferGetPage(buffer);
606 
607  GinPageGetOpaque(page)->rightlink = data->newRightlink;
608 
609  PageSetLSN(page, lsn);
610  MarkBufferDirty(buffer);
611  }
612  if (BufferIsValid(buffer))
613  UnlockReleaseBuffer(buffer);
614  }
615 
616  UnlockReleaseBuffer(metabuffer);
617 }
static bool PageIsEmpty(Page page)
Definition: bufpage.h:223
#define OffsetNumberNext(offsetNumber)
Definition: off.h:52

References Assert, BLK_NEEDS_REDO, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), data, elog, XLogReaderState::EndRecPtr, ERROR, FirstOffsetNumber, GIN_METAPAGE_BLKNO, GinInitMetabuffer(), GinPageGetMeta, GinPageGetOpaque, i, IndexTupleSize, InvalidBlockNumber, InvalidOffsetNumber, MarkBufferDirty(), OffsetNumberNext, PageAddItem, PageGetMaxOffsetNumber(), PageIsEmpty(), PageSetLSN(), UnlockReleaseBuffer(), XLogInitBufferForRedo(), XLogReadBufferForRedo(), XLogRecGetBlockData(), and XLogRecGetData.

Referenced by gin_redo().

◆ ginRedoVacuumDataLeafPage()

static void ginRedoVacuumDataLeafPage ( XLogReaderState record)
static

Definition at line 452 of file ginxlog.c.

453 {
454  XLogRecPtr lsn = record->EndRecPtr;
455  Buffer buffer;
456 
457  if (XLogReadBufferForRedo(record, 0, &buffer) == BLK_NEEDS_REDO)
458  {
459  Page page = BufferGetPage(buffer);
460  Size len;
462 
463  xlrec = (ginxlogVacuumDataLeafPage *) XLogRecGetBlockData(record, 0, &len);
464 
465  Assert(GinPageIsLeaf(page));
466  Assert(GinPageIsData(page));
467 
468  ginRedoRecompress(page, &xlrec->data);
469  PageSetLSN(page, lsn);
470  MarkBufferDirty(buffer);
471  }
472  if (BufferIsValid(buffer))
473  UnlockReleaseBuffer(buffer);
474 }
ginxlogRecompressDataLeaf data
Definition: ginxlog.h:145

References Assert, BLK_NEEDS_REDO, BufferGetPage(), BufferIsValid(), ginxlogVacuumDataLeafPage::data, XLogReaderState::EndRecPtr, GinPageIsData, GinPageIsLeaf, ginRedoRecompress(), len, MarkBufferDirty(), PageSetLSN(), UnlockReleaseBuffer(), XLogReadBufferForRedo(), and XLogRecGetBlockData().

Referenced by gin_redo().

◆ ginRedoVacuumPage()

static void ginRedoVacuumPage ( XLogReaderState record)
static

Definition at line 440 of file ginxlog.c.

441 {
442  Buffer buffer;
443 
444  if (XLogReadBufferForRedo(record, 0, &buffer) != BLK_RESTORED)
445  {
446  elog(ERROR, "replay of gin entry tree page vacuum did not restore the page");
447  }
448  UnlockReleaseBuffer(buffer);
449 }

References BLK_RESTORED, elog, ERROR, UnlockReleaseBuffer(), and XLogReadBufferForRedo().

Referenced by gin_redo().

Variable Documentation

◆ opCtx

MemoryContext opCtx
static

Definition at line 22 of file ginxlog.c.

Referenced by gin_redo(), gin_xlog_cleanup(), gin_xlog_startup(), and ginInsertCleanup().