diff options
Diffstat (limited to 'src/backend/access/gin')
-rw-r--r-- | src/backend/access/gin/ginarrayproc.c | 67 | ||||
-rw-r--r-- | src/backend/access/gin/ginbtree.c | 315 | ||||
-rw-r--r-- | src/backend/access/gin/ginbulk.c | 240 | ||||
-rw-r--r-- | src/backend/access/gin/gindatapage.c | 506 | ||||
-rw-r--r-- | src/backend/access/gin/ginentrypage.c | 419 | ||||
-rw-r--r-- | src/backend/access/gin/ginget.c | 448 | ||||
-rw-r--r-- | src/backend/access/gin/gininsert.c | 249 | ||||
-rw-r--r-- | src/backend/access/gin/ginscan.c | 235 | ||||
-rw-r--r-- | src/backend/access/gin/ginutil.c | 160 | ||||
-rw-r--r-- | src/backend/access/gin/ginvacuum.c | 591 | ||||
-rw-r--r-- | src/backend/access/gin/ginxlog.c | 453 |
11 files changed, 2091 insertions, 1592 deletions
diff --git a/src/backend/access/gin/ginarrayproc.c b/src/backend/access/gin/ginarrayproc.c index 911cf629832..33a8b44a14d 100644 --- a/src/backend/access/gin/ginarrayproc.c +++ b/src/backend/access/gin/ginarrayproc.c @@ -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; } diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c index bc3e02973f9..fc44a5a0c7f 100644 --- a/src/backend/access/gin/ginbtree.c +++ b/src/backend/access/gin/ginbtree.c @@ -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) { - - Page page; - Buffer buffer; - BlockNumber blkno, leftmostBlkno; +findParents(GinBtree btree, GinBtreeStack *stack, + BlockNumber rootBlkno) +{ + + 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 { + } + else + { /* split non-root page */ - ((ginxlogSplit*)(rdata->data))->isRootSplit = FALSE; - ((ginxlogSplit*)(rdata->data))->rrlink = savedRightLink; + ((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE; + ((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink; - lpage = BufferGetPage( stack->buffer ); - rpage = BufferGetPage( rbuffer ); + 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; } } - - diff --git a/src/backend/access/gin/ginbulk.c b/src/backend/access/gin/ginbulk.c index 5bcd91af141..3db9e332a75 100644 --- a/src/backend/access/gin/ginbulk.c +++ b/src/backend/access/gin/ginbulk.c @@ -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; - - while( ea ) { +ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) +{ + EntryAccumulator *ea = accum->entries, + *pea = NULL; + int res = 0; + uint32 depth = 1; + + 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; - - 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 ); +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]); + + 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; } - diff --git a/src/backend/access/gin/gindatapage.c b/src/backend/access/gin/gindatapage.c index 5789dc18f9b..94b07f3ed91 100644 --- a/src/backend/access/gin/gindatapage.c +++ b/src/backend/access/gin/gindatapage.c @@ -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 ); - - Assert( !GinPageIsLeaf(page) ); - Assert( GinPageIsData(page) ); - - if ( btree->fullScan ) { +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)); + + 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; - - Assert( GinPageIsLeaf(page) ); - Assert( GinPageIsData(page) ); - - if ( btree->fullScan ) { +dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) +{ + Page page = BufferGetPage(stack->buffer); + OffsetNumber low, + high; + int result; + + Assert(GinPageIsLeaf(page)); + Assert(GinPageIsData(page)); + + 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; - - 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) ); + char *ptr; + + 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); - - 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) ) +dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off) +{ + Page page = BufferGetPage(buf); + + 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)) 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; - - 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; + 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; 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; } - diff --git a/src/backend/access/gin/ginentrypage.c b/src/backend/access/gin/ginentrypage.c index 6e3cc75ce08..129c9550969 100644 --- a/src/backend/access/gin/ginentrypage.c +++ b/src/backend/access/gin/ginentrypage.c @@ -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 ); - - Assert( !GinPageIsLeaf(page) ); - Assert( !GinPageIsData(page) ); - - if ( btree->fullScan ) { +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)); + + 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)); - if ( btree->isDelete ) { - IndexTuple itup = (IndexTuple)PageGetItem(page, PageGetItemId(page, off)); - itupsz = MAXALIGN( IndexTupleSize( itup ) ) + sizeof(ItemIdData); + 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; - - if ( lsize > totalsize/2 ) { - if ( separator==InvalidOffsetNumber ) - separator = i-1; + for (i = FirstOffsetNumber; i <= maxoff; i++) + { + itup = (IndexTuple) ptr; + + 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); - - itup = getRightMostTuple( page ); - if ( GinPageIsLeaf(page) && !GinIsPostingTree(itup) ) { - nitup = (IndexTuple)palloc( MAXALIGN(GinGetOrigSizePosting(itup)) ); - memcpy( nitup, itup, GinGetOrigSizePosting(itup) ); +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)); 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; } - diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index d40612f3ada..090bbe4f256 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -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 ); - - if ( (entry->offset=findItemInPage(page , &entry->curItem, FirstOffsetNumber))!=InvalidOffsetNumber ) + 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) 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; - - 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 ); +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); 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; - - if ( key->isFinished ) +keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx, GinScanKey key) +{ + uint32 i; + GinScanEntry entry; + bool res; + MemoryContext oldCtx; + + 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; - - 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 ) +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; + + 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; + + for (;;) + { + int cmp = compareItemPointers(item, &key->curItem); - if ( cmp == 0 ) + 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); } diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 60107a57709..e4f87e720da 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -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)); - - if ( res ) { +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) + { /* 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); } - diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index 2093f1ce8a6..b69f409e1cd 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -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 ); - - entryValues = (Datum*)DatumGetPointer( - FunctionCall3( - &so->ginstate.extractQueryFn, - scankey[i].sk_argument, - PointerGetDatum( &nEntryValues ), - UInt16GetDatum(scankey[i].sk_strategy) - ) - ); - if ( entryValues==NULL || nEntryValues == 0 ) + 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) /* 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(); } diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 17eca3d239f..e64137a1062 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -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; } diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index 31e5f647f07..e0718862c51 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -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); - for( i=FirstOffsetNumber ; i <= GinPageGetOpaque(page)->maxoff ; i++ ) { - PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page, i); - if ( ginVacuumPostingTreeLeaves( gvs, PostingItemGetBlockNumber(pitem), FALSE, NULL ) ) + 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; - - LockBuffer( dBuffer, GIN_EXCLUSIVE ); - if ( !isParentRoot ) /* parent is already locked by LockBufferForCleanup() */ - LockBuffer( pBuffer, GIN_EXCLUSIVE ); +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); 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; - - if ( isRoot ) { +ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDeleteStack *parent, OffsetNumber myoff) +{ + DataPageDeleteStack *me; + Buffer buffer; + Page page; + bool meDelete = FALSE; + + 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; - - if ( ginVacuumPostingTreeLeaves(gvs, rootBlkno, TRUE, &rootBuffer)==FALSE ) { - Assert( rootBuffer == InvalidBuffer ); +ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno) +{ + Buffer rootBuffer = InvalidBuffer; + DataPageDeleteStack root, + *ptr, + *tmp; + + 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); - if ( newN > 0 ) { - Size pos = ((char*)GinGetPosting(itup)) - ((char*)origpage); - memcpy( tmppage+pos, cleaned, sizeof(ItemPointerData)*newN ); + 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); } - diff --git a/src/backend/access/gin/ginxlog.c b/src/backend/access/gin/ginxlog.c index 265e7de70c4..788f290b843 100644 --- a/src/backend/access/gin/ginxlog.c +++ b/src/backend/access/gin/ginxlog.c @@ -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) ); - - 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) ) ); + } + 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; + + 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); |