@ -1015,87 +1015,106 @@ gistFindPath(Relation r, BlockNumber child, OffsetNumber *downlinkoffnum)
* remain so at exit , but it might not be the same page anymore .
* remain so at exit , but it might not be the same page anymore .
*/
*/
static void
static void
gistFindCorrectParent ( Relation r , GISTInsertStack * child )
gistFindCorrectParent ( Relation r , GISTInsertStack * child , bool is_build )
{
{
GISTInsertStack * parent = child - > parent ;
GISTInsertStack * parent = child - > parent ;
ItemId iid ;
IndexTuple idxtuple ;
OffsetNumber maxoff ;
GISTInsertStack * ptr ;
gistcheckpage ( r , parent - > buffer ) ;
gistcheckpage ( r , parent - > buffer ) ;
parent - > page = ( Page ) BufferGetPage ( parent - > buffer ) ;
parent - > page = ( Page ) BufferGetPage ( parent - > buffer ) ;
maxoff = PageGetMaxOffsetNumber ( parent - > page ) ;
/* here we don't need to distinguish between split and page update */
/* Check if the downlink is still where it was before */
if ( child - > downlinkoffnum = = InvalidOffsetNumber | |
if ( child - > downlinkoffnum ! = InvalidOffsetNumber & & child - > downlinkoffnum < = maxoff )
parent - > lsn ! = PageGetLSN ( parent - > page ) )
{
{
/* parent is changed, look child in right links until found */
iid = PageGetItemId ( parent - > page , child - > downlinkoffnum ) ;
OffsetNumber i ,
idxtuple = ( IndexTuple ) PageGetItem ( parent - > page , iid ) ;
maxoff ;
if ( ItemPointerGetBlockNumber ( & ( idxtuple - > t_tid ) ) = = child - > blkno )
ItemId iid ;
return ; /* still there */
IndexTuple idxtuple ;
}
GISTInsertStack * ptr ;
while ( true )
/*
{
* The page has changed since we looked . During normal operation , every
maxoff = PageGetMaxOffsetNumber ( parent - > page ) ;
* update of a page changes its LSN , so the LSN we memorized should have
for ( i = FirstOffsetNumber ; i < = maxoff ; i = OffsetNumberNext ( i ) )
* changed too . During index build , however , we don ' t WAL - log the changes
{
* until we have built the index , so the LSN doesn ' t change . There is no
iid = PageGetItemId ( parent - > page , i ) ;
* concurrent activity during index build , but we might have changed the
idxtuple = ( IndexTuple ) PageGetItem ( parent - > page , iid ) ;
* parent ourselves .
if ( ItemPointerGetBlockNumber ( & ( idxtuple - > t_tid ) ) = = child - > blkno )
*/
{
Assert ( parent - > lsn ! = PageGetLSN ( parent - > page ) | | is_build ) ;
/* yes!!, found */
child - > downlinkoffnum = i ;
/*
return ;
* Scan the page to re - find the downlink . If the page was split , it might
}
* have moved to a different page , so follow the right links until we find
}
* it .
*/
while ( true )
{
OffsetNumber i ;
parent - > blkno = GistPageGetOpaque ( parent - > page ) - > rightlink ;
maxoff = PageGetMaxOffsetNumber ( parent - > page ) ;
UnlockReleaseBuffer ( parent - > buffer ) ;
for ( i = FirstOffsetNumber ; i < = maxoff ; i = OffsetNumberNext ( i ) )
if ( parent - > blkno = = InvalidBlockNumber )
{
iid = PageGetItemId ( parent - > page , i ) ;
idxtuple = ( IndexTuple ) PageGetItem ( parent - > page , iid ) ;
if ( ItemPointerGetBlockNumber ( & ( idxtuple - > t_tid ) ) = = child - > blkno )
{
{
/*
/* yes!!, found */
* End of chain and still didn ' t find parent . It ' s a very - very
child - > downlinkoffnum = i ;
* rare situation when root splitted .
return ;
*/
break ;
}
}
parent - > buffer = ReadBuffer ( r , parent - > blkno ) ;
LockBuffer ( parent - > buffer , GIST_EXCLUSIVE ) ;
gistcheckpage ( r , parent - > buffer ) ;
parent - > page = ( Page ) BufferGetPage ( parent - > buffer ) ;
}
}
/*
parent - > blkno = GistPageGetOpaque ( parent - > page ) - > rightlink ;
* awful ! ! , we need search tree to find parent . . . , but before we
parent - > downlinkoffnum = InvalidOffsetNumber ;
* should release all old parent
UnlockReleaseBuffer ( parent - > buffer ) ;
*/
if ( parent - > blkno = = InvalidBlockNumber )
ptr = child - > parent - > parent ; /* child->parent already released
* above */
while ( ptr )
{
{
ReleaseBuffer ( ptr - > buffer ) ;
/*
ptr = ptr - > parent ;
* End of chain and still didn ' t find parent . It ' s a very - very
* rare situation when root splitted .
*/
break ;
}
}
parent - > buffer = ReadBuffer ( r , parent - > blkno ) ;
LockBuffer ( parent - > buffer , GIST_EXCLUSIVE ) ;
gistcheckpage ( r , parent - > buffer ) ;
parent - > page = ( Page ) BufferGetPage ( parent - > buffer ) ;
}
/* ok, find new path */
/*
ptr = parent = gistFindPath ( r , child - > blkno , & child - > downlinkoffnum ) ;
* awful ! ! , we need search tree to find parent . . . , but before we should
* release all old parent
*/
/* read all buffers as expected by caller */
ptr = child - > parent - > parent ; /* child->parent already released above */
/* note we don't lock them or gistcheckpage them here! */
while ( ptr )
while ( ptr )
{
{
ReleaseBuffer ( ptr - > buffer ) ;
ptr - > buffer = ReadBuffer ( r , ptr - > blkno ) ;
ptr = ptr - > parent ;
ptr - > page = ( Page ) BufferGetPage ( ptr - > buffer ) ;
}
ptr = ptr - > parent ;
}
/* install new chain of parents to stack */
/* ok, find new path */
child - > parent = parent ;
ptr = parent = gistFindPath ( r , child - > blkno , & child - > downlinkoffnum ) ;
/* make recursive call to normal processing */
/* read all buffers as expected by caller */
LockBuffer ( child - > parent - > buffer , GIST_EXCLUSIVE ) ;
/* note we don't lock them or gistcheckpage them here! */
gistFindCorrectParent ( r , child ) ;
while ( ptr )
{
ptr - > buffer = ReadBuffer ( r , ptr - > blkno ) ;
ptr - > page = ( Page ) BufferGetPage ( ptr - > buffer ) ;
ptr = ptr - > parent ;
}
}
/* install new chain of parents to stack */
child - > parent = parent ;
/* make recursive call to normal processing */
LockBuffer ( child - > parent - > buffer , GIST_EXCLUSIVE ) ;
gistFindCorrectParent ( r , child , is_build ) ;
}
}
/*
/*
@ -1103,7 +1122,7 @@ gistFindCorrectParent(Relation r, GISTInsertStack *child)
*/
*/
static IndexTuple
static IndexTuple
gistformdownlink ( Relation rel , Buffer buf , GISTSTATE * giststate ,
gistformdownlink ( Relation rel , Buffer buf , GISTSTATE * giststate ,
GISTInsertStack * stack )
GISTInsertStack * stack , bool is_build )
{
{
Page page = BufferGetPage ( buf ) ;
Page page = BufferGetPage ( buf ) ;
OffsetNumber maxoff ;
OffsetNumber maxoff ;
@ -1144,7 +1163,7 @@ gistformdownlink(Relation rel, Buffer buf, GISTSTATE *giststate,
ItemId iid ;
ItemId iid ;
LockBuffer ( stack - > parent - > buffer , GIST_EXCLUSIVE ) ;
LockBuffer ( stack - > parent - > buffer , GIST_EXCLUSIVE ) ;
gistFindCorrectParent ( rel , stack ) ;
gistFindCorrectParent ( rel , stack , is_build ) ;
iid = PageGetItemId ( stack - > parent - > page , stack - > downlinkoffnum ) ;
iid = PageGetItemId ( stack - > parent - > page , stack - > downlinkoffnum ) ;
downlink = ( IndexTuple ) PageGetItem ( stack - > parent - > page , iid ) ;
downlink = ( IndexTuple ) PageGetItem ( stack - > parent - > page , iid ) ;
downlink = CopyIndexTuple ( downlink ) ;
downlink = CopyIndexTuple ( downlink ) ;
@ -1189,7 +1208,7 @@ gistfixsplit(GISTInsertState *state, GISTSTATE *giststate)
page = BufferGetPage ( buf ) ;
page = BufferGetPage ( buf ) ;
/* Form the new downlink tuples to insert to parent */
/* Form the new downlink tuples to insert to parent */
downlink = gistformdownlink ( state - > r , buf , giststate , stack ) ;
downlink = gistformdownlink ( state - > r , buf , giststate , stack , state - > is_build ) ;
si - > buf = buf ;
si - > buf = buf ;
si - > downlink = downlink ;
si - > downlink = downlink ;
@ -1343,7 +1362,7 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
right = ( GISTPageSplitInfo * ) list_nth ( splitinfo , pos ) ;
right = ( GISTPageSplitInfo * ) list_nth ( splitinfo , pos ) ;
left = ( GISTPageSplitInfo * ) list_nth ( splitinfo , pos - 1 ) ;
left = ( GISTPageSplitInfo * ) list_nth ( splitinfo , pos - 1 ) ;
gistFindCorrectParent ( state - > r , stack ) ;
gistFindCorrectParent ( state - > r , stack , state - > is_build ) ;
if ( gistinserttuples ( state , stack - > parent , giststate ,
if ( gistinserttuples ( state , stack - > parent , giststate ,
& right - > downlink , 1 ,
& right - > downlink , 1 ,
InvalidOffsetNumber ,
InvalidOffsetNumber ,
@ -1368,21 +1387,22 @@ gistfinishsplit(GISTInsertState *state, GISTInsertStack *stack,
*/
*/
tuples [ 0 ] = left - > downlink ;
tuples [ 0 ] = left - > downlink ;
tuples [ 1 ] = right - > downlink ;
tuples [ 1 ] = right - > downlink ;
gistFindCorrectParent ( state - > r , stack ) ;
gistFindCorrectParent ( state - > r , stack , state - > is_build ) ;
if ( gistinserttuples ( state , stack - > parent , giststate ,
( void ) gistinserttuples ( state , stack - > parent , giststate ,
tuples , 2 ,
tuples , 2 ,
stack - > downlinkoffnum ,
stack - > downlinkoffnum ,
left - > buf , right - > buf ,
left - > buf , right - > buf ,
true , /* Unlock parent */
true , /* Unlock parent */
unlockbuf /* Unlock stack->buffer if caller wants
unlockbuf /* Unlock stack->buffer if caller
* that */
* wants that */
) )
) ;
{
/*
/*
* If the parent page was split , the downlink might have moved .
* The downlink might have moved when we updated it . Even if the page
*/
* wasn ' t split , because gistinserttuples ( ) implements updating the old
stack - > downlinkoffnum = InvalidOffsetNumber ;
* tuple by removing and re - inserting it !
}
*/
stack - > downlinkoffnum = InvalidOffsetNumber ;
Assert ( left - > buf = = stack - > buffer ) ;
Assert ( left - > buf = = stack - > buffer ) ;