@ -30,7 +30,7 @@ dataIsMoveRight(GinBtree btree, Page page)
if ( GinPageRightMost ( page ) )
return FALSE ;
return ( ginCompareItemPointers ( btree - > items + btree - > cur item, iptr ) > 0 ) ? TRUE : FALSE ;
return ( ginCompareItemPointers ( & btree - > itemptr , iptr ) > 0 ) ? TRUE : FALSE ;
}
/*
@ -80,7 +80,7 @@ dataLocateItem(GinBtree btree, GinBtreeStack *stack)
else
{
pitem = GinDataPageGetPostingItem ( page , mid ) ;
result = ginCompareItemPointers ( btree - > items + btree - > cur item, & ( pitem - > key ) ) ;
result = ginCompareItemPointers ( & btree - > itemptr , & ( pitem - > key ) ) ;
}
if ( result = = 0 )
@ -138,7 +138,7 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack)
{
OffsetNumber mid = low + ( ( high - low ) / 2 ) ;
result = ginCompareItemPointers ( btree - > items + btree - > cur item,
result = ginCompareItemPointers ( & btree - > itemptr ,
GinDataPageGetItemPointer ( page , mid ) ) ;
if ( result = = 0 )
@ -298,18 +298,19 @@ GinPageDeletePostingItem(Page page, OffsetNumber offset)
* item pointer never deletes !
*/
static bool
dataIsEnoughSpace ( GinBtree btree , Buffer buf , OffsetNumber off )
dataIsEnoughSpace ( GinBtree btree , Buffer buf , OffsetNumber off , void * insertdata )
{
Page page = BufferGetPage ( buf ) ;
Assert ( GinPageIsData ( page ) ) ;
Assert ( ! btree - > isDelete ) ;
if ( GinPageIsLeaf ( page ) )
{
GinBtreeDataLeafInsertData * items = insertdata ;
if ( GinPageRightMost ( page ) & & off > GinPageGetOpaque ( page ) - > maxoff )
{
if ( ( btree - > nitem - btree - > curitem ) * sizeof ( ItemPointerData ) < = GinDataPageGetFreeSpace ( page ) )
if ( ( items - > nitem - items - > curitem ) * sizeof ( ItemPointerData ) < = GinDataPageGetFreeSpace ( page ) )
return true ;
}
else if ( sizeof ( ItemPointerData ) < = GinDataPageGetFreeSpace ( page ) )
@ -321,43 +322,22 @@ dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
return false ;
}
/*
* In case of previous split update old child blkno to
* new right page
* item pointer never deletes !
*/
static BlockNumber
dataPrepareData ( GinBtree btree , Page page , OffsetNumber off )
{
BlockNumber ret = InvalidBlockNumber ;
Assert ( GinPageIsData ( page ) ) ;
if ( ! GinPageIsLeaf ( page ) & & btree - > rightblkno ! = InvalidBlockNumber )
{
PostingItem * pitem = GinDataPageGetPostingItem ( page , off ) ;
PostingItemSetBlockNumber ( pitem , btree - > rightblkno ) ;
ret = btree - > rightblkno ;
}
btree - > rightblkno = InvalidBlockNumber ;
return ret ;
}
/*
* Places keys to page and fills WAL record . In case leaf page and
* build mode puts all ItemPointers to page .
*
* If none of the keys fit , returns false without modifying the page .
*
* On insertion to an internal node , in addition to inserting the given item ,
* the downlink of the existing item at ' off ' is updated to point to
* ' updateblkno ' .
*/
static bool
dataPlaceToPage ( GinBtree btree , Buffer buf , OffsetNumber off ,
void * insertdata , BlockNumber updateblkno ,
XLogRecData * * prdata )
{
Page page = BufferGetPage ( buf ) ;
int sizeofitem = GinSizeOfDataPageItem ( page ) ;
int cnt = 0 ;
/* these must be static so they can be returned to caller */
@ -365,14 +345,21 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
static ginxlogInsert data ;
/* quick exit if it doesn't fit */
if ( ! dataIsEnoughSpace ( btree , buf , off ) )
if ( ! dataIsEnoughSpace ( btree , buf , off , insertdata ) )
return false ;
* prdata = rdata ;
Assert ( GinPageIsData ( page ) ) ;
data . updateBlkno = dataPrepareData ( btree , page , off ) ;
/* Update existing downlink to point to next page (on internal page) */
if ( ! GinPageIsLeaf ( page ) )
{
PostingItem * pitem = GinDataPageGetPostingItem ( page , off ) ;
PostingItemSetBlockNumber ( pitem , updateblkno ) ;
}
data . updateBlkno = updateblkno ;
data . node = btree - > index - > rd_node ;
data . blkno = BufferGetBlockNumber ( buf ) ;
data . offset = off ;
@ -405,34 +392,43 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
cnt + + ;
rdata [ cnt ] . buffer = InvalidBuffer ;
rdata [ cnt ] . data = ( GinPageIsLeaf ( page ) ) ? ( ( char * ) ( btree - > items + btree - > curitem ) ) : ( ( char * ) & ( btree - > pitem ) ) ;
rdata [ cnt ] . len = sizeofitem ;
/* data and len filled in below */
rdata [ cnt ] . next = NULL ;
if ( GinPageIsLeaf ( page ) )
{
GinBtreeDataLeafInsertData * items = insertdata ;
uint32 savedPos = items - > curitem ;
if ( GinPageRightMost ( page ) & & off > GinPageGetOpaque ( page ) - > maxoff )
{
/* usually, create index... */
uint32 savedPos = btree - > curitem ;
while ( btree - > curitem < btree - > nitem )
while ( items - > curitem < items - > nitem )
{
GinDataPageAddItemPointer ( page , btree - > items + btree - > curitem , off ) ;
GinDataPageAddItemPointer ( page , items - > items + items - > curitem , off ) ;
off + + ;
btree - > curitem + + ;
items - > curitem + + ;
}
data . nitem = btree - > curitem - savedPos ;
rdata [ cnt ] . len = sizeofitem * data . nitem ;
data . nitem = items - > curitem - savedPos ;
}
else
{
GinDataPageAddItemPointer ( page , btree - > items + btree - > curitem , off ) ;
btree - > curitem + + ;
GinDataPageAddItemPointer ( page , items - > items + items - > curitem , off ) ;
items - > curitem + + ;
}
rdata [ cnt ] . data = ( char * ) & items - > items [ savedPos ] ;
rdata [ cnt ] . len = sizeof ( ItemPointerData ) * data . nitem ;
}
else
GinDataPageAddPostingItem ( page , & ( btree - > pitem ) , off ) ;
{
PostingItem * pitem = insertdata ;
GinDataPageAddPostingItem ( page , pitem , off ) ;
rdata [ cnt ] . data = ( char * ) pitem ;
rdata [ cnt ] . len = sizeof ( PostingItem ) ;
}
return true ;
}
@ -444,7 +440,8 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off,
* left page
*/
static Page
dataSplitPage ( GinBtree btree , Buffer lbuf , Buffer rbuf , OffsetNumber off , XLogRecData * * prdata )
dataSplitPage ( GinBtree btree , Buffer lbuf , Buffer rbuf , OffsetNumber off ,
void * insertdata , BlockNumber updateblkno , XLogRecData * * prdata )
{
char * ptr ;
OffsetNumber separator ;
@ -457,7 +454,6 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
Page rpage = BufferGetPage ( rbuf ) ;
Size pageSize = PageGetPageSize ( lpage ) ;
Size freeSpace ;
uint32 nCopied = 1 ;
/* these must be static so they can be returned to caller */
static ginxlogSplit data ;
@ -468,9 +464,14 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
freeSpace = GinDataPageGetFreeSpace ( rpage ) ;
* prdata = rdata ;
data . leftChildBlkno = ( GinPageIsLeaf ( lpage ) ) ?
InvalidOffsetNumber : PostingItemGetBlockNumber ( & ( btree - > pitem ) ) ;
data . updateBlkno = dataPrepareData ( btree , lpage , off ) ;
/* Update existing downlink to point to next page (on internal page) */
if ( ! isleaf )
{
PostingItem * pitem = GinDataPageGetPostingItem ( lpage , off ) ;
PostingItemSetBlockNumber ( pitem , updateblkno ) ;
}
if ( isleaf )
{
@ -487,16 +488,16 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
if ( isleaf & & GinPageRightMost ( lpage ) & & off > GinPageGetOpaque ( lpage ) - > maxoff )
{
nCopied = 0 ;
while ( btree - > curitem < btree - > nitem & &
GinBtreeDataLeafInsertData * items = insertdata ;
while ( items - > curitem < items - > nitem & &
maxoff * sizeof ( ItemPointerData ) < 2 * ( freeSpace - sizeof ( ItemPointerData ) ) )
{
memcpy ( vector + maxoff * sizeof ( ItemPointerData ) ,
btree - > items + btree - > curitem ,
items - > items + items - > curitem ,
sizeof ( ItemPointerData ) ) ;
maxoff + + ;
nCopied + + ;
btree - > curitem + + ;
items - > curitem + + ;
}
}
else
@ -506,11 +507,17 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
memmove ( ptr + sizeofitem , ptr , ( maxoff - off + 1 ) * sizeofitem ) ;
if ( isleaf )
{
memcpy ( ptr , btree - > items + btree - > curitem , sizeofitem ) ;
btree - > curitem + + ;
GinBtreeDataLeafInsertData * items = insertdata ;
memcpy ( ptr , items - > items + items - > curitem , sizeofitem ) ;
items - > curitem + + ;
}
else
memcpy ( ptr , & ( btree - > pitem ) , sizeofitem ) ;
{
PostingItem * pitem = insertdata ;
memcpy ( ptr , pitem , sizeofitem ) ;
}
maxoff + + ;
}
@ -553,7 +560,7 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
GinPageGetOpaque ( lpage ) - > maxoff ) ;
else
* bound = GinDataPageGetPostingItem ( lpage ,
GinPageGetOpaque ( lpage ) - > maxoff ) - > key ;
GinPageGetOpaque ( lpage ) - > maxoff ) - > key ;
/* set up right bound for right page */
bound = GinDataPageGetRightBound ( rpage ) ;
@ -584,16 +591,18 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
}
/*
* Prepare the state in ' btree ' for inserting a downlink for given buffer .
* Construct insertion payload for inserting the downlink for given buffer .
*/
static void
static void *
dataPrepareDownlink ( GinBtree btree , Buffer lbuf )
{
PostingItem * pitem = palloc ( sizeof ( PostingItem ) ) ;
Page lpage = BufferGetPage ( lbuf ) ;
PostingItemSetBlockNumber ( & ( btree - > pitem ) , BufferGetBlockNumber ( lbuf ) ) ;
btree - > pitem . key = * GinDataPageGetRightBound ( lpage ) ;
btree - > rightblkno = GinPageGetOpaque ( lpage ) - > rightlink ;
PostingItemSetBlockNumber ( pitem , BufferGetBlockNumber ( lbuf ) ) ;
pitem - > key = * GinDataPageGetRightBound ( lpage ) ;
return pitem ;
}
/*
@ -698,11 +707,12 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems,
}
void
ginPrepareDataScan ( GinBtree btree , Relation index )
ginPrepareDataScan ( GinBtree btree , Relation index , BlockNumber rootBlkno )
{
memset ( btree , 0 , sizeof ( GinBtreeData ) ) ;
btree - > index = index ;
btree - > rootBlkno = rootBlkno ;
btree - > findChildPage = dataLocateItem ;
btree - > getLeftMostChild = dataGetLeftMostPage ;
@ -715,7 +725,6 @@ ginPrepareDataScan(GinBtree btree, Relation index)
btree - > prepareDownlink = dataPrepareDownlink ;
btree - > isData = TRUE ;
btree - > isDelete = FALSE ;
btree - > fullScan = FALSE ;
btree - > isBuild = FALSE ;
}
@ -729,29 +738,32 @@ ginInsertItemPointers(Relation index, BlockNumber rootBlkno,
GinStatsData * buildStats )
{
GinBtreeData btree ;
GinBtreeDataLeafInsertData insertdata ;
GinBtreeStack * stack ;
ginPrepareDataScan ( & btree , index ) ;
ginPrepareDataScan ( & btree , index , rootBlkno ) ;
btree . isBuild = ( buildStats ! = NULL ) ;
btree . items = items ;
btree . nitem = nitem ;
btree . curitem = 0 ;
insertdata . items = items ;
insertdata . nitem = nitem ;
insertdata . curitem = 0 ;
while ( btree . curitem < btree . nitem )
while ( insertdata . curitem < insertdata . nitem )
{
stack = ginFindLeafPage ( & btree , rootBlkno , false ) ;
/* search for the leaf page where the first item should go to */
btree . itemptr = insertdata . items [ insertdata . curitem ] ;
stack = ginFindLeafPage ( & btree , false ) ;
if ( btree . findItem ( & btree , stack ) )
{
/*
* btree . items [ btree . curitem ] already exists in index
* Current item already exists in index .
*/
btree . curitem + + ;
insertdata . curitem + + ;
LockBuffer ( stack - > buffer , GIN_UNLOCK ) ;
freeGinBtreeStack ( stack ) ;
}
else
ginInsertValue ( & btree , stack , buildStats ) ;
ginInsertValue ( & btree , stack , & insertdata , buildStats ) ;
}
}
@ -764,11 +776,11 @@ ginScanBeginPostingTree(Relation index, BlockNumber rootBlkno)
GinBtreeData btree ;
GinBtreeStack * stack ;
ginPrepareDataScan ( & btree , index ) ;
ginPrepareDataScan ( & btree , index , rootBlkno ) ;
btree . fullScan = TRUE ;
stack = ginFindLeafPage ( & btree , rootBlkno , TRUE ) ;
stack = ginFindLeafPage ( & btree , TRUE ) ;
return stack ;
}