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-2017, 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 "utils/memutils.h"
22 #include "utils/rel.h"
23 
24 static void ginFindParents(GinBtree btree, GinBtreeStack *stack);
25 static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
26  void *insertdata, BlockNumber updateblkno,
27  Buffer childbuf, GinStatsData *buildStats);
28 static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack,
29  bool freestack, GinStatsData *buildStats);
30 
31 /*
32  * Lock buffer by needed method for search.
33  */
34 int
35 ginTraverseLock(Buffer buffer, bool searchMode)
36 {
37  Page page;
38  int access = GIN_SHARE;
39 
40  LockBuffer(buffer, GIN_SHARE);
41  page = BufferGetPage(buffer);
42  if (GinPageIsLeaf(page))
43  {
44  if (searchMode == false)
45  {
46  /* we should relock our page */
47  LockBuffer(buffer, GIN_UNLOCK);
48  LockBuffer(buffer, GIN_EXCLUSIVE);
49 
50  /* But root can become non-leaf during relock */
51  if (!GinPageIsLeaf(page))
52  {
53  /* restore old lock type (very rare) */
54  LockBuffer(buffer, GIN_UNLOCK);
55  LockBuffer(buffer, GIN_SHARE);
56  }
57  else
58  access = GIN_EXCLUSIVE;
59  }
60  }
61 
62  return access;
63 }
64 
65 /*
66  * Descend the tree to the leaf page that contains or would contain the key
67  * we're searching for. The key should already be filled in 'btree', in
68  * tree-type specific manner. If btree->fullScan is true, descends to the
69  * leftmost leaf page.
70  *
71  * If 'searchmode' is false, on return stack->buffer is exclusively locked,
72  * and the stack represents the full path to the root. Otherwise stack->buffer
73  * is share-locked, and stack->parent is NULL.
74  */
76 ginFindLeafPage(GinBtree btree, bool searchMode, Snapshot snapshot)
77 {
78  GinBtreeStack *stack;
79 
80  stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
81  stack->blkno = btree->rootBlkno;
82  stack->buffer = ReadBuffer(btree->index, btree->rootBlkno);
83  stack->parent = NULL;
84  stack->predictNumber = 1;
85 
86  for (;;)
87  {
88  Page page;
89  BlockNumber child;
90  int access;
91 
92  stack->off = InvalidOffsetNumber;
93 
94  page = BufferGetPage(stack->buffer);
95  TestForOldSnapshot(snapshot, btree->index, page);
96 
97  access = ginTraverseLock(stack->buffer, searchMode);
98 
99  /*
100  * If we're going to modify the tree, finish any incomplete splits we
101  * encounter on the way.
102  */
103  if (!searchMode && GinPageIsIncompleteSplit(page))
104  ginFinishSplit(btree, stack, false, NULL);
105 
106  /*
107  * ok, page is correctly locked, we should check to move right ..,
108  * root never has a right link, so small optimization
109  */
110  while (btree->fullScan == false && stack->blkno != btree->rootBlkno &&
111  btree->isMoveRight(btree, page))
112  {
113  BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
114 
115  if (rightlink == InvalidBlockNumber)
116  /* rightmost page */
117  break;
118 
119  stack->buffer = ginStepRight(stack->buffer, btree->index, access);
120  stack->blkno = rightlink;
121  page = BufferGetPage(stack->buffer);
122  TestForOldSnapshot(snapshot, btree->index, page);
123 
124  if (!searchMode && GinPageIsIncompleteSplit(page))
125  ginFinishSplit(btree, stack, false, NULL);
126  }
127 
128  if (GinPageIsLeaf(page)) /* we found, return locked page */
129  return stack;
130 
131  /* now we have correct buffer, try to find child */
132  child = btree->findChildPage(btree, stack);
133 
134  LockBuffer(stack->buffer, GIN_UNLOCK);
135  Assert(child != InvalidBlockNumber);
136  Assert(stack->blkno != child);
137 
138  if (searchMode)
139  {
140  /* in search mode we may forget path to leaf */
141  stack->blkno = child;
142  stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
143  }
144  else
145  {
146  GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
147 
148  ptr->parent = stack;
149  stack = ptr;
150  stack->blkno = child;
151  stack->buffer = ReadBuffer(btree->index, stack->blkno);
152  stack->predictNumber = 1;
153  }
154  }
155 }
156 
157 /*
158  * Step right from current page.
159  *
160  * The next page is locked first, before releasing the current page. This is
161  * crucial to protect from concurrent page deletion (see comment in
162  * ginDeletePage).
163  */
164 Buffer
166 {
167  Buffer nextbuffer;
168  Page page = BufferGetPage(buffer);
169  bool isLeaf = GinPageIsLeaf(page);
170  bool isData = GinPageIsData(page);
171  BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
172 
173  nextbuffer = ReadBuffer(index, blkno);
174  LockBuffer(nextbuffer, lockmode);
175  UnlockReleaseBuffer(buffer);
176 
177  /* Sanity check that the page we stepped to is of similar kind. */
178  page = BufferGetPage(nextbuffer);
179  if (isLeaf != GinPageIsLeaf(page) || isData != GinPageIsData(page))
180  elog(ERROR, "right sibling of GIN page is of different type");
181 
182  /*
183  * Given the proper lock sequence above, we should never land on a deleted
184  * page.
185  */
186  if (GinPageIsDeleted(page))
187  elog(ERROR, "right sibling of GIN page was deleted");
188 
189  return nextbuffer;
190 }
191 
192 void
194 {
195  while (stack)
196  {
197  GinBtreeStack *tmp = stack->parent;
198 
199  if (stack->buffer != InvalidBuffer)
200  ReleaseBuffer(stack->buffer);
201 
202  pfree(stack);
203  stack = tmp;
204  }
205 }
206 
207 /*
208  * Try to find parent for current stack position. Returns correct parent and
209  * child's offset in stack->parent. The root page is never released, to
210  * to prevent conflict with vacuum process.
211  */
212 static void
214 {
215  Page page;
216  Buffer buffer;
217  BlockNumber blkno,
218  leftmostBlkno;
219  OffsetNumber offset;
220  GinBtreeStack *root;
221  GinBtreeStack *ptr;
222 
223  /*
224  * Unwind the stack all the way up to the root, leaving only the root
225  * item.
226  *
227  * Be careful not to release the pin on the root page! The pin on root
228  * page is required to lock out concurrent vacuums on the tree.
229  */
230  root = stack->parent;
231  while (root->parent)
232  {
233  ReleaseBuffer(root->buffer);
234  root = root->parent;
235  }
236 
237  Assert(root->blkno == btree->rootBlkno);
238  Assert(BufferGetBlockNumber(root->buffer) == btree->rootBlkno);
239  root->off = InvalidOffsetNumber;
240 
241  blkno = root->blkno;
242  buffer = root->buffer;
243  offset = InvalidOffsetNumber;
244 
245  ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
246 
247  for (;;)
248  {
249  LockBuffer(buffer, GIN_EXCLUSIVE);
250  page = BufferGetPage(buffer);
251  if (GinPageIsLeaf(page))
252  elog(ERROR, "Lost path");
253 
254  if (GinPageIsIncompleteSplit(page))
255  {
256  Assert(blkno != btree->rootBlkno);
257  ptr->blkno = blkno;
258  ptr->buffer = buffer;
259 
260  /*
261  * parent may be wrong, but if so, the ginFinishSplit call will
262  * recurse to call ginFindParents again to fix it.
263  */
264  ptr->parent = root;
265  ptr->off = InvalidOffsetNumber;
266 
267  ginFinishSplit(btree, ptr, false, NULL);
268  }
269 
270  leftmostBlkno = btree->getLeftMostChild(btree, page);
271 
272  while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
273  {
274  blkno = GinPageGetOpaque(page)->rightlink;
275  if (blkno == InvalidBlockNumber)
276  {
277  UnlockReleaseBuffer(buffer);
278  break;
279  }
280  buffer = ginStepRight(buffer, btree->index, GIN_EXCLUSIVE);
281  page = BufferGetPage(buffer);
282 
283  /* finish any incomplete splits, as above */
284  if (GinPageIsIncompleteSplit(page))
285  {
286  Assert(blkno != btree->rootBlkno);
287  ptr->blkno = blkno;
288  ptr->buffer = buffer;
289  ptr->parent = root;
290  ptr->off = InvalidOffsetNumber;
291 
292  ginFinishSplit(btree, ptr, false, NULL);
293  }
294  }
295 
296  if (blkno != InvalidBlockNumber)
297  {
298  ptr->blkno = blkno;
299  ptr->buffer = buffer;
300  ptr->parent = root; /* it may be wrong, but in next call we will
301  * correct */
302  ptr->off = offset;
303  stack->parent = ptr;
304  return;
305  }
306 
307  /* Descend down to next level */
308  blkno = leftmostBlkno;
309  buffer = ReadBuffer(btree->index, blkno);
310  }
311 }
312 
313 /*
314  * Insert a new item to a page.
315  *
316  * Returns true if the insertion was finished. On false, the page was split and
317  * the parent needs to be updated. (A root split returns true as it doesn't
318  * need any further action by the caller to complete.)
319  *
320  * When inserting a downlink to an internal page, 'childbuf' contains the
321  * child page that was split. Its GIN_INCOMPLETE_SPLIT flag will be cleared
322  * atomically with the insert. Also, the existing item at offset stack->off
323  * in the target page is updated to point to updateblkno.
324  *
325  * stack->buffer is locked on entry, and is kept locked.
326  * Likewise for childbuf, if given.
327  */
328 static bool
330  void *insertdata, BlockNumber updateblkno,
331  Buffer childbuf, GinStatsData *buildStats)
332 {
333  Page page = BufferGetPage(stack->buffer);
334  bool result;
335  GinPlaceToPageRC rc;
336  uint16 xlflags = 0;
337  Page childpage = NULL;
338  Page newlpage = NULL,
339  newrpage = NULL;
340  void *ptp_workspace = NULL;
341  MemoryContext tmpCxt;
342  MemoryContext oldCxt;
343 
344  /*
345  * We do all the work of this function and its subfunctions in a temporary
346  * memory context. This avoids leakages and simplifies APIs, since some
347  * subfunctions allocate storage that has to survive until we've finished
348  * the WAL insertion.
349  */
351  "ginPlaceToPage temporary context",
353  oldCxt = MemoryContextSwitchTo(tmpCxt);
354 
355  if (GinPageIsData(page))
356  xlflags |= GIN_INSERT_ISDATA;
357  if (GinPageIsLeaf(page))
358  {
359  xlflags |= GIN_INSERT_ISLEAF;
360  Assert(!BufferIsValid(childbuf));
361  Assert(updateblkno == InvalidBlockNumber);
362  }
363  else
364  {
365  Assert(BufferIsValid(childbuf));
366  Assert(updateblkno != InvalidBlockNumber);
367  childpage = BufferGetPage(childbuf);
368  }
369 
370  /*
371  * See if the incoming tuple will fit on the page. beginPlaceToPage will
372  * decide if the page needs to be split, and will compute the split
373  * contents if so. See comments for beginPlaceToPage and execPlaceToPage
374  * functions for more details of the API here.
375  */
376  rc = btree->beginPlaceToPage(btree, stack->buffer, stack,
377  insertdata, updateblkno,
378  &ptp_workspace,
379  &newlpage, &newrpage);
380 
381  if (rc == GPTP_NO_WORK)
382  {
383  /* Nothing to do */
384  result = true;
385  }
386  else if (rc == GPTP_INSERT)
387  {
388  /* It will fit, perform the insertion */
390 
391  if (RelationNeedsWAL(btree->index))
392  {
393  XLogBeginInsert();
395  if (BufferIsValid(childbuf))
396  XLogRegisterBuffer(1, childbuf, REGBUF_STANDARD);
397  }
398 
399  /* Perform the page update, and register any extra WAL data */
400  btree->execPlaceToPage(btree, stack->buffer, stack,
401  insertdata, updateblkno, ptp_workspace);
402 
403  MarkBufferDirty(stack->buffer);
404 
405  /* An insert to an internal page finishes the split of the child. */
406  if (BufferIsValid(childbuf))
407  {
408  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
409  MarkBufferDirty(childbuf);
410  }
411 
412  if (RelationNeedsWAL(btree->index))
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;
454  ginxlogSplit data;
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.node = btree->index->rd_node;
474  data.flags = xlflags;
475  if (BufferIsValid(childbuf))
476  {
477  data.leftChildBlkno = BufferGetBlockNumber(childbuf);
478  data.rightChildBlkno = GinPageGetOpaque(childpage)->rightlink;
479  }
480  else
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  else
520  {
521  /* splitting a non-root page */
522  data.rrlink = savedRightLink;
523 
524  GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
525  GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
526  GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
527  }
528 
529  /*
530  * OK, we have the new contents of the left page in a temporary copy
531  * now (newlpage), and likewise for the new contents of the
532  * newly-allocated right block. The original page is still unchanged.
533  *
534  * If this is a root split, we also have a temporary page containing
535  * the new contents of the root.
536  */
537 
539 
540  MarkBufferDirty(rbuffer);
541  MarkBufferDirty(stack->buffer);
542 
543  /*
544  * Restore the temporary copies over the real buffers.
545  */
546  if (stack->parent == NULL)
547  {
548  /* Splitting the root, three pages to update */
549  MarkBufferDirty(lbuffer);
550  memcpy(page, newrootpg, BLCKSZ);
551  memcpy(BufferGetPage(lbuffer), newlpage, BLCKSZ);
552  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
553  }
554  else
555  {
556  /* Normal split, only two pages to update */
557  memcpy(page, newlpage, BLCKSZ);
558  memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
559  }
560 
561  /* We also clear childbuf's INCOMPLETE_SPLIT flag, if passed */
562  if (BufferIsValid(childbuf))
563  {
564  GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
565  MarkBufferDirty(childbuf);
566  }
567 
568  /* write WAL record */
569  if (RelationNeedsWAL(btree->index))
570  {
571  XLogRecPtr recptr;
572 
573  XLogBeginInsert();
574 
575  /*
576  * We just take full page images of all the split pages. Splits
577  * are uncommon enough that it's not worth complicating the code
578  * to be more efficient.
579  */
580  if (stack->parent == NULL)
581  {
585  }
586  else
587  {
590  }
591  if (BufferIsValid(childbuf))
592  XLogRegisterBuffer(3, childbuf, REGBUF_STANDARD);
593 
594  XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
595 
596  recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
597 
598  PageSetLSN(page, recptr);
599  PageSetLSN(BufferGetPage(rbuffer), recptr);
600  if (stack->parent == NULL)
601  PageSetLSN(BufferGetPage(lbuffer), recptr);
602  if (BufferIsValid(childbuf))
603  PageSetLSN(childpage, recptr);
604  }
606 
607  /*
608  * We can release the locks/pins on the new pages now, but keep
609  * stack->buffer locked. childbuf doesn't get unlocked either.
610  */
611  UnlockReleaseBuffer(rbuffer);
612  if (stack->parent == NULL)
613  UnlockReleaseBuffer(lbuffer);
614 
615  /*
616  * If we split the root, we're done. Otherwise the split is not
617  * complete until the downlink for the new page has been inserted to
618  * the parent.
619  */
620  result = (stack->parent == NULL);
621  }
622  else
623  {
624  elog(ERROR, "invalid return code from GIN placeToPage method: %d", rc);
625  result = false; /* keep compiler quiet */
626  }
627 
628  /* Clean up temp context */
629  MemoryContextSwitchTo(oldCxt);
630  MemoryContextDelete(tmpCxt);
631 
632  return result;
633 }
634 
635 /*
636  * Finish a split by inserting the downlink for the new page to parent.
637  *
638  * On entry, stack->buffer is exclusively locked.
639  *
640  * If freestack is true, all the buffers are released and unlocked as we
641  * crawl up the tree, and 'stack' is freed. Otherwise stack->buffer is kept
642  * locked, and stack is unmodified, except for possibly moving right to find
643  * the correct parent of page.
644  */
645 static void
646 ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack,
647  GinStatsData *buildStats)
648 {
649  Page page;
650  bool done;
651  bool first = true;
652 
653  /*
654  * freestack == false when we encounter an incompletely split page during
655  * a scan, while freestack == true is used in the normal scenario that a
656  * split is finished right after the initial insert.
657  */
658  if (!freestack)
659  elog(DEBUG1, "finishing incomplete split of block %u in gin index \"%s\"",
660  stack->blkno, RelationGetRelationName(btree->index));
661 
662  /* this loop crawls up the stack until the insertion is complete */
663  do
664  {
665  GinBtreeStack *parent = stack->parent;
666  void *insertdata;
667  BlockNumber updateblkno;
668 
669  /* search parent to lock */
670  LockBuffer(parent->buffer, GIN_EXCLUSIVE);
671 
672  /*
673  * If the parent page was incompletely split, finish that split first,
674  * then continue with the current one.
675  *
676  * Note: we have to finish *all* incomplete splits we encounter, even
677  * if we have to move right. Otherwise we might choose as the target a
678  * page that has no downlink in the parent, and splitting it further
679  * would fail.
680  */
682  ginFinishSplit(btree, parent, false, buildStats);
683 
684  /* move right if it's needed */
685  page = BufferGetPage(parent->buffer);
686  while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
687  {
688  if (GinPageRightMost(page))
689  {
690  /*
691  * rightmost page, but we don't find parent, we should use
692  * plain search...
693  */
694  LockBuffer(parent->buffer, GIN_UNLOCK);
695  ginFindParents(btree, stack);
696  parent = stack->parent;
697  Assert(parent != NULL);
698  break;
699  }
700 
701  parent->buffer = ginStepRight(parent->buffer, btree->index, GIN_EXCLUSIVE);
702  parent->blkno = BufferGetBlockNumber(parent->buffer);
703  page = BufferGetPage(parent->buffer);
704 
706  ginFinishSplit(btree, parent, false, buildStats);
707  }
708 
709  /* insert the downlink */
710  insertdata = btree->prepareDownlink(btree, stack->buffer);
711  updateblkno = GinPageGetOpaque(BufferGetPage(stack->buffer))->rightlink;
712  done = ginPlaceToPage(btree, parent,
713  insertdata, updateblkno,
714  stack->buffer, buildStats);
715  pfree(insertdata);
716 
717  /*
718  * If the caller requested to free the stack, unlock and release the
719  * child buffer now. Otherwise keep it pinned and locked, but if we
720  * have to recurse up the tree, we can unlock the upper pages, only
721  * keeping the page at the bottom of the stack locked.
722  */
723  if (!first || freestack)
724  LockBuffer(stack->buffer, GIN_UNLOCK);
725  if (freestack)
726  {
727  ReleaseBuffer(stack->buffer);
728  pfree(stack);
729  }
730  stack = parent;
731 
732  first = false;
733  } while (!done);
734 
735  /* unlock the parent */
736  LockBuffer(stack->buffer, GIN_UNLOCK);
737 
738  if (freestack)
739  freeGinBtreeStack(stack);
740 }
741 
742 /*
743  * Insert a value to tree described by stack.
744  *
745  * The value to be inserted is given in 'insertdata'. Its format depends
746  * on whether this is an entry or data tree, ginInsertValue just passes it
747  * through to the tree-specific callback function.
748  *
749  * During an index build, buildStats is non-null and the counters it contains
750  * are incremented as needed.
751  *
752  * NB: the passed-in stack is freed, as though by freeGinBtreeStack.
753  */
754 void
755 ginInsertValue(GinBtree btree, GinBtreeStack *stack, void *insertdata,
756  GinStatsData *buildStats)
757 {
758  bool done;
759 
760  /* If the leaf page was incompletely split, finish the split first */
762  ginFinishSplit(btree, stack, false, buildStats);
763 
764  done = ginPlaceToPage(btree, stack,
765  insertdata, InvalidBlockNumber,
766  InvalidBuffer, buildStats);
767  if (done)
768  {
769  LockBuffer(stack->buffer, GIN_UNLOCK);
770  freeGinBtreeStack(stack);
771  }
772  else
773  ginFinishSplit(btree, stack, true, buildStats);
774 }
#define GIN_UNLOCK
Definition: gin_private.h:43
BlockNumber nEntryPages
Definition: gin.h:45
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:289
static void ginFindParents(GinBtree btree, GinBtreeStack *stack)
Definition: ginbtree.c:213
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
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:340
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:646
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
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:76
unsigned short uint16
Definition: c.h:295
void pfree(void *pointer)
Definition: mcxt.c:949
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:165
#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:165
#define RelationGetRelationName(relation)
Definition: rel.h:436
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define GinPageIsLeaf(page)
Definition: ginblock.h:111
#define BufferGetPage(buffer)
Definition: bufmgr.h:160
#define GIN_SHARE
Definition: gin_private.h:44
#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
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:322
#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:755
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:85
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:670
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:214
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:505
#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:848
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:193
#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:329
#define PageSetLSN(page, lsn)
Definition: bufpage.h:364
int Buffer
Definition: buf.h:23
uint16 flags
Definition: ginxlog.h:120
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:111
Pointer Page
Definition: bufpage.h:74
int ginTraverseLock(Buffer buffer, bool searchMode)
Definition: ginbtree.c:35
#define GIN_LEAF
Definition: ginblock.h:40