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 "miscadmin.h"
#include "storage/predicate.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, bool rootConflictCheck)
 
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 192 of file ginbtree.c.

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

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

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

◆ ginFindLeafPage()

GinBtreeStack* ginFindLeafPage ( GinBtree  btree,
bool  searchMode,
bool  rootConflictCheck 
)

Definition at line 80 of file ginbtree.c.

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

References Assert(), GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage(), CheckForSerializableConflictIn(), 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(), and GinBtreeData::rootBlkno.

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

◆ ginFindParents()

static void ginFindParents ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 212 of file ginbtree.c.

213 {
214  Page page;
215  Buffer buffer;
216  BlockNumber blkno,
217  leftmostBlkno;
218  OffsetNumber offset;
219  GinBtreeStack *root;
220  GinBtreeStack *ptr;
221 
222  /*
223  * Unwind the stack all the way up to the root, leaving only the root
224  * item.
225  *
226  * Be careful not to release the pin on the root page! The pin on root
227  * page is required to lock out concurrent vacuums on the tree.
228  */
229  root = stack->parent;
230  while (root->parent)
231  {
232  ReleaseBuffer(root->buffer);
233  root = root->parent;
234  }
235 
236  Assert(root->blkno == btree->rootBlkno);
237  Assert(BufferGetBlockNumber(root->buffer) == btree->rootBlkno);
238  root->off = InvalidOffsetNumber;
239 
240  blkno = root->blkno;
241  buffer = root->buffer;
242 
243  ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
244 
245  for (;;)
246  {
247  LockBuffer(buffer, GIN_EXCLUSIVE);
248  page = BufferGetPage(buffer);
249  if (GinPageIsLeaf(page))
250  elog(ERROR, "Lost path");
251 
252  if (GinPageIsIncompleteSplit(page))
253  {
254  Assert(blkno != btree->rootBlkno);
255  ptr->blkno = blkno;
256  ptr->buffer = buffer;
257 
258  /*
259  * parent may be wrong, but if so, the ginFinishSplit call will
260  * recurse to call ginFindParents again to fix it.
261  */
262  ptr->parent = root;
263  ptr->off = InvalidOffsetNumber;
264 
265  ginFinishSplit(btree, ptr, false, NULL);
266  }
267 
268  leftmostBlkno = btree->getLeftMostChild(btree, page);
269 
270  while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
271  {
272  blkno = GinPageGetOpaque(page)->rightlink;
273  if (blkno == InvalidBlockNumber)
274  {
275  UnlockReleaseBuffer(buffer);
276  break;
277  }
278  buffer = ginStepRight(buffer, btree->index, GIN_EXCLUSIVE);
279  page = BufferGetPage(buffer);
280 
281  /* finish any incomplete splits, as above */
282  if (GinPageIsIncompleteSplit(page))
283  {
284  Assert(blkno != btree->rootBlkno);
285  ptr->blkno = blkno;
286  ptr->buffer = buffer;
287  ptr->parent = root;
288  ptr->off = InvalidOffsetNumber;
289 
290  ginFinishSplit(btree, ptr, false, NULL);
291  }
292  }
293 
294  if (blkno != InvalidBlockNumber)
295  {
296  ptr->blkno = blkno;
297  ptr->buffer = buffer;
298  ptr->parent = root; /* it may be wrong, but in next call we will
299  * correct */
300  ptr->off = offset;
301  stack->parent = ptr;
302  return;
303  }
304 
305  /* Descend down to next level */
306  blkno = leftmostBlkno;
307  buffer = ReadBuffer(btree->index, blkno);
308  }
309 }
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3290
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4497
#define ERROR
Definition: elog.h:39
#define GIN_EXCLUSIVE
Definition: gin_private.h:50
uint16 OffsetNumber
Definition: off.h:24
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:153
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:158

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

◆ ginFinishSplit()

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

Definition at line 664 of file ginbtree.c.

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

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

◆ ginInsertValue()

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

Definition at line 773 of file ginbtree.c.

775 {
776  bool done;
777 
778  /* If the leaf page was incompletely split, finish the split first */
780  ginFinishSplit(btree, stack, false, buildStats);
781 
782  done = ginPlaceToPage(btree, stack,
783  insertdata, InvalidBlockNumber,
784  InvalidBuffer, buildStats);
785  if (done)
786  {
787  LockBuffer(stack->buffer, GIN_UNLOCK);
788  freeGinBtreeStack(stack);
789  }
790  else
791  ginFinishSplit(btree, stack, true, buildStats);
792 }

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

◆ ginPlaceToPage()

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

Definition at line 327 of file ginbtree.c.

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

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), GinBtreeData::beginPlaceToPage, BlockIdSet(), GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), CurrentMemoryContext, data, elog(), END_CRIT_SECTION, ERROR, GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, ginxlogInsert::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::isBuild, GinBtreeData::isData, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nDataPages, GinStatsData::nEntryPages, PageGetTempPage(), PageSetLSN(), GinBtreeStack::parent, PredicateLockPageSplit(), RelationData::rd_locator, REGBUF_FORCE_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_INSERT, XLOG_GIN_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginFinishSplit(), and ginInsertValue().

◆ ginStepRight()

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

Definition at line 171 of file ginbtree.c.

172 {
173  Buffer nextbuffer;
174  Page page = BufferGetPage(buffer);
175  bool isLeaf = GinPageIsLeaf(page);
176  bool isData = GinPageIsData(page);
177  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
178 
179  nextbuffer = ReadBuffer(index, blkno);
180  LockBuffer(nextbuffer, lockmode);
181  UnlockReleaseBuffer(buffer);
182 
183  /* Sanity check that the page we stepped to is of similar kind. */
184  page = BufferGetPage(nextbuffer);
185  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
186  elog(ERROR, "right sibling of GIN page is of different type");
187 
188  return nextbuffer;
189 }
Definition: type.h:95

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

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 36 of file ginbtree.c.

37 {
38  Page page;
39  int access = GIN_SHARE;
40 
41  LockBuffer(buffer, GIN_SHARE);
42  page = BufferGetPage(buffer);
43  if (GinPageIsLeaf(page))
44  {
45  if (searchMode == false)
46  {
47  /* we should relock our page */
48  LockBuffer(buffer, GIN_UNLOCK);
49  LockBuffer(buffer, GIN_EXCLUSIVE);
50 
51  /* But root can become non-leaf during relock */
52  if (!GinPageIsLeaf(page))
53  {
54  /* restore old lock type (very rare) */
55  LockBuffer(buffer, GIN_UNLOCK);
56  LockBuffer(buffer, GIN_SHARE);
57  }
58  else
60  }
61  }
62 
63  return access;
64 }
#define GIN_SHARE
Definition: gin_private.h:49

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

Referenced by ginFindLeafPage().