PostgreSQL Source Code git master
ginbtree.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
#include "miscadmin.h"
#include "storage/predicate.h"
#include "utils/injection_point.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)
 
static void ginFinishOldSplit (GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats, int access)
 
int ginTraverseLock (Buffer buffer, bool searchMode)
 
GinBtreeStackginFindLeafPage (GinBtree btree, bool searchMode, bool rootConflictCheck)
 
Buffer ginStepRight (Buffer buffer, Relation index, int lockmode)
 
void freeGinBtreeStack (GinBtreeStack *stack)
 
void ginInsertValue (GinBtree btree, GinBtreeStack *stack, void *insertdata, GinStatsData *buildStats)
 

Function Documentation

◆ freeGinBtreeStack()

void freeGinBtreeStack ( GinBtreeStack stack)

Definition at line 198 of file ginbtree.c.

199{
200 while (stack)
201 {
202 GinBtreeStack *tmp = stack->parent;
203
204 if (stack->buffer != InvalidBuffer)
205 ReleaseBuffer(stack->buffer);
206
207 pfree(stack);
208 stack = tmp;
209 }
210}
#define InvalidBuffer
Definition: buf.h:25
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4866
void pfree(void *pointer)
Definition: mcxt.c:1521
struct GinBtreeStack * parent
Definition: gin_private.h:137

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

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

◆ ginFindLeafPage()

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

Definition at line 83 of file ginbtree.c.

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

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage(), CheckForSerializableConflictIn(), GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_UNLOCK, ginFinishOldSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), ReleaseAndReadBuffer(), and GinBtreeData::rootBlkno.

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

◆ ginFindParents()

static void ginFindParents ( GinBtree  btree,
GinBtreeStack stack 
)
static

Definition at line 218 of file ginbtree.c.

219{
220 Page page;
221 Buffer buffer;
222 BlockNumber blkno,
223 leftmostBlkno;
224 OffsetNumber offset;
226 GinBtreeStack *ptr;
227
228 /*
229 * Unwind the stack all the way up to the root, leaving only the root
230 * item.
231 *
232 * Be careful not to release the pin on the root page! The pin on root
233 * page is required to lock out concurrent vacuums on the tree.
234 */
235 root = stack->parent;
236 while (root->parent)
237 {
238 ReleaseBuffer(root->buffer);
239 root = root->parent;
240 }
241
242 Assert(root->blkno == btree->rootBlkno);
243 Assert(BufferGetBlockNumber(root->buffer) == btree->rootBlkno);
245
246 blkno = root->blkno;
247 buffer = root->buffer;
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;
270
271 ginFinishOldSplit(btree, ptr, NULL, GIN_EXCLUSIVE);
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 /* Link not present in this level */
282 LockBuffer(buffer, GIN_UNLOCK);
283 /* Do not release pin on the root buffer */
284 if (buffer != root->buffer)
285 ReleaseBuffer(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;
299
300 ginFinishOldSplit(btree, ptr, NULL, GIN_EXCLUSIVE);
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}
int Buffer
Definition: buf.h:23
BlockNumber BufferGetBlockNumber(Buffer buffer)
Definition: bufmgr.c:3724
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define GIN_EXCLUSIVE
Definition: gin_private.h:51
uint16 OffsetNumber
Definition: off.h:24
tree ctl root
Definition: radixtree.h:1857
BlockNumber(* getLeftMostChild)(GinBtree, Page)
Definition: gin_private.h:154
OffsetNumber(* findChildPtr)(GinBtree, Page, BlockNumber, OffsetNumber)
Definition: gin_private.h:159

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage(), elog, ERROR, GinBtreeData::findChildPtr, GinBtreeData::getLeftMostChild, GIN_EXCLUSIVE, GIN_UNLOCK, ginFinishOldSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, ginStepRight(), GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, ReadBuffer(), ReleaseBuffer(), root, and GinBtreeData::rootBlkno.

Referenced by ginFinishSplit().

◆ ginFinishOldSplit()

static void ginFinishOldSplit ( GinBtree  btree,
GinBtreeStack stack,
GinStatsData buildStats,
int  access 
)
static

Definition at line 779 of file ginbtree.c.

780{
781 INJECTION_POINT("gin-finish-incomplete-split");
782 elog(DEBUG1, "finishing incomplete split of block %u in gin index \"%s\"",
783 stack->blkno, RelationGetRelationName(btree->index));
784
785 if (access == GIN_SHARE)
786 {
789
791 {
792 /*
793 * Someone else already completed the split while we were not
794 * holding the lock.
795 */
796 return;
797 }
798 }
799
800 ginFinishSplit(btree, stack, false, buildStats);
801}
#define DEBUG1
Definition: elog.h:30
#define GIN_SHARE
Definition: gin_private.h:50
static void ginFinishSplit(GinBtree btree, GinBtreeStack *stack, bool freestack, GinStatsData *buildStats)
Definition: ginbtree.c:672
#define INJECTION_POINT(name)
#define RelationGetRelationName(relation)
Definition: rel.h:539

References GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage(), DEBUG1, elog, GIN_EXCLUSIVE, GIN_SHARE, GIN_UNLOCK, ginFinishSplit(), GinPageIsIncompleteSplit, GinBtreeData::index, INJECTION_POINT, LockBuffer(), and RelationGetRelationName.

Referenced by ginFindLeafPage(), ginFindParents(), ginFinishSplit(), and ginInsertValue().

◆ ginFinishSplit()

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

Definition at line 672 of file ginbtree.c.

674{
675 Page page;
676 bool done;
677 bool first = true;
678
679 /* this loop crawls up the stack until the insertion is complete */
680 do
681 {
682 GinBtreeStack *parent = stack->parent;
683 void *insertdata;
684 BlockNumber updateblkno;
685
686#ifdef USE_INJECTION_POINTS
688 INJECTION_POINT("gin-leave-leaf-split-incomplete");
689 else
690 INJECTION_POINT("gin-leave-internal-split-incomplete");
691#endif
692
693 /* search parent to lock */
695
696 /*
697 * If the parent page was incompletely split, finish that split first,
698 * then continue with the current one.
699 *
700 * Note: we have to finish *all* incomplete splits we encounter, even
701 * if we have to move right. Otherwise we might choose as the target a
702 * page that has no downlink in the parent, and splitting it further
703 * would fail.
704 */
706 ginFinishOldSplit(btree, parent, buildStats, GIN_EXCLUSIVE);
707
708 /* move right if it's needed */
709 page = BufferGetPage(parent->buffer);
710 while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
711 {
712 if (GinPageRightMost(page))
713 {
714 /*
715 * rightmost page, but we don't find parent, we should use
716 * plain search...
717 */
718 LockBuffer(parent->buffer, GIN_UNLOCK);
719 ginFindParents(btree, stack);
720 parent = stack->parent;
721 Assert(parent != NULL);
722 break;
723 }
724
725 parent->buffer = ginStepRight(parent->buffer, btree->index, GIN_EXCLUSIVE);
726 parent->blkno = BufferGetBlockNumber(parent->buffer);
727 page = BufferGetPage(parent->buffer);
728
730 ginFinishOldSplit(btree, parent, buildStats, GIN_EXCLUSIVE);
731 }
732
733 /* insert the downlink */
734 insertdata = btree->prepareDownlink(btree, stack->buffer);
735 updateblkno = GinPageGetOpaque(BufferGetPage(stack->buffer))->rightlink;
736 done = ginPlaceToPage(btree, parent,
737 insertdata, updateblkno,
738 stack->buffer, buildStats);
739 pfree(insertdata);
740
741 /*
742 * If the caller requested to free the stack, unlock and release the
743 * child buffer now. Otherwise keep it pinned and locked, but if we
744 * have to recurse up the tree, we can unlock the upper pages, only
745 * keeping the page at the bottom of the stack locked.
746 */
747 if (!first || freestack)
749 if (freestack)
750 {
751 ReleaseBuffer(stack->buffer);
752 pfree(stack);
753 }
754 stack = parent;
755
756 first = false;
757 } while (!done);
758
759 /* unlock the parent */
761
762 if (freestack)
763 freeGinBtreeStack(stack);
764}
#define GinPageRightMost(page)
Definition: ginblock.h:129
void freeGinBtreeStack(GinBtreeStack *stack)
Definition: ginbtree.c:198
static bool ginPlaceToPage(GinBtree btree, GinBtreeStack *stack, void *insertdata, BlockNumber updateblkno, Buffer childbuf, GinStatsData *buildStats)
Definition: ginbtree.c:337
static void ginFindParents(GinBtree btree, GinBtreeStack *stack)
Definition: ginbtree.c:218
void *(* prepareDownlink)(GinBtree, Buffer)
Definition: gin_private.h:162

References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage(), GinBtreeData::findChildPtr, freeGinBtreeStack(), GIN_EXCLUSIVE, GIN_UNLOCK, ginFindParents(), ginFinishOldSplit(), GinPageGetOpaque, GinPageIsIncompleteSplit, GinPageIsLeaf, GinPageRightMost, ginPlaceToPage(), ginStepRight(), GinBtreeData::index, INJECTION_POINT, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, GinBtreeStack::parent, pfree(), GinBtreeData::prepareDownlink, and ReleaseBuffer().

Referenced by ginFinishOldSplit(), and ginInsertValue().

◆ ginInsertValue()

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

Definition at line 816 of file ginbtree.c.

818{
819 bool done;
820
821 /* If the leaf page was incompletely split, finish the split first */
823 ginFinishOldSplit(btree, stack, buildStats, GIN_EXCLUSIVE);
824
825 done = ginPlaceToPage(btree, stack,
826 insertdata, InvalidBlockNumber,
827 InvalidBuffer, buildStats);
828 if (done)
829 {
831 freeGinBtreeStack(stack);
832 }
833 else
834 ginFinishSplit(btree, stack, true, buildStats);
835}

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

Referenced by ginEntryInsert(), and ginInsertItemPointers().

◆ ginPlaceToPage()

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

Definition at line 337 of file ginbtree.c.

340{
341 Page page = BufferGetPage(stack->buffer);
342 bool result;
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)
401
402 /*
403 * Perform the page update, dirty and register stack->buffer, and
404 * register any extra WAL data.
405 */
406 btree->execPlaceToPage(btree, stack->buffer, stack,
407 insertdata, updateblkno, ptp_workspace);
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 if (RelationNeedsWAL(btree->index) && !btree->isBuild)
416 }
417
418 if (RelationNeedsWAL(btree->index) && !btree->isBuild)
419 {
420 XLogRecPtr recptr;
421 ginxlogInsert xlrec;
422 BlockIdData childblknos[2];
423
424 xlrec.flags = xlflags;
425
426 XLogRegisterData((char *) &xlrec, sizeof(ginxlogInsert));
427
428 /*
429 * Log information about child if this was an insertion of a
430 * downlink.
431 */
432 if (BufferIsValid(childbuf))
433 {
434 BlockIdSet(&childblknos[0], BufferGetBlockNumber(childbuf));
435 BlockIdSet(&childblknos[1], GinPageGetOpaque(childpage)->rightlink);
436 XLogRegisterData((char *) childblknos,
437 sizeof(BlockIdData) * 2);
438 }
439
440 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT);
441 PageSetLSN(page, recptr);
442 if (BufferIsValid(childbuf))
443 PageSetLSN(childpage, recptr);
444 }
445
447
448 /* Insertion is complete. */
449 result = true;
450 }
451 else if (rc == GPTP_SPLIT)
452 {
453 /*
454 * Didn't fit, need to split. The split has been computed in newlpage
455 * and newrpage, which are pointers to palloc'd pages, not associated
456 * with buffers. stack->buffer is not touched yet.
457 */
458 Buffer rbuffer;
459 BlockNumber savedRightLink;
461 Buffer lbuffer = InvalidBuffer;
462 Page newrootpg = NULL;
463
464 /* Get a new index page to become the right page */
465 rbuffer = GinNewBuffer(btree->index);
466
467 /* During index build, count the new page */
468 if (buildStats)
469 {
470 if (btree->isData)
471 buildStats->nDataPages++;
472 else
473 buildStats->nEntryPages++;
474 }
475
476 savedRightLink = GinPageGetOpaque(page)->rightlink;
477
478 /* Begin setting up WAL record */
479 data.locator = btree->index->rd_locator;
480 data.flags = xlflags;
481 if (BufferIsValid(childbuf))
482 {
483 data.leftChildBlkno = BufferGetBlockNumber(childbuf);
484 data.rightChildBlkno = GinPageGetOpaque(childpage)->rightlink;
485 }
486 else
487 data.leftChildBlkno = data.rightChildBlkno = InvalidBlockNumber;
488
489 if (stack->parent == NULL)
490 {
491 /*
492 * splitting the root, so we need to allocate new left page and
493 * place pointers to left and right page on root page.
494 */
495 lbuffer = GinNewBuffer(btree->index);
496
497 /* During index build, count the new left page */
498 if (buildStats)
499 {
500 if (btree->isData)
501 buildStats->nDataPages++;
502 else
503 buildStats->nEntryPages++;
504 }
505
506 data.rrlink = InvalidBlockNumber;
507 data.flags |= GIN_SPLIT_ROOT;
508
509 GinPageGetOpaque(newrpage)->rightlink = InvalidBlockNumber;
510 GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
511
512 /*
513 * Construct a new root page containing downlinks to the new left
514 * and right pages. (Do this in a temporary copy rather than
515 * overwriting the original page directly, since we're not in the
516 * critical section yet.)
517 */
518 newrootpg = PageGetTempPage(newrpage);
519 GinInitPage(newrootpg, GinPageGetOpaque(newlpage)->flags & ~(GIN_LEAF | GIN_COMPRESSED), BLCKSZ);
520
521 btree->fillRoot(btree, newrootpg,
522 BufferGetBlockNumber(lbuffer), newlpage,
523 BufferGetBlockNumber(rbuffer), newrpage);
524
526 {
527
530 BufferGetBlockNumber(lbuffer));
531
534 BufferGetBlockNumber(rbuffer));
535 }
536 }
537 else
538 {
539 /* splitting a non-root page */
540 data.rrlink = savedRightLink;
541
542 GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
543 GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
544 GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
545
547 {
548
551 BufferGetBlockNumber(rbuffer));
552 }
553 }
554
555 /*
556 * OK, we have the new contents of the left page in a temporary copy
557 * now (newlpage), and likewise for the new contents of the
558 * newly-allocated right block. The original page is still unchanged.
559 *
560 * If this is a root split, we also have a temporary page containing
561 * the new contents of the root.
562 */
563
565
566 MarkBufferDirty(rbuffer);
567 MarkBufferDirty(stack->buffer);
568
569 /*
570 * Restore the temporary copies over the real buffers.
571 */
572 if (stack->parent == NULL)
573 {
574 /* Splitting the root, three pages to update */
575 MarkBufferDirty(lbuffer);
576 memcpy(page, newrootpg, BLCKSZ);
577 memcpy(BufferGetPage(lbuffer), newlpage, BLCKSZ);
578 memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
579 }
580 else
581 {
582 /* Normal split, only two pages to update */
583 memcpy(page, newlpage, BLCKSZ);
584 memcpy(BufferGetPage(rbuffer), newrpage, BLCKSZ);
585 }
586
587 /* We also clear childbuf's INCOMPLETE_SPLIT flag, if passed */
588 if (BufferIsValid(childbuf))
589 {
590 GinPageGetOpaque(childpage)->flags &= ~GIN_INCOMPLETE_SPLIT;
591 MarkBufferDirty(childbuf);
592 }
593
594 /* write WAL record */
595 if (RelationNeedsWAL(btree->index) && !btree->isBuild)
596 {
597 XLogRecPtr recptr;
598
600
601 /*
602 * We just take full page images of all the split pages. Splits
603 * are uncommon enough that it's not worth complicating the code
604 * to be more efficient.
605 */
606 if (stack->parent == NULL)
607 {
611 }
612 else
613 {
616 }
617 if (BufferIsValid(childbuf))
619
620 XLogRegisterData((char *) &data, sizeof(ginxlogSplit));
621
622 recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT);
623
624 PageSetLSN(page, recptr);
625 PageSetLSN(BufferGetPage(rbuffer), recptr);
626 if (stack->parent == NULL)
627 PageSetLSN(BufferGetPage(lbuffer), recptr);
628 if (BufferIsValid(childbuf))
629 PageSetLSN(childpage, recptr);
630 }
632
633 /*
634 * We can release the locks/pins on the new pages now, but keep
635 * stack->buffer locked. childbuf doesn't get unlocked either.
636 */
637 UnlockReleaseBuffer(rbuffer);
638 if (stack->parent == NULL)
639 UnlockReleaseBuffer(lbuffer);
640
641 /*
642 * If we split the root, we're done. Otherwise the split is not
643 * complete until the downlink for the new page has been inserted to
644 * the parent.
645 */
646 result = (stack->parent == NULL);
647 }
648 else
649 {
650 elog(ERROR, "invalid return code from GIN beginPlaceToPage method: %d", rc);
651 result = false; /* keep compiler quiet */
652 }
653
654 /* Clean up temp context */
655 MemoryContextSwitchTo(oldCxt);
656 MemoryContextDelete(tmpCxt);
657
658 return result;
659}
static void BlockIdSet(BlockIdData *blockId, BlockNumber blockNumber)
Definition: block.h:81
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4883
void MarkBufferDirty(Buffer buffer)
Definition: bufmgr.c:2532
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:347
Page PageGetTempPage(const PageData *page)
Definition: bufpage.c:354
static void PageSetLSN(Page page, XLogRecPtr lsn)
Definition: bufpage.h:391
uint16_t uint16
Definition: c.h:487
GinPlaceToPageRC
Definition: gin_private.h:144
@ GPTP_INSERT
Definition: gin_private.h:146
@ GPTP_SPLIT
Definition: gin_private.h:147
@ GPTP_NO_WORK
Definition: gin_private.h:145
#define GIN_COMPRESSED
Definition: ginblock.h:48
#define GIN_LEAF
Definition: ginblock.h:42
#define GinPageIsData(page)
Definition: ginblock.h:115
#define GIN_INCOMPLETE_SPLIT
Definition: ginblock.h:47
void GinInitPage(Page page, uint32 f, Size pageSize)
Definition: ginutil.c:339
Buffer GinNewBuffer(Relation index)
Definition: ginutil.c:301
#define GIN_INSERT_ISDATA
Definition: ginxlog.h:124
#define GIN_INSERT_ISLEAF
Definition: ginxlog.h:125
#define GIN_SPLIT_ROOT
Definition: ginxlog.h:126
#define XLOG_GIN_INSERT
Definition: ginxlog.h:35
#define XLOG_GIN_SPLIT
Definition: ginxlog.h:109
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define START_CRIT_SECTION()
Definition: miscadmin.h:149
#define END_CRIT_SECTION()
Definition: miscadmin.h:151
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
const void * data
void PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, BlockNumber newblkno)
Definition: predicate.c:3134
#define RelationNeedsWAL(relation)
Definition: rel.h:628
void(* execPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void *)
Definition: gin_private.h:161
GinPlaceToPageRC(* beginPlaceToPage)(GinBtree, Buffer, GinBtreeStack *, void *, BlockNumber, void **, Page *, Page *)
Definition: gin_private.h:160
void(* fillRoot)(GinBtree, Page, BlockNumber, Page, BlockNumber, Page)
Definition: gin_private.h:163
BlockNumber nDataPages
Definition: gin.h:47
BlockNumber nEntryPages
Definition: gin.h:46
RelFileLocator rd_locator
Definition: rel.h:57
uint16 flags
Definition: ginxlog.h:39
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogRegisterData(const char *data, uint32 len)
Definition: xloginsert.c:364
void XLogRegisterBuffer(uint8 block_id, Buffer buffer, uint8 flags)
Definition: xloginsert.c:242
void XLogBeginInsert(void)
Definition: xloginsert.c:149
#define REGBUF_STANDARD
Definition: xloginsert.h:35
#define REGBUF_FORCE_IMAGE
Definition: xloginsert.h:32

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, GinBtreeData::beginPlaceToPage, BlockIdSet(), GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage(), BufferIsValid(), CurrentMemoryContext, data, elog, END_CRIT_SECTION, ERROR, GinBtreeData::execPlaceToPage, GinBtreeData::fillRoot, ginxlogInsert::flags, GIN_COMPRESSED, GIN_INCOMPLETE_SPLIT, GIN_INSERT_ISDATA, GIN_INSERT_ISLEAF, GIN_LEAF, GIN_SPLIT_ROOT, GinInitPage(), GinNewBuffer(), GinPageGetOpaque, GinPageIsData, GinPageIsLeaf, GPTP_INSERT, GPTP_NO_WORK, GPTP_SPLIT, GinBtreeData::index, InvalidBlockNumber, InvalidBuffer, GinBtreeData::isBuild, GinBtreeData::isData, MarkBufferDirty(), MemoryContextDelete(), MemoryContextSwitchTo(), GinStatsData::nDataPages, GinStatsData::nEntryPages, PageGetTempPage(), PageSetLSN(), GinBtreeStack::parent, PredicateLockPageSplit(), RelationData::rd_locator, REGBUF_FORCE_IMAGE, REGBUF_STANDARD, RelationNeedsWAL, START_CRIT_SECTION, UnlockReleaseBuffer(), XLOG_GIN_INSERT, XLOG_GIN_SPLIT, XLogBeginInsert(), XLogInsert(), XLogRegisterBuffer(), and XLogRegisterData().

Referenced by ginFinishSplit(), and ginInsertValue().

◆ ginStepRight()

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

Definition at line 177 of file ginbtree.c.

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

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

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

◆ ginTraverseLock()

int ginTraverseLock ( Buffer  buffer,
bool  searchMode 
)

Definition at line 39 of file ginbtree.c.

40{
41 Page page;
42 int access = GIN_SHARE;
43
44 LockBuffer(buffer, GIN_SHARE);
45 page = BufferGetPage(buffer);
46 if (GinPageIsLeaf(page))
47 {
48 if (searchMode == false)
49 {
50 /* we should relock our page */
51 LockBuffer(buffer, GIN_UNLOCK);
53
54 /* But root can become non-leaf during relock */
55 if (!GinPageIsLeaf(page))
56 {
57 /* restore old lock type (very rare) */
58 LockBuffer(buffer, GIN_UNLOCK);
59 LockBuffer(buffer, GIN_SHARE);
60 }
61 else
63 }
64 }
65
66 return access;
67}

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

Referenced by ginFindLeafPage().