PostgreSQL Source Code  git master
ginbtree.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ginbtree.c
4  * page utilities routines for the postgres inverted index access method.
5  *
6  *
7  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
8  * Portions Copyright (c) 1994, Regents of the University of California
9  *
10  * IDENTIFICATION
11  * src/backend/access/gin/ginbtree.c
12  *-------------------------------------------------------------------------
13  */
14 
15 #include "postgres.h"
16 
17 #include "access/gin_private.h"
18 #include "access/ginxlog.h"
19 #include "access/xloginsert.h"
20 #include "miscadmin.h"
21 #include "storage/predicate.h"
22 #include "utils/memutils.h"
23 #include "utils/rel.h"
24 
25 static void ginFindParents(GinBtree btree, GinBtreeStack *stack);
26 static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
27  void *insertdata, BlockNumber updateblkno,
28  Buffer childbuf, GinStatsData *buildStats);
29 static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack,
30  bool freestack, GinStatsData *buildStats);
31 
32 /*
33  * Lock buffer by needed method for search.
34  */
35 int
36 ginTraverseLock(Buffer buffer, bool searchMode)
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 }
65 
66 /*
67  * Descend the tree to the leaf page that contains or would contain the key
68  * we're searching for. The key should already be filled in 'btree', in
69  * tree-type specific manner. If btree->fullScan is true, descends to the
70  * leftmost leaf page.
71  *
72  * If 'searchmode' is false, on return stack->buffer is exclusively locked,
73  * and the stack represents the full path to the root. Otherwise stack->buffer
74  * is share-locked, and stack->parent is NULL.
75  *
76  * If 'rootConflictCheck' is true, tree root is checked for serialization
77  * conflict.
78  */
80 ginFindLeafPage(GinBtree btree, bool searchMode,
81  bool rootConflictCheck)
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 }
162 
163 /*
164  * Step right from current page.
165  *
166  * The next page is locked first, before releasing the current page. This is
167  * crucial to protect from concurrent page deletion (see comment in
168  * ginDeletePage).
169  */
170 Buffer
171 ginStepRight(Buffer buffer, Relation index, int lockmode)
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 }
190 
191 void
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 }
205 
206 /*
207  * Try to find parent for current stack position. Returns correct parent and
208  * child's offset in stack->parent. The root page is never released, to
209  * prevent conflict with vacuum process.
210  */
211 static void
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  /* Link not present in this level */
276  LockBuffer(buffer, GIN_UNLOCK);
277  /* Do not release pin on the root buffer */
278  if (buffer != root->buffer)
279  ReleaseBuffer(buffer);
280  break;
281  }
282  buffer = ginStepRight(buffer, btree->index, GIN_EXCLUSIVE);
283  page = BufferGetPage(buffer);
284 
285  /* finish any incomplete splits, as above */
286  if (GinPageIsIncompleteSplit(page))
287  {
288  Assert(blkno != btree->rootBlkno);
289  ptr->blkno = blkno;
290  ptr->buffer = buffer;
291  ptr->parent = root;
292  ptr->off = InvalidOffsetNumber;
293 
294  ginFinishSplit(btree, ptr, false, NULL);
295  }
296  }
297 
298  if (blkno != InvalidBlockNumber)
299  {
300  ptr->blkno = blkno;
301  ptr->buffer = buffer;
302  ptr->parent = root; /* it may be wrong, but in next call we will
303  * correct */
304  ptr->off = offset;
305  stack->parent = ptr;
306  return;
307  }
308 
309  /* Descend down to next level */
310  blkno = leftmostBlkno;
311  buffer = ReadBuffer(btree->index, blkno);
312  }
313 }
314 
315 /*
316  * Insert a new item to a page.
317  *
318  * Returns true if the insertion was finished. On false, the page was split and
319  * the parent needs to be updated. (A root split returns true as it doesn't
320  * need any further action by the caller to complete.)
321  *
322  * When inserting a downlink to an internal page, 'childbuf' contains the
323  * child page that was split. Its GIN_INCOMPLETE_SPLIT flag will be cleared
324  * atomically with the insert. Also, the existing item at offset stack->off
325  * in the target page is updated to point to updateblkno.
326  *
327  * stack->buffer is locked on entry, and is kept locked.
328  * Likewise for childbuf, if given.
329  */
330 static bool
332  void *insertdata, BlockNumber updateblkno,
333  Buffer childbuf, GinStatsData *buildStats)
334 {
335  Page page = BufferGetPage(stack->buffer);
336  bool result;
337  GinPlaceToPageRC rc;
338  uint16 xlflags = 0;
339  Page childpage = NULL;
340  Page newlpage = NULL,
341  newrpage = NULL;
342  void *ptp_workspace = NULL;
343  MemoryContext tmpCxt;
344  MemoryContext oldCxt;
345 
346  /*
347  * We do all the work of this function and its subfunctions in a temporary
348  * memory context. This avoids leakages and simplifies APIs, since some
349  * subfunctions allocate storage that has to survive until we've finished
350  * the WAL insertion.
351  */
353  "ginPlaceToPage temporary context",
355  oldCxt = MemoryContextSwitchTo(tmpCxt);
356 
357  if (GinPageIsData(page))
358  xlflags |= GIN_INSERT_ISDATA;
359  if (GinPageIsLeaf(page))
360  {
361  xlflags |= GIN_INSERT_ISLEAF;
362  Assert(!BufferIsValid(childbuf));
363  Assert(updateblkno == InvalidBlockNumber);
364  }
365  else
366  {
367  Assert(BufferIsValid(childbuf));
368  Assert(updateblkno != InvalidBlockNumber);
369  childpage = BufferGetPage(childbuf);
370  }
371 
372  /*
373  * See if the incoming tuple will fit on the page. beginPlaceToPage will
374  * decide if the page needs to be split, and will compute the split
375  * contents if so. See comments for beginPlaceToPage and execPlaceToPage
376  * functions for more details of the API here.
377  */
378  rc = btree->beginPlaceToPage(btree, stack->buffer, stack,
379  insertdata, updateblkno,
380  &ptp_workspace,
381  &newlpage, &newrpage);
382 
383  if (rc == GPTP_NO_WORK)
384  {
385  /* Nothing to do */
386  result = true;
387  }
388  else if (rc == GPTP_INSERT)
389  {
390  /* It will fit, perform the insertion */
392 
393  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
394  XLogBeginInsert();
395 
396  /*
397  * Perform the page update, dirty and register stack->buffer, and
398  * register any extra WAL data.
399  */
400  btree->execPlaceToPage(btree, stack->buffer, stack,
401  insertdata, updateblkno, ptp_workspace);
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  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
409  XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
410  }
411 
412  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
413  {
414  XLogRecPtr recptr;
415  ginxlogInsert xlrec;
416  BlockIdData childblknos[2];
417 
418  xlrec.flags = xlflags;
419 
420  XLogRegisterData((char *) &xlrec, sizeof(ginxlogInsert));
421 
422  /*
423  * Log information about child if this was an insertion of a
424  * downlink.
425  */
426  if (BufferIsValid(childbuf))
427  {
428  BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
429  BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
430  XLogRegisterData((char *) childblknos,
431  sizeof(BlockIdData) * 2);
432  }
433 
434  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT);
435  PageSetLSN(page, recptr);
436  if (BufferIsValid(childbuf))
437  PageSetLSN(childpage, recptr);
438  }
439 
441 
442  /* Insertion is complete. */
443  result = true;
444  }
445  else if (rc == GPTP_SPLIT)
446  {
447  /*
448  * Didn't fit, need to split. The split has been computed in newlpage
449  * and newrpage, which are pointers to palloc'd pages, not associated
450  * with buffers. stack->buffer is not touched yet.
451  */
452  Buffer rbuffer;
453  BlockNumber savedRightLink;
455  Buffer lbuffer = InvalidBuffer;
456  Page newrootpg = NULL;
457 
458  /* Get a new index page to become the right page */
459  rbuffer = GinNewBuffer(btree->index);
460 
461  /* During index build, count the new page */
462  if (buildStats)
463  {
464  if (btree->isData)
465  buildStats->nDataPages++;
466  else
467  buildStats->nEntryPages++;
468  }
469 
470  savedRightLink = GinPageGetOpaque(page)->rightlink;
471 
472  /* Begin setting up WAL record */
473  data.locator = btree->index->rd_locator;
474  data.flags = xlflags;
475  if (BufferIsValid(childbuf))
476  {
477  data.leftChildBlkno = BufferGetBlockNumber(childbuf);
478  data.rightChildBlkno = GinPageGetOpaque(childpage)->rightlink;
479  }
480  else
481  data.leftChildBlkno = data.rightChildBlkno = InvalidBlockNumber;
482 
483  if (stack->parent == NULL)
484  {
485  /*
486  * splitting the root, so we need to allocate new left page and
487  * place pointers to left and right page on root page.
488  */
489  lbuffer = GinNewBuffer(btree->index);
490 
491  /* During index build, count the new left page */
492  if (buildStats)
493  {
494  if (btree->isData)
495  buildStats->nDataPages++;
496  else
497  buildStats->nEntryPages++;
498  }
499 
500  data.rrlink = InvalidBlockNumber;
501  data.flags |= GIN_SPLIT_ROOT;
502 
503  GinPageGetOpaque(newrpage)->rightlink = InvalidBlockNumber;
504  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
505 
506  /*
507  * Construct a new root page containing downlinks to the new left
508  * and right pages. (Do this in a temporary copy rather than
509  * overwriting the original page directly, since we're not in the
510  * critical section yet.)
511  */
512  newrootpg = PageGetTempPage(newrpage);
513  GinInitPage(newrootpg, GinPageGetOpaque(newlpage)->flags & ~(GIN_LEAF | GIN_COMPRESSED), BLCKSZ);
514 
515  btree->fillRoot(btree, newrootpg,
516  BufferGetBlockNumber(lbuffer), newlpage,
517  BufferGetBlockNumber(rbuffer), newrpage);
518 
519  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
520  {
521 
524  BufferGetBlockNumber(lbuffer));
525 
528  BufferGetBlockNumber(rbuffer));
529  }
530  }
531  else
532  {
533  /* splitting a non-root page */
534  data.rrlink = savedRightLink;
535 
536  GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
537  GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
538  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
539 
540  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
541  {
542 
545  BufferGetBlockNumber(rbuffer));
546  }
547  }
548 
549  /*
550  * OK, we have the new contents of the left page in a temporary copy
551  * now (newlpage), and likewise for the new contents of the
552  * newly-allocated right block. The original page is still unchanged.
553  *
554  * If this is a root split, we also have a temporary page containing
555  * the new contents of the root.
556  */
557 
559 
560  MarkBufferDirty(rbuffer);
561  MarkBufferDirty(stack->buffer);
562 
563  /*
564  * Restore the temporary copies over the real buffers.
565  */
566  if (stack->parent == NULL)
567  {
568  /* Splitting the root, three pages to update */
569  MarkBufferDirty(lbuffer);
570  memcpy(page, newrootpg, BLCKSZ);
571  memcpy(BufferGetPage(lbuffer), newlpage, BLCKSZ);
572  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
573  }
574  else
575  {
576  /* Normal split, only two pages to update */
577  memcpy(page, newlpage, BLCKSZ);
578  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
579  }
580 
581  /* We also clear childbuf's INCOMPLETE_SPLIT flag, if passed */
582  if (BufferIsValid(childbuf))
583  {
584  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
585  MarkBufferDirty(childbuf);
586  }
587 
588  /* write WAL record */
589  if (RelationNeedsWAL(btree->index) && !btree->isBuild)
590  {
591  XLogRecPtr recptr;
592 
593  XLogBeginInsert();
594 
595  /*
596  * We just take full page images of all the split pages. Splits
597  * are uncommon enough that it's not worth complicating the code
598  * to be more efficient.
599  */
600  if (stack->parent == NULL)
601  {
605  }
606  else
607  {
610  }
611  if (BufferIsValid(childbuf))
612  XLogRegisterBuffer(3, childbuf, REGBUF_STANDARD);
613 
614  XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
615 
616  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
617 
618  PageSetLSN(page, recptr);
619  PageSetLSN(BufferGetPage(rbuffer), recptr);
620  if (stack->parent == NULL)
621  PageSetLSN(BufferGetPage(lbuffer), recptr);
622  if (BufferIsValid(childbuf))
623  PageSetLSN(childpage, recptr);
624  }
626 
627  /*
628  * We can release the locks/pins on the new pages now, but keep
629  * stack->buffer locked. childbuf doesn't get unlocked either.
630  */
631  UnlockReleaseBuffer(rbuffer);
632  if (stack->parent == NULL)
633  UnlockReleaseBuffer(lbuffer);
634 
635  /*
636  * If we split the root, we're done. Otherwise the split is not
637  * complete until the downlink for the new page has been inserted to
638  * the parent.
639  */
640  result = (stack->parent == NULL);
641  }
642  else
643  {
644  elog(ERROR, "invalid return code from GIN beginPlaceToPage method: %d", rc);
645  result = false; /* keep compiler quiet */
646  }
647 
648  /* Clean up temp context */
649  MemoryContextSwitchTo(oldCxt);
650  MemoryContextDelete(tmpCxt);
651 
652  return result;
653 }
654 
655 /*
656  * Finish a split by inserting the downlink for the new page to parent.
657  *
658  * On entry, stack->buffer is exclusively locked.
659  *
660  * If freestack is true, all the buffers are released and unlocked as we
661  * crawl up the tree, and 'stack' is freed. Otherwise stack->buffer is kept
662  * locked, and stack is unmodified, except for possibly moving right to find
663  * the correct parent of page.
664  */
665 static void
666 ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack,
667  GinStatsData *buildStats)
668 {
669  Page page;
670  bool done;
671  bool first = true;
672 
673  /*
674  * freestack == false when we encounter an incompletely split page during
675  * a scan, while freestack == true is used in the normal scenario that a
676  * split is finished right after the initial insert.
677  */
678  if (!freestack)
679  elog(DEBUG1, "finishing incomplete split of block %u in gin index \"%s\"",
680  stack->blkno, RelationGetRelationName(btree->index));
681 
682  /* this loop crawls up the stack until the insertion is complete */
683  do
684  {
685  GinBtreeStack *parent = stack->parent;
686  void *insertdata;
687  BlockNumber updateblkno;
688 
689  /* search parent to lock */
690  LockBuffer(parent->buffer, GIN_EXCLUSIVE);
691 
692  /*
693  * If the parent page was incompletely split, finish that split first,
694  * then continue with the current one.
695  *
696  * Note: we have to finish *all* incomplete splits we encounter, even
697  * if we have to move right. Otherwise we might choose as the target a
698  * page that has no downlink in the parent, and splitting it further
699  * would fail.
700  */
702  ginFinishSplit(btree, parent, false, buildStats);
703 
704  /* move right if it's needed */
705  page = BufferGetPage(parent->buffer);
706  while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
707  {
708  if (GinPageRightMost(page))
709  {
710  /*
711  * rightmost page, but we don't find parent, we should use
712  * plain search...
713  */
714  LockBuffer(parent->buffer, GIN_UNLOCK);
715  ginFindParents(btree, stack);
716  parent = stack->parent;
717  Assert(parent != NULL);
718  break;
719  }
720 
721  parent->buffer = ginStepRight(parent->buffer, btree->index, GIN_EXCLUSIVE);
722  parent->blkno = BufferGetBlockNumber(parent->buffer);
723  page = BufferGetPage(parent->buffer);
724 
726  ginFinishSplit(btree, parent, false, buildStats);
727  }
728 
729  /* insert the downlink */
730  insertdata = btree->prepareDownlink(btree, stack->buffer);
731  updateblkno = GinPageGetOpaque(BufferGetPage(stack->buffer))->rightlink;
732  done = ginPlaceToPage(btree, parent,
733  insertdata, updateblkno,
734  stack->buffer, buildStats);
735  pfree(insertdata);
736 
737  /*
738  * If the caller requested to free the stack, unlock and release the
739  * child buffer now. Otherwise keep it pinned and locked, but if we
740  * have to recurse up the tree, we can unlock the upper pages, only
741  * keeping the page at the bottom of the stack locked.
742  */
743  if (!first || freestack)
744  LockBuffer(stack->buffer, GIN_UNLOCK);
745  if (freestack)
746  {
747  ReleaseBuffer(stack->buffer);
748  pfree(stack);
749  }
750  stack = parent;
751 
752  first = false;
753  } while (!done);
754 
755  /* unlock the parent */
756  LockBuffer(stack->buffer, GIN_UNLOCK);
757 
758  if (freestack)
759  freeGinBtreeStack(stack);
760 }
761 
762 /*
763  * Insert a value to tree described by stack.
764  *
765  * The value to be inserted is given in 'insertdata'. Its format depends
766  * on whether this is an entry or data tree, ginInsertValue just passes it
767  * through to the tree-specific callback function.
768  *
769  * During an index build, buildStats is non-null and the counters it contains
770  * are incremented as needed.
771  *
772  * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
773  */
774 void
775 ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata,
776  GinStatsData *buildStats)
777 {
778  bool done;
779 
780  /* If the leaf page was incompletely split, finish the split first */
782  ginFinishSplit(btree, stack, false, buildStats);
783 
784  done = ginPlaceToPage(btree, stack,
785  insertdata, InvalidBlockNumber,
786  InvalidBuffer, buildStats);
787  if (done)
788  {
789  LockBuffer(stack->buffer, GIN_UNLOCK);
790  freeGinBtreeStack(stack);
791  }
792  else
793  ginFinishSplit(btree, stack, true, buildStats);
794 }
uint32 BlockNumber
Definition: block.h:31
#define InvalidBlockNumber
Definition: block.h:33
static void BlockIdSet(BlockIdData *blockId, BlockNumber blockNumber)
Definition: block.h:81
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3386
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:2261
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4573
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4590
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2198
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4808
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:735
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
Page PageGetTempPage(Page page)
Definition: bufpage.c:365
Pointer Page
Definition: bufpage.h:78
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:388
unsigned short uint16
Definition: c.h:494
#define DEBUG1
Definition: elog.h:30
#define ERROR
Definition: elog.h:39
#define GIN_UNLOCK
Definition: gin_private.h:48
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_EXCLUSIVE
Definition: gin_private.h:50
#define GIN_SHARE
Definition: gin_private.h:49
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GinPageGetOpaque(page)
Definition: ginblock.h:110
#define GIN_LEAF
Definition: ginblock.h:42
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GinPageRightMost(page)
Definition: ginblock.h:129
#define GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:47
#define GinPageIsLeaf(page)
Definition: ginblock.h:112
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:127
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:192
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:775
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:331
static void ginFindParents(GinBtree btree, GinBtreeStack *stack)
Definition: ginbtree.c:212
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:666
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:171
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, bool rootConflictCheck)
Definition: ginbtree.c:80
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:338
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:300
#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
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1456
MemoryContext CurrentMemoryContext
Definition: mcxt.c:135
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:403
void * palloc(Size size)
Definition: mcxt.c:1226
#define AllocSetContextCreate
Definition: memutils.h:126
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:150
#define START_CRIT_SECTION()
Definition: miscadmin.h:148
#define END_CRIT_SECTION()
Definition: miscadmin.h:150
#define InvalidOffsetNumber
Definition: off.h:26
uint16 OffsetNumber
Definition: off.h:24
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3095
void CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno)
Definition: predicate.c:4287
short access
Definition: preproc-type.c:36
#define RelationGetRelationName(relation)
Definition: rel.h:538
#define RelationNeedsWAL(relation)
Definition: rel.h:629
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:152
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:160
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:153
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:154
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:159
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:161
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:158
Relation index
Definition: gin_private.h:166
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:162
BlockNumber rootBlkno
Definition: gin_private.h:167
OffsetNumber off
Definition: gin_private.h:132
uint32 predictNumber
Definition: gin_private.h:135
struct GinBtreeStack * parent
Definition: gin_private.h:136
BlockNumber blkno
Definition: gin_private.h:130
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
Definition: type.h:95
uint64 XLogRecPtr
Definition: xlogdefs.h:21
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:365
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:475
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