1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

pgindent run for 8.2.

This commit is contained in:
Bruce Momjian
2006-10-04 00:30:14 +00:00
parent 451e419e98
commit f99a569a2e
522 changed files with 21297 additions and 17170 deletions

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginarrayproc.c
* support functions for GIN's indexing of any array
* support functions for GIN's indexing of any array
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.5 2006/09/10 20:14:20 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -23,64 +23,73 @@
#define GinContainedStrategy 3
#define GinEqualStrategy 4
#define ARRAYCHECK(x) do { \
#define ARRAYCHECK(x) do { \
if ( ARR_HASNULL(x) ) \
ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \
} while(0)
ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \
} while(0)
/*
* Function used as extractValue and extractQuery both
*/
Datum
ginarrayextract(PG_FUNCTION_ARGS) {
ArrayType *array;
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
Datum *entries = NULL;
int16 elmlen;
bool elmbyval;
char elmalign;
ginarrayextract(PG_FUNCTION_ARGS)
{
ArrayType *array;
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
int16 elmlen;
bool elmbyval;
char elmalign;
/* we should guarantee that array will not be destroyed during all operation */
/*
* we should guarantee that array will not be destroyed during all
* operation
*/
array = PG_GETARG_ARRAYTYPE_P_COPY(0);
ARRAYCHECK(array);
get_typlenbyvalalign(ARR_ELEMTYPE(array),
&elmlen, &elmbyval, &elmalign);
&elmlen, &elmbyval, &elmalign);
deconstruct_array(array,
ARR_ELEMTYPE(array),
elmlen, elmbyval, elmalign,
&entries, NULL, (int*)nentries);
ARR_ELEMTYPE(array),
elmlen, elmbyval, elmalign,
&entries, NULL, (int *) nentries);
/* we should not free array, entries[i] points into it */
PG_RETURN_POINTER(entries);
}
Datum
ginarrayconsistent(PG_FUNCTION_ARGS) {
bool *check = (bool*)PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int res, i, nentries;
ginarrayconsistent(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int res,
i,
nentries;
/* ARRAYCHECK was already done by previous ginarrayextract call */
switch( strategy ) {
switch (strategy)
{
case GinOverlapStrategy:
case GinContainedStrategy:
/* at least one element in check[] is true, so result = true */
/* at least one element in check[] is true, so result = true */
res = TRUE;
break;
case GinContainsStrategy:
case GinEqualStrategy:
nentries=ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
res = TRUE;
for(i=0;i<nentries;i++)
if ( !check[i] ) {
for (i = 0; i < nentries; i++)
if (!check[i])
{
res = FALSE;
break;
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginbtree.c
* page utilities routines for the postgres inverted index access method.
* page utilities routines for the postgres inverted index access method.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -20,24 +20,29 @@
* Locks buffer by needed method for search.
*/
static int
ginTraverseLock(Buffer buffer, bool searchMode) {
Page page;
int access=GIN_SHARE;
ginTraverseLock(Buffer buffer, bool searchMode)
{
Page page;
int access = GIN_SHARE;
LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage( buffer );
if ( GinPageIsLeaf(page) ) {
if ( searchMode == FALSE ) {
page = BufferGetPage(buffer);
if (GinPageIsLeaf(page))
{
if (searchMode == FALSE)
{
/* we should relock our page */
LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_EXCLUSIVE);
/* But root can become non-leaf during relock */
if ( !GinPageIsLeaf(page) ) {
/* resore old lock type (very rare) */
if (!GinPageIsLeaf(page))
{
/* resore old lock type (very rare) */
LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_SHARE);
} else
}
else
access = GIN_EXCLUSIVE;
}
}
@@ -45,9 +50,10 @@ ginTraverseLock(Buffer buffer, bool searchMode) {
return access;
}
GinBtreeStack*
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
GinBtreeStack *stack = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
GinBtreeStack *
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno)
{
GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
stack->blkno = blkno;
stack->buffer = ReadBuffer(btree->index, stack->blkno);
@@ -62,63 +68,73 @@ ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
/*
* Locates leaf page contained tuple
*/
GinBtreeStack*
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
bool isfirst=TRUE;
GinBtreeStack *
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack)
{
bool isfirst = TRUE;
BlockNumber rootBlkno;
if ( !stack )
if (!stack)
stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO);
rootBlkno = stack->blkno;
for(;;) {
Page page;
for (;;)
{
Page page;
BlockNumber child;
int access=GIN_SHARE;
int access = GIN_SHARE;
stack->off = InvalidOffsetNumber;
page = BufferGetPage( stack->buffer );
if ( isfirst ) {
if ( GinPageIsLeaf(page) && !btree->searchMode )
page = BufferGetPage(stack->buffer);
if (isfirst)
{
if (GinPageIsLeaf(page) && !btree->searchMode)
access = GIN_EXCLUSIVE;
isfirst = FALSE;
} else
}
else
access = ginTraverseLock(stack->buffer, btree->searchMode);
/* ok, page is correctly locked, we should check to move right ..,
root never has a right link, so small optimization */
while( btree->fullScan==FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page) ) {
/*
* ok, page is correctly locked, we should check to move right ..,
* root never has a right link, so small optimization
*/
while (btree->fullScan == FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page))
{
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
if ( rightlink==InvalidBlockNumber )
if (rightlink == InvalidBlockNumber)
/* rightmost page */
break;
stack->blkno = rightlink;
LockBuffer(stack->buffer, GIN_UNLOCK);
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
LockBuffer(stack->buffer, access);
page = BufferGetPage( stack->buffer );
LockBuffer(stack->buffer, access);
page = BufferGetPage(stack->buffer);
}
if ( GinPageIsLeaf(page) ) /* we found, return locked page */
if (GinPageIsLeaf(page)) /* we found, return locked page */
return stack;
/* now we have correct buffer, try to find child */
child = btree->findChildPage(btree, stack);
LockBuffer(stack->buffer, GIN_UNLOCK);
Assert( child != InvalidBlockNumber );
Assert( stack->blkno != child );
Assert(child != InvalidBlockNumber);
Assert(stack->blkno != child);
if ( btree->searchMode ) {
if (btree->searchMode)
{
/* in search mode we may forget path to leaf */
stack->blkno = child;
stack->buffer = ReleaseAndReadBuffer( stack->buffer, btree->index, stack->blkno );
} else {
GinBtreeStack *ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
}
else
{
GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->parent = stack;
stack = ptr;
@@ -133,93 +149,110 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
}
void
freeGinBtreeStack( GinBtreeStack *stack ) {
while(stack) {
GinBtreeStack *tmp = stack->parent;
if ( stack->buffer != InvalidBuffer )
freeGinBtreeStack(GinBtreeStack *stack)
{
while (stack)
{
GinBtreeStack *tmp = stack->parent;
if (stack->buffer != InvalidBuffer)
ReleaseBuffer(stack->buffer);
pfree( stack );
pfree(stack);
stack = tmp;
}
}
/*
* Try to find parent for current stack position, returns correct
* Try to find parent for current stack position, returns correct
* parent and child's offset in stack->parent.
* Function should never release root page to prevent conflicts
* with vacuum process
*/
void
findParents( GinBtree btree, GinBtreeStack *stack,
BlockNumber rootBlkno) {
findParents(GinBtree btree, GinBtreeStack *stack,
BlockNumber rootBlkno)
{
Page page;
Buffer buffer;
BlockNumber blkno, leftmostBlkno;
Page page;
Buffer buffer;
BlockNumber blkno,
leftmostBlkno;
OffsetNumber offset;
GinBtreeStack *root = stack->parent;
GinBtreeStack *ptr;
GinBtreeStack *root = stack->parent;
GinBtreeStack *ptr;
if ( !root ) {
if (!root)
{
/* XLog mode... */
root = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
root->blkno = rootBlkno;
root->buffer = ReadBuffer(btree->index, rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE);
root->parent = NULL;
} else {
/* find root, we should not release root page until update is finished!! */
while( root->parent ) {
ReleaseBuffer( root->buffer );
}
else
{
/*
* find root, we should not release root page until update is
* finished!!
*/
while (root->parent)
{
ReleaseBuffer(root->buffer);
root = root->parent;
}
Assert( root->blkno == rootBlkno );
Assert( BufferGetBlockNumber(root->buffer) == rootBlkno );
Assert(root->blkno == rootBlkno);
Assert(BufferGetBlockNumber(root->buffer) == rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE);
}
root->off = InvalidOffsetNumber;
page = BufferGetPage(root->buffer);
Assert( !GinPageIsLeaf(page) );
Assert(!GinPageIsLeaf(page));
/* check trivial case */
if ( (root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber ) {
if ((root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber)
{
stack->parent = root;
return;
}
leftmostBlkno = blkno = btree->getLeftMostPage(btree, page);
LockBuffer(root->buffer, GIN_UNLOCK );
Assert( blkno!=InvalidBlockNumber );
LockBuffer(root->buffer, GIN_UNLOCK);
Assert(blkno != InvalidBlockNumber);
for(;;) {
for (;;)
{
buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
if ( GinPageIsLeaf(page) )
if (GinPageIsLeaf(page))
elog(ERROR, "Lost path");
leftmostBlkno = btree->getLeftMostPage(btree, page);
while( (offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber))==InvalidOffsetNumber ) {
while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
{
blkno = GinPageGetOpaque(page)->rightlink;
LockBuffer(buffer,GIN_UNLOCK);
LockBuffer(buffer, GIN_UNLOCK);
ReleaseBuffer(buffer);
if ( blkno == InvalidBlockNumber )
if (blkno == InvalidBlockNumber)
break;
buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
}
if ( blkno != InvalidBlockNumber ) {
ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
if (blkno != InvalidBlockNumber)
{
ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->blkno = blkno;
ptr->buffer = buffer;
ptr->parent = root; /* it's may be wrong, but in next call we will correct */
ptr->parent = root; /* it's may be wrong, but in next call we will
* correct */
ptr->off = offset;
stack->parent = ptr;
return;
@@ -233,79 +266,94 @@ findParents( GinBtree btree, GinBtreeStack *stack,
* Insert value (stored in GinBtree) to tree descibed by stack
*/
void
ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
GinBtreeStack *parent = stack;
BlockNumber rootBlkno = InvalidBuffer;
Page page, rpage, lpage;
ginInsertValue(GinBtree btree, GinBtreeStack *stack)
{
GinBtreeStack *parent = stack;
BlockNumber rootBlkno = InvalidBuffer;
Page page,
rpage,
lpage;
/* remember root BlockNumber */
while( parent ) {
while (parent)
{
rootBlkno = parent->blkno;
parent = parent->parent;
}
while( stack ) {
while (stack)
{
XLogRecData *rdata;
BlockNumber savedRightLink;
BlockNumber savedRightLink;
page = BufferGetPage( stack->buffer );
page = BufferGetPage(stack->buffer);
savedRightLink = GinPageGetOpaque(page)->rightlink;
if ( btree->isEnoughSpace( btree, stack->buffer, stack->off ) ) {
if (btree->isEnoughSpace(btree, stack->buffer, stack->off))
{
START_CRIT_SECTION();
btree->placeToPage( btree, stack->buffer, stack->off, &rdata );
btree->placeToPage(btree, stack->buffer, stack->off, &rdata);
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata);
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty( stack->buffer );
MarkBufferDirty(stack->buffer);
UnlockReleaseBuffer(stack->buffer);
END_CRIT_SECTION();
freeGinBtreeStack(stack->parent);
return;
} else {
Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage;
}
else
{
Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage;
/* newlpage is a pointer to memory page, it does'nt assosiates with buffer,
stack->buffer shoud be untouched */
newlpage = btree->splitPage( btree, stack->buffer, rbuffer, stack->off, &rdata );
/*
* newlpage is a pointer to memory page, it does'nt assosiates
* with buffer, stack->buffer shoud be untouched
*/
newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata);
((ginxlogSplit*)(rdata->data))->rootBlkno = rootBlkno;
((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno;
parent = stack->parent;
if ( parent == NULL ) {
/* split root, so we need to allocate new left page and
place pointer on root to left and right page */
Buffer lbuffer = GinNewBuffer(btree->index);
if (parent == NULL)
{
/*
* split root, so we need to allocate new left page and place
* pointer on root to left and right page
*/
Buffer lbuffer = GinNewBuffer(btree->index);
((ginxlogSplit*)(rdata->data))->isRootSplit = TRUE;
((ginxlogSplit*)(rdata->data))->rrlink = InvalidBlockNumber;
((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE;
((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber;
page = BufferGetPage( stack->buffer );
lpage = BufferGetPage( lbuffer );
rpage = BufferGetPage( rbuffer );
page = BufferGetPage(stack->buffer);
lpage = BufferGetPage(lbuffer);
rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
((ginxlogSplit*)(rdata->data))->lblkno = BufferGetBlockNumber(lbuffer);
((ginxlogSplit *) (rdata->data))->lblkno = BufferGetBlockNumber(lbuffer);
START_CRIT_SECTION();
GinInitBuffer( stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF );
PageRestoreTempPage( newlpage, lpage );
btree->fillRoot( btree, stack->buffer, lbuffer, rbuffer );
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF);
PageRestoreTempPage(newlpage, lpage);
btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer);
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
PageSetLSN(page, recptr);
@@ -324,23 +372,26 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
UnlockReleaseBuffer(stack->buffer);
END_CRIT_SECTION();
return;
} else {
/* split non-root page */
((ginxlogSplit*)(rdata->data))->isRootSplit = FALSE;
((ginxlogSplit*)(rdata->data))->rrlink = savedRightLink;
lpage = BufferGetPage( stack->buffer );
rpage = BufferGetPage( rbuffer );
return;
}
else
{
/* split non-root page */
((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE;
((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink;
lpage = BufferGetPage(stack->buffer);
rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = savedRightLink;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
START_CRIT_SECTION();
PageRestoreTempPage( newlpage, lpage );
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
PageRestoreTempPage(newlpage, lpage);
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
PageSetLSN(lpage, recptr);
@@ -350,7 +401,7 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
}
MarkBufferDirty(rbuffer);
UnlockReleaseBuffer(rbuffer);
MarkBufferDirty( stack->buffer );
MarkBufferDirty(stack->buffer);
END_CRIT_SECTION();
}
}
@@ -361,31 +412,33 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
/* move right if it's needed */
page = BufferGetPage( parent->buffer );
while( (parent->off=btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber ) {
page = BufferGetPage(parent->buffer);
while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
{
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
LockBuffer(parent->buffer, GIN_UNLOCK);
if ( rightlink==InvalidBlockNumber ) {
/* rightmost page, but we don't find parent, we should
use plain search... */
if (rightlink == InvalidBlockNumber)
{
/*
* rightmost page, but we don't find parent, we should use
* plain search...
*/
findParents(btree, stack, rootBlkno);
parent=stack->parent;
page = BufferGetPage( parent->buffer );
parent = stack->parent;
page = BufferGetPage(parent->buffer);
break;
}
parent->blkno = rightlink;
parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno);
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
page = BufferGetPage( parent->buffer );
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
page = BufferGetPage(parent->buffer);
}
UnlockReleaseBuffer(stack->buffer);
pfree( stack );
pfree(stack);
stack = parent;
}
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginbulk.c
* routines for fast build of inverted index
* routines for fast build of inverted index
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.5 2006/08/29 14:05:44 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -22,7 +22,8 @@
#define DEF_NPTR 4
void
ginInitBA(BuildAccumulator *accum) {
ginInitBA(BuildAccumulator *accum)
{
accum->maxdepth = 1;
accum->stackpos = 0;
accum->entries = NULL;
@@ -31,11 +32,13 @@ ginInitBA(BuildAccumulator *accum) {
accum->entryallocator = NULL;
}
static EntryAccumulator*
EAAllocate( BuildAccumulator *accum ) {
if ( accum->entryallocator == NULL || accum->length>=DEF_NENTRY ) {
accum->entryallocator = palloc(sizeof(EntryAccumulator)*DEF_NENTRY);
accum->allocatedMemory += sizeof(EntryAccumulator)*DEF_NENTRY;
static EntryAccumulator *
EAAllocate(BuildAccumulator *accum)
{
if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
{
accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
accum->allocatedMemory += sizeof(EntryAccumulator) * DEF_NENTRY;
accum->length = 0;
}
@@ -48,24 +51,27 @@ EAAllocate( BuildAccumulator *accum ) {
* item pointer are ordered
*/
static void
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr) {
if ( entry->number >= entry->length ) {
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr)
{
if (entry->number >= entry->length)
{
accum->allocatedMemory += sizeof(ItemPointerData) * entry->length;
entry->length *= 2;
entry->list = (ItemPointerData*)repalloc(entry->list,
sizeof(ItemPointerData)*entry->length);
entry->list = (ItemPointerData *) repalloc(entry->list,
sizeof(ItemPointerData) * entry->length);
}
if ( entry->shouldSort==FALSE ) {
int res = compareItemPointers( entry->list + entry->number - 1, heapptr );
if (entry->shouldSort == FALSE)
{
int res = compareItemPointers(entry->list + entry->number - 1, heapptr);
Assert( res != 0 );
Assert(res != 0);
if ( res > 0 )
entry->shouldSort=TRUE;
if (res > 0)
entry->shouldSort = TRUE;
}
entry->list[ entry->number ] = *heapptr;
entry->list[entry->number] = *heapptr;
entry->number++;
}
@@ -74,7 +80,8 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
* to avoid computing the datum size twice.
*/
static Datum
getDatumCopy(BuildAccumulator *accum, Datum value) {
getDatumCopy(BuildAccumulator *accum, Datum value)
{
Form_pg_attribute *att = accum->ginstate->tupdesc->attrs;
Datum res;
@@ -100,51 +107,58 @@ getDatumCopy(BuildAccumulator *accum, Datum value) {
* Find/store one entry from indexed value.
*/
static void
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
EntryAccumulator *ea = accum->entries, *pea = NULL;
int res = 0;
uint32 depth = 1;
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
{
EntryAccumulator *ea = accum->entries,
*pea = NULL;
int res = 0;
uint32 depth = 1;
while( ea ) {
while (ea)
{
res = compareEntries(accum->ginstate, entry, ea->value);
if ( res == 0 )
break; /* found */
else {
if (res == 0)
break; /* found */
else
{
pea = ea;
if ( res < 0 )
if (res < 0)
ea = ea->left;
else
ea = ea->right;
}
depth++;
}
if ( depth > accum->maxdepth )
if (depth > accum->maxdepth)
accum->maxdepth = depth;
if ( ea == NULL ) {
if (ea == NULL)
{
ea = EAAllocate(accum);
ea->left = ea->right = NULL;
ea->value = getDatumCopy(accum, entry);
ea->value = getDatumCopy(accum, entry);
ea->length = DEF_NPTR;
ea->number = 1;
ea->shouldSort = FALSE;
ea->list = (ItemPointerData*)palloc(sizeof(ItemPointerData)*DEF_NPTR);
ea->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
ea->list[0] = *heapptr;
accum->allocatedMemory += sizeof(ItemPointerData)*DEF_NPTR;
accum->allocatedMemory += sizeof(ItemPointerData) * DEF_NPTR;
if ( pea == NULL )
if (pea == NULL)
accum->entries = ea;
else {
Assert( res != 0 );
if ( res < 0 )
else
{
Assert(res != 0);
if (res < 0)
pea->left = ea;
else
pea->right = ea;
}
} else
ginInsertData( accum, ea, heapptr );
}
else
ginInsertData(accum, ea, heapptr);
}
/*
@@ -152,22 +166,23 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
* then calls itself for each parts
*/
static void
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
uint32 low, uint32 high, uint32 offset) {
uint32 pos;
uint32 middle = (low+high)>>1;
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
uint32 low, uint32 high, uint32 offset)
{
uint32 pos;
uint32 middle = (low + high) >> 1;
pos = (low+middle)>>1;
if ( low!=middle && pos>=offset && pos-offset < nentry )
ginInsertEntry( accum, heapptr, entries[ pos-offset ]);
pos = (high+middle+1)>>1;
if ( middle+1 != high && pos>=offset && pos-offset < nentry )
ginInsertEntry( accum, heapptr, entries[ pos-offset ]);
pos = (low + middle) >> 1;
if (low != middle && pos >= offset && pos - offset < nentry)
ginInsertEntry(accum, heapptr, entries[pos - offset]);
pos = (high + middle + 1) >> 1;
if (middle + 1 != high && pos >= offset && pos - offset < nentry)
ginInsertEntry(accum, heapptr, entries[pos - offset]);
if ( low!=middle )
ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset );
if ( high!=middle+1 )
ginChooseElem(accum, heapptr, entries, nentry, middle+1, high, offset );
if (low != middle)
ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset);
if (high != middle + 1)
ginChooseElem(accum, heapptr, entries, nentry, middle + 1, high, offset);
}
/*
@@ -176,56 +191,71 @@ ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint
* next middle on left part and middle of right part.
*/
void
ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry ) {
uint32 i, nbit=0, offset;
ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry)
{
uint32 i,
nbit = 0,
offset;
if (nentry==0)
if (nentry == 0)
return;
i=nentry-1;
for(;i>0;i>>=1) nbit++;
i = nentry - 1;
for (; i > 0; i >>= 1)
nbit++;
nbit = 1<<nbit;
offset = (nbit-nentry)/2;
nbit = 1 << nbit;
offset = (nbit - nentry) / 2;
ginInsertEntry( accum, heapptr, entries[ (nbit>>1)-offset ]);
ginInsertEntry(accum, heapptr, entries[(nbit >> 1) - offset]);
ginChooseElem(accum, heapptr, entries, nentry, 0, nbit, offset);
}
static int
qsortCompareItemPointers( const void *a, const void *b ) {
int res = compareItemPointers( (ItemPointer)a, (ItemPointer)b );
Assert( res!=0 );
static int
qsortCompareItemPointers(const void *a, const void *b)
{
int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
Assert(res != 0);
return res;
}
/*
* walk on binary tree and returns ordered nodes
*/
static EntryAccumulator*
walkTree( BuildAccumulator *accum ) {
EntryAccumulator *entry = accum->stack[ accum->stackpos ];
* walk on binary tree and returns ordered nodes
*/
static EntryAccumulator *
walkTree(BuildAccumulator *accum)
{
EntryAccumulator *entry = accum->stack[accum->stackpos];
if ( entry->list != NULL ) {
if (entry->list != NULL)
{
/* return entry itself: we already was at left sublink */
return entry;
} else if ( entry->right && entry->right != accum->stack[ accum->stackpos+1 ] ) {
}
else if (entry->right && entry->right != accum->stack[accum->stackpos + 1])
{
/* go on right sublink */
accum->stackpos++;
entry = entry->right;
/* find most-left value */
for(;;) {
accum->stack[ accum->stackpos ] = entry;
if ( entry->left ) {
for (;;)
{
accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++;
entry = entry->left;
} else
}
else
break;
}
} else {
}
else
{
/* we already return all left subtree, itself and right subtree */
if ( accum->stackpos == 0 )
if (accum->stackpos == 0)
return 0;
accum->stackpos--;
return walkTree(accum);
@@ -234,47 +264,53 @@ walkTree( BuildAccumulator *accum ) {
return entry;
}
ItemPointerData*
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
EntryAccumulator *entry;
ItemPointerData *
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
{
EntryAccumulator *entry;
ItemPointerData *list;
if ( accum->stack == NULL ) {
if (accum->stack == NULL)
{
/* first call */
accum->stack = palloc0(sizeof(EntryAccumulator*)*(accum->maxdepth+1));
accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
entry = accum->entries;
if ( entry == NULL )
if (entry == NULL)
return NULL;
/* find most-left value */
for(;;) {
accum->stack[ accum->stackpos ] = entry;
if ( entry->left ) {
for (;;)
{
accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++;
entry = entry->left;
} else
}
else
break;
}
} else {
pfree( accum->stack[ accum->stackpos ]->list );
accum->stack[ accum->stackpos ]->list = NULL;
entry = walkTree( accum );
}
else
{
pfree(accum->stack[accum->stackpos]->list);
accum->stack[accum->stackpos]->list = NULL;
entry = walkTree(accum);
}
if ( entry == NULL )
if (entry == NULL)
return NULL;
*n = entry->number;
*value = entry->value;
list = entry->list;
*n = entry->number;
*value = entry->value;
list = entry->list;
Assert(list != NULL);
if ( entry->shouldSort && entry->number > 1 )
if (entry->shouldSort && entry->number > 1)
qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);
return list;
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* gindatapage.c
* page utilities routines for the postgres inverted index access method.
* page utilities routines for the postgres inverted index access method.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.3 2006/07/16 00:52:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.4 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -16,50 +16,56 @@
#include "access/gin.h"
int
compareItemPointers( ItemPointer a, ItemPointer b ) {
if ( GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b) ) {
if ( GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b) )
compareItemPointers(ItemPointer a, ItemPointer b)
{
if (GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b))
{
if (GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b))
return 0;
return ( GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b) ) ? 1 : -1;
}
return (GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b)) ? 1 : -1;
}
return ( GinItemPointerGetBlockNumber(a) > GinItemPointerGetBlockNumber(b) ) ? 1 : -1;
return (GinItemPointerGetBlockNumber(a) > GinItemPointerGetBlockNumber(b)) ? 1 : -1;
}
/*
* Merge two ordered array of itempointer
*/
void
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) {
void
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb)
{
ItemPointerData *dptr = dst;
ItemPointerData *aptr = a, *bptr = b;
ItemPointerData *aptr = a,
*bptr = b;
while( aptr - a < na && bptr - b < nb ) {
if ( compareItemPointers(aptr, bptr) > 0 )
while (aptr - a < na && bptr - b < nb)
{
if (compareItemPointers(aptr, bptr) > 0)
*dptr++ = *bptr++;
else
*dptr++ = *aptr++;
}
while( aptr - a < na )
while (aptr - a < na)
*dptr++ = *aptr++;
while( bptr - b < nb )
while (bptr - b < nb)
*dptr++ = *bptr++;
}
/*
* Checks, should we move to right link...
* Checks, should we move to right link...
* Compares inserting itemp pointer with right bound of current page
*/
static bool
dataIsMoveRight(GinBtree btree, Page page) {
ItemPointer iptr = GinDataPageGetRightBound(page);
dataIsMoveRight(GinBtree btree, Page page)
{
ItemPointer iptr = GinDataPageGetRightBound(page);
if ( GinPageRightMost(page) )
return FALSE;
if (GinPageRightMost(page))
return FALSE;
return ( compareItemPointers( btree->items + btree->curitem, iptr ) > 0 ) ? TRUE : FALSE;
return (compareItemPointers(btree->items + btree->curitem, iptr) > 0) ? TRUE : FALSE;
}
/*
@@ -67,94 +73,113 @@ dataIsMoveRight(GinBtree btree, Page page) {
* page correctly choosen and searching value SHOULD be on page
*/
static BlockNumber
dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
OffsetNumber low, high, maxoff;
PostingItem *pitem=NULL;
int result;
Page page = BufferGetPage( stack->buffer );
dataLocateItem(GinBtree btree, GinBtreeStack *stack)
{
OffsetNumber low,
high,
maxoff;
PostingItem *pitem = NULL;
int result;
Page page = BufferGetPage(stack->buffer);
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
return btree->getLeftMostPage(btree, page);
}
low = FirstOffsetNumber;
maxoff = high = GinPageGetOpaque(page)->maxoff;
Assert( high >= low );
maxoff = high = GinPageGetOpaque(page)->maxoff;
Assert(high >= low);
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
pitem = (PostingItem*)GinDataPageGetItem(page,mid);
if ( mid == maxoff )
/* Right infinity, page already correctly choosen
with a help of dataIsMoveRight */
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
if (mid == maxoff)
/*
* Right infinity, page already correctly choosen with a help of
* dataIsMoveRight
*/
result = -1;
else {
pitem = (PostingItem*)GinDataPageGetItem(page,mid);
result = compareItemPointers( btree->items + btree->curitem, &( pitem->key ) );
else
{
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
result = compareItemPointers(btree->items + btree->curitem, &(pitem->key));
}
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
return PostingItemGetBlockNumber(pitem);
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
}
Assert( high>=FirstOffsetNumber && high <= maxoff );
Assert(high >= FirstOffsetNumber && high <= maxoff);
stack->off = high;
pitem = (PostingItem*)GinDataPageGetItem(page,high);
pitem = (PostingItem *) GinDataPageGetItem(page, high);
return PostingItemGetBlockNumber(pitem);
}
/*
/*
* Searches correct position for value on leaf page.
* Page should be corrrectly choosen.
* Page should be corrrectly choosen.
* Returns true if value found on page.
*/
static bool
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
Page page = BufferGetPage( stack->buffer );
OffsetNumber low, high;
int result;
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack)
{
Page page = BufferGetPage(stack->buffer);
OffsetNumber low,
high;
int result;
Assert( GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(GinPageIsLeaf(page));
Assert(GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
return TRUE;
}
low=FirstOffsetNumber;
low = FirstOffsetNumber;
high = GinPageGetOpaque(page)->maxoff;
if ( high < low ) {
if (high < low)
{
stack->off = FirstOffsetNumber;
return false;
}
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
result = compareItemPointers( btree->items + btree->curitem, (ItemPointer)GinDataPageGetItem(page,mid) );
result = compareItemPointers(btree->items + btree->curitem, (ItemPointer) GinDataPageGetItem(page, mid));
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
return true;
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
@@ -169,34 +194,41 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
* offset of PostingItem
*/
static OffsetNumber
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) {
OffsetNumber i, maxoff = GinPageGetOpaque(page)->maxoff;
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
{
OffsetNumber i,
maxoff = GinPageGetOpaque(page)->maxoff;
PostingItem *pitem;
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
/* if page isn't changed, we returns storedOff */
if ( storedOff>= FirstOffsetNumber && storedOff<=maxoff) {
pitem = (PostingItem*)GinDataPageGetItem(page, storedOff);
if ( PostingItemGetBlockNumber(pitem) == blkno )
if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
{
pitem = (PostingItem *) GinDataPageGetItem(page, storedOff);
if (PostingItemGetBlockNumber(pitem) == blkno)
return storedOff;
/* we hope, that needed pointer goes to right. It's true
if there wasn't a deletion */
for( i=storedOff+1 ; i <= maxoff ; i++ ) {
pitem = (PostingItem*)GinDataPageGetItem(page, i);
if ( PostingItemGetBlockNumber(pitem) == blkno )
/*
* we hope, that needed pointer goes to right. It's true if there
* wasn't a deletion
*/
for (i = storedOff + 1; i <= maxoff; i++)
{
pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i;
}
maxoff = storedOff-1;
maxoff = storedOff - 1;
}
/* last chance */
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) {
pitem = (PostingItem*)GinDataPageGetItem(page, i);
if ( PostingItemGetBlockNumber(pitem) == blkno )
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i;
}
@@ -207,14 +239,15 @@ dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber stor
* retunrs blkno of lefmost child
*/
static BlockNumber
dataGetLeftMostPage(GinBtree btree, Page page) {
dataGetLeftMostPage(GinBtree btree, Page page)
{
PostingItem *pitem;
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert( GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
Assert(GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber);
pitem = (PostingItem*)GinDataPageGetItem(page, FirstOffsetNumber);
pitem = (PostingItem *) GinDataPageGetItem(page, FirstOffsetNumber);
return PostingItemGetBlockNumber(pitem);
}
@@ -223,18 +256,22 @@ dataGetLeftMostPage(GinBtree btree, Page page) {
* correct value! depending on leaf or non-leaf page
*/
void
GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
GinDataPageAddItem(Page page, void *data, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
char *ptr;
char *ptr;
if ( offset == InvalidOffsetNumber ) {
ptr = GinDataPageGetItem(page,maxoff+1);
} else {
ptr = GinDataPageGetItem(page,offset);
if ( maxoff+1-offset != 0 )
memmove( ptr+GinSizeOfItem(page), ptr, (maxoff-offset+1) * GinSizeOfItem(page) );
if (offset == InvalidOffsetNumber)
{
ptr = GinDataPageGetItem(page, maxoff + 1);
}
memcpy( ptr, data, GinSizeOfItem(page) );
else
{
ptr = GinDataPageGetItem(page, offset);
if (maxoff + 1 - offset != 0)
memmove(ptr + GinSizeOfItem(page), ptr, (maxoff - offset + 1) * GinSizeOfItem(page));
}
memcpy(ptr, data, GinSizeOfItem(page));
GinPageGetOpaque(page)->maxoff++;
}
@@ -243,15 +280,16 @@ GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
* Deletes posting item from non-leaf page
*/
void
PageDeletePostingItem(Page page, OffsetNumber offset) {
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
PageDeletePostingItem(Page page, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
Assert( !GinPageIsLeaf(page) );
Assert( offset>=FirstOffsetNumber && offset <= maxoff );
Assert(!GinPageIsLeaf(page));
Assert(offset >= FirstOffsetNumber && offset <= maxoff);
if ( offset != maxoff )
memmove( GinDataPageGetItem(page,offset), GinDataPageGetItem(page,offset+1),
sizeof(PostingItem) * (maxoff-offset) );
if (offset != maxoff)
memmove(GinDataPageGetItem(page, offset), GinDataPageGetItem(page, offset + 1),
sizeof(PostingItem) * (maxoff - offset));
GinPageGetOpaque(page)->maxoff--;
}
@@ -261,19 +299,24 @@ PageDeletePostingItem(Page page, OffsetNumber offset) {
* item pointer never deletes!
*/
static bool
dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
Page page = BufferGetPage(buf);
dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
{
Page page = BufferGetPage(buf);
Assert( GinPageIsData(page) );
Assert( !btree->isDelete );
Assert(GinPageIsData(page));
Assert(!btree->isDelete);
if ( GinPageIsLeaf(page) ) {
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
if ( (btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) )
if (GinPageIsLeaf(page))
{
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
if ((btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true;
} else if ( sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) )
}
else if (sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true;
} else if ( sizeof(PostingItem) <= GinDataPageGetFreeSpace(page) )
}
else if (sizeof(PostingItem) <= GinDataPageGetFreeSpace(page))
return true;
return false;
@@ -285,14 +328,17 @@ dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
* item pointer never deletes!
*/
static BlockNumber
dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
dataPrepareData(GinBtree btree, Page page, OffsetNumber off)
{
BlockNumber ret = InvalidBlockNumber;
Assert( GinPageIsData(page) );
Assert(GinPageIsData(page));
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) {
PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page,off);
PostingItemSetBlockNumber( pitem, btree->rightblkno );
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
{
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, off);
PostingItemSetBlockNumber(pitem, btree->rightblkno);
ret = btree->rightblkno;
}
@@ -301,24 +347,25 @@ dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
return ret;
}
/*
/*
* Places keys to page and fills WAL record. In case leaf page and
* build mode puts all ItemPointers to page.
*/
static void
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) {
Page page = BufferGetPage(buf);
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
{
Page page = BufferGetPage(buf);
static XLogRecData rdata[3];
int sizeofitem = GinSizeOfItem(page);
static ginxlogInsert data;
int sizeofitem = GinSizeOfItem(page);
static ginxlogInsert data;
*prdata = rdata;
Assert( GinPageIsData(page) );
Assert(GinPageIsData(page));
data.updateBlkno = dataPrepareData( btree, page, off );
data.updateBlkno = dataPrepareData(btree, page, off);
data.node = btree->index->rd_node;
data.blkno = BufferGetBlockNumber( buf );
data.blkno = BufferGetBlockNumber(buf);
data.offset = off;
data.nitem = 1;
data.isDelete = FALSE;
@@ -337,109 +384,124 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
rdata[1].next = &rdata[2];
rdata[2].buffer = InvalidBuffer;
rdata[2].data = (GinPageIsLeaf(page)) ? ((char*)(btree->items+btree->curitem)) : ((char*)&(btree->pitem));
rdata[2].data = (GinPageIsLeaf(page)) ? ((char *) (btree->items + btree->curitem)) : ((char *) &(btree->pitem));
rdata[2].len = sizeofitem;
rdata[2].next = NULL;
if ( GinPageIsLeaf(page) ) {
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
if (GinPageIsLeaf(page))
{
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
/* usually, create index... */
uint32 savedPos = btree->curitem;
uint32 savedPos = btree->curitem;
while( btree->curitem < btree->nitem ) {
GinDataPageAddItem(page, btree->items+btree->curitem, off);
while (btree->curitem < btree->nitem)
{
GinDataPageAddItem(page, btree->items + btree->curitem, off);
off++;
btree->curitem++;
}
data.nitem = btree->curitem-savedPos;
data.nitem = btree->curitem - savedPos;
rdata[2].len = sizeofitem * data.nitem;
} else {
GinDataPageAddItem(page, btree->items+btree->curitem, off);
}
else
{
GinDataPageAddItem(page, btree->items + btree->curitem, off);
btree->curitem++;
}
} else
GinDataPageAddItem(page, &(btree->pitem), off);
}
else
GinDataPageAddItem(page, &(btree->pitem), off);
}
/*
* split page and fills WAL record. original buffer(lbuf) leaves untouched,
* returns shadow page of lbuf filled new data. In leaf page and build mode puts all
* returns shadow page of lbuf filled new data. In leaf page and build mode puts all
* ItemPointers to pages. Also, in build mode splits data by way to full fulled
* left page
*/
static Page
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata) {
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
{
static ginxlogSplit data;
static XLogRecData rdata[4];
static char vector[2*BLCKSZ];
char *ptr;
static char vector[2 * BLCKSZ];
char *ptr;
OffsetNumber separator;
ItemPointer bound;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) );
ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
int sizeofitem = GinSizeOfItem(lpage);
ItemPointer bound;
Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
int sizeofitem = GinSizeOfItem(lpage);
OffsetNumber maxoff = GinPageGetOpaque(lpage)->maxoff;
Page rpage = BufferGetPage( rbuf );
Size pageSize = PageGetPageSize( lpage );
Size freeSpace;
uint32 nCopied = 1;
Page rpage = BufferGetPage(rbuf);
Size pageSize = PageGetPageSize(lpage);
Size freeSpace;
uint32 nCopied = 1;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize );
GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
freeSpace = GinDataPageGetFreeSpace(rpage);
*prdata = rdata;
data.leftChildBlkno = ( GinPageIsLeaf(lpage) ) ?
InvalidOffsetNumber : PostingItemGetBlockNumber( &(btree->pitem) );
data.updateBlkno = dataPrepareData( btree, lpage, off );
data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
InvalidOffsetNumber : PostingItemGetBlockNumber(&(btree->pitem));
data.updateBlkno = dataPrepareData(btree, lpage, off);
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
maxoff*sizeofitem);
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
maxoff * sizeofitem);
if ( GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff ) {
if (GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff)
{
nCopied = 0;
while( btree->curitem < btree->nitem && maxoff*sizeof(ItemPointerData) < 2*(freeSpace - sizeof(ItemPointerData)) ) {
memcpy( vector + maxoff*sizeof(ItemPointerData), btree->items+btree->curitem,
sizeof(ItemPointerData) );
while (btree->curitem < btree->nitem && maxoff * sizeof(ItemPointerData) < 2 * (freeSpace - sizeof(ItemPointerData)))
{
memcpy(vector + maxoff * sizeof(ItemPointerData), btree->items + btree->curitem,
sizeof(ItemPointerData));
maxoff++;
nCopied++;
btree->curitem++;
}
} else {
ptr = vector + (off-1)*sizeofitem;
if ( maxoff+1-off != 0 )
memmove( ptr+sizeofitem, ptr, (maxoff-off+1) * sizeofitem );
if ( GinPageIsLeaf(lpage) ) {
memcpy(ptr, btree->items+btree->curitem, sizeofitem );
}
else
{
ptr = vector + (off - 1) * sizeofitem;
if (maxoff + 1 - off != 0)
memmove(ptr + sizeofitem, ptr, (maxoff - off + 1) * sizeofitem);
if (GinPageIsLeaf(lpage))
{
memcpy(ptr, btree->items + btree->curitem, sizeofitem);
btree->curitem++;
} else
memcpy(ptr, &(btree->pitem), sizeofitem );
}
else
memcpy(ptr, &(btree->pitem), sizeofitem);
maxoff++;
}
/* we suppose that during index creation table scaned from
begin to end, so ItemPointers are monotonically increased.. */
if ( btree->isBuild && GinPageRightMost(lpage) )
separator=freeSpace/sizeofitem;
/*
* we suppose that during index creation table scaned from begin to end,
* so ItemPointers are monotonically increased..
*/
if (btree->isBuild && GinPageRightMost(lpage))
separator = freeSpace / sizeofitem;
else
separator=maxoff/2;
separator = maxoff / 2;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize );
GinInitPage( lpage, GinPageGetOpaque(rpage)->flags, pageSize );
GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
memcpy( GinDataPageGetItem(lpage, FirstOffsetNumber), vector, separator * sizeofitem );
memcpy(GinDataPageGetItem(lpage, FirstOffsetNumber), vector, separator * sizeofitem);
GinPageGetOpaque(lpage)->maxoff = separator;
memcpy( GinDataPageGetItem(rpage, FirstOffsetNumber),
vector + separator * sizeofitem, (maxoff-separator) * sizeofitem );
GinPageGetOpaque(rpage)->maxoff = maxoff-separator;
memcpy(GinDataPageGetItem(rpage, FirstOffsetNumber),
vector + separator * sizeofitem, (maxoff - separator) * sizeofitem);
GinPageGetOpaque(rpage)->maxoff = maxoff - separator;
PostingItemSetBlockNumber( &(btree->pitem), BufferGetBlockNumber(lbuf) );
if ( GinPageIsLeaf(lpage) )
btree->pitem.key = *(ItemPointerData*)GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff);
else
btree->pitem.key = ((PostingItem*)GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff))->key;
PostingItemSetBlockNumber(&(btree->pitem), BufferGetBlockNumber(lbuf));
if (GinPageIsLeaf(lpage))
btree->pitem.key = *(ItemPointerData *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff);
else
btree->pitem.key = ((PostingItem *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff))->key;
btree->rightblkno = BufferGetBlockNumber(rbuf);
/* set up right bound for left page */
@@ -452,8 +514,8 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
data.node = btree->index->rd_node;
data.rootBlkno = InvalidBlockNumber;
data.lblkno = BufferGetBlockNumber( lbuf );
data.rblkno = BufferGetBlockNumber( rbuf );
data.lblkno = BufferGetBlockNumber(lbuf);
data.rblkno = BufferGetBlockNumber(rbuf);
data.separator = separator;
data.nitem = maxoff;
data.isData = TRUE;
@@ -468,34 +530,37 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
rdata[1].buffer = InvalidBuffer;
rdata[1].data = vector;
rdata[1].len = MAXALIGN( maxoff * sizeofitem );
rdata[1].len = MAXALIGN(maxoff * sizeofitem);
rdata[1].next = NULL;
return lpage;
}
/*
* Fills new root by right bound values from child.
* Fills new root by right bound values from child.
* Also called from ginxlog, should not use btree
*/
void
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
Page page = BufferGetPage(root),
lpage = BufferGetPage(lbuf),
rpage = BufferGetPage(rbuf);
PostingItem li, ri;
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
{
Page page = BufferGetPage(root),
lpage = BufferGetPage(lbuf),
rpage = BufferGetPage(rbuf);
PostingItem li,
ri;
li.key = *GinDataPageGetRightBound(lpage);
PostingItemSetBlockNumber( &li, BufferGetBlockNumber(lbuf) );
GinDataPageAddItem(page, &li, InvalidOffsetNumber );
PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf));
GinDataPageAddItem(page, &li, InvalidOffsetNumber);
ri.key = *GinDataPageGetRightBound(rpage);
PostingItemSetBlockNumber( &ri, BufferGetBlockNumber(rbuf) );
GinDataPageAddItem(page, &ri, InvalidOffsetNumber );
PostingItemSetBlockNumber(&ri, BufferGetBlockNumber(rbuf));
GinDataPageAddItem(page, &ri, InvalidOffsetNumber);
}
void
prepareDataScan( GinBtree btree, Relation index) {
prepareDataScan(GinBtree btree, Relation index)
{
memset(btree, 0, sizeof(GinBtreeData));
btree->index = index;
btree->isMoveRight = dataIsMoveRight;
@@ -509,21 +574,22 @@ prepareDataScan( GinBtree btree, Relation index) {
btree->fillRoot = dataFillRoot;
btree->searchMode = FALSE;
btree->isDelete = FALSE;
btree->isDelete = FALSE;
btree->fullScan = FALSE;
btree->isBuild= FALSE;
btree->isBuild = FALSE;
}
GinPostingTreeScan*
prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode) {
GinPostingTreeScan *gdi = (GinPostingTreeScan*)palloc0( sizeof(GinPostingTreeScan) );
GinPostingTreeScan *
prepareScanPostingTree(Relation index, BlockNumber rootBlkno, bool searchMode)
{
GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan));
prepareDataScan(&gdi->btree, index);
prepareDataScan( &gdi->btree, index );
gdi->btree.searchMode = searchMode;
gdi->btree.fullScan = searchMode;
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno );
gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
return gdi;
}
@@ -532,33 +598,35 @@ prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode)
* Inserts array of item pointers, may execute several tree scan (very rare)
*/
void
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem) {
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem)
{
BlockNumber rootBlkno = gdi->stack->blkno;
gdi->btree.items = items;
gdi->btree.nitem = nitem;
gdi->btree.curitem = 0;
while( gdi->btree.curitem < gdi->btree.nitem ) {
while (gdi->btree.curitem < gdi->btree.nitem)
{
if (!gdi->stack)
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno );
gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
gdi->stack = ginFindLeafPage( &gdi->btree, gdi->stack );
gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
if ( gdi->btree.findItem( &(gdi->btree), gdi->stack ) )
elog(ERROR,"item pointer (%u,%d) already exists",
ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem),
ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem));
if (gdi->btree.findItem(&(gdi->btree), gdi->stack))
elog(ERROR, "item pointer (%u,%d) already exists",
ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem),
ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem));
ginInsertValue(&(gdi->btree), gdi->stack);
gdi->stack=NULL;
gdi->stack = NULL;
}
}
Buffer
scanBeginPostingTree( GinPostingTreeScan *gdi ) {
gdi->stack = ginFindLeafPage( &gdi->btree, gdi->stack );
scanBeginPostingTree(GinPostingTreeScan *gdi)
{
gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
return gdi->stack->buffer;
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginentrypage.c
* page utilities routines for the postgres inverted index access method.
* page utilities routines for the postgres inverted index access method.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.3 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginentrypage.c,v 1.4 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -23,48 +23,52 @@
* 1) Posting list
* - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usial
* - ItemPointerGetBlockNumber(&itup->t_tid) contains original
* size of tuple (without posting list).
* size of tuple (without posting list).
* Macroses: GinGetOrigSizePosting(itup) / GinSetOrigSizePosting(itup,n)
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains number
* of elements in posting list (number of heap itempointer)
* Macroses: GinGetNPosting(itup) / GinSetNPosting(itup,n)
* - After usial part of tuple there is a posting list
* - After usial part of tuple there is a posting list
* Macros: GinGetPosting(itup)
* 2) Posting tree
* - itup->t_info & INDEX_SIZE_MASK contains size of tuple as usial
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* - ItemPointerGetBlockNumber(&itup->t_tid) contains block number of
* root of posting tree
* - ItemPointerGetOffsetNumber(&itup->t_tid) contains magick number GIN_TREE_POSTING
*/
IndexTuple
GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
bool isnull=FALSE;
GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd)
{
bool isnull = FALSE;
IndexTuple itup;
itup = index_form_tuple(ginstate->tupdesc, &key, &isnull);
itup = index_form_tuple(ginstate->tupdesc, &key, &isnull);
GinSetOrigSizePosting( itup, IndexTupleSize(itup) );
GinSetOrigSizePosting(itup, IndexTupleSize(itup));
if ( nipd > 0 ) {
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData)*nipd);
if (nipd > 0)
{
uint32 newsize = MAXALIGN(SHORTALIGN(IndexTupleSize(itup)) + sizeof(ItemPointerData) * nipd);
if ( newsize >= INDEX_SIZE_MASK )
if (newsize >= INDEX_SIZE_MASK)
return NULL;
if ( newsize > TOAST_INDEX_TARGET && nipd > 1 )
if (newsize > TOAST_INDEX_TARGET && nipd > 1)
return NULL;
itup = repalloc( itup, newsize );
itup = repalloc(itup, newsize);
/* set new size */
itup->t_info &= ~INDEX_SIZE_MASK;
itup->t_info &= ~INDEX_SIZE_MASK;
itup->t_info |= newsize;
if ( ipd )
memcpy( GinGetPosting(itup), ipd, sizeof(ItemPointerData)*nipd );
GinSetNPosting(itup, nipd);
} else {
GinSetNPosting(itup, 0);
if (ipd)
memcpy(GinGetPosting(itup), ipd, sizeof(ItemPointerData) * nipd);
GinSetNPosting(itup, nipd);
}
else
{
GinSetNPosting(itup, 0);
}
return itup;
}
@@ -74,31 +78,35 @@ GinFormTuple(GinState *ginstate, Datum key, ItemPointerData *ipd, uint32 nipd) {
* so we don't use right bound, we use rightest key instead.
*/
static IndexTuple
getRightMostTuple(Page page) {
getRightMostTuple(Page page)
{
OffsetNumber maxoff = PageGetMaxOffsetNumber(page);
return (IndexTuple) PageGetItem(page, PageGetItemId(page, maxoff));
}
Datum
ginGetHighKey(GinState *ginstate, Page page) {
IndexTuple itup;
bool isnull;
ginGetHighKey(GinState *ginstate, Page page)
{
IndexTuple itup;
bool isnull;
itup = getRightMostTuple(page);
return index_getattr(itup, FirstOffsetNumber, ginstate->tupdesc, &isnull);
return index_getattr(itup, FirstOffsetNumber, ginstate->tupdesc, &isnull);
}
static bool
entryIsMoveRight(GinBtree btree, Page page) {
Datum highkey;
static bool
entryIsMoveRight(GinBtree btree, Page page)
{
Datum highkey;
if ( GinPageRightMost(page) )
if (GinPageRightMost(page))
return FALSE;
highkey = ginGetHighKey(btree->ginstate, page);
if ( compareEntries(btree->ginstate, btree->entryValue, highkey) > 0 )
if (compareEntries(btree->ginstate, btree->entryValue, highkey) > 0)
return TRUE;
return FALSE;
@@ -109,16 +117,20 @@ entryIsMoveRight(GinBtree btree, Page page) {
* page correctly choosen and searching value SHOULD be on page
*/
static BlockNumber
entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
OffsetNumber low, high, maxoff;
IndexTuple itup = NULL;
int result;
Page page = BufferGetPage( stack->buffer );
entryLocateEntry(GinBtree btree, GinBtreeStack *stack)
{
OffsetNumber low,
high,
maxoff;
IndexTuple itup = NULL;
int result;
Page page = BufferGetPage(stack->buffer);
Assert( !GinPageIsLeaf(page) );
Assert( !GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(!GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
stack->predictNumber *= PageGetMaxOffsetNumber(page);
return btree->getLeftMostPage(btree, page);
@@ -126,39 +138,43 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
low = FirstOffsetNumber;
maxoff = high = PageGetMaxOffsetNumber(page);
Assert( high >= low );
Assert(high >= low);
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
if ( mid == maxoff && GinPageRightMost(page) )
if (mid == maxoff && GinPageRightMost(page))
/* Right infinity */
result = -1;
else {
bool isnull;
else
{
bool isnull;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
result = compareEntries(btree->ginstate, btree->entryValue,
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull) );
result = compareEntries(btree->ginstate, btree->entryValue,
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
}
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
Assert( GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO );
Assert(GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO);
return GinItemPointerGetBlockNumber(&(itup)->t_tid);
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
}
Assert( high>=FirstOffsetNumber && high <= maxoff );
Assert(high >= FirstOffsetNumber && high <= maxoff);
stack->off = high;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, high));
Assert( GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO );
Assert(GinItemPointerGetBlockNumber(&(itup)->t_tid) != GIN_ROOT_BLKNO);
return GinItemPointerGetBlockNumber(&(itup)->t_tid);
}
@@ -168,15 +184,18 @@ entryLocateEntry(GinBtree btree, GinBtreeStack *stack) {
* Returns true if value found on page.
*/
static bool
entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
Page page = BufferGetPage( stack->buffer );
OffsetNumber low, high;
IndexTuple itup;
entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack)
{
Page page = BufferGetPage(stack->buffer);
OffsetNumber low,
high;
IndexTuple itup;
Assert( GinPageIsLeaf(page) );
Assert( !GinPageIsData(page) );
Assert(GinPageIsLeaf(page));
Assert(!GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
return TRUE;
}
@@ -184,26 +203,30 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
low = FirstOffsetNumber;
high = PageGetMaxOffsetNumber(page);
if ( high < low ) {
if (high < low)
{
stack->off = FirstOffsetNumber;
return false;
}
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
bool isnull;
int result;
bool isnull;
int result;
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, mid));
result = compareEntries(btree->ginstate, btree->entryValue,
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull) );
index_getattr(itup, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull));
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
return true;
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
@@ -214,33 +237,40 @@ entryLocateLeafEntry(GinBtree btree, GinBtreeStack *stack) {
}
static OffsetNumber
entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) {
OffsetNumber i, maxoff = PageGetMaxOffsetNumber(page);
IndexTuple itup;
entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
{
OffsetNumber i,
maxoff = PageGetMaxOffsetNumber(page);
IndexTuple itup;
Assert( !GinPageIsLeaf(page) );
Assert( !GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(!GinPageIsData(page));
/* if page isn't changed, we returns storedOff */
if ( storedOff>= FirstOffsetNumber && storedOff<=maxoff) {
if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, storedOff));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno )
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return storedOff;
/* we hope, that needed pointer goes to right. It's true
if there wasn't a deletion */
for( i=storedOff+1 ; i <= maxoff ; i++ ) {
/*
* we hope, that needed pointer goes to right. It's true if there
* wasn't a deletion
*/
for (i = storedOff + 1; i <= maxoff; i++)
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno )
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return i;
}
maxoff = storedOff-1;
maxoff = storedOff - 1;
}
/* last chance */
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) {
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
if ( GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno )
if (GinItemPointerGetBlockNumber(&(itup)->t_tid) == blkno)
return i;
}
@@ -248,31 +278,35 @@ entryFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber sto
}
static BlockNumber
entryGetLeftMostPage(GinBtree btree, Page page) {
IndexTuple itup;
entryGetLeftMostPage(GinBtree btree, Page page)
{
IndexTuple itup;
Assert( !GinPageIsLeaf(page) );
Assert( !GinPageIsData(page) );
Assert( PageGetMaxOffsetNumber(page) >= FirstOffsetNumber );
Assert(!GinPageIsLeaf(page));
Assert(!GinPageIsData(page));
Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber);
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
return GinItemPointerGetBlockNumber(&(itup)->t_tid);
return GinItemPointerGetBlockNumber(&(itup)->t_tid);
}
static bool
entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
Size itupsz = 0;
Page page = BufferGetPage(buf);
entryIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
{
Size itupsz = 0;
Page page = BufferGetPage(buf);
Assert( btree->entry );
Assert( !GinPageIsData(page) );
Assert(btree->entry);
Assert(!GinPageIsData(page));
if ( btree->isDelete ) {
IndexTuple itup = (IndexTuple)PageGetItem(page, PageGetItemId(page, off));
itupsz = MAXALIGN( IndexTupleSize( itup ) ) + sizeof(ItemIdData);
if (btree->isDelete)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
itupsz = MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
}
if ( PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData) )
if (PageGetFreeSpace(page) + itupsz >= MAXALIGN(IndexTupleSize(btree->entry)) + sizeof(ItemIdData))
return true;
return false;
@@ -284,19 +318,23 @@ entryIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
* if child split is occured
*/
static BlockNumber
entryPreparePage( GinBtree btree, Page page, OffsetNumber off) {
entryPreparePage(GinBtree btree, Page page, OffsetNumber off)
{
BlockNumber ret = InvalidBlockNumber;
Assert( btree->entry );
Assert( !GinPageIsData(page) );
Assert(btree->entry);
Assert(!GinPageIsData(page));
if ( btree->isDelete ) {
Assert( GinPageIsLeaf(page) );
if (btree->isDelete)
{
Assert(GinPageIsLeaf(page));
PageIndexTupleDelete(page, off);
}
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) {
IndexTuple itup = (IndexTuple)PageGetItem(page, PageGetItemId(page, off));
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, off));
ItemPointerSet(&itup->t_tid, btree->rightblkno, InvalidOffsetNumber);
ret = btree->rightblkno;
}
@@ -310,22 +348,23 @@ entryPreparePage( GinBtree btree, Page page, OffsetNumber off) {
* Place tuple on page and fills WAL record
*/
static void
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) {
Page page = BufferGetPage(buf);
entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
{
Page page = BufferGetPage(buf);
static XLogRecData rdata[3];
OffsetNumber placed;
static ginxlogInsert data;
OffsetNumber placed;
static ginxlogInsert data;
*prdata = rdata;
data.updateBlkno = entryPreparePage( btree, page, off );
data.updateBlkno = entryPreparePage(btree, page, off);
placed = PageAddItem( page, (Item)btree->entry, IndexTupleSize(btree->entry), off, LP_USED);
if ( placed != off )
placed = PageAddItem(page, (Item) btree->entry, IndexTupleSize(btree->entry), off, LP_USED);
if (placed != off)
elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(btree->index));
RelationGetRelationName(btree->index));
data.node = btree->index->rd_node;
data.blkno = BufferGetBlockNumber( buf );
data.blkno = BufferGetBlockNumber(buf);
data.offset = off;
data.nitem = 1;
data.isDelete = btree->isDelete;
@@ -358,87 +397,99 @@ entryPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prd
* an equal number!
*/
static Page
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata) {
entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
{
static XLogRecData rdata[2];
OffsetNumber i, maxoff, separator=InvalidOffsetNumber;
Size totalsize=0;
Size lsize = 0, size;
static char tupstore[ 2*BLCKSZ ];
char *ptr;
IndexTuple itup, leftrightmost=NULL;
static ginxlogSplit data;
Datum value;
bool isnull;
Page page;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) );
Page rpage = BufferGetPage( rbuf );
Size pageSize = PageGetPageSize( lpage );
OffsetNumber i,
maxoff,
separator = InvalidOffsetNumber;
Size totalsize = 0;
Size lsize = 0,
size;
static char tupstore[2 * BLCKSZ];
char *ptr;
IndexTuple itup,
leftrightmost = NULL;
static ginxlogSplit data;
Datum value;
bool isnull;
Page page;
Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
Page rpage = BufferGetPage(rbuf);
Size pageSize = PageGetPageSize(lpage);
*prdata = rdata;
data.leftChildBlkno = ( GinPageIsLeaf(lpage) ) ?
InvalidOffsetNumber : GinItemPointerGetBlockNumber( &(btree->entry->t_tid) );
data.updateBlkno = entryPreparePage( btree, lpage, off );
data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
InvalidOffsetNumber : GinItemPointerGetBlockNumber(&(btree->entry->t_tid));
data.updateBlkno = entryPreparePage(btree, lpage, off);
maxoff = PageGetMaxOffsetNumber(lpage);
ptr = tupstore;
ptr = tupstore;
for(i=FirstOffsetNumber; i<=maxoff; i++) {
if ( i==off ) {
size = MAXALIGN( IndexTupleSize(btree->entry) );
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
if (i == off)
{
size = MAXALIGN(IndexTupleSize(btree->entry));
memcpy(ptr, btree->entry, size);
ptr+=size;
ptr += size;
totalsize += size + sizeof(ItemIdData);
}
itup = (IndexTuple)PageGetItem(lpage, PageGetItemId(lpage, i));
size = MAXALIGN( IndexTupleSize(itup) );
itup = (IndexTuple) PageGetItem(lpage, PageGetItemId(lpage, i));
size = MAXALIGN(IndexTupleSize(itup));
memcpy(ptr, itup, size);
ptr+=size;
ptr += size;
totalsize += size + sizeof(ItemIdData);
}
if ( off==maxoff+1 ) {
size = MAXALIGN( IndexTupleSize(btree->entry) );
if (off == maxoff + 1)
{
size = MAXALIGN(IndexTupleSize(btree->entry));
memcpy(ptr, btree->entry, size);
ptr+=size;
ptr += size;
totalsize += size + sizeof(ItemIdData);
}
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize );
GinInitPage( lpage, GinPageGetOpaque(rpage)->flags, pageSize );
GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
ptr = tupstore;
maxoff++;
maxoff++;
lsize = 0;
page = lpage;
for(i=FirstOffsetNumber; i<=maxoff; i++) {
itup = (IndexTuple)ptr;
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
itup = (IndexTuple) ptr;
if ( lsize > totalsize/2 ) {
if ( separator==InvalidOffsetNumber )
separator = i-1;
if (lsize > totalsize / 2)
{
if (separator == InvalidOffsetNumber)
separator = i - 1;
page = rpage;
} else {
}
else
{
leftrightmost = itup;
lsize += MAXALIGN( IndexTupleSize(itup) ) + sizeof(ItemIdData);
lsize += MAXALIGN(IndexTupleSize(itup)) + sizeof(ItemIdData);
}
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(btree->index));
ptr += MAXALIGN( IndexTupleSize(itup) );
RelationGetRelationName(btree->index));
ptr += MAXALIGN(IndexTupleSize(itup));
}
value = index_getattr(leftrightmost, FirstOffsetNumber, btree->ginstate->tupdesc, &isnull);
btree->entry = GinFormTuple( btree->ginstate, value, NULL, 0);
ItemPointerSet(&(btree->entry)->t_tid, BufferGetBlockNumber( lbuf ), InvalidOffsetNumber);
btree->rightblkno = BufferGetBlockNumber( rbuf );
btree->entry = GinFormTuple(btree->ginstate, value, NULL, 0);
ItemPointerSet(&(btree->entry)->t_tid, BufferGetBlockNumber(lbuf), InvalidOffsetNumber);
btree->rightblkno = BufferGetBlockNumber(rbuf);
data.node = btree->index->rd_node;
data.rootBlkno = InvalidBlockNumber;
data.lblkno = BufferGetBlockNumber( lbuf );
data.rblkno = BufferGetBlockNumber( rbuf );
data.lblkno = BufferGetBlockNumber(lbuf);
data.rblkno = BufferGetBlockNumber(rbuf);
data.separator = separator;
data.nitem = maxoff;
data.isData = FALSE;
@@ -458,23 +509,28 @@ entrySplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogR
return lpage;
}
/*
/*
* return newly allocate rightmost tuple
*/
IndexTuple
ginPageGetLinkItup(Buffer buf) {
IndexTuple itup, nitup;
Page page = BufferGetPage(buf);
ginPageGetLinkItup(Buffer buf)
{
IndexTuple itup,
nitup;
Page page = BufferGetPage(buf);
itup = getRightMostTuple( page );
if ( GinPageIsLeaf(page) && !GinIsPostingTree(itup) ) {
nitup = (IndexTuple)palloc( MAXALIGN(GinGetOrigSizePosting(itup)) );
memcpy( nitup, itup, GinGetOrigSizePosting(itup) );
itup = getRightMostTuple(page);
if (GinPageIsLeaf(page) && !GinIsPostingTree(itup))
{
nitup = (IndexTuple) palloc(MAXALIGN(GinGetOrigSizePosting(itup)));
memcpy(nitup, itup, GinGetOrigSizePosting(itup));
nitup->t_info &= ~INDEX_SIZE_MASK;
nitup->t_info |= GinGetOrigSizePosting(itup);
} else {
nitup = (IndexTuple)palloc( MAXALIGN(IndexTupleSize(itup)) );
memcpy( nitup, itup, IndexTupleSize(itup) );
}
else
{
nitup = (IndexTuple) palloc(MAXALIGN(IndexTupleSize(itup)));
memcpy(nitup, itup, IndexTupleSize(itup));
}
ItemPointerSet(&nitup->t_tid, BufferGetBlockNumber(buf), InvalidOffsetNumber);
@@ -486,23 +542,25 @@ ginPageGetLinkItup(Buffer buf) {
* Also called from ginxlog, should not use btree
*/
void
entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
Page page;
IndexTuple itup;
entryFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
{
Page page;
IndexTuple itup;
page = BufferGetPage(root);
itup = ginPageGetLinkItup( lbuf );
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
itup = ginPageGetLinkItup(lbuf);
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page");
itup = ginPageGetLinkItup( rbuf );
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
itup = ginPageGetLinkItup(rbuf);
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index root page");
}
void
prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstate) {
prepareEntryScan(GinBtree btree, Relation index, Datum value, GinState *ginstate)
{
memset(btree, 0, sizeof(GinBtreeData));
btree->isMoveRight = entryIsMoveRight;
@@ -524,4 +582,3 @@ prepareEntryScan( GinBtree btree, Relation index, Datum value, GinState *ginstat
btree->fullScan = FALSE;
btree->isBuild = FALSE;
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginget.c
* fetch tuples from a GIN scan.
* fetch tuples from a GIN scan.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.3 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -18,15 +18,17 @@
#include "utils/memutils.h"
static OffsetNumber
findItemInPage( Page page, ItemPointer item, OffsetNumber off ) {
findItemInPage(Page page, ItemPointer item, OffsetNumber off)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
int res;
int res;
for(; off<=maxoff; off++) {
res = compareItemPointers( item, (ItemPointer)GinDataPageGetItem(page, off) );
Assert( res>= 0 );
for (; off <= maxoff; off++)
{
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, off));
Assert(res >= 0);
if ( res == 0 )
if (res == 0)
return off;
}
@@ -38,24 +40,29 @@ findItemInPage( Page page, ItemPointer item, OffsetNumber off ) {
* Stop* functions unlock buffer (but don't release!)
*/
static void
startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall ) {
if ( entry->master != NULL ) {
startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firstCall)
{
if (entry->master != NULL)
{
entry->isFinished = entry->master->isFinished;
return;
}
if ( firstCall ) {
/* at first call we should find entry, and
begin scan of posting tree or just store posting list in memory */
if (firstCall)
{
/*
* 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;
GinBtreeStack *stackEntry;
Page page;
bool needUnlock = TRUE;
prepareEntryScan( &btreeEntry, index, entry->entry, ginstate );
prepareEntryScan(&btreeEntry, index, entry->entry, ginstate);
btreeEntry.searchMode = TRUE;
stackEntry = ginFindLeafPage(&btreeEntry, NULL);
page = BufferGetPage( stackEntry->buffer );
page = BufferGetPage(stackEntry->buffer);
entry->isFinished = TRUE;
entry->buffer = InvalidBuffer;
@@ -65,103 +72,115 @@ startScanEntry( Relation index, GinState *ginstate, GinScanEntry entry, bool fir
entry->reduceResult = FALSE;
entry->predictNumberResult = 0;
if ( btreeEntry.findItem( &btreeEntry, stackEntry ) ) {
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
if (btreeEntry.findItem(&btreeEntry, stackEntry))
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
if ( GinIsPostingTree(itup) ) {
if (GinIsPostingTree(itup))
{
BlockNumber rootPostingTree = GinGetPostingTree(itup);
GinPostingTreeScan *gdi;
Page page;
Page page;
LockBuffer(stackEntry->buffer, GIN_UNLOCK);
needUnlock = FALSE;
gdi = prepareScanPostingTree( index, rootPostingTree, TRUE );
needUnlock = FALSE;
gdi = prepareScanPostingTree(index, rootPostingTree, TRUE);
entry->buffer = scanBeginPostingTree( gdi );
IncrBufferRefCount( entry->buffer );
entry->buffer = scanBeginPostingTree(gdi);
IncrBufferRefCount(entry->buffer);
page = BufferGetPage( entry->buffer );
entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff;
page = BufferGetPage(entry->buffer);
entry->predictNumberResult = gdi->stack->predictNumber * GinPageGetOpaque(page)->maxoff;
freeGinBtreeStack( gdi->stack );
pfree( gdi );
freeGinBtreeStack(gdi->stack);
pfree(gdi);
entry->isFinished = FALSE;
} else if ( GinGetNPosting(itup) > 0 ) {
}
else if (GinGetNPosting(itup) > 0)
{
entry->nlist = GinGetNPosting(itup);
entry->list = (ItemPointerData*)palloc( sizeof(ItemPointerData) * entry->nlist );
memcpy( entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist );
entry->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * entry->nlist);
memcpy(entry->list, GinGetPosting(itup), sizeof(ItemPointerData) * entry->nlist);
entry->isFinished = FALSE;
}
}
if ( needUnlock )
if (needUnlock)
LockBuffer(stackEntry->buffer, GIN_UNLOCK);
freeGinBtreeStack( stackEntry );
} else if ( entry->buffer != InvalidBuffer ) {
freeGinBtreeStack(stackEntry);
}
else if (entry->buffer != InvalidBuffer)
{
/* we should find place were we was stopped */
BlockNumber blkno;
Page page;
Page page;
LockBuffer( entry->buffer, GIN_SHARE );
LockBuffer(entry->buffer, GIN_SHARE);
if ( !ItemPointerIsValid( &entry->curItem ) )
if (!ItemPointerIsValid(&entry->curItem))
/* start position */
return;
Assert( entry->offset!=InvalidOffsetNumber );
Assert(entry->offset != InvalidOffsetNumber);
page = BufferGetPage( entry->buffer );
page = BufferGetPage(entry->buffer);
/* try to find curItem in current buffer */
if ( (entry->offset=findItemInPage(page , &entry->curItem, entry->offset))!=InvalidOffsetNumber )
if ((entry->offset = findItemInPage(page, &entry->curItem, entry->offset)) != InvalidOffsetNumber)
return;
/* walk to right */
while( (blkno = GinPageGetOpaque( page )->rightlink)!=InvalidBlockNumber ) {
LockBuffer( entry->buffer, GIN_UNLOCK );
entry->buffer = ReleaseAndReadBuffer( entry->buffer, index, blkno );
LockBuffer( entry->buffer, GIN_SHARE );
page = BufferGetPage( entry->buffer );
while ((blkno = GinPageGetOpaque(page)->rightlink) != InvalidBlockNumber)
{
LockBuffer(entry->buffer, GIN_UNLOCK);
entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
LockBuffer(entry->buffer, GIN_SHARE);
page = BufferGetPage(entry->buffer);
if ( (entry->offset=findItemInPage(page , &entry->curItem, FirstOffsetNumber))!=InvalidOffsetNumber )
if ((entry->offset = findItemInPage(page, &entry->curItem, FirstOffsetNumber)) != InvalidOffsetNumber)
return;
}
elog(ERROR,"Logic error: lost previously founded ItemId");
elog(ERROR, "Logic error: lost previously founded ItemId");
}
}
static void
stopScanEntry( GinScanEntry entry ) {
if ( entry->buffer != InvalidBuffer )
LockBuffer( entry->buffer, GIN_UNLOCK );
stopScanEntry(GinScanEntry entry)
{
if (entry->buffer != InvalidBuffer)
LockBuffer(entry->buffer, GIN_UNLOCK);
}
static void
startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
uint32 i;
startScanKey(Relation index, GinState *ginstate, GinScanKey key)
{
uint32 i;
for(i=0;i<key->nentries;i++)
startScanEntry( index, ginstate, key->scanEntry+i, key->firstCall );
if ( key->firstCall ) {
memset( key->entryRes, TRUE, sizeof(bool) * key->nentries );
for (i = 0; i < key->nentries; i++)
startScanEntry(index, ginstate, key->scanEntry + i, key->firstCall);
if (key->firstCall)
{
memset(key->entryRes, TRUE, sizeof(bool) * key->nentries);
key->isFinished = FALSE;
key->firstCall = FALSE;
if ( GinFuzzySearchLimit > 0 ) {
if (GinFuzzySearchLimit > 0)
{
/*
* If all of keys more than treshold we will try to reduce
* result, we hope (and only hope, for intersection operation of array
* our supposition isn't true), that total result will not more
* than minimal predictNumberResult.
* If all of keys more than treshold we will try to reduce result,
* we hope (and only hope, for intersection operation of array our
* supposition isn't true), that total result will not more than
* minimal predictNumberResult.
*/
for(i=0;i<key->nentries;i++)
if ( key->scanEntry[i].predictNumberResult <= key->nentries * GinFuzzySearchLimit )
return;
for(i=0;i<key->nentries;i++)
if ( key->scanEntry[i].predictNumberResult > key->nentries * GinFuzzySearchLimit ) {
for (i = 0; i < key->nentries; i++)
if (key->scanEntry[i].predictNumberResult <= key->nentries * GinFuzzySearchLimit)
return;
for (i = 0; i < key->nentries; i++)
if (key->scanEntry[i].predictNumberResult > key->nentries * GinFuzzySearchLimit)
{
key->scanEntry[i].predictNumberResult /= key->nentries;
key->scanEntry[i].reduceResult = TRUE;
}
@@ -170,50 +189,60 @@ startScanKey( Relation index, GinState *ginstate, GinScanKey key ) {
}
static void
stopScanKey( GinScanKey key ) {
uint32 i;
stopScanKey(GinScanKey key)
{
uint32 i;
for(i=0;i<key->nentries;i++)
stopScanEntry( key->scanEntry+i );
for (i = 0; i < key->nentries; i++)
stopScanEntry(key->scanEntry + i);
}
static void
startScan( IndexScanDesc scan ) {
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
startScan(IndexScanDesc scan)
{
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
for(i=0; i<so->nkeys; i++)
startScanKey( scan->indexRelation, &so->ginstate, so->keys + i );
for (i = 0; i < so->nkeys; i++)
startScanKey(scan->indexRelation, &so->ginstate, so->keys + i);
}
static void
stopScan( IndexScanDesc scan ) {
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
stopScan(IndexScanDesc scan)
{
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
for(i=0; i<so->nkeys; i++)
stopScanKey( so->keys + i );
for (i = 0; i < so->nkeys; i++)
stopScanKey(so->keys + i);
}
static void
entryGetNextItem( Relation index, GinScanEntry entry ) {
Page page = BufferGetPage( entry->buffer );
entryGetNextItem(Relation index, GinScanEntry entry)
{
Page page = BufferGetPage(entry->buffer);
entry->offset++;
if ( entry->offset <= GinPageGetOpaque( page )->maxoff && GinPageGetOpaque( page )->maxoff >= FirstOffsetNumber ) {
entry->curItem = *(ItemPointerData*)GinDataPageGetItem(page, entry->offset);
} else {
BlockNumber blkno = GinPageGetOpaque( page )->rightlink;
LockBuffer( entry->buffer, GIN_UNLOCK );
if ( blkno == InvalidBlockNumber ) {
ReleaseBuffer( entry->buffer );
if (entry->offset <= GinPageGetOpaque(page)->maxoff && GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber)
{
entry->curItem = *(ItemPointerData *) GinDataPageGetItem(page, entry->offset);
}
else
{
BlockNumber blkno = GinPageGetOpaque(page)->rightlink;
LockBuffer(entry->buffer, GIN_UNLOCK);
if (blkno == InvalidBlockNumber)
{
ReleaseBuffer(entry->buffer);
entry->buffer = InvalidBuffer;
entry->isFinished = TRUE;
} else {
entry->buffer = ReleaseAndReadBuffer( entry->buffer, index, blkno );
LockBuffer( entry->buffer, GIN_SHARE );
}
else
{
entry->buffer = ReleaseAndReadBuffer(entry->buffer, index, blkno);
LockBuffer(entry->buffer, GIN_SHARE);
entry->offset = InvalidOffsetNumber;
entryGetNextItem(index, entry);
}
@@ -221,29 +250,37 @@ entryGetNextItem( Relation index, GinScanEntry entry ) {
}
#define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
#define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
/*
* Sets entry->curItem to new found heap item pointer for one
* Sets entry->curItem to new found heap item pointer for one
* entry of one scan key
*/
static bool
entryGetItem( Relation index, GinScanEntry entry ) {
if ( entry->master ) {
entryGetItem(Relation index, GinScanEntry entry)
{
if (entry->master)
{
entry->isFinished = entry->master->isFinished;
entry->curItem = entry->master->curItem;
} else if ( entry->list ) {
}
else if (entry->list)
{
entry->offset++;
if ( entry->offset <= entry->nlist )
entry->curItem = entry->list[ entry->offset - 1 ];
else {
ItemPointerSet( &entry->curItem, InvalidBlockNumber, InvalidOffsetNumber );
if (entry->offset <= entry->nlist)
entry->curItem = entry->list[entry->offset - 1];
else
{
ItemPointerSet(&entry->curItem, InvalidBlockNumber, InvalidOffsetNumber);
entry->isFinished = TRUE;
}
} else {
do {
}
else
{
do
{
entryGetNextItem(index, entry);
} while ( entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry) );
} while (entry->isFinished == FALSE && entry->reduceResult == TRUE && dropItem(entry));
}
return entry->isFinished;
@@ -254,155 +291,180 @@ entryGetItem( Relation index, GinScanEntry entry ) {
* returns isFinished!
*/
static bool
keyGetItem( Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key ) {
uint32 i;
GinScanEntry entry;
bool res;
MemoryContext oldCtx;
keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key)
{
uint32 i;
GinScanEntry entry;
bool res;
MemoryContext oldCtx;
if ( key->isFinished )
if (key->isFinished)
return TRUE;
do {
/* move forward from previously value and set new curItem,
which is minimal from entries->curItems */
ItemPointerSetMax( &key->curItem );
for(i=0;i<key->nentries;i++) {
entry = key->scanEntry+i;
if ( key->entryRes[i] ) {
if ( entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE ) {
if (compareItemPointers( &entry->curItem, &key->curItem ) < 0)
do
{
/*
* move forward from previously value and set new curItem, which is
* minimal from entries->curItems
*/
ItemPointerSetMax(&key->curItem);
for (i = 0; i < key->nentries; i++)
{
entry = key->scanEntry + i;
if (key->entryRes[i])
{
if (entry->isFinished == FALSE && entryGetItem(index, entry) == FALSE)
{
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
key->curItem = entry->curItem;
} else
}
else
key->entryRes[i] = FALSE;
} else if ( entry->isFinished == FALSE ) {
if (compareItemPointers( &entry->curItem, &key->curItem ) < 0)
}
else if (entry->isFinished == FALSE)
{
if (compareItemPointers(&entry->curItem, &key->curItem) < 0)
key->curItem = entry->curItem;
}
}
}
if ( ItemPointerIsMax( &key->curItem ) ) {
if (ItemPointerIsMax(&key->curItem))
{
/* all entries are finished */
key->isFinished = TRUE;
return TRUE;
}
if ( key->nentries == 1 ) {
if (key->nentries == 1)
{
/* we can do not call consistentFn !! */
key->entryRes[0] = TRUE;
return FALSE;
}
/* setting up array for consistentFn */
for(i=0;i<key->nentries;i++) {
entry = key->scanEntry+i;
if ( entry->isFinished == FALSE && compareItemPointers( &entry->curItem, &key->curItem )==0 )
for (i = 0; i < key->nentries; i++)
{
entry = key->scanEntry + i;
if (entry->isFinished == FALSE && compareItemPointers(&entry->curItem, &key->curItem) == 0)
key->entryRes[i] = TRUE;
else
key->entryRes[i] = FALSE;
}
oldCtx = MemoryContextSwitchTo(tempCtx);
res = DatumGetBool( FunctionCall3(
&ginstate->consistentFn,
PointerGetDatum( key->entryRes ),
UInt16GetDatum( key->strategy ),
key->query
));
res = DatumGetBool(FunctionCall3(
&ginstate->consistentFn,
PointerGetDatum(key->entryRes),
UInt16GetDatum(key->strategy),
key->query
));
MemoryContextSwitchTo(oldCtx);
MemoryContextReset(tempCtx);
} while( !res );
} while (!res);
return FALSE;
}
/*
* Get heap item pointer from scan
* returns true if found
* Get heap item pointer from scan
* returns true if found
*/
static bool
scanGetItem( IndexScanDesc scan, ItemPointerData *item ) {
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
scanGetItem(IndexScanDesc scan, ItemPointerData *item)
{
uint32 i;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
ItemPointerSetMin( item );
for(i=0;i<so->nkeys;i++) {
GinScanKey key = so->keys+i;
ItemPointerSetMin(item);
for (i = 0; i < so->nkeys; i++)
{
GinScanKey key = so->keys + i;
if ( keyGetItem( scan->indexRelation, &so->ginstate, so->tempCtx, key )==FALSE ) {
if ( compareItemPointers( item, &key->curItem ) < 0 )
if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == FALSE)
{
if (compareItemPointers(item, &key->curItem) < 0)
*item = key->curItem;
} else
return FALSE; /* finshed one of keys */
}
else
return FALSE; /* finshed one of keys */
}
for(i=1;i<=so->nkeys;i++) {
GinScanKey key = so->keys+i-1;
for(;;) {
int cmp = compareItemPointers( item, &key->curItem );
for (i = 1; i <= so->nkeys; i++)
{
GinScanKey key = so->keys + i - 1;
if ( cmp == 0 )
for (;;)
{
int cmp = compareItemPointers(item, &key->curItem);
if (cmp == 0)
break;
else if ( cmp > 0 ) {
if ( keyGetItem( scan->indexRelation, &so->ginstate, so->tempCtx, key )==TRUE )
return FALSE; /* finshed one of keys */
} else { /* returns to begin */
else if (cmp > 0)
{
if (keyGetItem(scan->indexRelation, &so->ginstate, so->tempCtx, key) == TRUE)
return FALSE; /* finshed one of keys */
}
else
{ /* returns to begin */
*item = key->curItem;
i=0;
i = 0;
break;
}
}
}
return TRUE;
return TRUE;
}
#define GinIsNewKey(s) ( ((GinScanOpaque) scan->opaque)->keys == NULL )
Datum
gingetmulti(PG_FUNCTION_ARGS) {
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
Datum
gingetmulti(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ItemPointer tids = (ItemPointer) PG_GETARG_POINTER(1);
int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
int32 max_tids = PG_GETARG_INT32(2);
int32 *returned_tids = (int32 *) PG_GETARG_POINTER(3);
if ( GinIsNewKey(scan) )
newScanKey( scan );
if (GinIsNewKey(scan))
newScanKey(scan);
startScan( scan );
startScan(scan);
*returned_tids = 0;
do {
if ( scanGetItem( scan, tids + *returned_tids ) )
do
{
if (scanGetItem(scan, tids + *returned_tids))
(*returned_tids)++;
else
break;
} while ( *returned_tids < max_tids );
} while (*returned_tids < max_tids);
stopScan( scan );
stopScan(scan);
PG_RETURN_BOOL(*returned_tids == max_tids);
}
Datum
gingettuple(PG_FUNCTION_ARGS) {
gingettuple(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
bool res;
bool res;
if ( dir != ForwardScanDirection )
if (dir != ForwardScanDirection)
elog(ERROR, "Gin doesn't support other scan directions than forward");
if ( GinIsNewKey(scan) )
newScanKey( scan );
startScan( scan );
if (GinIsNewKey(scan))
newScanKey(scan);
startScan(scan);
res = scanGetItem(scan, &scan->xs_ctup.t_self);
stopScan( scan );
stopScan(scan);
PG_RETURN_BOOL(res);
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* gininsert.c
* insert routines for the postgres inverted index access method.
* insert routines for the postgres inverted index access method.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -19,12 +19,13 @@
#include "miscadmin.h"
#include "utils/memutils.h"
typedef struct {
GinState ginstate;
double indtuples;
MemoryContext tmpCtx;
MemoryContext funcCtx;
BuildAccumulator accum;
typedef struct
{
GinState ginstate;
double indtuples;
MemoryContext tmpCtx;
MemoryContext funcCtx;
BuildAccumulator accum;
} GinBuildState;
/*
@@ -32,24 +33,26 @@ typedef struct {
* suppose that items[] fits to page
*/
static BlockNumber
createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
{
BlockNumber blkno;
Buffer buffer = GinNewBuffer(index);
Page page;
Buffer buffer = GinNewBuffer(index);
Page page;
START_CRIT_SECTION();
GinInitBuffer( buffer, GIN_DATA|GIN_LEAF );
GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
page = BufferGetPage(buffer);
blkno = BufferGetBlockNumber(buffer);
memcpy( GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems );
memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems);
GinPageGetOpaque(page)->maxoff = nitems;
if (!index->rd_istemp) {
XLogRecPtr recptr;
if (!index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData rdata[2];
ginxlogCreatePostingTree data;
ginxlogCreatePostingTree data;
data.node = index->rd_node;
data.blkno = blkno;
@@ -71,7 +74,7 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
@@ -89,21 +92,25 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
* GinFormTuple().
*/
static IndexTuple
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild) {
bool isnull;
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild)
{
bool isnull;
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
if ( res ) {
if (res)
{
/* good, small enough */
MergeItemPointers( GinGetPosting(res),
GinGetPosting(old), GinGetNPosting(old),
items, nitem
);
MergeItemPointers(GinGetPosting(res),
GinGetPosting(old), GinGetNPosting(old),
items, nitem
);
GinSetNPosting(res, nitem + GinGetNPosting(old));
} else {
}
else
{
BlockNumber postingRoot;
GinPostingTreeScan *gdi;
@@ -112,7 +119,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
postingRoot = createPostingTree(index, GinGetPosting(old), GinGetNPosting(old));
GinSetPostingTree(res, postingRoot);
gdi = prepareScanPostingTree(index, postingRoot, FALSE);
gdi = prepareScanPostingTree(index, postingRoot, FALSE);
gdi->btree.isBuild = isBuild;
insertItemPointer(gdi, items, nitem);
@@ -124,36 +131,39 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
}
/*
* Inserts only one entry to the index, but it can adds more that 1
* ItemPointer.
* Inserts only one entry to the index, but it can adds more that 1
* ItemPointer.
*/
static void
ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild) {
GinBtreeData btree;
ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild)
{
GinBtreeData btree;
GinBtreeStack *stack;
IndexTuple itup;
Page page;
IndexTuple itup;
Page page;
prepareEntryScan( &btree, index, value, ginstate );
prepareEntryScan(&btree, index, value, ginstate);
stack = ginFindLeafPage(&btree, NULL);
page = BufferGetPage( stack->buffer );
page = BufferGetPage(stack->buffer);
if ( btree.findItem( &btree, stack ) ) {
if (btree.findItem(&btree, stack))
{
/* found entry */
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
if ( GinIsPostingTree(itup) ) {
if (GinIsPostingTree(itup))
{
/* lock root of posting tree */
GinPostingTreeScan *gdi;
BlockNumber rootPostingTree = GinGetPostingTree(itup);
BlockNumber rootPostingTree = GinGetPostingTree(itup);
/* release all stack */
LockBuffer(stack->buffer, GIN_UNLOCK);
freeGinBtreeStack( stack );
freeGinBtreeStack(stack);
/* insert into posting tree */
gdi = prepareScanPostingTree( index, rootPostingTree, FALSE );
gdi = prepareScanPostingTree(index, rootPostingTree, FALSE);
gdi->btree.isBuild = isBuild;
insertItemPointer(gdi, items, nitem);
@@ -163,23 +173,26 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
itup = addItemPointersToTuple(index, ginstate, stack, itup, items, nitem, isBuild);
btree.isDelete = TRUE;
} else {
}
else
{
/* We suppose, that tuple can store at list one itempointer */
itup = GinFormTuple( ginstate, value, items, 1);
if ( itup==NULL || IndexTupleSize(itup) >= GinMaxItemSize )
itup = GinFormTuple(ginstate, value, items, 1);
if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
elog(ERROR, "huge tuple");
if ( nitem>1 ) {
if (nitem > 1)
{
IndexTuple previtup = itup;
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items+1, nitem-1, isBuild);
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
pfree(previtup);
}
}
btree.entry = itup;
ginInsertValue(&btree, stack);
pfree( itup );
pfree(itup);
}
/*
@@ -187,48 +200,53 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
* Function isnt use during normal insert
*/
static uint32
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr) {
Datum *entries;
uint32 nentries;
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
{
Datum *entries;
uint32 nentries;
MemoryContext oldCtx;
oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
entries = extractEntriesSU( buildstate->accum.ginstate, value, &nentries);
entries = extractEntriesSU(buildstate->accum.ginstate, value, &nentries);
MemoryContextSwitchTo(oldCtx);
if ( nentries==0 )
if (nentries == 0)
/* nothing to insert */
return 0;
ginInsertRecordBA( &buildstate->accum, heapptr, entries, nentries);
ginInsertRecordBA(&buildstate->accum, heapptr, entries, nentries);
MemoryContextReset(buildstate->funcCtx);
return nentries;
}
static void
static void
ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
bool *isnull, bool tupleIsAlive, void *state) {
bool *isnull, bool tupleIsAlive, void *state)
{
GinBuildState *buildstate = (GinBuildState*)state;
GinBuildState *buildstate = (GinBuildState *) state;
MemoryContext oldCtx;
if ( *isnull )
if (*isnull)
return;
oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self);
/* we use only half maintenance_work_mem, because there is some leaks
during insertion and extract values */
if ( buildstate->accum.allocatedMemory >= maintenance_work_mem*1024L/2L ) {
ItemPointerData *list;
Datum entry;
uint32 nlist;
/*
* we use only half maintenance_work_mem, because there is some leaks
* during insertion and extract values
*/
if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L / 2L)
{
ItemPointerData *list;
Datum entry;
uint32 nlist;
while( (list=ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL )
while ((list = ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL)
ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE);
MemoryContextReset(buildstate->tmpCtx);
@@ -239,22 +257,23 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
}
Datum
ginbuild(PG_FUNCTION_ARGS) {
Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1);
ginbuild(PG_FUNCTION_ARGS)
{
Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1);
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
GinBuildState buildstate;
double reltuples;
GinBuildState buildstate;
Buffer buffer;
ItemPointerData *list;
Datum entry;
uint32 nlist;
ItemPointerData *list;
Datum entry;
uint32 nlist;
MemoryContext oldCtx;
if (RelationGetNumberOfBlocks(index) != 0)
elog(ERROR, "index \"%s\" already contains data",
RelationGetRelationName(index));
RelationGetRelationName(index));
initGinState(&buildstate.ginstate, index);
@@ -262,10 +281,11 @@ ginbuild(PG_FUNCTION_ARGS) {
buffer = GinNewBuffer(index);
START_CRIT_SECTION();
GinInitBuffer(buffer, GIN_LEAF);
if (!index->rd_istemp) {
XLogRecPtr recptr;
if (!index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData rdata;
Page page;
Page page;
rdata.buffer = InvalidBuffer;
rdata.data = (char *) &(index->rd_node);
@@ -279,7 +299,7 @@ ginbuild(PG_FUNCTION_ARGS) {
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
@@ -293,26 +313,26 @@ ginbuild(PG_FUNCTION_ARGS) {
* inserted into the index
*/
buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin build temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin build temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx,
"Gin build temporary context for user-defined function",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin build temporary context for user-defined function",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
buildstate.accum.ginstate = &buildstate.ginstate;
ginInitBA( &buildstate.accum );
ginInitBA(&buildstate.accum);
/* do the heap scan */
reltuples = IndexBuildHeapScan(heap, index, indexInfo,
ginBuildCallback, (void *) &buildstate);
ginBuildCallback, (void *) &buildstate);
oldCtx = MemoryContextSwitchTo(buildstate.tmpCtx);
while( (list=ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL )
while ((list = ginGetEntry(&buildstate.accum, &entry, &nlist)) != NULL)
ginEntryInsert(index, &buildstate.ginstate, entry, list, nlist, TRUE);
MemoryContextSwitchTo(oldCtx);
@@ -333,55 +353,58 @@ ginbuild(PG_FUNCTION_ARGS) {
* Inserts value during normal insertion
*/
static uint32
ginHeapTupleInsert( Relation index, GinState *ginstate, Datum value, ItemPointer item) {
Datum *entries;
uint32 i,nentries;
ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
{
Datum *entries;
uint32 i,
nentries;
entries = extractEntriesSU( ginstate, value, &nentries);
entries = extractEntriesSU(ginstate, value, &nentries);
if ( nentries==0 )
if (nentries == 0)
/* nothing to insert */
return 0;
for(i=0;i<nentries;i++)
for (i = 0; i < nentries; i++)
ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE);
return nentries;
}
Datum
gininsert(PG_FUNCTION_ARGS) {
Relation index = (Relation) PG_GETARG_POINTER(0);
Datum *values = (Datum *) PG_GETARG_POINTER(1);
bool *isnull = (bool *) PG_GETARG_POINTER(2);
gininsert(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
Datum *values = (Datum *) PG_GETARG_POINTER(1);
bool *isnull = (bool *) PG_GETARG_POINTER(2);
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
#ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
bool checkUnique = PG_GETARG_BOOL(5);
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
bool checkUnique = PG_GETARG_BOOL(5);
#endif
GinState ginstate;
GinState ginstate;
MemoryContext oldCtx;
MemoryContext insertCtx;
uint32 res;
uint32 res;
if ( *isnull )
if (*isnull)
PG_RETURN_BOOL(false);
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin insert temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin insert temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldCtx = MemoryContextSwitchTo(insertCtx);
initGinState(&ginstate, index);
res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx);
PG_RETURN_BOOL(res>0);
PG_RETURN_BOOL(res > 0);
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginscan.c
* routines to manage scans inverted index relations
* routines to manage scans inverted index relations
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.5 2006/09/14 11:26:49 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.6 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -19,11 +19,12 @@
#include "utils/memutils.h"
Datum
ginbeginscan(PG_FUNCTION_ARGS) {
Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
Datum
ginbeginscan(PG_FUNCTION_ARGS)
{
Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
IndexScanDesc scan;
scan = RelationGetIndexScan(rel, keysz, scankey);
@@ -32,22 +33,25 @@ ginbeginscan(PG_FUNCTION_ARGS) {
}
static void
fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy ) {
uint32 i,j;
fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy)
{
uint32 i,
j;
key->nentries = nEntryValues;
key->entryRes = (bool*)palloc0( sizeof(bool) * nEntryValues );
key->scanEntry = (GinScanEntry) palloc( sizeof(GinScanEntryData) * nEntryValues );
key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
key->strategy = strategy;
key->query = query;
key->firstCall= TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber );
key->firstCall = TRUE;
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
for(i=0; i<nEntryValues; i++) {
for (i = 0; i < nEntryValues; i++)
{
key->scanEntry[i].pval = key->entryRes + i;
key->scanEntry[i].entry = entryValues[i];
ItemPointerSet( &(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber );
ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
key->scanEntry[i].offset = InvalidOffsetNumber;
key->scanEntry[i].buffer = InvalidBuffer;
key->scanEntry[i].list = NULL;
@@ -55,8 +59,9 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
/* link to the equals entry in current scan key */
key->scanEntry[i].master = NULL;
for( j=0; j<i; j++)
if ( compareEntries( ginstate, entryValues[i], entryValues[j] ) == 0 ) {
for (j = 0; j < i; j++)
if (compareEntries(ginstate, entryValues[i], entryValues[j]) == 0)
{
key->scanEntry[i].master = key->scanEntry + j;
break;
}
@@ -66,23 +71,27 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
#ifdef NOT_USED
static void
resetScanKeys(GinScanKey keys, uint32 nkeys) {
uint32 i, j;
resetScanKeys(GinScanKey keys, uint32 nkeys)
{
uint32 i,
j;
if ( keys == NULL )
if (keys == NULL)
return;
for(i=0;i<nkeys;i++) {
GinScanKey key = keys + i;
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
key->firstCall = TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber );
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
for(j=0;j<key->nentries;j++) {
if ( key->scanEntry[j].buffer != InvalidBuffer )
ReleaseBuffer( key->scanEntry[i].buffer );
for (j = 0; j < key->nentries; j++)
{
if (key->scanEntry[j].buffer != InvalidBuffer)
ReleaseBuffer(key->scanEntry[i].buffer);
ItemPointerSet( &(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber );
ItemPointerSet(&(key->scanEntry[j].curItem), InvalidBlockNumber, InvalidOffsetNumber);
key->scanEntry[j].offset = InvalidOffsetNumber;
key->scanEntry[j].buffer = InvalidBuffer;
key->scanEntry[j].list = NULL;
@@ -90,111 +99,121 @@ resetScanKeys(GinScanKey keys, uint32 nkeys) {
}
}
}
#endif
static void
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) {
uint32 i, j;
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
{
uint32 i,
j;
if ( keys == NULL )
if (keys == NULL)
return;
for(i=0;i<nkeys;i++) {
GinScanKey key = keys + i;
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
for(j=0;j<key->nentries;j++) {
if ( key->scanEntry[j].buffer != InvalidBuffer )
ReleaseBuffer( key->scanEntry[j].buffer );
if ( removeRes && key->scanEntry[j].list )
for (j = 0; j < key->nentries; j++)
{
if (key->scanEntry[j].buffer != InvalidBuffer)
ReleaseBuffer(key->scanEntry[j].buffer);
if (removeRes && key->scanEntry[j].list)
pfree(key->scanEntry[j].list);
}
if ( removeRes )
if (removeRes)
pfree(key->entryRes);
pfree(key->scanEntry);
}
pfree(keys);
}
void
newScanKey( IndexScanDesc scan ) {
ScanKey scankey = scan->keyData;
newScanKey(IndexScanDesc scan)
{
ScanKey scankey = scan->keyData;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
int i;
uint32 nkeys = 0;
int i;
uint32 nkeys = 0;
so->keys = (GinScanKey) palloc( scan->numberOfKeys * sizeof(GinScanKeyData) );
so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
if (scan->numberOfKeys < 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GIN indexes do not support whole-index scans")));
errmsg("GIN indexes do not support whole-index scans")));
for(i=0; i<scan->numberOfKeys; i++) {
Datum* entryValues;
uint32 nEntryValues;
for (i = 0; i < scan->numberOfKeys; i++)
{
Datum *entryValues;
uint32 nEntryValues;
if ( scankey[i].sk_flags & SK_ISNULL )
if (scankey[i].sk_flags & SK_ISNULL)
elog(ERROR, "Gin doesn't support NULL as scan key");
Assert( scankey[i].sk_attno == 1 );
Assert(scankey[i].sk_attno == 1);
entryValues = (Datum*)DatumGetPointer(
FunctionCall3(
&so->ginstate.extractQueryFn,
scankey[i].sk_argument,
PointerGetDatum( &nEntryValues ),
UInt16GetDatum(scankey[i].sk_strategy)
)
);
if ( entryValues==NULL || nEntryValues == 0 )
entryValues = (Datum *) DatumGetPointer(
FunctionCall3(
&so->ginstate.extractQueryFn,
scankey[i].sk_argument,
PointerGetDatum(&nEntryValues),
UInt16GetDatum(scankey[i].sk_strategy)
)
);
if (entryValues == NULL || nEntryValues == 0)
/* full scan... */
continue;
fillScanKey( &so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, nEntryValues, scankey[i].sk_strategy );
fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, nEntryValues, scankey[i].sk_strategy);
nkeys++;
}
so->nkeys = nkeys;
if ( so->nkeys == 0 )
if (so->nkeys == 0)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("GIN index doesn't support search with void query")));
errmsg("GIN index doesn't support search with void query")));
pgstat_count_index_scan(&scan->xs_pgstat_info);
}
Datum
ginrescan(PG_FUNCTION_ARGS) {
ginrescan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so;
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so;
so = (GinScanOpaque) scan->opaque;
if ( so == NULL ) {
if (so == NULL)
{
/* if called from ginbeginscan */
so = (GinScanOpaque)palloc( sizeof(GinScanOpaqueData) );
so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
initGinState(&so->ginstate, scan->indexRelation);
scan->opaque = so;
} else {
}
else
{
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
}
so->markPos=so->keys=NULL;
so->markPos = so->keys = NULL;
if ( scankey && scan->numberOfKeys > 0 ) {
if (scankey && scan->numberOfKeys > 0)
{
memmove(scan->keyData, scankey,
scan->numberOfKeys * sizeof(ScanKeyData));
scan->numberOfKeys * sizeof(ScanKeyData));
}
PG_RETURN_VOID();
@@ -202,13 +221,15 @@ ginrescan(PG_FUNCTION_ARGS) {
Datum
ginendscan(PG_FUNCTION_ARGS) {
ginendscan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
if ( so != NULL ) {
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
if (so != NULL)
{
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
MemoryContextDelete(so->tempCtx);
@@ -219,22 +240,28 @@ ginendscan(PG_FUNCTION_ARGS) {
}
static GinScanKey
copyScanKeys( GinScanKey keys, uint32 nkeys ) {
copyScanKeys(GinScanKey keys, uint32 nkeys)
{
GinScanKey newkeys;
uint32 i, j;
uint32 i,
j;
newkeys = (GinScanKey)palloc( sizeof(GinScanKeyData) * nkeys );
memcpy( newkeys, keys, sizeof(GinScanKeyData) * nkeys );
newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
memcpy(newkeys, keys, sizeof(GinScanKeyData) * nkeys);
for(i=0;i<nkeys;i++) {
newkeys[i].scanEntry = (GinScanEntry)palloc(sizeof(GinScanEntryData) * keys[i].nentries );
memcpy( newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries );
for (i = 0; i < nkeys; i++)
{
newkeys[i].scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * keys[i].nentries);
memcpy(newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries);
for (j = 0; j < keys[i].nentries; j++)
{
if (keys[i].scanEntry[j].buffer != InvalidBuffer)
IncrBufferRefCount(keys[i].scanEntry[j].buffer);
if (keys[i].scanEntry[j].master)
{
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
for(j=0;j<keys[i].nentries; j++) {
if ( keys[i].scanEntry[j].buffer != InvalidBuffer )
IncrBufferRefCount( keys[i].scanEntry[j].buffer );
if ( keys[i].scanEntry[j].master ) {
int masterN = keys[i].scanEntry[j].master - keys[i].scanEntry;
newkeys[i].scanEntry[j].master = newkeys[i].scanEntry + masterN;
}
}
@@ -243,24 +270,26 @@ copyScanKeys( GinScanKey keys, uint32 nkeys ) {
return newkeys;
}
Datum
ginmarkpos(PG_FUNCTION_ARGS) {
Datum
ginmarkpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->markPos, so->nkeys, FALSE);
so->markPos = copyScanKeys( so->keys, so->nkeys );
so->markPos = copyScanKeys(so->keys, so->nkeys);
PG_RETURN_VOID();
}
Datum
ginrestrpos(PG_FUNCTION_ARGS) {
Datum
ginrestrpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->keys, so->nkeys, FALSE);
so->keys = copyScanKeys( so->markPos, so->nkeys );
so->keys = copyScanKeys(so->markPos, so->nkeys);
PG_RETURN_VOID();
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginutil.c
* utilities routines for the postgres inverted index access method.
* utilities routines for the postgres inverted index access method.
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.6 2006/09/05 18:25:10 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.7 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -19,26 +19,27 @@
#include "access/reloptions.h"
#include "storage/freespace.h"
void
initGinState( GinState *state, Relation index ) {
if ( index->rd_att->natts != 1 )
elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts);
void
initGinState(GinState *state, Relation index)
{
if (index->rd_att->natts != 1)
elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts);
state->tupdesc = index->rd_att;
fmgr_info_copy(&(state->compareFn),
index_getprocinfo(index, 1, GIN_COMPARE_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_COMPARE_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->extractValueFn),
index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->extractQueryFn),
index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->consistentFn),
index_getprocinfo(index, 1, GIN_CONSISTENT_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_CONSISTENT_PROC),
CurrentMemoryContext);
}
/*
@@ -48,13 +49,16 @@ initGinState( GinState *state, Relation index ) {
*/
Buffer
GinNewBuffer(Relation index) {
Buffer buffer;
bool needLock;
GinNewBuffer(Relation index)
{
Buffer buffer;
bool needLock;
/* First, try to get a page from FSM */
for(;;) {
for (;;)
{
BlockNumber blkno = GetFreeIndexPage(&index->rd_node);
if (blkno == InvalidBlockNumber)
break;
@@ -64,14 +68,15 @@ GinNewBuffer(Relation index) {
* We have to guard against the possibility that someone else already
* recycled this page; the buffer may be locked if so.
*/
if (ConditionalLockBuffer(buffer)) {
Page page = BufferGetPage(buffer);
if (ConditionalLockBuffer(buffer))
{
Page page = BufferGetPage(buffer);
if (PageIsNew(page))
return buffer; /* OK to use, if never initialized */
return buffer; /* OK to use, if never initialized */
if (GinPageIsDeleted(page))
return buffer; /* OK to use */
return buffer; /* OK to use */
LockBuffer(buffer, GIN_UNLOCK);
}
@@ -95,36 +100,39 @@ GinNewBuffer(Relation index) {
}
void
GinInitPage(Page page, uint32 f, Size pageSize) {
GinInitPage(Page page, uint32 f, Size pageSize)
{
GinPageOpaque opaque;
PageInit(page, pageSize, sizeof(GinPageOpaqueData));
opaque = GinPageGetOpaque(page);
memset( opaque, 0, sizeof(GinPageOpaqueData) );
opaque->flags = f;
memset(opaque, 0, sizeof(GinPageOpaqueData));
opaque->flags = f;
opaque->rightlink = InvalidBlockNumber;
}
void
GinInitBuffer(Buffer b, uint32 f) {
GinInitPage( BufferGetPage(b), f, BufferGetPageSize(b) );
GinInitBuffer(Buffer b, uint32 f)
{
GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b));
}
int
compareEntries(GinState *ginstate, Datum a, Datum b) {
compareEntries(GinState *ginstate, Datum a, Datum b)
{
return DatumGetInt32(
FunctionCall2(
&ginstate->compareFn,
a, b
)
FunctionCall2(
&ginstate->compareFn,
a, b
)
);
}
static FmgrInfo* cmpDatumPtr=NULL;
static FmgrInfo *cmpDatumPtr = NULL;
#if defined(__INTEL_COMPILER) && (defined(__ia64__) || defined(__ia64))
/*
#if defined(__INTEL_COMPILER) && (defined(__ia64__) || defined(__ia64))
/*
* Intel Compiler on Intel Itanium with -O2 has a bug around
* change static variable by user function called from
* libc func: it doesn't change. So mark it as volatile.
@@ -132,7 +140,7 @@ static FmgrInfo* cmpDatumPtr=NULL;
* It's a pity, but it's impossible to define optimization
* level here.
*/
#define VOLATILE volatile
#define VOLATILE volatile
#else
#define VOLATILE
#endif
@@ -140,57 +148,64 @@ static FmgrInfo* cmpDatumPtr=NULL;
static bool VOLATILE needUnique = FALSE;
static int
cmpEntries(const void * a, const void * b) {
int res = DatumGetInt32(
FunctionCall2(
cmpDatumPtr,
*(Datum*)a,
*(Datum*)b
)
cmpEntries(const void *a, const void *b)
{
int res = DatumGetInt32(
FunctionCall2(
cmpDatumPtr,
*(Datum *) a,
*(Datum *) b
)
);
if ( res == 0 )
if (res == 0)
needUnique = TRUE;
return res;
}
Datum*
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
Datum *entries;
Datum *
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries;
entries = (Datum*)DatumGetPointer(
FunctionCall2(
&ginstate->extractValueFn,
value,
PointerGetDatum( nentries )
)
);
entries = (Datum *) DatumGetPointer(
FunctionCall2(
&ginstate->extractValueFn,
value,
PointerGetDatum(nentries)
)
);
if ( entries == NULL )
if (entries == NULL)
*nentries = 0;
if ( *nentries > 1 ) {
if (*nentries > 1)
{
cmpDatumPtr = &ginstate->compareFn;
needUnique = FALSE;
qsort(entries, *nentries, sizeof(Datum), cmpEntries);
qsort(entries, *nentries, sizeof(Datum), cmpEntries);
}
return entries;
}
Datum*
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
Datum *entries = extractEntriesS(ginstate, value, nentries);
Datum *
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries = extractEntriesS(ginstate, value, nentries);
if ( *nentries>1 && needUnique ) {
Datum *ptr, *res;
if (*nentries > 1 && needUnique)
{
Datum *ptr,
*res;
ptr = res = entries;
while( ptr - entries < *nentries ) {
if ( compareEntries(ginstate, *ptr, *res ) != 0 )
while (ptr - entries < *nentries)
{
if (compareEntries(ginstate, *ptr, *res) != 0)
*(++res) = *ptr++;
else
ptr++;
@@ -206,13 +221,14 @@ extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
* It's analog of PageGetTempPage(), but copies whole page
*/
Page
GinPageGetCopyPage( Page page ) {
Size pageSize = PageGetPageSize( page );
Page tmppage;
GinPageGetCopyPage(Page page)
{
Size pageSize = PageGetPageSize(page);
Page tmppage;
tmppage = (Page) palloc(pageSize);
memcpy(tmppage, page, pageSize);
tmppage=(Page)palloc( pageSize );
memcpy( tmppage, page, pageSize );
return tmppage;
}

View File

@@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* ginvacuum.c
* delete & vacuum routines for the postgres GIN
* delete & vacuum routines for the postgres GIN
*
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.6 2006/09/21 20:31:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.7 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
@@ -21,42 +21,50 @@
#include "storage/freespace.h"
#include "commands/vacuum.h"
typedef struct {
Relation index;
IndexBulkDeleteResult *result;
IndexBulkDeleteCallback callback;
void *callback_state;
GinState ginstate;
typedef struct
{
Relation index;
IndexBulkDeleteResult *result;
IndexBulkDeleteCallback callback;
void *callback_state;
GinState ginstate;
} GinVacuumState;
/*
* Cleans array of ItemPointer (removes dead pointers)
* Results are always stored in *cleaned, which will be allocated
* if its needed. In case of *cleaned!=NULL caller is resposible to
* if its needed. In case of *cleaned!=NULL caller is resposible to
* enough space. *cleaned and items may point to the same
* memory addres.
*/
static uint32
ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned ) {
uint32 i,j=0;
ginVacuumPostingList(GinVacuumState *gvs, ItemPointerData *items, uint32 nitem, ItemPointerData **cleaned)
{
uint32 i,
j = 0;
/*
* just scan over ItemPointer array
*/
for(i=0;i<nitem;i++) {
if ( gvs->callback(items+i, gvs->callback_state) ) {
for (i = 0; i < nitem; i++)
{
if (gvs->callback(items + i, gvs->callback_state))
{
gvs->result->tuples_removed += 1;
if ( !*cleaned ) {
*cleaned = (ItemPointerData*)palloc(sizeof(ItemPointerData)*nitem);
if ( i!=0 )
memcpy( *cleaned, items, sizeof(ItemPointerData)*i);
if (!*cleaned)
{
*cleaned = (ItemPointerData *) palloc(sizeof(ItemPointerData) * nitem);
if (i != 0)
memcpy(*cleaned, items, sizeof(ItemPointerData) * i);
}
} else {
}
else
{
gvs->result->num_index_tuples += 1;
if (i!=j)
if (i != j)
(*cleaned)[j] = items[i];
j++;
}
@@ -69,56 +77,65 @@ ginVacuumPostingList( GinVacuumState *gvs, ItemPointerData *items, uint32 nitem,
* fills WAL record for vacuum leaf page
*/
static void
xlogVacuumPage(Relation index, Buffer buffer) {
Page page = BufferGetPage( buffer );
XLogRecPtr recptr;
xlogVacuumPage(Relation index, Buffer buffer)
{
Page page = BufferGetPage(buffer);
XLogRecPtr recptr;
XLogRecData rdata[3];
ginxlogVacuumPage data;
char *backup;
char itups[BLCKSZ];
uint32 len=0;
ginxlogVacuumPage data;
char *backup;
char itups[BLCKSZ];
uint32 len = 0;
Assert( GinPageIsLeaf( page ) );
Assert(GinPageIsLeaf(page));
if (index->rd_istemp)
return;
return;
data.node = index->rd_node;
data.blkno = BufferGetBlockNumber(buffer);
if ( GinPageIsData( page ) ) {
backup = GinDataPageGetData( page );
data.nitem = GinPageGetOpaque( page )->maxoff;
if ( data.nitem )
len = MAXALIGN( sizeof(ItemPointerData)*data.nitem );
} else {
char *ptr;
if (GinPageIsData(page))
{
backup = GinDataPageGetData(page);
data.nitem = GinPageGetOpaque(page)->maxoff;
if (data.nitem)
len = MAXALIGN(sizeof(ItemPointerData) * data.nitem);
}
else
{
char *ptr;
OffsetNumber i;
ptr = backup = itups;
for(i=FirstOffsetNumber;i<=PageGetMaxOffsetNumber(page);i++) {
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
memcpy( ptr, itup, IndexTupleSize( itup ) );
ptr += MAXALIGN( IndexTupleSize( itup ) );
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, i));
memcpy(ptr, itup, IndexTupleSize(itup));
ptr += MAXALIGN(IndexTupleSize(itup));
}
data.nitem = PageGetMaxOffsetNumber(page);
len = ptr-backup;
len = ptr - backup;
}
rdata[0].buffer = buffer;
rdata[0].buffer_std = ( GinPageIsData( page ) ) ? FALSE : TRUE;
rdata[0].buffer_std = (GinPageIsData(page)) ? FALSE : TRUE;
rdata[0].len = 0;
rdata[0].data = NULL;
rdata[0].next = rdata + 1;
rdata[1].buffer = InvalidBuffer;
rdata[1].len = sizeof(ginxlogVacuumPage);
rdata[1].data = (char*)&data;
rdata[1].data = (char *) &data;
if ( len == 0 ) {
if (len == 0)
{
rdata[1].next = NULL;
} else {
}
else
{
rdata[1].next = rdata + 2;
rdata[2].buffer = InvalidBuffer;
@@ -133,71 +150,84 @@ xlogVacuumPage(Relation index, Buffer buffer) {
}
static bool
ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer ) {
Buffer buffer = ReadBuffer( gvs->index, blkno );
Page page = BufferGetPage( buffer );
bool hasVoidPage = FALSE;
ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, Buffer *rootBuffer)
{
Buffer buffer = ReadBuffer(gvs->index, blkno);
Page page = BufferGetPage(buffer);
bool hasVoidPage = FALSE;
/*
/*
* We should be sure that we don't concurrent with inserts, insert process
* never release root page until end (but it can unlock it and lock again).
* If we lock root with with LockBufferForCleanup, new scan process can't begin,
* but previous may run.
* ginmarkpos/start* keeps buffer pinned, so we will wait for it.
* We lock only one posting tree in whole index, so, it's concurrent enough..
* Side effect: after this is full complete, tree is unused by any other process
* never release root page until end (but it can unlock it and lock
* again). If we lock root with with LockBufferForCleanup, new scan
* process can't begin, but previous may run. ginmarkpos/start* keeps
* buffer pinned, so we will wait for it. We lock only one posting tree in
* whole index, so, it's concurrent enough.. Side effect: after this is
* full complete, tree is unused by any other process
*/
LockBufferForCleanup( buffer );
LockBufferForCleanup(buffer);
Assert( GinPageIsData(page) );
Assert(GinPageIsData(page));
if ( GinPageIsLeaf(page) ) {
OffsetNumber newMaxOff, oldMaxOff = GinPageGetOpaque(page)->maxoff;
if (GinPageIsLeaf(page))
{
OffsetNumber newMaxOff,
oldMaxOff = GinPageGetOpaque(page)->maxoff;
ItemPointerData *cleaned = NULL;
newMaxOff = ginVacuumPostingList( gvs,
(ItemPointer)GinDataPageGetData(page), oldMaxOff, &cleaned );
newMaxOff = ginVacuumPostingList(gvs,
(ItemPointer) GinDataPageGetData(page), oldMaxOff, &cleaned);
/* saves changes about deleted tuple ... */
if ( oldMaxOff != newMaxOff ) {
if (oldMaxOff != newMaxOff)
{
START_CRIT_SECTION();
if ( newMaxOff > 0 )
memcpy( GinDataPageGetData(page), cleaned, sizeof(ItemPointerData) * newMaxOff );
pfree( cleaned );
if (newMaxOff > 0)
memcpy(GinDataPageGetData(page), cleaned, sizeof(ItemPointerData) * newMaxOff);
pfree(cleaned);
GinPageGetOpaque(page)->maxoff = newMaxOff;
xlogVacuumPage(gvs->index, buffer);
xlogVacuumPage(gvs->index, buffer);
MarkBufferDirty( buffer );
MarkBufferDirty(buffer);
END_CRIT_SECTION();
/* if root is a leaf page, we don't desire futher processing */
if ( !isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber )
/* if root is a leaf page, we don't desire futher processing */
if (!isRoot && GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
hasVoidPage = TRUE;
}
} else {
}
else
{
OffsetNumber i;
bool isChildHasVoid = FALSE;
bool isChildHasVoid = FALSE;
for( i=FirstOffsetNumber ; i <= GinPageGetOpaque(page)->maxoff ; i++ ) {
PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page, i);
if ( ginVacuumPostingTreeLeaves( gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL ) )
for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
{
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (ginVacuumPostingTreeLeaves(gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL))
isChildHasVoid = TRUE;
}
if ( isChildHasVoid )
if (isChildHasVoid)
hasVoidPage = TRUE;
}
/* if we have root and theres void pages in tree, then we don't release lock
to go further processing and guarantee that tree is unused */
if ( !(isRoot && hasVoidPage) ) {
UnlockReleaseBuffer( buffer );
} else {
Assert( rootBuffer );
/*
* if we have root and theres void pages in tree, then we don't release
* lock to go further processing and guarantee that tree is unused
*/
if (!(isRoot && hasVoidPage))
{
UnlockReleaseBuffer(buffer);
}
else
{
Assert(rootBuffer);
*rootBuffer = buffer;
}
@@ -205,49 +235,54 @@ ginVacuumPostingTreeLeaves( GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
}
static void
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot ) {
Buffer dBuffer = ReadBuffer( gvs->index, deleteBlkno );
Buffer lBuffer = (leftBlkno==InvalidBlockNumber) ? InvalidBuffer : ReadBuffer( gvs->index, leftBlkno );
Buffer pBuffer = ReadBuffer( gvs->index, parentBlkno );
Page page, parentPage;
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
{
Buffer dBuffer = ReadBuffer(gvs->index, deleteBlkno);
Buffer lBuffer = (leftBlkno == InvalidBlockNumber) ? InvalidBuffer : ReadBuffer(gvs->index, leftBlkno);
Buffer pBuffer = ReadBuffer(gvs->index, parentBlkno);
Page page,
parentPage;
LockBuffer( dBuffer, GIN_EXCLUSIVE );
if ( !isParentRoot ) /* parent is already locked by LockBufferForCleanup() */
LockBuffer( pBuffer, GIN_EXCLUSIVE );
LockBuffer(dBuffer, GIN_EXCLUSIVE);
if (!isParentRoot) /* parent is already locked by
* LockBufferForCleanup() */
LockBuffer(pBuffer, GIN_EXCLUSIVE);
START_CRIT_SECTION();
if ( leftBlkno!= InvalidBlockNumber ) {
if (leftBlkno != InvalidBlockNumber)
{
BlockNumber rightlink;
LockBuffer( lBuffer, GIN_EXCLUSIVE );
LockBuffer(lBuffer, GIN_EXCLUSIVE);
page = BufferGetPage( dBuffer );
page = BufferGetPage(dBuffer);
rightlink = GinPageGetOpaque(page)->rightlink;
page = BufferGetPage( lBuffer );
page = BufferGetPage(lBuffer);
GinPageGetOpaque(page)->rightlink = rightlink;
}
parentPage = BufferGetPage( pBuffer );
parentPage = BufferGetPage(pBuffer);
PageDeletePostingItem(parentPage, myoff);
page = BufferGetPage( dBuffer );
page = BufferGetPage(dBuffer);
GinPageGetOpaque(page)->flags = GIN_DELETED;
if (!gvs->index->rd_istemp) {
XLogRecPtr recptr;
if (!gvs->index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData rdata[4];
ginxlogDeletePage data;
int n;
ginxlogDeletePage data;
int n;
data.node = gvs->index->rd_node;
data.blkno = deleteBlkno;
data.parentBlkno = parentBlkno;
data.parentOffset = myoff;
data.leftBlkno = leftBlkno;
data.rightLink = GinPageGetOpaque(page)->rightlink;
data.leftBlkno = leftBlkno;
data.rightLink = GinPageGetOpaque(page)->rightlink;
rdata[0].buffer = dBuffer;
rdata[0].buffer_std = FALSE;
@@ -261,20 +296,22 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
rdata[1].len = 0;
rdata[1].next = rdata + 2;
if ( leftBlkno!= InvalidBlockNumber ) {
if (leftBlkno != InvalidBlockNumber)
{
rdata[2].buffer = lBuffer;
rdata[2].buffer_std = FALSE;
rdata[2].data = NULL;
rdata[2].len = 0;
rdata[2].next = rdata + 3;
n = 3;
} else
}
else
n = 2;
rdata[n].buffer = InvalidBuffer;
rdata[n].buffer_std = FALSE;
rdata[n].len = sizeof(ginxlogDeletePage);
rdata[n].data = (char*)&data;
rdata[n].data = (char *) &data;
rdata[n].next = NULL;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_DELETE_PAGE, rdata);
@@ -282,122 +319,141 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
PageSetTLI(page, ThisTimeLineID);
PageSetLSN(parentPage, recptr);
PageSetTLI(parentPage, ThisTimeLineID);
if ( leftBlkno!= InvalidBlockNumber ) {
page = BufferGetPage( lBuffer );
if (leftBlkno != InvalidBlockNumber)
{
page = BufferGetPage(lBuffer);
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty( pBuffer );
if ( !isParentRoot )
LockBuffer( pBuffer, GIN_UNLOCK );
ReleaseBuffer( pBuffer );
MarkBufferDirty(pBuffer);
if (!isParentRoot)
LockBuffer(pBuffer, GIN_UNLOCK);
ReleaseBuffer(pBuffer);
if ( leftBlkno!= InvalidBlockNumber ) {
MarkBufferDirty( lBuffer );
UnlockReleaseBuffer( lBuffer );
if (leftBlkno != InvalidBlockNumber)
{
MarkBufferDirty(lBuffer);
UnlockReleaseBuffer(lBuffer);
}
MarkBufferDirty( dBuffer );
UnlockReleaseBuffer( dBuffer );
MarkBufferDirty(dBuffer);
UnlockReleaseBuffer(dBuffer);
END_CRIT_SECTION();
gvs->result->pages_deleted++;
}
typedef struct DataPageDeleteStack {
struct DataPageDeleteStack *child;
struct DataPageDeleteStack *parent;
typedef struct DataPageDeleteStack
{
struct DataPageDeleteStack *child;
struct DataPageDeleteStack *parent;
BlockNumber blkno;
bool isRoot;
BlockNumber blkno;
bool isRoot;
} DataPageDeleteStack;
/*
* scans posting tree and deletes empty pages
*/
static bool
ginScanToDelete( GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff ) {
DataPageDeleteStack *me;
Buffer buffer;
Page page;
bool meDelete = FALSE;
ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff)
{
DataPageDeleteStack *me;
Buffer buffer;
Page page;
bool meDelete = FALSE;
if ( isRoot ) {
if (isRoot)
{
me = parent;
} else {
if ( ! parent->child ) {
me = (DataPageDeleteStack*)palloc0(sizeof(DataPageDeleteStack));
me->parent=parent;
}
else
{
if (!parent->child)
{
me = (DataPageDeleteStack *) palloc0(sizeof(DataPageDeleteStack));
me->parent = parent;
parent->child = me;
me->blkno = InvalidBlockNumber;
} else
}
else
me = parent->child;
}
buffer = ReadBuffer( gvs->index, blkno );
page = BufferGetPage( buffer );
buffer = ReadBuffer(gvs->index, blkno);
page = BufferGetPage(buffer);
Assert( GinPageIsData(page) );
Assert(GinPageIsData(page));
if ( !GinPageIsLeaf(page) ) {
if (!GinPageIsLeaf(page))
{
OffsetNumber i;
for(i=FirstOffsetNumber;i<=GinPageGetOpaque(page)->maxoff;i++) {
PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page, i);
for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
{
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
if ( ginScanToDelete( gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i ) )
if (ginScanToDelete(gvs, PostingItemGetBlockNumber(pitem), FALSE, me, i))
i--;
}
}
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) {
if ( !( me->blkno == InvalidBlockNumber && GinPageRightMost(page) ) ) {
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
{
if (!(me->blkno == InvalidBlockNumber && GinPageRightMost(page)))
{
/* we never delete right most branch */
Assert( !isRoot );
if ( GinPageGetOpaque(page)->maxoff < FirstOffsetNumber ) {
ginDeletePage( gvs, blkno, me->blkno, me->parent->blkno, myoff, me->parent->isRoot );
Assert(!isRoot);
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
{
ginDeletePage(gvs, blkno, me->blkno, me->parent->blkno, myoff, me->parent->isRoot);
meDelete = TRUE;
}
}
}
ReleaseBuffer( buffer );
ReleaseBuffer(buffer);
if ( !meDelete )
if (!meDelete)
me->blkno = blkno;
return meDelete;
}
static void
ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
Buffer rootBuffer = InvalidBuffer;
DataPageDeleteStack root, *ptr, *tmp;
ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
{
Buffer rootBuffer = InvalidBuffer;
DataPageDeleteStack root,
*ptr,
*tmp;
if ( ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer)==FALSE ) {
Assert( rootBuffer == InvalidBuffer );
if (ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer) == FALSE)
{
Assert(rootBuffer == InvalidBuffer);
return;
}
memset(&root,0,sizeof(DataPageDeleteStack));
memset(&root, 0, sizeof(DataPageDeleteStack));
root.blkno = rootBlkno;
root.isRoot = TRUE;
vacuum_delay_point();
ginScanToDelete( gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber );
ginScanToDelete(gvs, rootBlkno, TRUE, &root, InvalidOffsetNumber);
ptr = root.child;
while( ptr ) {
while (ptr)
{
tmp = ptr->child;
pfree( ptr );
pfree(ptr);
ptr = tmp;
}
UnlockReleaseBuffer( rootBuffer );
UnlockReleaseBuffer(rootBuffer);
}
/*
@@ -406,48 +462,65 @@ ginVacuumPostingTree( GinVacuumState *gvs, BlockNumber rootBlkno ) {
* then page is copied into temprorary one.
*/
static Page
ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot) {
Page origpage = BufferGetPage( buffer ), tmppage;
OffsetNumber i, maxoff = PageGetMaxOffsetNumber( origpage );
ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint32 *nroot)
{
Page origpage = BufferGetPage(buffer),
tmppage;
OffsetNumber i,
maxoff = PageGetMaxOffsetNumber(origpage);
tmppage = origpage;
*nroot=0;
*nroot = 0;
for(i=FirstOffsetNumber; i<= maxoff; i++) {
IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
IndexTuple itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
if ( GinIsPostingTree(itup) ) {
/* store posting tree's roots for further processing,
we can't vacuum it just now due to risk of deadlocks with scans/inserts */
roots[ *nroot ] = GinItemPointerGetBlockNumber(&itup->t_tid);
if (GinIsPostingTree(itup))
{
/*
* store posting tree's roots for further processing, we can't
* vacuum it just now due to risk of deadlocks with scans/inserts
*/
roots[*nroot] = GinItemPointerGetBlockNumber(&itup->t_tid);
(*nroot)++;
} else if ( GinGetNPosting(itup) > 0 ) {
/* if we already create temrorary page, we will make changes in place */
ItemPointerData *cleaned = (tmppage==origpage) ? NULL : GinGetPosting(itup );
uint32 newN = ginVacuumPostingList( gvs, GinGetPosting(itup), GinGetNPosting(itup), &cleaned );
if ( GinGetNPosting(itup) != newN ) {
bool isnull;
Datum value;
}
else if (GinGetNPosting(itup) > 0)
{
/*
* if we already create temrorary page, we will make changes in
* place
*/
ItemPointerData *cleaned = (tmppage == origpage) ? NULL : GinGetPosting(itup);
uint32 newN = ginVacuumPostingList(gvs, GinGetPosting(itup), GinGetNPosting(itup), &cleaned);
if (GinGetNPosting(itup) != newN)
{
bool isnull;
Datum value;
/*
* Some ItemPointers was deleted, so we should remake our tuple
* Some ItemPointers was deleted, so we should remake our
* tuple
*/
if ( tmppage==origpage ) {
if (tmppage == origpage)
{
/*
* On first difference we create temprorary page in memory
* and copies content in to it.
*/
tmppage=GinPageGetCopyPage ( origpage );
tmppage = GinPageGetCopyPage(origpage);
if ( newN > 0 ) {
Size pos = ((char*)GinGetPosting(itup)) - ((char*)origpage);
memcpy( tmppage+pos, cleaned, sizeof(ItemPointerData)*newN );
if (newN > 0)
{
Size pos = ((char *) GinGetPosting(itup)) - ((char *) origpage);
memcpy(tmppage + pos, cleaned, sizeof(ItemPointerData) * newN);
}
pfree( cleaned );
pfree(cleaned);
/* set itup pointer to new page */
itup = (IndexTuple) PageGetItem(tmppage, PageGetItemId(tmppage, i));
@@ -457,30 +530,31 @@ ginVacuumEntryPage(GinVacuumState *gvs, Buffer buffer, BlockNumber *roots, uint3
itup = GinFormTuple(&gvs->ginstate, value, GinGetPosting(itup), newN);
PageIndexTupleDelete(tmppage, i);
if ( PageAddItem( tmppage, (Item)itup, IndexTupleSize(itup), i, LP_USED ) != i )
elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(gvs->index));
if (PageAddItem(tmppage, (Item) itup, IndexTupleSize(itup), i, LP_USED) != i)
elog(ERROR, "failed to add item to index page in \"%s\"",
RelationGetRelationName(gvs->index));
pfree( itup );
pfree(itup);
}
}
}
return ( tmppage==origpage ) ? NULL : tmppage;
return (tmppage == origpage) ? NULL : tmppage;
}
Datum
ginbulkdelete(PG_FUNCTION_ARGS) {
ginbulkdelete(PG_FUNCTION_ARGS)
{
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(2);
void *callback_state = (void *) PG_GETARG_POINTER(3);
Relation index = info->index;
BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs;
Buffer buffer;
BlockNumber rootOfPostingTree[ BLCKSZ/ (sizeof(IndexTupleData)+sizeof(ItemId)) ];
uint32 nRoot;
BlockNumber blkno = GIN_ROOT_BLKNO;
GinVacuumState gvs;
Buffer buffer;
BlockNumber rootOfPostingTree[BLCKSZ / (sizeof(IndexTupleData) + sizeof(ItemId))];
uint32 nRoot;
/* first time through? */
if (stats == NULL)
@@ -494,107 +568,117 @@ ginbulkdelete(PG_FUNCTION_ARGS) {
gvs.callback_state = callback_state;
initGinState(&gvs.ginstate, index);
buffer = ReadBuffer( index, blkno );
buffer = ReadBuffer(index, blkno);
/* find leaf page */
for(;;) {
Page page = BufferGetPage( buffer );
IndexTuple itup;
for (;;)
{
Page page = BufferGetPage(buffer);
IndexTuple itup;
LockBuffer(buffer,GIN_SHARE);
LockBuffer(buffer, GIN_SHARE);
Assert( !GinPageIsData(page) );
Assert(!GinPageIsData(page));
if ( GinPageIsLeaf(page) ) {
LockBuffer(buffer,GIN_UNLOCK);
LockBuffer(buffer,GIN_EXCLUSIVE);
if (GinPageIsLeaf(page))
{
LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_EXCLUSIVE);
if ( blkno==GIN_ROOT_BLKNO && !GinPageIsLeaf(page) ) {
LockBuffer(buffer,GIN_UNLOCK);
continue; /* check it one more */
if (blkno == GIN_ROOT_BLKNO && !GinPageIsLeaf(page))
{
LockBuffer(buffer, GIN_UNLOCK);
continue; /* check it one more */
}
break;
break;
}
Assert( PageGetMaxOffsetNumber(page) >= FirstOffsetNumber );
Assert(PageGetMaxOffsetNumber(page) >= FirstOffsetNumber);
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, FirstOffsetNumber));
blkno = GinItemPointerGetBlockNumber(&(itup)->t_tid);
Assert( blkno!= InvalidBlockNumber );
Assert(blkno != InvalidBlockNumber);
LockBuffer(buffer,GIN_UNLOCK);
buffer = ReleaseAndReadBuffer( buffer, index, blkno );
LockBuffer(buffer, GIN_UNLOCK);
buffer = ReleaseAndReadBuffer(buffer, index, blkno);
}
/* right now we found leftmost page in entry's BTree */
for(;;) {
Page page = BufferGetPage( buffer );
Page resPage;
uint32 i;
for (;;)
{
Page page = BufferGetPage(buffer);
Page resPage;
uint32 i;
Assert( !GinPageIsData(page) );
Assert(!GinPageIsData(page));
resPage = ginVacuumEntryPage(&gvs, buffer, rootOfPostingTree, &nRoot);
blkno = GinPageGetOpaque( page )->rightlink;
blkno = GinPageGetOpaque(page)->rightlink;
if ( resPage ) {
if (resPage)
{
START_CRIT_SECTION();
PageRestoreTempPage( resPage, page );
xlogVacuumPage(gvs.index, buffer);
MarkBufferDirty( buffer );
PageRestoreTempPage(resPage, page);
xlogVacuumPage(gvs.index, buffer);
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
END_CRIT_SECTION();
} else {
}
else
{
UnlockReleaseBuffer(buffer);
}
vacuum_delay_point();
for(i=0; i<nRoot; i++) {
ginVacuumPostingTree( &gvs, rootOfPostingTree[i] );
for (i = 0; i < nRoot; i++)
{
ginVacuumPostingTree(&gvs, rootOfPostingTree[i]);
vacuum_delay_point();
}
if ( blkno==InvalidBlockNumber ) /*rightmost page*/
if (blkno == InvalidBlockNumber) /* rightmost page */
break;
buffer = ReadBuffer( index, blkno );
LockBuffer(buffer,GIN_EXCLUSIVE);
buffer = ReadBuffer(index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE);
}
PG_RETURN_POINTER(gvs.result);
}
Datum
ginvacuumcleanup(PG_FUNCTION_ARGS) {
Datum
ginvacuumcleanup(PG_FUNCTION_ARGS)
{
IndexVacuumInfo *info = (IndexVacuumInfo *) PG_GETARG_POINTER(0);
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(1);
Relation index = info->index;
bool needLock;
BlockNumber npages,
Relation index = info->index;
bool needLock;
BlockNumber npages,
blkno;
BlockNumber totFreePages,
nFreePages,
*freePages,
maxFreePages;
maxFreePages;
BlockNumber lastBlock = GIN_ROOT_BLKNO,
lastFilledBlock = GIN_ROOT_BLKNO;
lastFilledBlock = GIN_ROOT_BLKNO;
/* Set up all-zero stats if ginbulkdelete wasn't called */
if (stats == NULL)
stats = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
/*
* XXX we always report the heap tuple count as the number of index
* entries. This is bogus if the index is partial, but it's real hard
* to tell how many distinct heap entries are referenced by a GIN index.
* entries. This is bogus if the index is partial, but it's real hard to
* tell how many distinct heap entries are referenced by a GIN index.
*/
stats->num_index_tuples = info->num_heap_tuples;
/*
* If vacuum full, we already have exclusive lock on the index.
* Otherwise, need lock unless it's local to this backend.
* If vacuum full, we already have exclusive lock on the index. Otherwise,
* need lock unless it's local to this backend.
*/
if (info->vacuum_full)
needLock = false;
@@ -614,32 +698,38 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
totFreePages = nFreePages = 0;
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++) {
Buffer buffer;
Page page;
for (blkno = GIN_ROOT_BLKNO + 1; blkno < npages; blkno++)
{
Buffer buffer;
Page page;
vacuum_delay_point();
buffer = ReadBuffer(index, blkno);
LockBuffer(buffer, GIN_SHARE);
page = (Page) BufferGetPage(buffer);
if ( GinPageIsDeleted(page) ) {
if (GinPageIsDeleted(page))
{
if (nFreePages < maxFreePages)
freePages[nFreePages++] = blkno;
totFreePages++;
} else
}
else
lastFilledBlock = blkno;
UnlockReleaseBuffer(buffer);
}
lastBlock = npages - 1;
if (info->vacuum_full && nFreePages > 0) {
if (info->vacuum_full && nFreePages > 0)
{
/* try to truncate index */
int i;
for (i = 0; i < nFreePages; i++)
if (freePages[i] >= lastFilledBlock) {
int i;
for (i = 0; i < nFreePages; i++)
if (freePages[i] >= lastFilledBlock)
{
totFreePages = nFreePages = i;
break;
}
@@ -661,4 +751,3 @@ ginvacuumcleanup(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(stats);
}

View File

@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.4 2006/08/07 16:57:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginxlog.c,v 1.5 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@@ -17,12 +17,13 @@
#include "access/heapam.h"
#include "utils/memutils.h"
static MemoryContext opCtx; /* working memory for operations */
static MemoryContext opCtx; /* working memory for operations */
static MemoryContext topCtx;
typedef struct ginIncompleteSplit {
RelFileNode node;
BlockNumber leftBlkno;
typedef struct ginIncompleteSplit
{
RelFileNode node;
BlockNumber leftBlkno;
BlockNumber rightBlkno;
BlockNumber rootBlkno;
} ginIncompleteSplit;
@@ -30,10 +31,11 @@ typedef struct ginIncompleteSplit {
static List *incomplete_splits;
static void
pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno) {
ginIncompleteSplit *split;
pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBlkno, BlockNumber rootBlkno)
{
ginIncompleteSplit *split;
MemoryContextSwitchTo( topCtx );
MemoryContextSwitchTo(topCtx);
split = palloc(sizeof(ginIncompleteSplit));
@@ -44,17 +46,20 @@ pushIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber rightBl
incomplete_splits = lappend(incomplete_splits, split);
MemoryContextSwitchTo( opCtx );
MemoryContextSwitchTo(opCtx);
}
static void
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno) {
forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updateBlkno)
{
ListCell *l;
foreach(l, incomplete_splits) {
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
foreach(l, incomplete_splits)
{
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
if ( RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno ) {
if (RelFileNodeEquals(node, split->node) && leftBlkno == split->leftBlkno && updateBlkno == split->rightBlkno)
{
incomplete_splits = list_delete_ptr(incomplete_splits, split);
break;
}
@@ -62,7 +67,8 @@ forgetIncompleteSplit(RelFileNode node, BlockNumber leftBlkno, BlockNumber updat
}
static void
ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
{
RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
Relation reln;
Buffer buffer;
@@ -83,9 +89,10 @@ ginRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
}
static void
ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree*)XLogRecGetData(record);
ItemPointerData *items = (ItemPointerData*)(XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record)
{
ginxlogCreatePostingTree *data = (ginxlogCreatePostingTree *) XLogRecGetData(record);
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogCreatePostingTree));
Relation reln;
Buffer buffer;
Page page;
@@ -95,8 +102,8 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
GinInitBuffer(buffer, GIN_DATA|GIN_LEAF);
memcpy( GinDataPageGetData(page), items, sizeof(ItemPointerData) * data->nitem );
GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * data->nitem);
GinPageGetOpaque(page)->maxoff = data->nitem;
PageSetLSN(page, lsn);
@@ -107,8 +114,9 @@ ginRedoCreatePTree(XLogRecPtr lsn, XLogRecord *record) {
}
static void
ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
ginxlogInsert *data = (ginxlogInsert*)XLogRecGetData(record);
ginRedoInsert(XLogRecPtr lsn, XLogRecord *record)
{
ginxlogInsert *data = (ginxlogInsert *) XLogRecGetData(record);
Relation reln;
Buffer buffer;
Page page;
@@ -122,64 +130,73 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
if ( data->isData ) {
Assert( data->isDelete == FALSE );
Assert( GinPageIsData( page ) );
if (data->isData)
{
Assert(data->isDelete == FALSE);
Assert(GinPageIsData(page));
if ( data->isLeaf ) {
if (data->isLeaf)
{
OffsetNumber i;
ItemPointerData *items = (ItemPointerData*)( XLogRecGetData(record) + sizeof(ginxlogInsert) );
ItemPointerData *items = (ItemPointerData *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
Assert( GinPageIsLeaf( page ) );
Assert( data->updateBlkno == InvalidBlockNumber );
Assert(GinPageIsLeaf(page));
Assert(data->updateBlkno == InvalidBlockNumber);
for(i=0;i<data->nitem;i++)
GinDataPageAddItem( page, items+i, data->offset + i );
} else {
for (i = 0; i < data->nitem; i++)
GinDataPageAddItem(page, items + i, data->offset + i);
}
else
{
PostingItem *pitem;
Assert( !GinPageIsLeaf( page ) );
Assert(!GinPageIsLeaf(page));
if ( data->updateBlkno != InvalidBlockNumber ) {
/* update link to right page after split */
pitem = (PostingItem*)GinDataPageGetItem(page, data->offset);
PostingItemSetBlockNumber( pitem, data->updateBlkno );
if (data->updateBlkno != InvalidBlockNumber)
{
/* update link to right page after split */
pitem = (PostingItem *) GinDataPageGetItem(page, data->offset);
PostingItemSetBlockNumber(pitem, data->updateBlkno);
}
pitem = (PostingItem*)( XLogRecGetData(record) + sizeof(ginxlogInsert) );
pitem = (PostingItem *) (XLogRecGetData(record) + sizeof(ginxlogInsert));
GinDataPageAddItem( page, pitem, data->offset );
GinDataPageAddItem(page, pitem, data->offset);
if ( data->updateBlkno != InvalidBlockNumber )
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber( pitem ), data->updateBlkno);
if (data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, PostingItemGetBlockNumber(pitem), data->updateBlkno);
}
} else {
IndexTuple itup;
}
else
{
IndexTuple itup;
Assert( !GinPageIsData( page ) );
Assert(!GinPageIsData(page));
if ( data->updateBlkno != InvalidBlockNumber ) {
/* update link to right page after split */
Assert( !GinPageIsLeaf( page ) );
Assert( data->offset>=FirstOffsetNumber && data->offset<=PageGetMaxOffsetNumber(page) );
if (data->updateBlkno != InvalidBlockNumber)
{
/* update link to right page after split */
Assert(!GinPageIsLeaf(page));
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, data->offset));
ItemPointerSet(&itup->t_tid, data->updateBlkno, InvalidOffsetNumber);
}
if ( data->isDelete ) {
Assert( GinPageIsLeaf( page ) );
Assert( data->offset>=FirstOffsetNumber && data->offset<=PageGetMaxOffsetNumber(page) );
if (data->isDelete)
{
Assert(GinPageIsLeaf(page));
Assert(data->offset >= FirstOffsetNumber && data->offset <= PageGetMaxOffsetNumber(page));
PageIndexTupleDelete(page, data->offset);
}
itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogInsert) );
itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogInsert));
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), data->offset, LP_USED) == InvalidOffsetNumber )
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode );
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), data->offset, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode);
if ( !data->isLeaf && data->updateBlkno != InvalidBlockNumber )
forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber( &itup->t_tid ), data->updateBlkno);
if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, GinItemPointerGetBlockNumber(&itup->t_tid), data->updateBlkno);
}
PageSetLSN(page, lsn);
@@ -190,18 +207,21 @@ ginRedoInsert(XLogRecPtr lsn, XLogRecord *record) {
}
static void
ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
ginxlogSplit *data = (ginxlogSplit*)XLogRecGetData(record);
ginRedoSplit(XLogRecPtr lsn, XLogRecord *record)
{
ginxlogSplit *data = (ginxlogSplit *) XLogRecGetData(record);
Relation reln;
Buffer lbuffer, rbuffer;
Page lpage, rpage;
Buffer lbuffer,
rbuffer;
Page lpage,
rpage;
uint32 flags = 0;
reln = XLogOpenRelation(data->node);
if ( data->isLeaf )
if (data->isLeaf)
flags |= GIN_LEAF;
if ( data->isData )
if (data->isData)
flags |= GIN_DATA;
lbuffer = XLogReadBuffer(reln, data->lblkno, data->isRootSplit);
@@ -214,50 +234,57 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
rpage = (Page) BufferGetPage(rbuffer);
GinInitBuffer(rbuffer, flags);
GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber( rbuffer );
GinPageGetOpaque(lpage)->rightlink = BufferGetBlockNumber(rbuffer);
GinPageGetOpaque(rpage)->rightlink = data->rrlink;
if ( data->isData ) {
char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
Size sizeofitem = GinSizeOfItem(lpage);
if (data->isData)
{
char *ptr = XLogRecGetData(record) + sizeof(ginxlogSplit);
Size sizeofitem = GinSizeOfItem(lpage);
OffsetNumber i;
ItemPointer bound;
ItemPointer bound;
for(i=0;i<data->separator;i++) {
GinDataPageAddItem( lpage, ptr, InvalidOffsetNumber );
for (i = 0; i < data->separator; i++)
{
GinDataPageAddItem(lpage, ptr, InvalidOffsetNumber);
ptr += sizeofitem;
}
for(i=data->separator;i<data->nitem;i++) {
GinDataPageAddItem( rpage, ptr, InvalidOffsetNumber );
for (i = data->separator; i < data->nitem; i++)
{
GinDataPageAddItem(rpage, ptr, InvalidOffsetNumber);
ptr += sizeofitem;
}
/* set up right key */
bound = GinDataPageGetRightBound(lpage);
if ( data->isLeaf )
*bound = *(ItemPointerData*)GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff);
if (data->isLeaf)
*bound = *(ItemPointerData *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff);
else
*bound = ((PostingItem*)GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff))->key;
*bound = ((PostingItem *) GinDataPageGetItem(lpage, GinPageGetOpaque(lpage)->maxoff))->key;
bound = GinDataPageGetRightBound(rpage);
*bound = data->rightbound;
} else {
IndexTuple itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogSplit) );
}
else
{
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogSplit));
OffsetNumber i;
for(i=0;i<data->separator;i++) {
if ( PageAddItem( lpage, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode );
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) );
for (i = 0; i < data->separator; i++)
{
if (PageAddItem(lpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
}
for(i=data->separator;i<data->nitem;i++) {
if ( PageAddItem( rpage, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode );
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) );
for (i = data->separator; i < data->nitem; i++)
{
if (PageAddItem(rpage, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
}
}
@@ -269,20 +296,24 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
PageSetTLI(lpage, ThisTimeLineID);
MarkBufferDirty(lbuffer);
if ( !data->isLeaf && data->updateBlkno != InvalidBlockNumber )
if (!data->isLeaf && data->updateBlkno != InvalidBlockNumber)
forgetIncompleteSplit(data->node, data->leftChildBlkno, data->updateBlkno);
if ( data->isRootSplit ) {
Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
Page rootPage = BufferGetPage( rootBuf );
if (data->isRootSplit)
{
Buffer rootBuf = XLogReadBuffer(reln, data->rootBlkno, false);
Page rootPage = BufferGetPage(rootBuf);
GinInitBuffer( rootBuf, flags & ~GIN_LEAF );
GinInitBuffer(rootBuf, flags & ~GIN_LEAF);
if ( data->isData ) {
Assert( data->rootBlkno != GIN_ROOT_BLKNO );
if (data->isData)
{
Assert(data->rootBlkno != GIN_ROOT_BLKNO);
dataFillRoot(NULL, rootBuf, lbuffer, rbuffer);
} else {
Assert( data->rootBlkno == GIN_ROOT_BLKNO );
}
else
{
Assert(data->rootBlkno == GIN_ROOT_BLKNO);
entryFillRoot(NULL, rootBuf, lbuffer, rbuffer);
}
@@ -291,7 +322,8 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
MarkBufferDirty(rootBuf);
UnlockReleaseBuffer(rootBuf);
} else
}
else
pushIncompleteSplit(data->node, data->lblkno, data->rblkno, data->rootBlkno);
UnlockReleaseBuffer(rbuffer);
@@ -299,8 +331,9 @@ ginRedoSplit(XLogRecPtr lsn, XLogRecord *record) {
}
static void
ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
ginxlogVacuumPage *data = (ginxlogVacuumPage*)XLogRecGetData(record);
ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record)
{
ginxlogVacuumPage *data = (ginxlogVacuumPage *) XLogRecGetData(record);
Relation reln;
Buffer buffer;
Page page;
@@ -314,25 +347,30 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
if ( GinPageIsData( page ) ) {
memcpy( GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage),
GinSizeOfItem(page) * data->nitem );
if (GinPageIsData(page))
{
memcpy(GinDataPageGetData(page), XLogRecGetData(record) + sizeof(ginxlogVacuumPage),
GinSizeOfItem(page) *data->nitem);
GinPageGetOpaque(page)->maxoff = data->nitem;
} else {
OffsetNumber i, *tod;
IndexTuple itup = (IndexTuple)( XLogRecGetData(record) + sizeof(ginxlogVacuumPage) );
}
else
{
OffsetNumber i,
*tod;
IndexTuple itup = (IndexTuple) (XLogRecGetData(record) + sizeof(ginxlogVacuumPage));
tod = (OffsetNumber*)palloc( sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page) );
for(i=FirstOffsetNumber;i<=PageGetMaxOffsetNumber(page);i++)
tod[i-1] = i;
tod = (OffsetNumber *) palloc(sizeof(OffsetNumber) * PageGetMaxOffsetNumber(page));
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i++)
tod[i - 1] = i;
PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page));
for(i=0;i<data->nitem;i++) {
if ( PageAddItem( page, (Item)itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber )
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode );
itup = (IndexTuple)( ((char*)itup) + MAXALIGN( IndexTupleSize(itup) ) );
PageIndexMultiDelete(page, tod, PageGetMaxOffsetNumber(page));
for (i = 0; i < data->nitem; i++)
{
if (PageAddItem(page, (Item) itup, IndexTupleSize(itup), InvalidOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in %u/%u/%u",
data->node.spcNode, data->node.dbNode, data->node.relNode);
itup = (IndexTuple) (((char *) itup) + MAXALIGN(IndexTupleSize(itup)));
}
}
@@ -344,17 +382,19 @@ ginRedoVacuumPage(XLogRecPtr lsn, XLogRecord *record) {
}
static void
ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
ginxlogDeletePage *data = (ginxlogDeletePage*)XLogRecGetData(record);
ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record)
{
ginxlogDeletePage *data = (ginxlogDeletePage *) XLogRecGetData(record);
Relation reln;
Buffer buffer;
Page page;
reln = XLogOpenRelation(data->node);
if ( !( record->xl_info & XLR_BKP_BLOCK_1) ) {
if (!(record->xl_info & XLR_BKP_BLOCK_1))
{
buffer = XLogReadBuffer(reln, data->blkno, false);
page = BufferGetPage( buffer );
page = BufferGetPage(buffer);
Assert(GinPageIsData(page));
GinPageGetOpaque(page)->flags = GIN_DELETED;
PageSetLSN(page, lsn);
@@ -363,9 +403,10 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
UnlockReleaseBuffer(buffer);
}
if ( !( record->xl_info & XLR_BKP_BLOCK_2) ) {
if (!(record->xl_info & XLR_BKP_BLOCK_2))
{
buffer = XLogReadBuffer(reln, data->parentBlkno, false);
page = BufferGetPage( buffer );
page = BufferGetPage(buffer);
Assert(GinPageIsData(page));
Assert(!GinPageIsLeaf(page));
PageDeletePostingItem(page, data->parentOffset);
@@ -375,9 +416,10 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
UnlockReleaseBuffer(buffer);
}
if ( !( record->xl_info & XLR_BKP_BLOCK_2) && data->leftBlkno != InvalidBlockNumber ) {
if (!(record->xl_info & XLR_BKP_BLOCK_2) && data->leftBlkno != InvalidBlockNumber)
{
buffer = XLogReadBuffer(reln, data->leftBlkno, false);
page = BufferGetPage( buffer );
page = BufferGetPage(buffer);
Assert(GinPageIsData(page));
GinPageGetOpaque(page)->rightlink = data->rightLink;
PageSetLSN(page, lsn);
@@ -387,28 +429,30 @@ ginRedoDeletePage(XLogRecPtr lsn, XLogRecord *record) {
}
}
void
gin_redo(XLogRecPtr lsn, XLogRecord *record) {
uint8 info = record->xl_info & ~XLR_INFO_MASK;
void
gin_redo(XLogRecPtr lsn, XLogRecord *record)
{
uint8 info = record->xl_info & ~XLR_INFO_MASK;
topCtx = MemoryContextSwitchTo(opCtx);
switch (info) {
case XLOG_GIN_CREATE_INDEX:
switch (info)
{
case XLOG_GIN_CREATE_INDEX:
ginRedoCreateIndex(lsn, record);
break;
case XLOG_GIN_CREATE_PTREE:
case XLOG_GIN_CREATE_PTREE:
ginRedoCreatePTree(lsn, record);
break;
case XLOG_GIN_INSERT:
case XLOG_GIN_INSERT:
ginRedoInsert(lsn, record);
break;
case XLOG_GIN_SPLIT:
case XLOG_GIN_SPLIT:
ginRedoSplit(lsn, record);
break;
case XLOG_GIN_VACUUM_PAGE:
case XLOG_GIN_VACUUM_PAGE:
ginRedoVacuumPage(lsn, record);
break;
case XLOG_GIN_DELETE_PAGE:
case XLOG_GIN_DELETE_PAGE:
ginRedoDeletePage(lsn, record);
break;
default:
@@ -419,110 +463,122 @@ gin_redo(XLogRecPtr lsn, XLogRecord *record) {
}
static void
desc_node( StringInfo buf, RelFileNode node, BlockNumber blkno ) {
appendStringInfo(buf,"node: %u/%u/%u blkno: %u",
node.spcNode, node.dbNode, node.relNode, blkno);
desc_node(StringInfo buf, RelFileNode node, BlockNumber blkno)
{
appendStringInfo(buf, "node: %u/%u/%u blkno: %u",
node.spcNode, node.dbNode, node.relNode, blkno);
}
void
gin_desc(StringInfo buf, uint8 xl_info, char *rec) {
uint8 info = xl_info & ~XLR_INFO_MASK;
void
gin_desc(StringInfo buf, uint8 xl_info, char *rec)
{
uint8 info = xl_info & ~XLR_INFO_MASK;
switch (info) {
case XLOG_GIN_CREATE_INDEX:
appendStringInfo(buf,"Create index, ");
desc_node(buf, *(RelFileNode*)rec, GIN_ROOT_BLKNO );
switch (info)
{
case XLOG_GIN_CREATE_INDEX:
appendStringInfo(buf, "Create index, ");
desc_node(buf, *(RelFileNode *) rec, GIN_ROOT_BLKNO);
break;
case XLOG_GIN_CREATE_PTREE:
appendStringInfo(buf,"Create posting tree, ");
desc_node(buf, ((ginxlogCreatePostingTree*)rec)->node, ((ginxlogCreatePostingTree*)rec)->blkno );
case XLOG_GIN_CREATE_PTREE:
appendStringInfo(buf, "Create posting tree, ");
desc_node(buf, ((ginxlogCreatePostingTree *) rec)->node, ((ginxlogCreatePostingTree *) rec)->blkno);
break;
case XLOG_GIN_INSERT:
appendStringInfo(buf,"Insert item, ");
desc_node(buf, ((ginxlogInsert*)rec)->node, ((ginxlogInsert*)rec)->blkno );
appendStringInfo(buf," offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
((ginxlogInsert*)rec)->offset,
((ginxlogInsert*)rec)->nitem,
( ((ginxlogInsert*)rec)->isData ) ? 'T' : 'F',
( ((ginxlogInsert*)rec)->isLeaf ) ? 'T' : 'F',
( ((ginxlogInsert*)rec)->isDelete ) ? 'T' : 'F',
((ginxlogInsert*)rec)->updateBlkno
);
case XLOG_GIN_INSERT:
appendStringInfo(buf, "Insert item, ");
desc_node(buf, ((ginxlogInsert *) rec)->node, ((ginxlogInsert *) rec)->blkno);
appendStringInfo(buf, " offset: %u nitem: %u isdata: %c isleaf %c isdelete %c updateBlkno:%u",
((ginxlogInsert *) rec)->offset,
((ginxlogInsert *) rec)->nitem,
(((ginxlogInsert *) rec)->isData) ? 'T' : 'F',
(((ginxlogInsert *) rec)->isLeaf) ? 'T' : 'F',
(((ginxlogInsert *) rec)->isDelete) ? 'T' : 'F',
((ginxlogInsert *) rec)->updateBlkno
);
break;
case XLOG_GIN_SPLIT:
appendStringInfo(buf,"Page split, ");
desc_node(buf, ((ginxlogSplit*)rec)->node, ((ginxlogSplit*)rec)->lblkno );
appendStringInfo(buf," isrootsplit: %c", ( ((ginxlogSplit*)rec)->isRootSplit ) ? 'T' : 'F');
case XLOG_GIN_SPLIT:
appendStringInfo(buf, "Page split, ");
desc_node(buf, ((ginxlogSplit *) rec)->node, ((ginxlogSplit *) rec)->lblkno);
appendStringInfo(buf, " isrootsplit: %c", (((ginxlogSplit *) rec)->isRootSplit) ? 'T' : 'F');
break;
case XLOG_GIN_VACUUM_PAGE:
appendStringInfo(buf,"Vacuum page, ");
desc_node(buf, ((ginxlogVacuumPage*)rec)->node, ((ginxlogVacuumPage*)rec)->blkno );
case XLOG_GIN_VACUUM_PAGE:
appendStringInfo(buf, "Vacuum page, ");
desc_node(buf, ((ginxlogVacuumPage *) rec)->node, ((ginxlogVacuumPage *) rec)->blkno);
break;
case XLOG_GIN_DELETE_PAGE:
appendStringInfo(buf,"Delete page, ");
desc_node(buf, ((ginxlogDeletePage*)rec)->node, ((ginxlogDeletePage*)rec)->blkno );
case XLOG_GIN_DELETE_PAGE:
appendStringInfo(buf, "Delete page, ");
desc_node(buf, ((ginxlogDeletePage *) rec)->node, ((ginxlogDeletePage *) rec)->blkno);
break;
default:
elog(PANIC, "gin_desc: unknown op code %u", info);
}
}
void
gin_xlog_startup(void) {
void
gin_xlog_startup(void)
{
incomplete_splits = NIL;
opCtx = AllocSetContextCreate(CurrentMemoryContext,
"GIN recovery temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"GIN recovery temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
}
static void
ginContinueSplit( ginIncompleteSplit *split ) {
ginContinueSplit(ginIncompleteSplit *split)
{
GinBtreeData btree;
Relation reln;
Buffer buffer;
GinBtreeStack stack;
GinBtreeStack stack;
/* elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u", split->rootBlkno, split->leftBlkno, split->rightBlkno); */
/*
* elog(NOTICE,"ginContinueSplit root:%u l:%u r:%u", split->rootBlkno,
* split->leftBlkno, split->rightBlkno);
*/
reln = XLogOpenRelation(split->node);
buffer = XLogReadBuffer(reln, split->leftBlkno, false);
buffer = XLogReadBuffer(reln, split->leftBlkno, false);
if ( split->rootBlkno == GIN_ROOT_BLKNO ) {
prepareEntryScan( &btree, reln, (Datum)0, NULL );
btree.entry = ginPageGetLinkItup( buffer );
} else {
Page page = BufferGetPage( buffer );
if (split->rootBlkno == GIN_ROOT_BLKNO)
{
prepareEntryScan(&btree, reln, (Datum) 0, NULL);
btree.entry = ginPageGetLinkItup(buffer);
}
else
{
Page page = BufferGetPage(buffer);
prepareDataScan( &btree, reln );
prepareDataScan(&btree, reln);
PostingItemSetBlockNumber( &(btree.pitem), split->leftBlkno );
if ( GinPageIsLeaf(page) )
btree.pitem.key = *(ItemPointerData*)GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff);
PostingItemSetBlockNumber(&(btree.pitem), split->leftBlkno);
if (GinPageIsLeaf(page))
btree.pitem.key = *(ItemPointerData *) GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff);
else
btree.pitem.key = ((PostingItem*)GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff))->key;
btree.pitem.key = ((PostingItem *) GinDataPageGetItem(page,
GinPageGetOpaque(page)->maxoff))->key;
}
btree.rightblkno = split->rightBlkno;
btree.rightblkno = split->rightBlkno;
stack.blkno = split->leftBlkno;
stack.buffer = buffer;
stack.off = InvalidOffsetNumber;
stack.parent = NULL;
findParents( &btree, &stack, split->rootBlkno);
ginInsertValue( &btree, stack.parent );
findParents(&btree, &stack, split->rootBlkno);
ginInsertValue(&btree, stack.parent);
UnlockReleaseBuffer( buffer );
UnlockReleaseBuffer(buffer);
}
void
gin_xlog_cleanup(void) {
void
gin_xlog_cleanup(void)
{
ListCell *l;
MemoryContext topCtx;
@@ -531,8 +587,9 @@ gin_xlog_cleanup(void) {
foreach(l, incomplete_splits)
{
ginIncompleteSplit *split = (ginIncompleteSplit *) lfirst(l);
ginContinueSplit( split );
MemoryContextReset( opCtx );
ginContinueSplit(split);
MemoryContextReset(opCtx);
}
MemoryContextSwitchTo(topCtx);