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-2018, 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 "storage/predicate.h"
21 #include "miscadmin.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
59  access = GIN_EXCLUSIVE;
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  */
77 ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
78 {
79  GinBtreeStack *stack;
80 
81  stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
82  stack->blkno = btree->rootBlkno;
83  stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
84  stack->parent = NULL;
85  stack->predictNumber = 1;
86 
87  if (!searchMode)
88  CheckForSerializableConflictIn(btree->index, NULL, stack->buffer);
89 
90  for (;;)
91  {
92  Page page;
93  BlockNumber child;
94  int access;
95 
96  stack->off = InvalidOffsetNumber;
97 
98  page = BufferGetPage(stack->buffer);
99  TestForOldSnapshot(snapshot, btree->index, page);
100 
101  access = ginTraverseLock(stack->buffer, searchMode);
102 
103  /*
104  * If we're going to modify the tree, finish any incomplete splits we
105  * encounter on the way.
106  */
107  if (!searchMode && GinPageIsIncompleteSplit(page))
108  ginFinishSplit(btree, stack, false, NULL);
109 
110  /*
111  * ok, page is correctly locked, we should check to move right ..,
112  * root never has a right link, so small optimization
113  */
114  while (btree->fullScan == false && stack->blkno != btree->rootBlkno &&
115  btree->isMoveRight(btree, page))
116  {
117  BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
118 
119  if (rightlink == InvalidBlockNumber)
120  /* rightmost page */
121  break;
122 
123  stack->buffer = ginStepRight(stack->buffer, btree->index, access);
124  stack->blkno = rightlink;
125  page = BufferGetPage(stack->buffer);
126  TestForOldSnapshot(snapshot, btree->index, page);
127 
128  if (!searchMode && GinPageIsIncompleteSplit(page))
129  ginFinishSplit(btree, stack, false, NULL);
130  }
131 
132  if (GinPageIsLeaf(page)) /* we found, return locked page */
133  return stack;
134 
135  /* now we have correct buffer, try to find child */
136  child = btree->findChildPage(btree, stack);
137 
138  LockBuffer(stack->buffer, GIN_UNLOCK);
139  Assert(child != InvalidBlockNumber);
140  Assert(stack->blkno != child);
141 
142  if (searchMode)
143  {
144  /* in search mode we may forget path to leaf */
145  stack->blkno = child;
146  stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
147  }
148  else
149  {
150  GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
151 
152  ptr->parent = stack;
153  stack = ptr;
154  stack->blkno = child;
155  stack->buffer = ReadBuffer(btree->index, stack->blkno);
156  stack->predictNumber = 1;
157  }
158  }
159 }
160 
161 /*
162  * Step right from current page.
163  *
164  * The next page is locked first, before releasing the current page. This is
165  * crucial to protect from concurrent page deletion (see comment in
166  * ginDeletePage).
167  */
168 Buffer
170 {
171  Buffer nextbuffer;
172  Page page = BufferGetPage(buffer);
173  bool isLeaf = GinPageIsLeaf(page);
174  bool isData = GinPageIsData(page);
175  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
176 
177  nextbuffer = ReadBuffer(index, blkno);
178  LockBuffer(nextbuffer, lockmode);
179  UnlockReleaseBuffer(buffer);
180 
181  /* Sanity check that the page we stepped to is of similar kind. */
182  page = BufferGetPage(nextbuffer);
183  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
184  elog(ERROR, "right sibling of GIN page is of different type");
185 
186  /*
187  * Given the proper lock sequence above, we should never land on a deleted
188  * page.
189  */
190  if (GinPageIsDeleted(page))
191  elog(ERROR, "right sibling of GIN page was deleted");
192 
193  return nextbuffer;
194 }
195 
196 void
198 {
199  while (stack)
200  {
201  GinBtreeStack *tmp = stack->parent;
202 
203  if (stack->buffer != InvalidBuffer)
204  ReleaseBuffer(stack->buffer);
205 
206  pfree(stack);
207  stack = tmp;
208  }
209 }
210 
211 /*
212  * Try to find parent for current stack position. Returns correct parent and
213  * child's offset in stack->parent. The root page is never released, to
214  * to prevent conflict with vacuum process.
215  */
216 static void
218 {
219  Page page;
220  Buffer buffer;
221  BlockNumber blkno,
222  leftmostBlkno;
223  OffsetNumber offset;
224  GinBtreeStack *root;
225  GinBtreeStack *ptr;
226 
227  /*
228  * Unwind the stack all the way up to the root, leaving only the root
229  * item.
230  *
231  * Be careful not to release the pin on the root page! The pin on root
232  * page is required to lock out concurrent vacuums on the tree.
233  */
234  root = stack->parent;
235  while (root->parent)
236  {
237  ReleaseBuffer(root->buffer);
238  root = root->parent;
239  }
240 
241  Assert(root->blkno == btree->rootBlkno);
242  Assert(BufferGetBlockNumber(root->buffer) == btree->rootBlkno);
243  root->off = InvalidOffsetNumber;
244 
245  blkno = root->blkno;
246  buffer = root->buffer;
247  offset = InvalidOffsetNumber;
248 
249  ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
250 
251  for (;;)
252  {
253  LockBuffer(buffer, GIN_EXCLUSIVE);
254  page = BufferGetPage(buffer);
255  if (GinPageIsLeaf(page))
256  elog(ERROR, "Lost path");
257 
258  if (GinPageIsIncompleteSplit(page))
259  {
260  Assert(blkno != btree->rootBlkno);
261  ptr->blkno = blkno;
262  ptr->buffer = buffer;
263 
264  /*
265  * parent may be wrong, but if so, the ginFinishSplit call will
266  * recurse to call ginFindParents again to fix it.
267  */
268  ptr->parent = root;
269  ptr->off = InvalidOffsetNumber;
270 
271  ginFinishSplit(btree, ptr, false, NULL);
272  }
273 
274  leftmostBlkno = btree->getLeftMostChild(btree, page);
275 
276  while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
277  {
278  blkno = GinPageGetOpaque(page)->rightlink;
279  if (blkno == InvalidBlockNumber)
280  {
281  UnlockReleaseBuffer(buffer);
282  break;
283  }
284  buffer = ginStepRight(buffer, btree->index, GIN_EXCLUSIVE);
285  page = BufferGetPage(buffer);
286 
287  /* finish any incomplete splits, as above */
288  if (GinPageIsIncompleteSplit(page))
289  {
290  Assert(blkno != btree->rootBlkno);
291  ptr->blkno = blkno;
292  ptr->buffer = buffer;
293  ptr->parent = root;
294  ptr->off = InvalidOffsetNumber;
295 
296  ginFinishSplit(btree, ptr, false, NULL);
297  }
298  }
299 
300  if (blkno != InvalidBlockNumber)
301  {
302  ptr->blkno = blkno;
303  ptr->buffer = buffer;
304  ptr->parent = root; /* it may be wrong, but in next call we will
305  * correct */
306  ptr->off = offset;
307  stack->parent = ptr;
308  return;
309  }
310 
311  /* Descend down to next level */
312  blkno = leftmostBlkno;
313  buffer = ReadBuffer(btree->index, blkno);
314  }
315 }
316 
317 /*
318  * Insert a new item to a page.
319  *
320  * Returns true if the insertion was finished. On false, the page was split and
321  * the parent needs to be updated. (A root split returns true as it doesn't
322  * need any further action by the caller to complete.)
323  *
324  * When inserting a downlink to an internal page, 'childbuf' contains the
325  * child page that was split. Its GIN_INCOMPLETE_SPLIT flag will be cleared
326  * atomically with the insert. Also, the existing item at offset stack->off
327  * in the target page is updated to point to updateblkno.
328  *
329  * stack->buffer is locked on entry, and is kept locked.
330  * Likewise for childbuf, if given.
331  */
332 static bool
334  void *insertdata, BlockNumber updateblkno,
335  Buffer childbuf, GinStatsData *buildStats)
336 {
337  Page page = BufferGetPage(stack->buffer);
338  bool result;
339  GinPlaceToPageRC rc;
340  uint16 xlflags = 0;
341  Page childpage = NULL;
342  Page newlpage = NULL,
343  newrpage = NULL;
344  void *ptp_workspace = NULL;
345  MemoryContext tmpCxt;
346  MemoryContext oldCxt;
347 
348  /*
349  * We do all the work of this function and its subfunctions in a temporary
350  * memory context. This avoids leakages and simplifies APIs, since some
351  * subfunctions allocate storage that has to survive until we've finished
352  * the WAL insertion.
353  */
355  "ginPlaceToPage temporary context",
357  oldCxt = MemoryContextSwitchTo(tmpCxt);
358 
359  if (GinPageIsData(page))
360  xlflags |= GIN_INSERT_ISDATA;
361  if (GinPageIsLeaf(page))
362  {
363  xlflags |= GIN_INSERT_ISLEAF;
364  Assert(!BufferIsValid(childbuf));
365  Assert(updateblkno == InvalidBlockNumber);
366  }
367  else
368  {
369  Assert(BufferIsValid(childbuf));
370  Assert(updateblkno != InvalidBlockNumber);
371  childpage = BufferGetPage(childbuf);
372  }
373 
374  /*
375  * See if the incoming tuple will fit on the page. beginPlaceToPage will
376  * decide if the page needs to be split, and will compute the split
377  * contents if so. See comments for beginPlaceToPage and execPlaceToPage
378  * functions for more details of the API here.
379  */
380  rc = btree->beginPlaceToPage(btree, stack->buffer, stack,
381  insertdata, updateblkno,
382  &ptp_workspace,
383  &newlpage, &newrpage);
384 
385  if (rc == GPTP_NO_WORK)
386  {
387  /* Nothing to do */
388  result = true;
389  }
390  else if (rc == GPTP_INSERT)
391  {
392  /* It will fit, perform the insertion */
394 
395  if (RelationNeedsWAL(btree->index))
396  {
397  XLogBeginInsert();
399  if (BufferIsValid(childbuf))
400  XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
401  }
402 
403  /* Perform the page update, and register any extra WAL data */
404  btree->execPlaceToPage(btree, stack->buffer, stack,
405  insertdata, updateblkno, ptp_workspace);
406 
407  MarkBufferDirty(stack->buffer);
408 
409  /* An insert to an internal page finishes the split of the child. */
410  if (BufferIsValid(childbuf))
411  {
412  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
413  MarkBufferDirty(childbuf);
414  }
415 
416  if (RelationNeedsWAL(btree->index))
417  {
418  XLogRecPtr recptr;
419  ginxlogInsert xlrec;
420  BlockIdData childblknos[2];
421 
422  xlrec.flags = xlflags;
423 
424  XLogRegisterData((char *) &xlrec, sizeof(ginxlogInsert));
425 
426  /*
427  * Log information about child if this was an insertion of a
428  * downlink.
429  */
430  if (BufferIsValid(childbuf))
431  {
432  BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
433  BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
434  XLogRegisterData((char *) childblknos,
435  sizeof(BlockIdData) * 2);
436  }
437 
438  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT);
439  PageSetLSN(page, recptr);
440  if (BufferIsValid(childbuf))
441  PageSetLSN(childpage, recptr);
442  }
443 
445 
446  /* Insertion is complete. */
447  result = true;
448  }
449  else if (rc == GPTP_SPLIT)
450  {
451  /*
452  * Didn't fit, need to split. The split has been computed in newlpage
453  * and newrpage, which are pointers to palloc'd pages, not associated
454  * with buffers. stack->buffer is not touched yet.
455  */
456  Buffer rbuffer;
457  BlockNumber savedRightLink;
458  ginxlogSplit data;
459  Buffer lbuffer = InvalidBuffer;
460  Page newrootpg = NULL;
461 
462  /* Get a new index page to become the right page */
463  rbuffer = GinNewBuffer(btree->index);
464 
465  /* During index build, count the new page */
466  if (buildStats)
467  {
468  if (btree->isData)
469  buildStats->nDataPages++;
470  else
471  buildStats->nEntryPages++;
472  }
473 
474  savedRightLink = GinPageGetOpaque(page)->rightlink;
475 
476  /* Begin setting up WAL record */
477  data.node = btree->index->rd_node;
478  data.flags = xlflags;
479  if (BufferIsValid(childbuf))
480  {
481  data.leftChildBlkno = BufferGetBlockNumber(childbuf);
482  data.rightChildBlkno = GinPageGetOpaque(childpage)->rightlink;
483  }
484  else
486 
487  if (stack->parent == NULL)
488  {
489  /*
490  * splitting the root, so we need to allocate new left page and
491  * place pointers to left and right page on root page.
492  */
493  lbuffer = GinNewBuffer(btree->index);
494 
495  /* During index build, count the new left page */
496  if (buildStats)
497  {
498  if (btree->isData)
499  buildStats->nDataPages++;
500  else
501  buildStats->nEntryPages++;
502  }
503 
504  data.rrlink = InvalidBlockNumber;
505  data.flags |= GIN_SPLIT_ROOT;
506 
507  GinPageGetOpaque(newrpage)->rightlink = InvalidBlockNumber;
508  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
509 
510  /*
511  * Construct a new root page containing downlinks to the new left
512  * and right pages. (Do this in a temporary copy rather than
513  * overwriting the original page directly, since we're not in the
514  * critical section yet.)
515  */
516  newrootpg = PageGetTempPage(newrpage);
517  GinInitPage(newrootpg, GinPageGetOpaque(newlpage)->flags & ~(GIN_LEAF | GIN_COMPRESSED), BLCKSZ);
518 
519  btree->fillRoot(btree, newrootpg,
520  BufferGetBlockNumber(lbuffer), newlpage,
521  BufferGetBlockNumber(rbuffer), newrpage);
522 
523  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
524  {
525 
528  BufferGetBlockNumber(lbuffer));
529 
532  BufferGetBlockNumber(rbuffer));
533  }
534 
535  }
536  else
537  {
538  /* splitting a non-root page */
539  data.rrlink = savedRightLink;
540 
541  GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
542  GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
543  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
544 
545  if (GinPageIsLeaf(BufferGetPage(stack->buffer)))
546  {
547 
550  BufferGetBlockNumber(rbuffer));
551  }
552  }
553 
554  /*
555  * OK, we have the new contents of the left page in a temporary copy
556  * now (newlpage), and likewise for the new contents of the
557  * newly-allocated right block. The original page is still unchanged.
558  *
559  * If this is a root split, we also have a temporary page containing
560  * the new contents of the root.
561  */
562 
564 
565  MarkBufferDirty(rbuffer);
566  MarkBufferDirty(stack->buffer);
567 
568  /*
569  * Restore the temporary copies over the real buffers.
570  */
571  if (stack->parent == NULL)
572  {
573  /* Splitting the root, three pages to update */
574  MarkBufferDirty(lbuffer);
575  memcpy(page, newrootpg, BLCKSZ);
576  memcpy(BufferGetPage(lbuffer), newlpage, BLCKSZ);
577  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
578  }
579  else
580  {
581  /* Normal split, only two pages to update */
582  memcpy(page, newlpage, BLCKSZ);
583  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
584  }
585 
586  /* We also clear childbuf's INCOMPLETE_SPLIT flag, if passed */
587  if (BufferIsValid(childbuf))
588  {
589  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
590  MarkBufferDirty(childbuf);
591  }
592 
593  /* write WAL record */
594  if (RelationNeedsWAL(btree->index))
595  {
596  XLogRecPtr recptr;
597 
598  XLogBeginInsert();
599 
600  /*
601  * We just take full page images of all the split pages. Splits
602  * are uncommon enough that it's not worth complicating the code
603  * to be more efficient.
604  */
605  if (stack->parent == NULL)
606  {
610  }
611  else
612  {
615  }
616  if (BufferIsValid(childbuf))
617  XLogRegisterBuffer(3, childbuf, REGBUF_STANDARD);
618 
619  XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
620 
621  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
622 
623  PageSetLSN(page, recptr);
624  PageSetLSN(BufferGetPage(rbuffer), recptr);
625  if (stack->parent == NULL)
626  PageSetLSN(BufferGetPage(lbuffer), recptr);
627  if (BufferIsValid(childbuf))
628  PageSetLSN(childpage, recptr);
629  }
631 
632  /*
633  * We can release the locks/pins on the new pages now, but keep
634  * stack->buffer locked. childbuf doesn't get unlocked either.
635  */
636  UnlockReleaseBuffer(rbuffer);
637  if (stack->parent == NULL)
638  UnlockReleaseBuffer(lbuffer);
639 
640  /*
641  * If we split the root, we're done. Otherwise the split is not
642  * complete until the downlink for the new page has been inserted to
643  * the parent.
644  */
645  result = (stack->parent == NULL);
646  }
647  else
648  {
649  elog(ERROR, "invalid return code from GIN placeToPage method: %d", rc);
650  result = false; /* keep compiler quiet */
651  }
652 
653  /* Clean up temp context */
654  MemoryContextSwitchTo(oldCxt);
655  MemoryContextDelete(tmpCxt);
656 
657  return result;
658 }
659 
660 /*
661  * Finish a split by inserting the downlink for the new page to parent.
662  *
663  * On entry, stack->buffer is exclusively locked.
664  *
665  * If freestack is true, all the buffers are released and unlocked as we
666  * crawl up the tree, and 'stack' is freed. Otherwise stack->buffer is kept
667  * locked, and stack is unmodified, except for possibly moving right to find
668  * the correct parent of page.
669  */
670 static void
671 ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack,
672  GinStatsData *buildStats)
673 {
674  Page page;
675  bool done;
676  bool first = true;
677 
678  /*
679  * freestack == false when we encounter an incompletely split page during
680  * a scan, while freestack == true is used in the normal scenario that a
681  * split is finished right after the initial insert.
682  */
683  if (!freestack)
684  elog(DEBUG1, "finishing incomplete split of block %u in gin index \"%s\"",
685  stack->blkno, RelationGetRelationName(btree->index));
686 
687  /* this loop crawls up the stack until the insertion is complete */
688  do
689  {
690  GinBtreeStack *parent = stack->parent;
691  void *insertdata;
692  BlockNumber updateblkno;
693 
694  /* search parent to lock */
695  LockBuffer(parent->buffer, GIN_EXCLUSIVE);
696 
697  /*
698  * If the parent page was incompletely split, finish that split first,
699  * then continue with the current one.
700  *
701  * Note: we have to finish *all* incomplete splits we encounter, even
702  * if we have to move right. Otherwise we might choose as the target a
703  * page that has no downlink in the parent, and splitting it further
704  * would fail.
705  */
707  ginFinishSplit(btree, parent, false, buildStats);
708 
709  /* move right if it's needed */
710  page = BufferGetPage(parent->buffer);
711  while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
712  {
713  if (GinPageRightMost(page))
714  {
715  /*
716  * rightmost page, but we don't find parent, we should use
717  * plain search...
718  */
719  LockBuffer(parent->buffer, GIN_UNLOCK);
720  ginFindParents(btree, stack);
721  parent = stack->parent;
722  Assert(parent != NULL);
723  break;
724  }
725 
726  parent->buffer = ginStepRight(parent->buffer, btree->index, GIN_EXCLUSIVE);
727  parent->blkno = BufferGetBlockNumber(parent->buffer);
728  page = BufferGetPage(parent->buffer);
729 
731  ginFinishSplit(btree, parent, false, buildStats);
732  }
733 
734  /* insert the downlink */
735  insertdata = btree->prepareDownlink(btree, stack->buffer);
736  updateblkno = GinPageGetOpaque(BufferGetPage(stack->buffer))->rightlink;
737  done = ginPlaceToPage(btree, parent,
738  insertdata, updateblkno,
739  stack->buffer, buildStats);
740  pfree(insertdata);
741 
742  /*
743  * If the caller requested to free the stack, unlock and release the
744  * child buffer now. Otherwise keep it pinned and locked, but if we
745  * have to recurse up the tree, we can unlock the upper pages, only
746  * keeping the page at the bottom of the stack locked.
747  */
748  if (!first || freestack)
749  LockBuffer(stack->buffer, GIN_UNLOCK);
750  if (freestack)
751  {
752  ReleaseBuffer(stack->buffer);
753  pfree(stack);
754  }
755  stack = parent;
756 
757  first = false;
758  } while (!done);
759 
760  /* unlock the parent */
761  LockBuffer(stack->buffer, GIN_UNLOCK);
762 
763  if (freestack)
764  freeGinBtreeStack(stack);
765 }
766 
767 /*
768  * Insert a value to tree described by stack.
769  *
770  * The value to be inserted is given in 'insertdata'. Its format depends
771  * on whether this is an entry or data tree, ginInsertValue just passes it
772  * through to the tree-specific callback function.
773  *
774  * During an index build, buildStats is non-null and the counters it contains
775  * are incremented as needed.
776  *
777  * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
778  */
779 void
780 ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata,
781  GinStatsData *buildStats)
782 {
783  bool done;
784 
785  /* If the leaf page was incompletely split, finish the split first */
787  ginFinishSplit(btree, stack, false, buildStats);
788 
789  done = ginPlaceToPage(btree, stack,
790  insertdata, InvalidBlockNumber,
791  InvalidBuffer, buildStats);
792  if (done)
793  {
794  LockBuffer(stack->buffer, GIN_UNLOCK);
795  freeGinBtreeStack(stack);
796  }
797  else
798  ginFinishSplit(btree, stack, true, buildStats);
799 }
#define GIN_UNLOCK
Definition: gin_private.h:43
BlockNumber nEntryPages
Definition: gin.h:45
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:291
static void ginFindParents(GinBtree btree, GinBtreeStack *stack)
Definition: ginbtree.c:217
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
static void TestForOldSnapshot(Snapshot snapshot, Relation relation, Page page)
Definition: bufmgr.h:265
#define DEBUG1
Definition: elog.h:25
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:156
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:342
OffsetNumber off
Definition: gin_private.h:126
#define GinPageIsIncompleteSplit(page)
Definition: ginblock.h:126
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:1450
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:213
bool(* isMoveRight)(GinBtree, Page)
Definition: gin_private.h:148
#define END_CRIT_SECTION()
Definition: miscadmin.h:133
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:671
BlockNumber rightChildBlkno
Definition: ginxlog.h:119
#define InvalidBuffer
Definition: buf.h:25
#define START_CRIT_SECTION()
Definition: miscadmin.h:131
BlockNumber rootBlkno
Definition: gin_private.h:161
uint32 BlockNumber
Definition: block.h:31
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3309
#define GinPageGetOpaque(page)
Definition: ginblock.h:109
#define GIN_SPLIT_ROOT
Definition: ginxlog.h:128
#define GIN_INSERT_ISLEAF
Definition: ginxlog.h:127
#define GIN_COMPRESSED
Definition: ginblock.h:47
void CheckForSerializableConflictIn(Relation relation, HeapTuple tuple, Buffer buffer)
Definition: predicate.c:4280
uint16 flags
Definition: ginxlog.h:41
uint16 OffsetNumber
Definition: off.h:24
Definition: type.h:89
GinBtreeStack * ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
Definition: ginbtree.c:77
unsigned short uint16
Definition: c.h:324
void pfree(void *pointer)
Definition: mcxt.c:1031
GinPlaceToPageRC
Definition: gin_private.h:136
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:3332
#define ERROR
Definition: elog.h:43
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:153
#define GinPageRightMost(page)
Definition: ginblock.h:128
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:154
BlockNumber(* findChildPage)(GinBtree, GinBtreeStack *)
Definition: gin_private.h:146
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define GIN_INSERT_ISDATA
Definition: ginxlog.h:126
RelFileNode node
Definition: ginxlog.h:115
#define REGBUF_STANDARD
Definition: xloginsert.h:34
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:147
Buffer ginStepRight(Buffer buffer, Relation index, int lockmode)
Definition: ginbtree.c:169
#define RelationGetRelationName(relation)
Definition: rel.h:441
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GIN_SHARE
Definition: gin_private.h:44
#define AllocSetContextCreate(parent, name, allocparams)
Definition: memutils.h:170
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:30
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
Page PageGetTempPage(Page page)
Definition: bufpage.c:348
#define GinPageIsDeleted(page)
Definition: ginblock.h:123
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:3546
void ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
Definition: ginbtree.c:780
Relation index
Definition: gin_private.h:160
#define InvalidOffsetNumber
Definition: off.h:26
BlockNumber nDataPages
Definition: gin.h:46
BlockNumber leftChildBlkno
Definition: ginxlog.h:118
#define GinPageIsData(page)
Definition: ginblock.h:114
RelFileNode rd_node
Definition: rel.h:55
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:699
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
Buffer ReadBuffer(Relation reln, BlockNumber blockNum)
Definition: bufmgr.c:594
#define InvalidBlockNumber
Definition: block.h:33
Buffer ReleaseAndReadBuffer(Buffer buffer, Relation relation, BlockNumber blockNum)
Definition: bufmgr.c:1513
#define BufferIsValid(bufnum)
Definition: bufmgr.h:114
BlockNumber blkno
Definition: gin_private.h:124
#define RelationNeedsWAL(relation)
Definition: rel.h:510
#define BlockIdSet(blockId, blockNumber)
Definition: block.h:84
BlockNumber rrlink
Definition: ginxlog.h:116
uint32 predictNumber
Definition: gin_private.h:129
#define GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:45
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:2605
#define XLOG_GIN_INSERT
Definition: ginxlog.h:37
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:155
void * palloc(Size size)
Definition: mcxt.c:924
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:197
#define elog
Definition: elog.h:219
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:152
void XLogBeginInsert(void)
Definition: xloginsert.c:120
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:333
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
uint16 flags
Definition: ginxlog.h:120
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3065
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:111
Pointer Page
Definition: bufpage.h:74
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:36
#define GIN_LEAF
Definition: ginblock.h:40