return access;
}
-GinBtreeStack *
-ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno)
-{
- 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;
-}
-
/*
- * Locates leaf page contained tuple
+ * Descends the tree to the leaf page that contains or would contain the
+ * key we're searching for. The key should already be filled in 'btree',
+ * in tree-type specific manner. If btree->fullScan is true, descends to the
+ * leftmost leaf page.
+ *
+ * If 'searchmode' is false, on return stack->buffer is exclusively locked,
+ * and the stack represents the full path to the root. Otherwise stack->buffer
+ * is share-locked, and stack->parent is NULL.
*/
GinBtreeStack *
-ginFindLeafPage(GinBtree btree, GinBtreeStack *stack)
+ginFindLeafPage(GinBtree btree, BlockNumber rootBlkno, bool searchMode)
{
- bool isfirst = TRUE;
- BlockNumber rootBlkno;
+ GinBtreeStack *stack;
- if (!stack)
- stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO);
- rootBlkno = stack->blkno;
+ stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
+ stack->blkno = rootBlkno;
+ stack->buffer = ReadBuffer(btree->index, rootBlkno);
+ stack->parent = NULL;
+ stack->predictNumber = 1;
for (;;)
{
Page page;
BlockNumber child;
- int access = GIN_SHARE;
+ int access;
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);
+ access = ginTraverseLock(stack->buffer, searchMode);
/*
* ok, page is correctly locked, we should check to move right ..,
Assert(child != InvalidBlockNumber);
Assert(stack->blkno != child);
- if (btree->searchMode)
+ if (searchMode)
{
/* in search mode we may forget path to leaf */
stack->blkno = child;
return;
}
- leftmostBlkno = blkno = btree->getLeftMostPage(btree, page);
+ leftmostBlkno = blkno = btree->getLeftMostChild(btree, page);
LockBuffer(root->buffer, GIN_UNLOCK);
Assert(blkno != InvalidBlockNumber);
if (GinPageIsLeaf(page))
elog(ERROR, "Lost path");
- leftmostBlkno = btree->getLeftMostPage(btree, page);
+ leftmostBlkno = btree->getLeftMostChild(btree, page);
while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
{
{
stack->off = FirstOffsetNumber;
stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
- return btree->getLeftMostPage(btree, page);
+ return btree->getLeftMostChild(btree, page);
}
low = FirstOffsetNumber;
*/
if (nitems > nrootitems)
{
- GinPostingTreeScan *gdi;
-
- gdi = ginPrepareScanPostingTree(index, blkno, FALSE);
- gdi->btree.isBuild = (buildStats != NULL);
-
- ginInsertItemPointers(gdi,
+ ginInsertItemPointers(index, blkno,
items + nrootitems,
nitems - nrootitems,
buildStats);
-
- pfree(gdi);
}
return blkno;
btree->index = index;
btree->findChildPage = dataLocateItem;
+ btree->getLeftMostChild = dataGetLeftMostPage;
btree->isMoveRight = dataIsMoveRight;
btree->findItem = dataLocateLeafItem;
btree->findChildPtr = dataFindChildPtr;
- btree->getLeftMostPage = dataGetLeftMostPage;
btree->placeToPage = dataPlaceToPage;
btree->splitPage = dataSplitPage;
btree->fillRoot = ginDataFillRoot;
btree->isData = TRUE;
- btree->searchMode = FALSE;
btree->isDelete = FALSE;
btree->fullScan = FALSE;
btree->isBuild = FALSE;
}
-GinPostingTreeScan *
-ginPrepareScanPostingTree(Relation index, BlockNumber rootBlkno, bool searchMode)
-{
- GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan));
-
- ginPrepareDataScan(&gdi->btree, index);
-
- gdi->btree.searchMode = searchMode;
- gdi->btree.fullScan = searchMode;
-
- gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
-
- return gdi;
-}
-
/*
* Inserts array of item pointers, may execute several tree scan (very rare)
*/
void
-ginInsertItemPointers(GinPostingTreeScan *gdi,
+ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
ItemPointerData *items, uint32 nitem,
GinStatsData *buildStats)
{
- BlockNumber rootBlkno = gdi->stack->blkno;
+ GinBtreeData btree;
+ GinBtreeStack *stack;
- gdi->btree.items = items;
- gdi->btree.nitem = nitem;
- gdi->btree.curitem = 0;
+ ginPrepareDataScan(&btree, index);
+ btree.isBuild = (buildStats != NULL);
+ btree.items = items;
+ btree.nitem = nitem;
+ btree.curitem = 0;
- while (gdi->btree.curitem < gdi->btree.nitem)
+ while (btree.curitem < btree.nitem)
{
- if (!gdi->stack)
- gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
-
- gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
+ stack = ginFindLeafPage(&btree, rootBlkno, false);
- if (gdi->btree.findItem(&(gdi->btree), gdi->stack))
+ if (btree.findItem(&btree, stack))
{
/*
- * gdi->btree.items[gdi->btree.curitem] already exists in index
+ * btree.items[btree.curitem] already exists in index
*/
- gdi->btree.curitem++;
- LockBuffer(gdi->stack->buffer, GIN_UNLOCK);
- freeGinBtreeStack(gdi->stack);
+ btree.curitem++;
+ LockBuffer(stack->buffer, GIN_UNLOCK);
+ freeGinBtreeStack(stack);
}
else
- ginInsertValue(&(gdi->btree), gdi->stack, buildStats);
-
- gdi->stack = NULL;
+ ginInsertValue(&btree, stack, buildStats);
}
}
-Buffer
-ginScanBeginPostingTree(GinPostingTreeScan *gdi)
+/*
+ * Starts a new scan on a posting tree.
+ */
+GinBtreeStack *
+ginScanBeginPostingTree(Relation index, BlockNumber rootBlkno)
{
- gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
- return gdi->stack->buffer;
+ GinBtreeData btree;
+ GinBtreeStack *stack;
+
+ ginPrepareDataScan(&btree, index);
+
+ btree.fullScan = TRUE;
+
+ stack = ginFindLeafPage(&btree, rootBlkno, TRUE);
+
+ return stack;
}
{
stack->off = FirstOffsetNumber;
stack->predictNumber *= PageGetMaxOffsetNumber(page);
- return btree->getLeftMostPage(btree, page);
+ return btree->getLeftMostChild(btree, page);
}
low = FirstOffsetNumber;
btree->ginstate = ginstate;
btree->findChildPage = entryLocateEntry;
+ btree->getLeftMostChild = entryGetLeftMostPage;
btree->isMoveRight = entryIsMoveRight;
btree->findItem = entryLocateLeafEntry;
btree->findChildPtr = entryFindChildPtr;
- btree->getLeftMostPage = entryGetLeftMostPage;
btree->placeToPage = entryPlaceToPage;
btree->splitPage = entrySplitPage;
btree->fillRoot = ginEntryFillRoot;
btree->isData = FALSE;
- btree->searchMode = FALSE;
btree->fullScan = FALSE;
btree->isBuild = FALSE;
scanPostingTree(Relation index, GinScanEntry scanEntry,
BlockNumber rootPostingTree)
{
- GinPostingTreeScan *gdi;
+ GinBtreeStack *stack;
Buffer buffer;
Page page;
/* Descend to the leftmost leaf page */
- gdi = ginPrepareScanPostingTree(index, rootPostingTree, TRUE);
-
- buffer = ginScanBeginPostingTree(gdi);
+ stack = ginScanBeginPostingTree(index, rootPostingTree);
+ buffer = stack->buffer;
IncrBufferRefCount(buffer); /* prevent unpin in freeGinBtreeStack */
- freeGinBtreeStack(gdi->stack);
- pfree(gdi);
+ freeGinBtreeStack(stack);
/*
* Loop iterates through all leaf pages of posting tree
ginPrepareEntryScan(&btreeEntry, entry->attnum,
entry->queryKey, entry->queryCategory,
ginstate);
- btreeEntry.searchMode = TRUE;
- stackEntry = ginFindLeafPage(&btreeEntry, NULL);
+ stackEntry = ginFindLeafPage(&btreeEntry, GIN_ROOT_BLKNO, true);
page = BufferGetPage(stackEntry->buffer);
needUnlock = TRUE;
if (GinIsPostingTree(itup))
{
BlockNumber rootPostingTree = GinGetPostingTree(itup);
- GinPostingTreeScan *gdi;
+ GinBtreeStack *stack;
Page page;
/*
*/
LockBuffer(stackEntry->buffer, GIN_UNLOCK);
needUnlock = FALSE;
- gdi = ginPrepareScanPostingTree(ginstate->index, rootPostingTree, TRUE);
- entry->buffer = ginScanBeginPostingTree(gdi);
+ stack = ginScanBeginPostingTree(ginstate->index, rootPostingTree);
+ entry->buffer = stack->buffer;
/*
* We keep buffer pinned because we need to prevent deletion of
IncrBufferRefCount(entry->buffer);
page = BufferGetPage(entry->buffer);
- entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff;
+ entry->predictNumberResult = stack->predictNumber * GinPageGetOpaque(page)->maxoff;
/*
* Keep page content in memory to prevent durable page locking
GinPageGetOpaque(page)->maxoff * sizeof(ItemPointerData));
LockBuffer(entry->buffer, GIN_UNLOCK);
- freeGinBtreeStack(gdi->stack);
- pfree(gdi);
+ freeGinBtreeStack(stack);
entry->isFinished = FALSE;
}
else if (GinGetNPosting(itup) > 0)
{
/* posting list would be too big, convert to posting tree */
BlockNumber postingRoot;
- GinPostingTreeScan *gdi;
/*
* Initialize posting tree with the old tuple's posting list. It's
buildStats);
/* Now insert the TIDs-to-be-added into the posting tree */
- gdi = ginPrepareScanPostingTree(ginstate->index, postingRoot, FALSE);
- gdi->btree.isBuild = (buildStats != NULL);
-
- ginInsertItemPointers(gdi, items, nitem, buildStats);
-
- pfree(gdi);
+ ginInsertItemPointers(ginstate->index, postingRoot,
+ items, nitem,
+ buildStats);
/* And build a new posting-tree-only result tuple */
res = GinFormTuple(ginstate, attnum, key, category, NULL, 0, true);
ginPrepareEntryScan(&btree, attnum, key, category, ginstate);
- stack = ginFindLeafPage(&btree, NULL);
+ stack = ginFindLeafPage(&btree, GIN_ROOT_BLKNO, false);
page = BufferGetPage(stack->buffer);
if (btree.findItem(&btree, stack))
{
/* add entries to existing posting tree */
BlockNumber rootPostingTree = GinGetPostingTree(itup);
- GinPostingTreeScan *gdi;
/* release all stack */
LockBuffer(stack->buffer, GIN_UNLOCK);
freeGinBtreeStack(stack);
/* insert into posting tree */
- gdi = ginPrepareScanPostingTree(ginstate->index, rootPostingTree, FALSE);
- gdi->btree.isBuild = (buildStats != NULL);
- ginInsertItemPointers(gdi, items, nitem, buildStats);
- pfree(gdi);
-
+ ginInsertItemPointers(ginstate->index, rootPostingTree,
+ items, nitem,
+ buildStats);
return;
}
{
/* search methods */
BlockNumber (*findChildPage) (GinBtree, GinBtreeStack *);
+ BlockNumber (*getLeftMostChild) (GinBtree, Page);
bool (*isMoveRight) (GinBtree, Page);
bool (*findItem) (GinBtree, GinBtreeStack *);
/* insert methods */
OffsetNumber (*findChildPtr) (GinBtree, Page, BlockNumber, OffsetNumber);
- BlockNumber (*getLeftMostPage) (GinBtree, Page);
bool (*placeToPage) (GinBtree, Buffer, OffsetNumber, XLogRecData **);
Page (*splitPage) (GinBtree, Buffer, Buffer, OffsetNumber, XLogRecData **);
void (*fillRoot) (GinBtree, Buffer, Buffer, Buffer);
bool isData;
- bool searchMode;
Relation index;
GinState *ginstate; /* not valid in a data scan */
PostingItem pitem;
} GinBtreeData;
-extern GinBtreeStack *ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno);
-extern GinBtreeStack *ginFindLeafPage(GinBtree btree, GinBtreeStack *stack);
+extern GinBtreeStack *ginFindLeafPage(GinBtree btree, BlockNumber rootBlkno, bool searchMode);
extern Buffer ginStepRight(Buffer buffer, Relation index, int lockmode);
extern void freeGinBtreeStack(GinBtreeStack *stack);
extern void ginInsertValue(GinBtree btree, GinBtreeStack *stack,
extern void GinDataPageAddItemPointer(Page page, ItemPointer data, OffsetNumber offset);
extern void GinDataPageAddPostingItem(Page page, PostingItem *data, OffsetNumber offset);
extern void GinPageDeletePostingItem(Page page, OffsetNumber offset);
-
-typedef struct
-{
- GinBtreeData btree;
- GinBtreeStack *stack;
-} GinPostingTreeScan;
-
-extern GinPostingTreeScan *ginPrepareScanPostingTree(Relation index,
- BlockNumber rootBlkno, bool searchMode);
-extern void ginInsertItemPointers(GinPostingTreeScan *gdi,
+extern void ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
ItemPointerData *items, uint32 nitem,
GinStatsData *buildStats);
-extern Buffer ginScanBeginPostingTree(GinPostingTreeScan *gdi);
+extern GinBtreeStack *ginScanBeginPostingTree(Relation index, BlockNumber rootBlkno);
extern void ginDataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf);
extern void ginPrepareDataScan(GinBtree btree, Relation index);