#include "postgres.h"
#include "access/gin_private.h"
#include "miscadmin.h"
#include "utils/rel.h"
Go to the source code of this file.
Functions | |
static int | ginTraverseLock (Buffer buffer, bool searchMode) |
GinBtreeStack * | ginPrepareFindLeafPage (GinBtree btree, BlockNumber blkno) |
GinBtreeStack * | ginFindLeafPage (GinBtree btree, GinBtreeStack *stack) |
void | freeGinBtreeStack (GinBtreeStack *stack) |
void | ginFindParents (GinBtree btree, GinBtreeStack *stack, BlockNumber rootBlkno) |
void | ginInsertValue (GinBtree btree, GinBtreeStack *stack, GinStatsData *buildStats) |
void freeGinBtreeStack | ( | GinBtreeStack * | stack | ) |
Definition at line 152 of file ginbtree.c.
References GinBtreeStack::buffer, InvalidBuffer, GinBtreeStack::parent, pfree(), and ReleaseBuffer().
Referenced by ginEntryInsert(), ginInsertItemPointers(), ginInsertValue(), scanPostingTree(), and startScanEntry().
{ while (stack) { GinBtreeStack *tmp = stack->parent; if (stack->buffer != InvalidBuffer) ReleaseBuffer(stack->buffer); pfree(stack); stack = tmp; } }
GinBtreeStack* ginFindLeafPage | ( | GinBtree | btree, | |
GinBtreeStack * | stack | |||
) |
Definition at line 74 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetPage, FALSE, GinBtreeData::findChildPage, GinBtreeData::fullScan, GIN_ROOT_BLKNO, GIN_UNLOCK, GinPageGetOpaque, GinPageIsLeaf, ginPrepareFindLeafPage(), ginTraverseLock(), GinBtreeData::index, InvalidBlockNumber, GinBtreeData::isMoveRight, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), ReleaseAndReadBuffer(), and GinBtreeData::searchMode.
Referenced by ginEntryInsert(), ginInsertItemPointers(), ginScanBeginPostingTree(), and startScanEntry().
{ bool isfirst = TRUE; BlockNumber rootBlkno; if (!stack) stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO); rootBlkno = stack->blkno; for (;;) { Page page; BlockNumber child; int access = GIN_SHARE; stack->off = InvalidOffsetNumber; page = BufferGetPage(stack->buffer); if (isfirst) { if (GinPageIsLeaf(page) && !btree->searchMode) access = GIN_EXCLUSIVE; isfirst = FALSE; } else access = ginTraverseLock(stack->buffer, btree->searchMode); /* * ok, page is correctly locked, we should check to move right .., * root never has a right link, so small optimization */ while (btree->fullScan == FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page)) { BlockNumber rightlink = GinPageGetOpaque(page)->rightlink; if (rightlink == InvalidBlockNumber) /* rightmost page */ break; stack->blkno = rightlink; LockBuffer(stack->buffer, GIN_UNLOCK); stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno); LockBuffer(stack->buffer, access); page = BufferGetPage(stack->buffer); } if (GinPageIsLeaf(page)) /* we found, return locked page */ return stack; /* now we have correct buffer, try to find child */ child = btree->findChildPage(btree, stack); LockBuffer(stack->buffer, GIN_UNLOCK); Assert(child != InvalidBlockNumber); Assert(stack->blkno != child); if (btree->searchMode) { /* in search mode we may forget path to leaf */ stack->blkno = child; stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno); } else { GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); ptr->parent = stack; stack = ptr; stack->blkno = child; stack->buffer = ReadBuffer(btree->index, stack->blkno); stack->predictNumber = 1; } } }
void ginFindParents | ( | GinBtree | btree, | |
GinBtreeStack * | stack, | |||
BlockNumber | rootBlkno | |||
) |
Definition at line 173 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, elog, ERROR, GinBtreeData::findChildPtr, GinBtreeData::getLeftMostPage, GIN_EXCLUSIVE, GIN_UNLOCK, GinPageGetOpaque, GinPageIsLeaf, GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, LockBuffer(), GinBtreeStack::off, palloc(), GinBtreeStack::parent, ReadBuffer(), and ReleaseBuffer().
Referenced by ginContinueSplit(), and ginInsertValue().
{ Page page; Buffer buffer; BlockNumber blkno, leftmostBlkno; OffsetNumber offset; GinBtreeStack *root = stack->parent; GinBtreeStack *ptr; if (!root) { /* XLog mode... */ root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); root->blkno = rootBlkno; root->buffer = ReadBuffer(btree->index, rootBlkno); LockBuffer(root->buffer, GIN_EXCLUSIVE); root->parent = NULL; } else { /* * find root, we should not release root page until update is * finished!! */ while (root->parent) { ReleaseBuffer(root->buffer); root = root->parent; } Assert(root->blkno == rootBlkno); Assert(BufferGetBlockNumber(root->buffer) == rootBlkno); LockBuffer(root->buffer, GIN_EXCLUSIVE); } root->off = InvalidOffsetNumber; page = BufferGetPage(root->buffer); Assert(!GinPageIsLeaf(page)); /* check trivial case */ if ((root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber) { stack->parent = root; return; } leftmostBlkno = blkno = btree->getLeftMostPage(btree, page); LockBuffer(root->buffer, GIN_UNLOCK); Assert(blkno != InvalidBlockNumber); for (;;) { buffer = ReadBuffer(btree->index, blkno); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); if (GinPageIsLeaf(page)) elog(ERROR, "Lost path"); leftmostBlkno = btree->getLeftMostPage(btree, page); while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber) { blkno = GinPageGetOpaque(page)->rightlink; LockBuffer(buffer, GIN_UNLOCK); ReleaseBuffer(buffer); if (blkno == InvalidBlockNumber) break; buffer = ReadBuffer(btree->index, blkno); LockBuffer(buffer, GIN_EXCLUSIVE); page = BufferGetPage(buffer); } if (blkno != InvalidBlockNumber) { ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); ptr->blkno = blkno; ptr->buffer = buffer; ptr->parent = root; /* it's may be wrong, but in next call we will * correct */ ptr->off = offset; stack->parent = ptr; return; } blkno = leftmostBlkno; } }
void ginInsertValue | ( | GinBtree | btree, | |
GinBtreeStack * | stack, | |||
GinStatsData * | buildStats | |||
) |
Definition at line 273 of file ginbtree.c.
References Assert, GinBtreeStack::blkno, BlockNumberIsValid, GinBtreeStack::buffer, BufferGetBlockNumber(), BufferGetPage, XLogRecData::data, END_CRIT_SECTION, FALSE, GinBtreeData::fillRoot, GinBtreeData::findChildPtr, freeGinBtreeStack(), GIN_EXCLUSIVE, GIN_LEAF, GIN_UNLOCK, ginFindParents(), GinInitBuffer(), GinNewBuffer(), GinPageGetOpaque, GinBtreeData::index, InvalidBlockNumber, InvalidOffsetNumber, GinBtreeData::isData, GinBtreeData::isDelete, GinBtreeData::isEnoughSpace, LockBuffer(), MarkBufferDirty(), GinStatsData::nDataPages, GinStatsData::nEntryPages, NULL, GinBtreeStack::off, PageRestoreTempPage(), PageSetLSN, GinBtreeStack::parent, pfree(), GinBtreeData::placeToPage, RelationNeedsWAL, ReleaseAndReadBuffer(), GinBtreeData::splitPage, START_CRIT_SECTION, TRUE, UnlockReleaseBuffer(), XLOG_GIN_INSERT, XLOG_GIN_SPLIT, and XLogInsert().
Referenced by ginContinueSplit(), ginEntryInsert(), and ginInsertItemPointers().
{ GinBtreeStack *parent; BlockNumber rootBlkno; Page page, rpage, lpage; /* extract root BlockNumber from stack */ Assert(stack != NULL); parent = stack; while (parent->parent) parent = parent->parent; rootBlkno = parent->blkno; Assert(BlockNumberIsValid(rootBlkno)); /* this loop crawls up the stack until the insertion is complete */ for (;;) { XLogRecData *rdata; BlockNumber savedRightLink; page = BufferGetPage(stack->buffer); savedRightLink = GinPageGetOpaque(page)->rightlink; if (btree->isEnoughSpace(btree, stack->buffer, stack->off)) { START_CRIT_SECTION(); btree->placeToPage(btree, stack->buffer, stack->off, &rdata); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata); PageSetLSN(page, recptr); } LockBuffer(stack->buffer, GIN_UNLOCK); END_CRIT_SECTION(); freeGinBtreeStack(stack); return; } else { Buffer rbuffer = GinNewBuffer(btree->index); Page newlpage; /* * newlpage is a pointer to memory page, it doesn't associate with * buffer, stack->buffer should be untouched */ newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata); ((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno; /* During index build, count the newly-split page */ if (buildStats) { if (btree->isData) buildStats->nDataPages++; else buildStats->nEntryPages++; } parent = stack->parent; if (parent == NULL) { /* * split root, so we need to allocate new left page and place * pointer on root to left and right page */ Buffer lbuffer = GinNewBuffer(btree->index); ((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE; ((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber; page = BufferGetPage(stack->buffer); lpage = BufferGetPage(lbuffer); rpage = BufferGetPage(rbuffer); GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber; GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); ((ginxlogSplit *) (rdata->data))->lblkno = BufferGetBlockNumber(lbuffer); START_CRIT_SECTION(); GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF); PageRestoreTempPage(newlpage, lpage); btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer); MarkBufferDirty(rbuffer); MarkBufferDirty(lbuffer); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); PageSetLSN(page, recptr); PageSetLSN(lpage, recptr); PageSetLSN(rpage, recptr); } UnlockReleaseBuffer(rbuffer); UnlockReleaseBuffer(lbuffer); LockBuffer(stack->buffer, GIN_UNLOCK); END_CRIT_SECTION(); freeGinBtreeStack(stack); /* During index build, count the newly-added root page */ if (buildStats) { if (btree->isData) buildStats->nDataPages++; else buildStats->nEntryPages++; } return; } else { /* split non-root page */ ((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE; ((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink; lpage = BufferGetPage(stack->buffer); rpage = BufferGetPage(rbuffer); GinPageGetOpaque(rpage)->rightlink = savedRightLink; GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer); START_CRIT_SECTION(); PageRestoreTempPage(newlpage, lpage); MarkBufferDirty(rbuffer); MarkBufferDirty(stack->buffer); if (RelationNeedsWAL(btree->index)) { XLogRecPtr recptr; recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata); PageSetLSN(lpage, recptr); PageSetLSN(rpage, recptr); } UnlockReleaseBuffer(rbuffer); END_CRIT_SECTION(); } } btree->isDelete = FALSE; /* search parent to lock */ LockBuffer(parent->buffer, GIN_EXCLUSIVE); /* move right if it's needed */ page = BufferGetPage(parent->buffer); while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber) { BlockNumber rightlink = GinPageGetOpaque(page)->rightlink; LockBuffer(parent->buffer, GIN_UNLOCK); if (rightlink == InvalidBlockNumber) { /* * rightmost page, but we don't find parent, we should use * plain search... */ ginFindParents(btree, stack, rootBlkno); parent = stack->parent; Assert(parent != NULL); break; } parent->blkno = rightlink; parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno); LockBuffer(parent->buffer, GIN_EXCLUSIVE); page = BufferGetPage(parent->buffer); } UnlockReleaseBuffer(stack->buffer); pfree(stack); stack = parent; } }
GinBtreeStack* ginPrepareFindLeafPage | ( | GinBtree | btree, | |
BlockNumber | blkno | |||
) |
Definition at line 56 of file ginbtree.c.
References GinBtreeStack::blkno, GinBtreeStack::buffer, ginTraverseLock(), GinBtreeData::index, palloc(), GinBtreeStack::parent, GinBtreeStack::predictNumber, ReadBuffer(), and GinBtreeData::searchMode.
Referenced by ginFindLeafPage(), ginInsertItemPointers(), and ginPrepareScanPostingTree().
{ GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack)); stack->blkno = blkno; stack->buffer = ReadBuffer(btree->index, stack->blkno); stack->parent = NULL; stack->predictNumber = 1; ginTraverseLock(stack->buffer, btree->searchMode); return stack; }
Definition at line 25 of file ginbtree.c.
References BufferGetPage, FALSE, GIN_EXCLUSIVE, GIN_SHARE, GIN_UNLOCK, GinPageIsLeaf, and LockBuffer().
Referenced by ginFindLeafPage(), and ginPrepareFindLeafPage().
{ Page page; int access = GIN_SHARE; LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); if (GinPageIsLeaf(page)) { if (searchMode == FALSE) { /* we should relock our page */ LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_EXCLUSIVE); /* But root can become non-leaf during relock */ if (!GinPageIsLeaf(page)) { /* restore old lock type (very rare) */ LockBuffer(buffer, GIN_UNLOCK); LockBuffer(buffer, GIN_SHARE); } else access = GIN_EXCLUSIVE; } } return access; }