firststack.blkno = GIST_ROOT_BLKNO;
firststack.lsn.xrecoff = 0;
firststack.parent = NULL;
+ firststack.downlinkoffnum = InvalidOffsetNumber;
state.stack = stack = &firststack;
/*
BlockNumber childblkno;
IndexTuple newtup;
GISTInsertStack *item;
+ OffsetNumber downlinkoffnum;
- stack->childoffnum = gistchoose(state.r, stack->page, itup, giststate);
- iid = PageGetItemId(stack->page, stack->childoffnum);
+ downlinkoffnum = gistchoose(state.r, stack->page, itup, giststate);
+ iid = PageGetItemId(stack->page, downlinkoffnum);
idxtuple = (IndexTuple) PageGetItem(stack->page, iid);
childblkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
* tuple.
*/
if (gistinserttuples(&state, stack, giststate, &newtup, 1,
- stack->childoffnum, InvalidBuffer))
+ downlinkoffnum, InvalidBuffer))
{
/*
* If this was a root split, the root page continues to be
item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
item->blkno = childblkno;
item->parent = stack;
+ item->downlinkoffnum = downlinkoffnum;
state.stack = stack = item;
}
else
/*
* Traverse the tree to find path from root page to specified "child" block.
*
- * returns from the beginning of closest parent;
+ * returns a new insertion stack, starting from the parent of "child", up
+ * to the root. *downlinkoffnum is set to the offset of the downlink in the
+ * direct parent of child.
*
* To prevent deadlocks, this should lock only one page at a time.
*/
-GISTInsertStack *
-gistFindPath(Relation r, BlockNumber child)
+static GISTInsertStack *
+gistFindPath(Relation r, BlockNumber child, OffsetNumber *downlinkoffnum)
{
Page page;
Buffer buffer;
maxoff;
ItemId iid;
IndexTuple idxtuple;
+ List *fifo;
GISTInsertStack *top,
- *tail,
*ptr;
BlockNumber blkno;
- top = tail = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
+ top = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
top->blkno = GIST_ROOT_BLKNO;
+ top->downlinkoffnum = InvalidOffsetNumber;
- while (top && top->blkno != child)
+ fifo = list_make1(top);
+ while (fifo != NIL)
{
+ /* Get next page to visit */
+ top = linitial(fifo);
+ fifo = list_delete_first(fifo);
+
buffer = ReadBuffer(r, top->blkno);
LockBuffer(buffer, GIST_SHARE);
gistcheckpage(r, buffer);
*/
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
ptr->blkno = GistPageGetOpaque(page)->rightlink;
- ptr->childoffnum = InvalidOffsetNumber;
+ ptr->downlinkoffnum = InvalidOffsetNumber;
ptr->parent = top->parent;
- ptr->next = top->next;
- top->next = ptr;
- if (tail == top)
- tail = ptr;
+
+ fifo = lcons(ptr, fifo);
}
maxoff = PageGetMaxOffsetNumber(page);
blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
if (blkno == child)
{
- OffsetNumber poff = InvalidOffsetNumber;
-
- /* make childs links */
- ptr = top;
- while (ptr->parent)
- {
- /* move childoffnum.. */
- if (ptr == top)
- {
- /* first iteration */
- poff = ptr->parent->childoffnum;
- ptr->parent->childoffnum = ptr->childoffnum;
- }
- else
- {
- OffsetNumber tmp = ptr->parent->childoffnum;
-
- ptr->parent->childoffnum = poff;
- poff = tmp;
- }
- ptr = ptr->parent;
- }
- top->childoffnum = i;
+ /* Found it! */
UnlockReleaseBuffer(buffer);
+ *downlinkoffnum = i;
return top;
}
else
{
- /* Install next inner page to the end of stack */
+ /* Append this child to the list of pages to visit later */
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
ptr->blkno = blkno;
- ptr->childoffnum = i; /* set offsetnumber of child to child
- * !!! */
+ ptr->downlinkoffnum = i;
ptr->parent = top;
- ptr->next = NULL;
- tail->next = ptr;
- tail = ptr;
+
+ fifo = lappend(fifo, ptr);
}
}
UnlockReleaseBuffer(buffer);
- top = top->next;
}
elog(ERROR, "failed to re-find parent of a page in index \"%s\", block %u",
parent->page = (Page) BufferGetPage(parent->buffer);
/* here we don't need to distinguish between split and page update */
- if (parent->childoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))
+ if (child->downlinkoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))
{
/* parent is changed, look child in right links until found */
OffsetNumber i,
if (ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno)
{
/* yes!!, found */
- parent->childoffnum = i;
+ child->downlinkoffnum = i;
return;
}
}
parent->blkno = GistPageGetOpaque(parent->page)->rightlink;
UnlockReleaseBuffer(parent->buffer);
if (parent->blkno == InvalidBlockNumber)
-
+ {
/*
- * end of chain and still didn't found parent, It's very-very
- * rare situation when root splited
+ * End of chain and still didn't find parent. It's a very-very
+ * rare situation when root splited.
*/
break;
+ }
parent->buffer = ReadBuffer(r, parent->blkno);
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
gistcheckpage(r, parent->buffer);
}
/* ok, find new path */
- ptr = parent = gistFindPath(r, child->blkno);
+ ptr = parent = gistFindPath(r, child->blkno, &child->downlinkoffnum);
/* read all buffers as expected by caller */
/* note we don't lock them or gistcheckpage them here! */
LockBuffer(stack->parent->buffer, GIST_EXCLUSIVE);
gistFindCorrectParent(rel, stack);
- iid = PageGetItemId(stack->parent->page, stack->parent->childoffnum);
+ iid = PageGetItemId(stack->parent->page, stack->downlinkoffnum);
downlink = (IndexTuple) PageGetItem(stack->parent->page, iid);
downlink = CopyIndexTuple(downlink);
LockBuffer(stack->parent->buffer, GIST_UNLOCK);
RelationGetRelationName(state->r), stack->blkno);
Assert(GistFollowRight(stack->page));
- Assert(OffsetNumberIsValid(stack->parent->childoffnum));
+ Assert(OffsetNumberIsValid(stack->downlinkoffnum));
buf = stack->buffer;
tuples[1] = right->downlink;
gistinserttuples(state, stack->parent, giststate,
tuples, 2,
- stack->parent->childoffnum,
+ stack->downlinkoffnum,
left->buf);
LockBuffer(stack->parent->buffer, GIST_UNLOCK);
UnlockReleaseBuffer(right->buf);