PostgreSQL Source Code  git master
ginbtree.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
#include "storage/predicate.h"
#include "miscadmin.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for ginbtree.c:

Go to the source code of this file.

Functions

static void ginFindParents (GinBtree btree, GinBtreeStack *stack)
 
static bool ginPlaceToPage (GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
 
static void ginFinishSplit (GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 
GinBtreeStackginFindLeafPage (GinBtree btree, bool searchMode, Snapshot snapshot)
 
Buffer ginStepRight (Buffer buffer, Relation index, int lockmode)
 
void freeGinBtreeStack (GinBtreeStack *stack)
 
void ginInsertValue (GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
 

Function Documentation

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 194 of file ginbtree.c.

References GinBtreeStack::buffer, InvalidBuffer, GinBtreeStack::parent, pfree(), and ReleaseBuffer().

Referenced by entryLoadMoreItems(), ginEntryInsert(), ginFinishSplit(), ginInsertValue(), scanPostingTree(), and startScanEntry().

195 {
196  while (stack)
197  {
198  GinBtreeStack *tmp = stack->parent;
199 
200  if (stack->buffer != InvalidBuffer)
201  ReleaseBuffer(stack->buffer);
202 
203  pfree(stack);
204  stack = tmp;
205  }
206 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
void pfree(void *pointer)
Definition: mcxt.c:1031
struct GinBtreeStack * parent
Definition: gin_private.h:132

◆ ginFindLeafPage()

GinBtreeStack* ginFindLeafPage ( GinBtree  btree,
bool  searchMode,
Snapshot  snapshot 
)

Definition at line 77 of file ginbtree.c.

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage, GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_UNLOCK, ginFinishSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), ReleaseAndReadBuffer(), GinBtreeData::rootBlkno, and TestForOldSnapshot().

Referenced by entryLoadMoreItems(), ginEntryInsert(), ginInsertItemPointers(), ginScanBeginPostingTree(), and startScanEntry().

78 {
79  GinBtreeStack *stack;
80 
81  stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
82  stack->blkno = btree->rootBlkno;
83  stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
84  stack->parent = NULL;
85  stack->predictNumber = 1;
86 
87  for (;;)
88  {
89  Page page;
90  BlockNumber child;
91  int access;
92 
93  stack->off = InvalidOffsetNumber;
94 
95  page = BufferGetPage(stack->buffer);
96  TestForOldSnapshot(snapshot, btree->index, page);
97 
98  access = ginTraverseLock(stack->buffer, searchMode);
99 
100  /*
101  * If we're going to modify the tree, finish any incomplete splits we
102  * encounter on the way.
103  */
104  if (!searchMode && GinPageIsIncompleteSplit(page))
105  ginFinishSplit(btree, stack, false, NULL);
106 
107  /*
108  * ok, page is correctly locked, we should check to move right ..,
109  * root never has a right link, so small optimization
110  */
111  while (btree->fullScan == false && stack->blkno != btree->rootBlkno &&
112  btree->isMoveRight(btree, page))
113  {
114  BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
115 
116  if (rightlink == InvalidBlockNumber)
117  /* rightmost page */
118  break;
119 
120  stack->buffer = ginStepRight(stack->buffer, btree->index, access);
121  stack->blkno = rightlink;
122  page = BufferGetPage(stack->buffer);
123  TestForOldSnapshot(snapshot, btree->index, page);
124 
125  if (!searchMode && GinPageIsIncompleteSplit(page))
126  ginFinishSplit(btree, stack, false, NULL);
127  }
128 
129  if (GinPageIsLeaf(page)) /* we found, return locked page */
130  return stack;
131 
132  /* now we have correct buffer, try to find child */
133  child = btree->findChildPage(btree, stack);
134 
135  LockBuffer(stack->buffer, GIN_UNLOCK);
136  Assert(child != InvalidBlockNumber);
137  Assert(stack->blkno != child);
138 
139  if (searchMode)
140  {
141  /* in search mode we may forget path to leaf */
142  stack->blkno = child;
143  stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
144  }
145  else
146  {
147  GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
148 
149  ptr->parent = stack;
150  stack = ptr;
151  stack->blkno = child;
152  stack->buffer = ReadBuffer(btree->index, stack->blkno);
153  stack->predictNumber = 1;
154  }
155  }
156 }
#define GIN_UNLOCK
Definition: gin_private.h:43
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
OffsetNumber off
Definition: gin_private.h:128
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:150
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:668
BlockNumber rootBlkno
Definition: gin_private.h:163
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:148
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:166
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct GinBtreeStack * parent
Definition: gin_private.h:132
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Relation index
Definition: gin_private.h:162
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:699
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1513
BlockNumber blkno
Definition: gin_private.h:126
uint32 predictNumber
Definition: gin_private.h:131
void * palloc(Size size)
Definition: mcxt.c:924
Pointer Page
Definition: bufpage.h:74
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36

◆ ginFindParents()

static void ginFindParents ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 214 of file ginbtree.c.

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, buffer, BufferGetBlockNumber(), BufferGetPage, elog, ERROR, GinBtreeData::findChildPtr, GinBtreeData::getLeftMostChild, GIN_EXCLUSIVE, ginFinishSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, ReadBuffer(), ReleaseBuffer(), GinBtreeData::rootBlkno, and UnlockReleaseBuffer().

Referenced by ginFinishSplit().

215 {
216  Page page;
217  Buffer buffer;
218  BlockNumber blkno,
219  leftmostBlkno;
220  OffsetNumber offset;
221  GinBtreeStack *root;
222  GinBtreeStack *ptr;
223 
224  /*
225  * Unwind the stack all the way up to the root, leaving only the root
226  * item.
227  *
228  * Be careful not to release the pin on the root page! The pin on root
229  * page is required to lock out concurrent vacuums on the tree.
230  */
231  root = stack->parent;
232  while (root->parent)
233  {
234  ReleaseBuffer(root->buffer);
235  root = root->parent;
236  }
237 
238  Assert(root->blkno == btree->rootBlkno);
239  Assert(BufferGetBlockNumber(root->buffer) == btree->rootBlkno);
240  root->off = InvalidOffsetNumber;
241 
242  blkno = root->blkno;
243  buffer = root->buffer;
244  offset = InvalidOffsetNumber;
245 
246  ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
247 
248  for (;;)
249  {
250  LockBuffer(buffer, GIN_EXCLUSIVE);
251  page = BufferGetPage(buffer);
252  if (GinPageIsLeaf(page))
253  elog(ERROR, "Lost path");
254 
255  if (GinPageIsIncompleteSplit(page))
256  {
257  Assert(blkno != btree->rootBlkno);
258  ptr->blkno = blkno;
259  ptr->buffer = buffer;
260 
261  /*
262  * parent may be wrong, but if so, the ginFinishSplit call will
263  * recurse to call ginFindParents again to fix it.
264  */
265  ptr->parent = root;
266  ptr->off = InvalidOffsetNumber;
267 
268  ginFinishSplit(btree, ptr, false, NULL);
269  }
270 
271  leftmostBlkno = btree->getLeftMostChild(btree, page);
272 
273  while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
274  {
275  blkno = GinPageGetOpaque(page)->rightlink;
276  if (blkno == InvalidBlockNumber)
277  {
278  UnlockReleaseBuffer(buffer);
279  break;
280  }
281  buffer = ginStepRight(buffer, btree->index, GIN_EXCLUSIVE);
282  page = BufferGetPage(buffer);
283 
284  /* finish any incomplete splits, as above */
285  if (GinPageIsIncompleteSplit(page))
286  {
287  Assert(blkno != btree->rootBlkno);
288  ptr->blkno = blkno;
289  ptr->buffer = buffer;
290  ptr->parent = root;
291  ptr->off = InvalidOffsetNumber;
292 
293  ginFinishSplit(btree, ptr, false, NULL);
294  }
295  }
296 
297  if (blkno != InvalidBlockNumber)
298  {
299  ptr->blkno = blkno;
300  ptr->buffer = buffer;
301  ptr->parent = root; /* it may be wrong, but in next call we will
302  * correct */
303  ptr->off = offset;
304  stack->parent = ptr;
305  return;
306  }
307 
308  /* Descend down to next level */
309  blkno = leftmostBlkno;
310  buffer = ReadBuffer(btree->index, blkno);
311  }
312 }
OffsetNumber off
Definition: gin_private.h:128
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:668
BlockNumber rootBlkno
Definition: gin_private.h:163
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
uint16 OffsetNumber
Definition: off.h:24
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:149
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:166
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct GinBtreeStack * parent
Definition: gin_private.h:132
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Relation index
Definition: gin_private.h:162
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
BlockNumber blkno
Definition: gin_private.h:126
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
void * palloc(Size size)
Definition: mcxt.c:924
#define elog
Definition: elog.h:219
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:154
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ginFinishSplit()

static void ginFinishSplit ( GinBtree  btree,
GinBtreeStack stack,
bool  freestack,
GinStatsData buildStats 
)
static

Definition at line 668 of file ginbtree.c.

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, DEBUG1, elog, GinBtreeData::findChildPtr, freeGinBtreeStack(), GIN_EXCLUSIVE, GIN_UNLOCK, ginFindParents(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageRightMost, ginPlaceToPage(), ginStepRight(), GinBtreeData::index, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, GinBtreeStack::parent, pfree(), GinBtreeData::prepareDownlink, RelationGetRelationName, and ReleaseBuffer().

Referenced by ginFindLeafPage(), ginFindParents(), and ginInsertValue().

670 {
671  Page page;
672  bool done;
673  bool first = true;
674 
675  /*
676  * freestack == false when we encounter an incompletely split page during
677  * a scan, while freestack == true is used in the normal scenario that a
678  * split is finished right after the initial insert.
679  */
680  if (!freestack)
681  elog(DEBUG1, "finishing incomplete split of block %u in gin index \"%s\"",
682  stack->blkno, RelationGetRelationName(btree->index));
683 
684  /* this loop crawls up the stack until the insertion is complete */
685  do
686  {
687  GinBtreeStack *parent = stack->parent;
688  void *insertdata;
689  BlockNumber updateblkno;
690 
691  /* search parent to lock */
692  LockBuffer(parent->buffer, GIN_EXCLUSIVE);
693 
694  /*
695  * If the parent page was incompletely split, finish that split first,
696  * then continue with the current one.
697  *
698  * Note: we have to finish *all* incomplete splits we encounter, even
699  * if we have to move right. Otherwise we might choose as the target a
700  * page that has no downlink in the parent, and splitting it further
701  * would fail.
702  */
704  ginFinishSplit(btree, parent, false, buildStats);
705 
706  /* move right if it's needed */
707  page = BufferGetPage(parent->buffer);
708  while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
709  {
710  if (GinPageRightMost(page))
711  {
712  /*
713  * rightmost page, but we don't find parent, we should use
714  * plain search...
715  */
716  LockBuffer(parent->buffer, GIN_UNLOCK);
717  ginFindParents(btree, stack);
718  parent = stack->parent;
719  Assert(parent != NULL);
720  break;
721  }
722 
723  parent->buffer = ginStepRight(parent->buffer, btree->index, GIN_EXCLUSIVE);
724  parent->blkno = BufferGetBlockNumber(parent->buffer);
725  page = BufferGetPage(parent->buffer);
726 
728  ginFinishSplit(btree, parent, false, buildStats);
729  }
730 
731  /* insert the downlink */
732  insertdata = btree->prepareDownlink(btree, stack->buffer);
733  updateblkno = GinPageGetOpaque(BufferGetPage(stack->buffer))->rightlink;
734  done = ginPlaceToPage(btree, parent,
735  insertdata, updateblkno,
736  stack->buffer, buildStats);
737  pfree(insertdata);
738 
739  /*
740  * If the caller requested to free the stack, unlock and release the
741  * child buffer now. Otherwise keep it pinned and locked, but if we
742  * have to recurse up the tree, we can unlock the upper pages, only
743  * keeping the page at the bottom of the stack locked.
744  */
745  if (!first || freestack)
746  LockBuffer(stack->buffer, GIN_UNLOCK);
747  if (freestack)
748  {
749  ReleaseBuffer(stack->buffer);
750  pfree(stack);
751  }
752  stack = parent;
753 
754  first = false;
755  } while (!done);
756 
757  /* unlock the parent */
758  LockBuffer(stack->buffer, GIN_UNLOCK);
759 
760  if (freestack)
761  freeGinBtreeStack(stack);
762 }
#define GIN_UNLOCK
Definition: gin_private.h:43
static void ginFindParents(GinBtree btree, GinBtreeStack *stack)
Definition: ginbtree.c:214
#define DEBUG1
Definition: elog.h:25
OffsetNumber off
Definition: gin_private.h:128
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:668
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
void pfree(void *pointer)
Definition: mcxt.c:1031
#define GinPageRightMost(page)
Definition: ginblock.h:128
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:166
#define RelationGetRelationName(relation)
Definition: rel.h:441
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
struct GinBtreeStack * parent
Definition: gin_private.h:132
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
Relation index
Definition: gin_private.h:162
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:699
BlockNumber blkno
Definition: gin_private.h:126
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:157
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:194
#define elog
Definition: elog.h:219
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:154
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:330
Pointer Page
Definition: bufpage.h:74

◆ ginInsertValue()

void ginInsertValue ( GinBtree  btree,
GinBtreeStack stack,
void *  insertdata,
GinStatsData buildStats 
)

Definition at line 777 of file ginbtree.c.

References GinBtreeStack::buffer, BufferGetPage, freeGinBtreeStack(), GIN_UNLOCK, ginFinishSplit(), GinPageIsIncompleteSplit, ginPlaceToPage(), InvalidBlockNumber, InvalidBuffer, and LockBuffer().

Referenced by ginEntryInsert(), and ginInsertItemPointers().

779 {
780  bool done;
781 
782  /* If the leaf page was incompletely split, finish the split first */
784  ginFinishSplit(btree, stack, false, buildStats);
785 
786  done = ginPlaceToPage(btree, stack,
787  insertdata, InvalidBlockNumber,
788  InvalidBuffer, buildStats);
789  if (done)
790  {
791  LockBuffer(stack->buffer, GIN_UNLOCK);
792  freeGinBtreeStack(stack);
793  }
794  else
795  ginFinishSplit(btree, stack, true, buildStats);
796 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:668
#define InvalidBuffer
Definition: buf.h:25
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define InvalidBlockNumber
Definition: block.h:33
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:194
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:330

◆ ginPlaceToPage()

static bool ginPlaceToPage ( GinBtree  btree,
GinBtreeStack stack,
void *  insertdata,
BlockNumber  updateblkno,
Buffer  childbuf,
GinStatsData buildStats 
)
static

Definition at line 330 of file ginbtree.c.

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, GinBtreeData::beginPlaceToPage, BlockIdSet, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, BufferIsValid, CurrentMemoryContext, elog, END_CRIT_SECTION, ERROR, GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, ginxlogInsert::flags, ginxlogSplit::flags, GIN_COMPRESSED, GIN_INCOMPLETE_SPLIT, GIN_INSERT_ISDATA, GIN_INSERT_ISLEAF, GIN_LEAF, GIN_SPLIT_ROOT, GinInitPage(), GinNewBuffer(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GPTP_INSERT, GPTP_NO_WORK, GPTP_SPLIT, GinBtreeData::index, InvalidBlockNumber, InvalidBuffer, GinBtreeData::isData, ginxlogSplit::leftChildBlkno, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nDataPages, GinStatsData::nEntryPages, ginxlogSplit::node, PageGetTempPage(), PageSetLSN, GinBtreeStack::parent, PredicateLockPageSplit(), RelationData::rd_node, REGBUF_FORCE_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, ginxlogSplit::rightChildBlkno, ginxlogSplit::rrlink, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_INSERT, XLOG_GIN_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginFinishSplit(), and ginInsertValue().

333 {
334  Page page = BufferGetPage(stack->buffer);
335  bool result;
336  GinPlaceToPageRC rc;
337  uint16 xlflags = 0;
338  Page childpage = NULL;
339  Page newlpage = NULL,
340  newrpage = NULL;
341  void *ptp_workspace = NULL;
342  MemoryContext tmpCxt;
343  MemoryContext oldCxt;
344 
345  /*
346  * We do all the work of this function and its subfunctions in a temporary
347  * memory context. This avoids leakages and simplifies APIs, since some
348  * subfunctions allocate storage that has to survive until we've finished
349  * the WAL insertion.
350  */
352  "ginPlaceToPage temporary context",
354  oldCxt = MemoryContextSwitchTo(tmpCxt);
355 
356  if (GinPageIsData(page))
357  xlflags |= GIN_INSERT_ISDATA;
358  if (GinPageIsLeaf(page))
359  {
360  xlflags |= GIN_INSERT_ISLEAF;
361  Assert(!BufferIsValid(childbuf));
362  Assert(updateblkno == InvalidBlockNumber);
363  }
364  else
365  {
366  Assert(BufferIsValid(childbuf));
367  Assert(updateblkno != InvalidBlockNumber);
368  childpage = BufferGetPage(childbuf);
369  }
370 
371  /*
372  * See if the incoming tuple will fit on the page. beginPlaceToPage will
373  * decide if the page needs to be split, and will compute the split
374  * contents if so. See comments for beginPlaceToPage and execPlaceToPage
375  * functions for more details of the API here.
376  */
377  rc = btree->beginPlaceToPage(btree, stack->buffer, stack,
378  insertdata, updateblkno,
379  &ptp_workspace,
380  &newlpage, &newrpage);
381 
382  if (rc == GPTP_NO_WORK)
383  {
384  /* Nothing to do */
385  result = true;
386  }
387  else if (rc == GPTP_INSERT)
388  {
389  /* It will fit, perform the insertion */
391 
392  if (RelationNeedsWAL(btree->index))
393  {
394  XLogBeginInsert();
396  if (BufferIsValid(childbuf))
397  XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
398  }
399 
400  /* Perform the page update, and register any extra WAL data */
401  btree->execPlaceToPage(btree, stack->buffer, stack,
402  insertdata, updateblkno, ptp_workspace);
403 
404  MarkBufferDirty(stack->buffer);
405 
406  /* An insert to an internal page finishes the split of the child. */
407  if (BufferIsValid(childbuf))
408  {
409  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
410  MarkBufferDirty(childbuf);
411  }
412 
413  if (RelationNeedsWAL(btree->index))
414  {
415  XLogRecPtr recptr;
416  ginxlogInsert xlrec;
417  BlockIdData childblknos[2];
418 
419  xlrec.flags = xlflags;
420 
421  XLogRegisterData((char *) &xlrec, sizeof(ginxlogInsert));
422 
423  /*
424  * Log information about child if this was an insertion of a
425  * downlink.
426  */
427  if (BufferIsValid(childbuf))
428  {
429  BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
430  BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
431  XLogRegisterData((char *) childblknos,
432  sizeof(BlockIdData) * 2);
433  }
434 
435  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT);
436  PageSetLSN(page, recptr);
437  if (BufferIsValid(childbuf))
438  PageSetLSN(childpage, recptr);
439  }
440 
442 
443  /* Insertion is complete. */
444  result = true;
445  }
446  else if (rc == GPTP_SPLIT)
447  {
448  /*
449  * Didn't fit, need to split. The split has been computed in newlpage
450  * and newrpage, which are pointers to palloc'd pages, not associated
451  * with buffers. stack->buffer is not touched yet.
452  */
453  Buffer rbuffer;
454  BlockNumber savedRightLink;
455  ginxlogSplit data;
456  Buffer lbuffer = InvalidBuffer;
457  Page newrootpg = NULL;
458 
459  /* Get a new index page to become the right page */
460  rbuffer = GinNewBuffer(btree->index);
461 
462  /* During index build, count the new page */
463  if (buildStats)
464  {
465  if (btree->isData)
466  buildStats->nDataPages++;
467  else
468  buildStats->nEntryPages++;
469  }
470 
471  savedRightLink = GinPageGetOpaque(page)->rightlink;
472 
473  /* Begin setting up WAL record */
474  data.node = btree->index->rd_node;
475  data.flags = xlflags;
476  if (BufferIsValid(childbuf))
477  {
478  data.leftChildBlkno = BufferGetBlockNumber(childbuf);
479  data.rightChildBlkno = GinPageGetOpaque(childpage)->rightlink;
480  }
481  else
483 
484  if (stack->parent == NULL)
485  {
486  /*
487  * splitting the root, so we need to allocate new left page and
488  * place pointers to left and right page on root page.
489  */
490  lbuffer = GinNewBuffer(btree->index);
491 
492  /* During index build, count the new left page */
493  if (buildStats)
494  {
495  if (btree->isData)
496  buildStats->nDataPages++;
497  else
498  buildStats->nEntryPages++;
499  }
500 
501  data.rrlink = InvalidBlockNumber;
502  data.flags |= GIN_SPLIT_ROOT;
503 
504  GinPageGetOpaque(newrpage)->rightlink = InvalidBlockNumber;
505  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
506 
507  /*
508  * Construct a new root page containing downlinks to the new left
509  * and right pages. (Do this in a temporary copy rather than
510  * overwriting the original page directly, since we're not in the
511  * critical section yet.)
512  */
513  newrootpg = PageGetTempPage(newrpage);
514  GinInitPage(newrootpg, GinPageGetOpaque(newlpage)->flags & ~(GIN_LEAF | GIN_COMPRESSED), BLCKSZ);
515 
516  btree->fillRoot(btree, newrootpg,
517  BufferGetBlockNumber(lbuffer), newlpage,
518  BufferGetBlockNumber(rbuffer), newrpage);
519 
520  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
521  {
522 
525  BufferGetBlockNumber(lbuffer));
526 
529  BufferGetBlockNumber(rbuffer));
530  }
531 
532  }
533  else
534  {
535  /* splitting a non-root page */
536  data.rrlink = savedRightLink;
537 
538  GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
539  GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
540  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
541 
542  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
543  {
544 
547  BufferGetBlockNumber(rbuffer));
548  }
549  }
550 
551  /*
552  * OK, we have the new contents of the left page in a temporary copy
553  * now (newlpage), and likewise for the new contents of the
554  * newly-allocated right block. The original page is still unchanged.
555  *
556  * If this is a root split, we also have a temporary page containing
557  * the new contents of the root.
558  */
559 
561 
562  MarkBufferDirty(rbuffer);
563  MarkBufferDirty(stack->buffer);
564 
565  /*
566  * Restore the temporary copies over the real buffers.
567  */
568  if (stack->parent == NULL)
569  {
570  /* Splitting the root, three pages to update */
571  MarkBufferDirty(lbuffer);
572  memcpy(page, newrootpg, BLCKSZ);
573  memcpy(BufferGetPage(lbuffer), newlpage, BLCKSZ);
574  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
575  }
576  else
577  {
578  /* Normal split, only two pages to update */
579  memcpy(page, newlpage, BLCKSZ);
580  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
581  }
582 
583  /* We also clear childbuf's INCOMPLETE_SPLIT flag, if passed */
584  if (BufferIsValid(childbuf))
585  {
586  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
587  MarkBufferDirty(childbuf);
588  }
589 
590  /* write WAL record */
591  if (RelationNeedsWAL(btree->index))
592  {
593  XLogRecPtr recptr;
594 
595  XLogBeginInsert();
596 
597  /*
598  * We just take full page images of all the split pages. Splits
599  * are uncommon enough that it's not worth complicating the code
600  * to be more efficient.
601  */
602  if (stack->parent == NULL)
603  {
607  }
608  else
609  {
612  }
613  if (BufferIsValid(childbuf))
614  XLogRegisterBuffer(3, childbuf, REGBUF_STANDARD);
615 
616  XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
617 
618  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
619 
620  PageSetLSN(page, recptr);
621  PageSetLSN(BufferGetPage(rbuffer), recptr);
622  if (stack->parent == NULL)
623  PageSetLSN(BufferGetPage(lbuffer), recptr);
624  if (BufferIsValid(childbuf))
625  PageSetLSN(childpage, recptr);
626  }
628 
629  /*
630  * We can release the locks/pins on the new pages now, but keep
631  * stack->buffer locked. childbuf doesn't get unlocked either.
632  */
633  UnlockReleaseBuffer(rbuffer);
634  if (stack->parent == NULL)
635  UnlockReleaseBuffer(lbuffer);
636 
637  /*
638  * If we split the root, we're done. Otherwise the split is not
639  * complete until the downlink for the new page has been inserted to
640  * the parent.
641  */
642  result = (stack->parent == NULL);
643  }
644  else
645  {
646  elog(ERROR, "invalid return code from GIN placeToPage method: %d", rc);
647  result = false; /* keep compiler quiet */
648  }
649 
650  /* Clean up temp context */
651  MemoryContextSwitchTo(oldCxt);
652  MemoryContextDelete(tmpCxt);
653 
654  return result;
655 }
BlockNumber nEntryPages
Definition: gin.h:45
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:291
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:158
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:342
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
BlockNumber rightChildBlkno
Definition: ginxlog.h:119
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_SPLIT_ROOT
Definition: ginxlog.h:128
#define GIN_INSERT_ISLEAF
Definition: ginxlog.h:127
#define GIN_COMPRESSED
Definition: ginblock.h:47
uint16 flags
Definition: ginxlog.h:41
unsigned short uint16
Definition: c.h:324
GinPlaceToPageRC
Definition: gin_private.h:138
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:155
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:156
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define GIN_INSERT_ISDATA
Definition: ginxlog.h:126
RelFileNode node
Definition: ginxlog.h:115
#define REGBUF_STANDARD
Definition: xloginsert.h:34
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:30
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
Page PageGetTempPage(Page page)
Definition: bufpage.c:348
struct GinBtreeStack * parent
Definition: gin_private.h:132
Relation index
Definition: gin_private.h:162
BlockNumber nDataPages
Definition: gin.h:46
BlockNumber leftChildBlkno
Definition: ginxlog.h:118
#define GinPageIsData(page)
Definition: ginblock.h:114
RelFileNode rd_node
Definition: rel.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
#define InvalidBlockNumber
Definition: block.h:33
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define BlockIdSet(blockId, blockNumber)
Definition: block.h:84
BlockNumber rrlink
Definition: ginxlog.h:116
#define GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:45
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define XLOG_GIN_INSERT
Definition: ginxlog.h:37
#define elog
Definition: elog.h:219
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
uint16 flags
Definition: ginxlog.h:120
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3065
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:111
Pointer Page
Definition: bufpage.h:74
#define GIN_LEAF
Definition: ginblock.h:40

◆ ginStepRight()

Buffer ginStepRight ( Buffer  buffer,
Relation  index,
int  lockmode 
)

Definition at line 166 of file ginbtree.c.

References BufferGetPage, elog, ERROR, GinPageGetOpaque, GinPageIsData, GinPageIsDeleted, GinPageIsLeaf, LockBuffer(), ReadBuffer(), and UnlockReleaseBuffer().

Referenced by entryLoadMoreItems(), ginFindLeafPage(), ginFindParents(), ginFinishSplit(), moveRightIfItNeeded(), and scanPostingTree().

167 {
168  Buffer nextbuffer;
169  Page page = BufferGetPage(buffer);
170  bool isLeaf = GinPageIsLeaf(page);
171  bool isData = GinPageIsData(page);
172  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
173 
174  nextbuffer = ReadBuffer(index, blkno);
175  LockBuffer(nextbuffer, lockmode);
177 
178  /* Sanity check that the page we stepped to is of similar kind. */
179  page = BufferGetPage(nextbuffer);
180  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
181  elog(ERROR, "right sibling of GIN page is of different type");
182 
183  /*
184  * Given the proper lock sequence above, we should never land on a deleted
185  * page.
186  */
187  if (GinPageIsDeleted(page))
188  elog(ERROR, "right sibling of GIN page was deleted");
189 
190  return nextbuffer;
191 }
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
#define GinPageIsData(page)
Definition: ginblock.h:114
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define elog
Definition: elog.h:219
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:74

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 36 of file ginbtree.c.

References BufferGetPage, GIN_EXCLUSIVE, GIN_SHARE, GIN_UNLOCK, GinPageIsLeaf, and LockBuffer().

Referenced by ginCompareItemPointers(), ginFindLeafPage(), and ginVacuumPostingTreeLeaves().

37 {
38  Page page;
39  int access = GIN_SHARE;
40 
42  page = BufferGetPage(buffer);
43  if (GinPageIsLeaf(page))
44  {
45  if (searchMode == false)
46  {
47  /* we should relock our page */
50 
51  /* But root can become non-leaf during relock */
52  if (!GinPageIsLeaf(page))
53  {
54  /* restore old lock type (very rare) */
57  }
58  else
59  access = GIN_EXCLUSIVE;
60  }
61  }
62 
63  return access;
64 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GIN_SHARE
Definition: gin_private.h:44
#define GIN_EXCLUSIVE
Definition: gin_private.h:45
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3546
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Pointer Page
Definition: bufpage.h:74