@ -8,7 +8,7 @@
* Portions Copyright ( c ) 1994 , Regents of the University of California
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
*
* IDENTIFICATION
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / access / gin / ginget . c , v 1.13 2008 / 04 / 14 17 : 05 : 33 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / access / gin / ginget . c , v 1.14 2008 / 04 / 22 17 : 52 : 43 teodor Exp $
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
*/
@ -29,58 +29,16 @@ findItemInPage(Page page, ItemPointer item, OffsetNumber *off)
/* page was deleted by concurrent vacuum */
/* page was deleted by concurrent vacuum */
return false ;
return false ;
if ( * off > maxoff | | * off = = InvalidOffsetNumber )
/*
res = - 1 ;
* scan page to find equal or first greater value
else
*/
res = compareItemPointers ( item , ( ItemPointer ) GinDataPageGetItem ( page , * off ) ) ;
if ( res = = 0 )
{
/* page isn't changed */
return true ;
}
else if ( res > 0 )
{
/*
* some items was added before our position , look further to find it
* or first greater
*/
( * off ) + + ;
for ( ; * off < = maxoff ; ( * off ) + + )
{
res = compareItemPointers ( item , ( ItemPointer ) GinDataPageGetItem ( page , * off ) ) ;
if ( res = = 0 )
return true ;
if ( res < 0 )
for ( * off = FirstOffsetNumber ; * off < = maxoff ; ( * off ) + + )
{
( * off ) - - ;
return true ;
}
}
}
else
{
{
/*
res = compareItemPointers ( item , ( ItemPointer ) GinDataPageGetItem ( page , * off ) ) ;
* some items was deleted before our position , look from begining to
* find it or first greater
*/
for ( * off = FirstOffsetNumber ; * off < = maxoff ; ( * off ) + + )
{
res = compareItemPointers ( item , ( ItemPointer ) GinDataPageGetItem ( page , * off ) ) ;
if ( res = = 0 )
return true ;
if ( res < 0 )
if ( res < = 0 )
{
return true ;
( * off ) - - ;
return true ;
}
}
}
}
return false ;
return false ;
@ -91,119 +49,87 @@ findItemInPage(Page page, ItemPointer item, OffsetNumber *off)
* Stop * functions unlock buffer ( but don ' t release ! )
* Stop * functions unlock buffer ( but don ' t release ! )
*/
*/
static void
static void
startScanEntry ( Relation index , GinState * ginstate , GinScanEntry entry , bool firstCall )
startScanEntry ( Relation index , GinState * ginstate , GinScanEntry entry )
{
{
GinBtreeData btreeEntry ;
GinBtreeStack * stackEntry ;
Page page ;
bool needUnlock = TRUE ;
if ( entry - > master ! = NULL )
if ( entry - > master ! = NULL )
{
{
entry - > isFinished = entry - > master - > isFinished ;
entry - > isFinished = entry - > master - > isFinished ;
return ;
return ;
}
}
if ( firstCall )
/*
{
* we should find entry , and begin scan of posting tree
/*
* or just store posting list in memory
* at first call we should find entry , and begin scan of posting tree
*/
* or just store posting list in memory
*/
GinBtreeData btreeEntry ;
GinBtreeStack * stackEntry ;
Page page ;
bool needUnlock = TRUE ;
prepareEntryScan ( & btreeEntry , index , entry - > entry , ginstate ) ;
btreeEntry . searchMode = TRUE ;
stackEntry = ginFindLeafPage ( & btreeEntry , NULL ) ;
page = BufferGetPage ( stackEntry - > buffer ) ;
entry - > isFinished = TRUE ;
entry - > buffer = InvalidBuffer ;
entry - > offset = InvalidOffsetNumber ;
entry - > list = NULL ;
entry - > nlist = 0 ;
entry - > reduceResult = FALSE ;
entry - > predictNumberResult = 0 ;
if ( btreeEntry . findItem ( & btreeEntry , stackEntry ) )
{
IndexTuple itup = ( IndexTuple ) PageGetItem ( page , PageGetItemId ( page , stackEntry - > off ) ) ;
if ( GinIsPostingTree ( itup ) )
{
BlockNumber rootPostingTree = GinGetPostingTree ( itup ) ;
GinPostingTreeScan * gdi ;
Page page ;
LockBuffer ( stackEntry - > buffer , GIN_UNLOCK ) ;
prepareEntryScan ( & btreeEntry , index , entry - > entry , ginstate ) ;
needUnlock = FALSE ;
btreeEntry . searchMode = TRUE ;
gdi = prepareScanPostingTree ( index , rootPostingTree , TRUE ) ;
stackEntry = ginFindLeafPage ( & btreeEntry , NULL ) ;
page = BufferGetPage ( stackEntry - > buffer ) ;
entry - > buffer = scanBeginPostingTree ( gdi ) ;
entry - > isFinished = TRUE ;
IncrBufferRefCount ( entry - > buffer ) ;
entry - > buffer = InvalidBuffer ;
entry - > offset = InvalidOffsetNumber ;
entry - > list = NULL ;
entry - > nlist = 0 ;
entry - > reduceResult = FALSE ;
entry - > predictNumberResult = 0 ;
page = BufferGetPage ( entry - > buffer ) ;
if ( btreeEntry . findItem ( & btreeEntry , stackEntry ) )
entry - > predictNumberResult = gdi - > stack - > predictNumber * GinPageGetOpaque ( page ) - > maxoff ;
{
IndexTuple itup = ( IndexTuple ) PageGetItem ( page , PageGetItemId ( page , stackEntry - > off ) ) ;
freeGinBtreeStack ( gdi - > stack ) ;
if ( GinIsPostingTree ( itup ) )
pfree ( gdi ) ;
{
entry - > isFinished = FALSE ;
BlockNumber rootPostingTree = GinGetPostingTree ( itup ) ;
}
GinPostingTreeScan * gdi ;
else if ( GinGetNPosting ( itup ) > 0 )
Page page ;
{
entry - > nlist = GinGetNPosting ( itup ) ;
entry - > list = ( ItemPointerData * ) palloc ( sizeof ( ItemPointerData ) * entry - > nlist ) ;
memcpy ( entry - > list , GinGetPosting ( itup ) , sizeof ( ItemPointerData ) * entry - > nlist ) ;
entry - > isFinished = FALSE ;
}
}
if ( needUnlock )
LockBuffer ( stackEntry - > buffer , GIN_UNLOCK ) ;
LockBuffer ( stackEntry - > buffer , GIN_UNLOCK ) ;
freeGinBtreeStack ( stackEntry ) ;
needUnlock = FALSE ;
}
gdi = prepareScanPostingTree ( index , rootPostingTree , TRUE ) ;
else if ( entry - > buffer ! = InvalidBuffer )
{
/* we should find place where we was stopped */
BlockNumber blkno ;
Page page ;
LockBuffer ( entry - > buffer , GIN_SHARE ) ;
entry - > buffer = scanBeginPostingTree ( gdi ) ;
/*
if ( ! ItemPointerIsValid ( & entry - > curItem ) )
* We keep buffer pinned because we need to prevent deletition
/* start position */
* page during scan . See GIN ' s vacuum implementation . RefCount
return ;
* is increased to keep buffer pinned after freeGinBtreeStack ( ) call .
Assert ( entry - > offset ! = InvalidOffsetNumber ) ;
*/
IncrBufferRefCount ( entry - > buffer ) ;
page = BufferGetPage ( entry - > buffer ) ;
page = BufferGetPage ( entry - > buffer ) ;
entry - > predictNumberResult = gdi - > stack - > predictNumber * GinPageGetOpaque ( page ) - > maxoff ;
/* try to find curItem in current buffer */
/*
if ( findItemInPage ( page , & entry - > curItem , & entry - > offset ) )
* Keep page content in memory to prevent durable page locking
return ;
*/
entry - > list = ( ItemPointerData * ) palloc ( BLCKSZ ) ;
entry - > nlist = GinPageGetOpaque ( page ) - > maxoff ;
memcpy ( entry - > list , GinDataPageGetItem ( page , FirstOffsetNumber ) ,
GinPageGetOpaque ( page ) - > maxoff * sizeof ( ItemPointerData ) ) ;
/* walk to right */
while ( ( blkno = GinPageGetOpaque ( page ) - > rightlink ) ! = InvalidBlockNumber )
{
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
entry - > buffer = ReleaseAndReadBuffer ( entry - > buffer , index , blkno ) ;
freeGinBtreeStack ( gdi - > stack ) ;
LockBuffer ( entry - > buffer , GIN_SHARE ) ;
pfree ( gdi ) ;
page = BufferGetPage ( entry - > buffer ) ;
entry - > isFinished = FALSE ;
}
entry - > offset = InvalidOffsetNumber ;
else if ( GinGetNPosting ( itup ) > 0 )
if ( findItemInPage ( page , & entry - > curItem , & entry - > offset ) )
{
return ;
entry - > nlist = GinGetNPosting ( itup ) ;
entry - > list = ( ItemPointerData * ) palloc ( sizeof ( ItemPointerData ) * entry - > nlist ) ;
memcpy ( entry - > list , GinGetPosting ( itup ) , sizeof ( ItemPointerData ) * entry - > nlist ) ;
entry - > isFinished = FALSE ;
}
}
/*
* curItem and any greated items was deleted by concurrent vacuum , so
* we finished scan with currrent entry
*/
}
}
}
static void
if ( needUnlock )
stopScanEntry ( GinScanEntry entry )
LockBuffer ( stackEntry - > buffer , GIN_UNLOCK ) ;
{
freeGinBtreeStack ( stackEntry ) ;
if ( entry - > buffer ! = InvalidBuffer )
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
}
}
static void
static void
@ -211,47 +137,38 @@ startScanKey(Relation index, GinState *ginstate, GinScanKey key)
{
{
uint32 i ;
uint32 i ;
if ( ! key - > firstCall )
return ;
for ( i = 0 ; i < key - > nentries ; i + + )
for ( i = 0 ; i < key - > nentries ; i + + )
startScanEntry ( index , ginstate , key - > scanEntry + i , key - > firstCall ) ;
startScanEntry ( index , ginstate , key - > scanEntry + i ) ;
if ( key - > firstCall )
memset ( key - > entryRes , TRUE , sizeof ( bool ) * key - > nentries ) ;
{
key - > isFinished = FALSE ;
memset ( key - > entryRes , TRUE , sizeof ( bool ) * key - > nentries ) ;
key - > firstCall = FALSE ;
key - > isFinished = FALSE ;
key - > firstCall = FALSE ;
if ( GinFuzzySearchLimit > 0 )
if ( GinFuzzySearchLimit > 0 )
{
{
/*
/*
* If all of keys more than threshold we will try to reduce
* If all of keys more than threshold we will try to reduce
* result , we hope ( and only hope , for intersection operation of
* result , we hope ( and only hope , for intersection operation of
* array our supposition isn ' t true ) , that total result will not
* array our supposition isn ' t true ) , that total result will not
* more than minimal predictNumberResult .
* more than minimal predictNumberResult .
*/
*/
for ( i = 0 ; i < key - > nentries ; i + + )
for ( i = 0 ; i < key - > nentries ; i + + )
if ( key - > scanEntry [ i ] . predictNumberResult < = key - > nentries * GinFuzzySearchLimit )
if ( key - > scanEntry [ i ] . predictNumberResult < = key - > nentries * GinFuzzySearchLimit )
return ;
return ;
for ( i = 0 ; i < key - > nentries ; i + + )
for ( i = 0 ; i < key - > nentries ; i + + )
if ( key - > scanEntry [ i ] . predictNumberResult > key - > nentries * GinFuzzySearchLimit )
if ( key - > scanEntry [ i ] . predictNumberResult > key - > nentries * GinFuzzySearchLimit )
{
{
key - > scanEntry [ i ] . predictNumberResult / = key - > nentries ;
key - > scanEntry [ i ] . predictNumberResult / = key - > nentries ;
key - > scanEntry [ i ] . reduceResult = TRUE ;
key - > scanEntry [ i ] . reduceResult = TRUE ;
}
}
}
}
}
}
}
static void
stopScanKey ( GinScanKey key )
{
uint32 i ;
for ( i = 0 ; i < key - > nentries ; i + + )
stopScanEntry ( key - > scanEntry + i ) ;
}
static void
static void
startScan ( IndexScanDesc scan )
startScan ( IndexScanDesc scan )
{
{
@ -262,44 +179,82 @@ startScan(IndexScanDesc scan)
startScanKey ( scan - > indexRelation , & so - > ginstate , so - > keys + i ) ;
startScanKey ( scan - > indexRelation , & so - > ginstate , so - > keys + i ) ;
}
}
static void
/*
stopScan ( IndexScanDesc scan )
* Gets next ItemPointer from PostingTree . Note , that we copy
{
* page into GinScanEntry - > list array and unlock page , but keep it pinned
uint32 i ;
* to prevent interference with vacuum
GinScanOpaque so = ( GinScanOpaque ) scan - > opaque ;
*/
for ( i = 0 ; i < so - > nkeys ; i + + )
stopScanKey ( so - > keys + i ) ;
}
static void
static void
entryGetNextItem ( Relation index , GinScanEntry entry )
entryGetNextItem ( Relation index , GinScanEntry entry )
{
{
Page page = BufferGetPage ( entry - > buffer ) ;
Page page ;
BlockNumber blkno ;
entry - > offset + + ;
for ( ; ; )
if ( entry - > offset < = GinPageGetOpaque ( page ) - > maxoff & & GinPageGetOpaque ( page ) - > maxoff > = FirstOffsetNumber )
{
{
entry - > curItem = * ( ItemPointerData * ) GinDataPageGetItem ( page , entry - > offset ) ;
entry - > offset + + ;
}
else
{
BlockNumber blkno = GinPageGetOpaque ( page ) - > rightlink ;
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
if ( entry - > offset < = entry - > nlist )
if ( blkno = = InvalidBlockNumber )
{
{
ReleaseBuffer ( entry - > buffer ) ;
entry - > curItem = entry - > list [ entry - > offset - 1 ] ;
entry - > buffer = InvalidBuffer ;
return ;
entry - > isFinished = TRUE ;
}
}
else
LockBuffer ( entry - > buffer , GIN_SHARE ) ;
page = BufferGetPage ( entry - > buffer ) ;
for ( ; ; )
{
{
/*
* It ' s needed to go by right link . During that we should refind
* first ItemPointer greater that stored
*/
blkno = GinPageGetOpaque ( page ) - > rightlink ;
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
if ( blkno = = InvalidBlockNumber )
{
ReleaseBuffer ( entry - > buffer ) ;
ItemPointerSet ( & entry - > curItem , InvalidBlockNumber , InvalidOffsetNumber ) ;
entry - > buffer = InvalidBuffer ;
entry - > isFinished = TRUE ;
return ;
}
entry - > buffer = ReleaseAndReadBuffer ( entry - > buffer , index , blkno ) ;
entry - > buffer = ReleaseAndReadBuffer ( entry - > buffer , index , blkno ) ;
LockBuffer ( entry - > buffer , GIN_SHARE ) ;
LockBuffer ( entry - > buffer , GIN_SHARE ) ;
page = BufferGetPage ( entry - > buffer ) ;
entry - > offset = InvalidOffsetNumber ;
entry - > offset = InvalidOffsetNumber ;
entryGetNextItem ( index , entry ) ;
if ( ! ItemPointerIsValid ( & entry - > curItem ) | | findItemInPage ( page , & entry - > curItem , & entry - > offset ) )
{
/*
* Found position equal to or greater than stored
*/
entry - > nlist = GinPageGetOpaque ( page ) - > maxoff ;
memcpy ( entry - > list , GinDataPageGetItem ( page , FirstOffsetNumber ) ,
GinPageGetOpaque ( page ) - > maxoff * sizeof ( ItemPointerData ) ) ;
LockBuffer ( entry - > buffer , GIN_UNLOCK ) ;
if ( ! ItemPointerIsValid ( & entry - > curItem ) | |
compareItemPointers ( & entry - > curItem , entry - > list + entry - > offset - 1 ) = = 0 )
{
/*
* First pages are deleted or empty , or we found exact position ,
* so break inner loop and continue outer one .
*/
break ;
}
/*
* Find greater than entry - > curItem position , store it .
*/
entry - > curItem = entry - > list [ entry - > offset - 1 ] ;
return ;
}
}
}
}
}
}
}
@ -319,7 +274,7 @@ entryGetItem(Relation index, GinScanEntry entry)
entry - > isFinished = entry - > master - > isFinished ;
entry - > isFinished = entry - > master - > isFinished ;
entry - > curItem = entry - > master - > curItem ;
entry - > curItem = entry - > master - > curItem ;
}
}
else if ( entry - > list )
else if ( ! BufferIsValid ( entry - > buffer ) )
{
{
entry - > offset + + ;
entry - > offset + + ;
if ( entry - > offset < = entry - > nlist )
if ( entry - > offset < = entry - > nlist )
@ -527,8 +482,6 @@ gingetbitmap(PG_FUNCTION_ARGS)
ntids + + ;
ntids + + ;
}
}
stopScan ( scan ) ;
PG_RETURN_INT64 ( ntids ) ;
PG_RETURN_INT64 ( ntids ) ;
}
}
@ -550,7 +503,6 @@ gingettuple(PG_FUNCTION_ARGS)
startScan ( scan ) ;
startScan ( scan ) ;
res = scanGetItem ( scan , & scan - > xs_ctup . t_self , & scan - > xs_recheck ) ;
res = scanGetItem ( scan , & scan - > xs_ctup . t_self , & scan - > xs_recheck ) ;
stopScan ( scan ) ;
PG_RETURN_BOOL ( res ) ;
PG_RETURN_BOOL ( res ) ;
}
}