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, bool rootConflictCheck, 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 201 of file ginbtree.c.

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

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

202 {
203  while (stack)
204  {
205  GinBtreeStack *tmp = stack->parent;
206 
207  if (stack->buffer != InvalidBuffer)
208  ReleaseBuffer(stack->buffer);
209 
210  pfree(stack);
211  stack = tmp;
212  }
213 }
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3365
void pfree(void *pointer)
Definition: mcxt.c:1056
struct GinBtreeStack * parent
Definition: gin_private.h:130

◆ ginFindLeafPage()

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

Definition at line 80 of file ginbtree.c.

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(), GinBtreeData::rootBlkno, and TestForOldSnapshot().

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

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, stack->buffer);
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  TestForOldSnapshot(snapshot, btree->index, page);
104 
105  access = ginTraverseLock(stack->buffer, searchMode);
106 
107  /*
108  * If we're going to modify the tree, finish any incomplete splits we
109  * encounter on the way.
110  */
111  if (!searchMode && GinPageIsIncompleteSplit(page))
112  ginFinishSplit(btree, stack, false, NULL);
113 
114  /*
115  * ok, page is correctly locked, we should check to move right ..,
116  * root never has a right link, so small optimization
117  */
118  while (btree->fullScan == false && stack->blkno != btree->rootBlkno &&
119  btree->isMoveRight(btree, page))
120  {
121  BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
122 
123  if (rightlink == InvalidBlockNumber)
124  /* rightmost page */
125  break;
126 
127  stack->buffer = ginStepRight(stack->buffer, btree->index, access);
128  stack->blkno = rightlink;
129  page = BufferGetPage(stack->buffer);
130  TestForOldSnapshot(snapshot, btree->index, page);
131 
132  if (!searchMode && GinPageIsIncompleteSplit(page))
133  ginFinishSplit(btree, stack, false, NULL);
134  }
135 
136  if (GinPageIsLeaf(page)) /* we found, return locked page */
137  return stack;
138 
139  /* now we have correct buffer, try to find child */
140  child = btree->findChildPage(btree, stack);
141 
142  LockBuffer(stack->buffer, GIN_UNLOCK);
143  Assert(child != InvalidBlockNumber);
144  Assert(stack->blkno != child);
145 
146  if (searchMode)
147  {
148  /* in search mode we may forget path to leaf */
149  stack->blkno = child;
150  stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
151  }
152  else
153  {
154  GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
155 
156  ptr->parent = stack;
157  stack = ptr;
158  stack->blkno = child;
159  stack->buffer = ReadBuffer(btree->index, stack->blkno);
160  stack->predictNumber = 1;
161  }
162  }
163 }
#define GIN_UNLOCK
Definition: gin_private.h:43
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:264
OffsetNumber off
Definition: gin_private.h:126
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:675
BlockNumber rootBlkno
Definition: gin_private.h:161
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4442
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:173
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
struct GinBtreeStack * parent
Definition: gin_private.h:130
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
Relation index
Definition: gin_private.h:160
#define InvalidOffsetNumber
Definition: off.h:26
#define Assert(condition)
Definition: c.h:732
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define InvalidBlockNumber
Definition: block.h:33
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1521
BlockNumber blkno
Definition: gin_private.h:124
uint32 predictNumber
Definition: gin_private.h:129
void * palloc(Size size)
Definition: mcxt.c:949
Pointer Page
Definition: bufpage.h:78
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36

◆ ginFindParents()

static void ginFindParents ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 221 of file ginbtree.c.

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

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

◆ ginFinishSplit()

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

Definition at line 675 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().

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

◆ ginInsertValue()

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

Definition at line 784 of file ginbtree.c.

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

786 {
787  bool done;
788 
789  /* If the leaf page was incompletely split, finish the split first */
791  ginFinishSplit(btree, stack, false, buildStats);
792 
793  done = ginPlaceToPage(btree, stack,
794  insertdata, InvalidBlockNumber,
795  InvalidBuffer, buildStats);
796  if (done)
797  {
798  LockBuffer(stack->buffer, GIN_UNLOCK);
799  freeGinBtreeStack(stack);
800  }
801  else
802  ginFinishSplit(btree, stack, true, buildStats);
803 }
#define GIN_UNLOCK
Definition: gin_private.h:43
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:675
#define InvalidBuffer
Definition: buf.h:25
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define InvalidBlockNumber
Definition: block.h:33
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:201
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:337

◆ ginPlaceToPage()

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

Definition at line 337 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::isBuild, 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().

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

◆ ginStepRight()

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

Definition at line 173 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().

174 {
175  Buffer nextbuffer;
176  Page page = BufferGetPage(buffer);
177  bool isLeaf = GinPageIsLeaf(page);
178  bool isData = GinPageIsData(page);
179  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
180 
181  nextbuffer = ReadBuffer(index, blkno);
182  LockBuffer(nextbuffer, lockmode);
183  UnlockReleaseBuffer(buffer);
184 
185  /* Sanity check that the page we stepped to is of similar kind. */
186  page = BufferGetPage(nextbuffer);
187  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
188  elog(ERROR, "right sibling of GIN page is of different type");
189 
190  /*
191  * Given the proper lock sequence above, we should never land on a deleted
192  * page.
193  */
194  if (GinPageIsDeleted(page))
195  elog(ERROR, "right sibling of GIN page was deleted");
196 
197  return nextbuffer;
198 }
uint32 BlockNumber
Definition: block.h:31
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3388
#define ERROR
Definition: elog.h:43
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#define GinPageIsDeleted(page)
Definition: ginblock.h:124
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:3602
#define GinPageIsData(page)
Definition: ginblock.h:115
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:596
#define elog(elevel,...)
Definition: elog.h:226
int Buffer
Definition: buf.h:23
Pointer Page
Definition: bufpage.h:78

◆ 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(), and ginFindLeafPage().

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
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:112
#define BufferGetPage(buffer)
Definition: bufmgr.h:159
#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:3602
Pointer Page
Definition: bufpage.h:78