1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

pgindent run for 8.2.

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

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.142 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.143 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -185,7 +185,7 @@ gistbuildCallback(Relation index,
/* form an index tuple and point it at the heap tuple */
itup = gistFormTuple(&buildstate->giststate, index,
values, isnull, true /* size is currently bogus */);
values, isnull, true /* size is currently bogus */ );
itup->t_tid = htup->t_self;
/*
@ -199,7 +199,7 @@ gistbuildCallback(Relation index,
* after initial build do not.
*/
gistdoinsert(index, itup,
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
&buildstate->giststate);
buildstate->indtuples += 1;
@ -236,7 +236,7 @@ gistinsert(PG_FUNCTION_ARGS)
initGISTstate(&giststate, r);
itup = gistFormTuple(&giststate, r,
values, isnull, true /* size is currently bogus */);
values, isnull, true /* size is currently bogus */ );
itup->t_tid = *ht_ctid;
gistdoinsert(r, itup, 0, &giststate);
@ -285,18 +285,17 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
/*
* if (!is_leaf) remove old key:
* This node's key has been modified, either because a child split
* occurred or because we needed to adjust our key for an insert in a
* child node. Therefore, remove the old version of this node's key.
* if (!is_leaf) remove old key: This node's key has been modified, either
* because a child split occurred or because we needed to adjust our key
* for an insert in a child node. Therefore, remove the old version of
* this node's key.
*
* for WAL replay, in the non-split case we handle this by
* setting up a one-element todelete array; in the split case, it's
* handled implicitly because the tuple vector passed to gistSplit
* won't include this tuple.
* for WAL replay, in the non-split case we handle this by setting up a
* one-element todelete array; in the split case, it's handled implicitly
* because the tuple vector passed to gistSplit won't include this tuple.
*
* XXX: If we want to change fillfactors between node and leaf,
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
* XXX: If we want to change fillfactors between node and leaf, fillfactor
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/
if (gistnospace(state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
@ -307,80 +306,88 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
int tlen;
SplitedPageLayout *dist = NULL,
*ptr;
BlockNumber rrlink = InvalidBlockNumber;
BlockNumber rrlink = InvalidBlockNumber;
GistNSN oldnsn;
is_splitted = true;
/*
* Form index tuples vector to split:
* remove old tuple if t's needed and add new tuples to vector
* Form index tuples vector to split: remove old tuple if t's needed
* and add new tuples to vector
*/
itvec = gistextractpage(state->stack->page, &tlen);
if ( !is_leaf ) {
if (!is_leaf)
{
/* on inner page we should remove old tuple */
int pos = state->stack->childoffnum - FirstOffsetNumber;
int pos = state->stack->childoffnum - FirstOffsetNumber;
tlen--;
if ( pos != tlen )
memmove( itvec+pos, itvec + pos + 1, sizeof( IndexTuple ) * (tlen-pos) );
tlen--;
if (pos != tlen)
memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
}
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
dist = gistSplit(state->r, state->stack->page, itvec, tlen, giststate);
state->itup = (IndexTuple*)palloc( sizeof(IndexTuple) * tlen);
state->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * tlen);
state->ituplen = 0;
if (state->stack->blkno != GIST_ROOT_BLKNO) {
/* if non-root split then we should not allocate new buffer,
but we must create temporary page to operate */
if (state->stack->blkno != GIST_ROOT_BLKNO)
{
/*
* if non-root split then we should not allocate new buffer, but
* we must create temporary page to operate
*/
dist->buffer = state->stack->buffer;
dist->page = PageGetTempPage( BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData) );
dist->page = PageGetTempPage(BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData));
/*clean all flags except F_LEAF */
/* clean all flags except F_LEAF */
GistPageGetOpaque(dist->page)->flags = (is_leaf) ? F_LEAF : 0;
}
/* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) {
int i;
char *data;
for (ptr = dist; ptr; ptr = ptr->next)
{
int i;
char *data;
/* get new page */
if ( ptr->buffer == InvalidBuffer ) {
ptr->buffer = gistNewBuffer( state->r );
GISTInitBuffer( ptr->buffer, (is_leaf) ? F_LEAF : 0 );
if (ptr->buffer == InvalidBuffer)
{
ptr->buffer = gistNewBuffer(state->r);
GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
ptr->page = BufferGetPage(ptr->buffer);
}
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
/* fill page, we can do it becouse all this pages are new (ie not linked in tree
or masked by temp page */
data = (char*)(ptr->list);
for(i=0;i<ptr->block.num;i++) {
if ( PageAddItem(ptr->page, (Item)data, IndexTupleSize((IndexTuple)data), i+FirstOffsetNumber, LP_USED) == InvalidOffsetNumber )
/*
* fill page, we can do it becouse all this pages are new (ie not
* linked in tree or masked by temp page
*/
data = (char *) (ptr->list);
for (i = 0; i < ptr->block.num; i++)
{
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
data += IndexTupleSize((IndexTuple)data);
data += IndexTupleSize((IndexTuple) data);
}
/* set up ItemPointer and remmeber it for parent */
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
state->itup[ state->ituplen ] = ptr->itup;
state->itup[state->ituplen] = ptr->itup;
state->ituplen++;
}
/* saves old rightlink */
if ( state->stack->blkno != GIST_ROOT_BLKNO )
rrlink = GistPageGetOpaque(dist->page)->rightlink;
if (state->stack->blkno != GIST_ROOT_BLKNO)
rrlink = GistPageGetOpaque(dist->page)->rightlink;
START_CRIT_SECTION();
/*
* must mark buffers dirty before XLogInsert, even though we'll
* still be changing their opaque fields below.
* set up right links.
* must mark buffers dirty before XLogInsert, even though we'll still
* be changing their opaque fields below. set up right links.
*/
for (ptr = dist; ptr; ptr = ptr->next)
for (ptr = dist; ptr; ptr = ptr->next)
{
MarkBufferDirty(ptr->buffer);
GistPageGetOpaque(ptr->page)->rightlink = (ptr->next) ?
@ -388,9 +395,10 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
}
/* restore splitted non-root page */
if ( state->stack->blkno != GIST_ROOT_BLKNO ) {
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
dist->page = BufferGetPage( dist->buffer );
if (state->stack->blkno != GIST_ROOT_BLKNO)
{
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
}
if (!state->r->rd_istemp)
@ -419,25 +427,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
/* set up NSN */
oldnsn = GistPageGetOpaque(dist->page)->nsn;
if ( state->stack->blkno == GIST_ROOT_BLKNO )
if (state->stack->blkno == GIST_ROOT_BLKNO)
/* if root split we should put initial value */
oldnsn = PageGetLSN(dist->page);
for (ptr = dist; ptr; ptr = ptr->next) {
for (ptr = dist; ptr; ptr = ptr->next)
{
/* only for last set oldnsn */
GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
PageGetLSN(ptr->page) : oldnsn;
}
/*
* release buffers, if it was a root split then
* release all buffers because we create all buffers
/*
* release buffers, if it was a root split then release all buffers
* because we create all buffers
*/
ptr = ( state->stack->blkno == GIST_ROOT_BLKNO ) ? dist : dist->next;
for(; ptr; ptr = ptr->next)
ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
for (; ptr; ptr = ptr->next)
UnlockReleaseBuffer(ptr->buffer);
if (state->stack->blkno == GIST_ROOT_BLKNO) {
if (state->stack->blkno == GIST_ROOT_BLKNO)
{
gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
state->needInsertComplete = false;
}
@ -470,7 +480,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
}
rdata = formUpdateRdata(state->r->rd_node, state->stack->buffer,
offs, noffs,
offs, noffs,
state->itup, state->ituplen,
&(state->key));
@ -922,16 +932,16 @@ gistSplit(Relation r,
GistSplitVector v;
GistEntryVector *entryvec;
int i;
SplitedPageLayout *res = NULL;
SplitedPageLayout *res = NULL;
/* generate the item array */
entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
entryvec->n = len + 1;
memset( v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
memset( v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
gistSplitByKey(r, page, itup, len, giststate,
&v, entryvec, 0);
memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
gistSplitByKey(r, page, itup, len, giststate,
&v, entryvec, 0);
/* form left and right vector */
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
@ -952,19 +962,20 @@ gistSplit(Relation r,
{
ROTATEDIST(res);
res->block.num = v.splitVector.spl_nright;
res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &( res->lenlist ) );
res->list = gistfillitupvec(rvectup, v.splitVector.spl_nright, &(res->lenlist));
res->itup = (v.spl_rightvalid) ? gistFormTuple(giststate, r, v.spl_rattr, v.spl_risnull, false)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
}
if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
{
SplitedPageLayout *resptr, *subres;
SplitedPageLayout *resptr,
*subres;
resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
/* install on list's tail */
while( resptr->next )
/* install on list's tail */
while (resptr->next)
resptr = resptr->next;
resptr->next = res;
@ -974,7 +985,7 @@ gistSplit(Relation r,
{
ROTATEDIST(res);
res->block.num = v.splitVector.spl_nleft;
res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &( res->lenlist ) );
res->list = gistfillitupvec(lvectup, v.splitVector.spl_nleft, &(res->lenlist));
res->itup = (v.spl_leftvalid) ? gistFormTuple(giststate, r, v.spl_lattr, v.spl_lisnull, false)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.60 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.61 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -360,8 +360,7 @@ gistindex_keytest(IndexTuple tuple,
IncrIndexProcessed();
/*
* Tuple doesn't restore after crash recovery because of incomplete
* insert
* Tuple doesn't restore after crash recovery because of incomplete insert
*/
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
return true;
@ -378,14 +377,18 @@ gistindex_keytest(IndexTuple tuple,
giststate->tupdesc,
&isNull);
if ( key->sk_flags & SK_ISNULL ) {
/* is the compared-to datum NULL? on non-leaf page it's possible
to have nulls in childs :( */
if (key->sk_flags & SK_ISNULL)
{
/*
* is the compared-to datum NULL? on non-leaf page it's possible
* to have nulls in childs :(
*/
if ( isNull || !GistPageIsLeaf(p) )
if (isNull || !GistPageIsLeaf(p))
return true;
return false;
} else if ( isNull )
}
else if (isNull)
return false;
gistdentryinit(giststate, key->sk_attno - 1, &de,

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.8 2006/09/10 00:29:34 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.9 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -112,7 +112,8 @@ gist_box_consistent(PG_FUNCTION_ARGS)
}
static void
adjustBox( BOX *b, BOX *addon ) {
adjustBox(BOX *b, BOX *addon)
{
if (b->high.x < addon->high.x)
b->high.x = addon->high.x;
if (b->low.x > addon->low.x)
@ -146,7 +147,7 @@ gist_box_union(PG_FUNCTION_ARGS)
for (i = 1; i < numranges; i++)
{
cur = DatumGetBoxP(entryvec->vector[i].key);
adjustBox( pageunion, cur );
adjustBox(pageunion, cur);
}
*sizep = sizeof(BOX);
@ -210,67 +211,79 @@ compare_KB(const void *a, const void *b)
}
static void
chooseLR( GIST_SPLITVEC *v,
OffsetNumber *list1, int nlist1, BOX *union1,
OffsetNumber *list2, int nlist2, BOX *union2 )
chooseLR(GIST_SPLITVEC *v,
OffsetNumber *list1, int nlist1, BOX *union1,
OffsetNumber *list2, int nlist2, BOX *union2)
{
bool firstToLeft = true;
bool firstToLeft = true;
if ( v->spl_ldatum_exists || v->spl_rdatum_exists ) {
if ( v->spl_ldatum_exists && v->spl_rdatum_exists ) {
BOX LRl = *union1, LRr = *union2;
BOX RLl = *union2, RLr = *union1;
double sizeLR, sizeRL;
if (v->spl_ldatum_exists || v->spl_rdatum_exists)
{
if (v->spl_ldatum_exists && v->spl_rdatum_exists)
{
BOX LRl = *union1,
LRr = *union2;
BOX RLl = *union2,
RLr = *union1;
double sizeLR,
sizeRL;
adjustBox( &LRl, DatumGetBoxP( v->spl_ldatum ) );
adjustBox( &LRr, DatumGetBoxP( v->spl_rdatum ) );
adjustBox( &RLl, DatumGetBoxP( v->spl_ldatum ) );
adjustBox( &RLr, DatumGetBoxP( v->spl_rdatum ) );
adjustBox(&LRl, DatumGetBoxP(v->spl_ldatum));
adjustBox(&LRr, DatumGetBoxP(v->spl_rdatum));
adjustBox(&RLl, DatumGetBoxP(v->spl_ldatum));
adjustBox(&RLr, DatumGetBoxP(v->spl_rdatum));
sizeLR = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)) );
sizeRL = size_box( DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)) );
sizeLR = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&LRl), BoxPGetDatum(&LRr)));
sizeRL = size_box(DirectFunctionCall2(rt_box_inter, BoxPGetDatum(&RLl), BoxPGetDatum(&RLr)));
if ( sizeLR > sizeRL )
if (sizeLR > sizeRL)
firstToLeft = false;
} else {
float p1, p2;
GISTENTRY oldUnion, addon;
}
else
{
float p1,
p2;
GISTENTRY oldUnion,
addon;
gistentryinit(oldUnion, ( v->spl_ldatum_exists ) ? v->spl_ldatum : v->spl_rdatum,
gistentryinit(oldUnion, (v->spl_ldatum_exists) ? v->spl_ldatum : v->spl_rdatum,
NULL, NULL, InvalidOffsetNumber, FALSE);
gistentryinit(addon, BoxPGetDatum(union1), NULL, NULL, InvalidOffsetNumber, FALSE);
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union1), PointerGetDatum(&p1));
gistentryinit(addon, BoxPGetDatum(union2), NULL, NULL, InvalidOffsetNumber, FALSE);
DirectFunctionCall3(gist_box_penalty, PointerGetDatum(&oldUnion), PointerGetDatum(&union2), PointerGetDatum(&p2));
if ( (v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2) )
firstToLeft = false;
if ((v->spl_ldatum_exists && p1 > p2) || (v->spl_rdatum_exists && p1 < p2))
firstToLeft = false;
}
}
if ( firstToLeft ) {
if (firstToLeft)
{
v->spl_left = list1;
v->spl_right = list2;
v->spl_nleft = nlist1;
v->spl_nright = nlist2;
if ( v->spl_ldatum_exists )
adjustBox(union1, DatumGetBoxP( v->spl_ldatum ) );
if (v->spl_ldatum_exists)
adjustBox(union1, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(union1);
if ( v->spl_rdatum_exists )
adjustBox(union2, DatumGetBoxP( v->spl_rdatum ) );
if (v->spl_rdatum_exists)
adjustBox(union2, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(union2);
} else {
}
else
{
v->spl_left = list2;
v->spl_right = list1;
v->spl_nleft = nlist2;
v->spl_nright = nlist1;
if ( v->spl_ldatum_exists )
adjustBox(union2, DatumGetBoxP( v->spl_ldatum ) );
if (v->spl_ldatum_exists)
adjustBox(union2, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(union2);
if ( v->spl_rdatum_exists )
adjustBox(union1, DatumGetBoxP( v->spl_rdatum ) );
if (v->spl_rdatum_exists)
adjustBox(union1, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(union1);
}
@ -326,7 +339,7 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
))
allisequal = false;
adjustBox( &pageunion, cur );
adjustBox(&pageunion, cur);
}
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
@ -359,12 +372,12 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
}
}
if ( v->spl_ldatum_exists )
adjustBox( unionL, DatumGetBoxP( v->spl_ldatum ) );
if (v->spl_ldatum_exists)
adjustBox(unionL, DatumGetBoxP(v->spl_ldatum));
v->spl_ldatum = BoxPGetDatum(unionL);
if ( v->spl_rdatum_exists )
adjustBox( unionR, DatumGetBoxP( v->spl_rdatum ) );
if (v->spl_rdatum_exists)
adjustBox(unionR, DatumGetBoxP(v->spl_rdatum));
v->spl_rdatum = BoxPGetDatum(unionR);
v->spl_ldatum_exists = v->spl_rdatum_exists = false;
@ -471,13 +484,13 @@ gist_box_picksplit(PG_FUNCTION_ARGS)
}
if (direction == 'x')
chooseLR( v,
listL, posL, unionL,
listR, posR, unionR );
else
chooseLR( v,
listB, posB, unionB,
listT, posT, unionT );
chooseLR(v,
listL, posL, unionL,
listR, posR, unionR);
else
chooseLR(v,
listB, posB, unionB,
listT, posT, unionT);
PG_RETURN_POINTER(v);
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.64 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -228,12 +228,12 @@ gistendscan(PG_FUNCTION_ARGS)
static void
gistfreestack(GISTSearchStack *s)
{
{
while (s != NULL)
{
GISTSearchStack *p = s->next;
pfree(s);
s = p;
}
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.3 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,12 +16,13 @@
#include "access/gist_private.h"
typedef struct {
Datum *attr;
int len;
typedef struct
{
Datum *attr;
int len;
OffsetNumber *entries;
bool *isnull;
bool *equiv;
bool *isnull;
bool *equiv;
} GistSplitUnion;
@ -29,25 +30,28 @@ typedef struct {
* Forms unions of subkeys after page split, but
* uses only tuples aren't in groups of equalent tuples
*/
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey) {
IndexTuple *cleanedItVec;
int i, cleanedLen=0;
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey)
{
IndexTuple *cleanedItVec;
int i,
cleanedLen = 0;
cleanedItVec = (IndexTuple*)palloc(sizeof(IndexTuple) * gsvp->len);
cleanedItVec = (IndexTuple *) palloc(sizeof(IndexTuple) * gsvp->len);
for(i=0;i<gsvp->len;i++) {
if ( gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
for (i = 0; i < gsvp->len; i++)
{
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
continue;
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
}
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull);
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull);
pfree( cleanedItVec );
pfree(cleanedItVec);
}
/*
@ -56,7 +60,7 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
static void
gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno)
{
GistSplitUnion gsvp;
GistSplitUnion gsvp;
gsvp.equiv = spl->spl_equiv;
@ -76,34 +80,40 @@ gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, i
}
/*
* find group in vector with equivalent value
* find group in vector with equivalent value
*/
static int
gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVector *spl, int attno)
{
int i;
GISTENTRY entry;
int len=0;
int len = 0;
/*
* attno key is always not null (see gistSplitByKey), so we may not check for
* nulls
* attno key is always not null (see gistSplitByKey), so we may not check
* for nulls
*/
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE);
for (i = 0; i < spl->splitVector.spl_nleft; i++) {
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], false);
if ( penalty == 0.0 ) {
for (i = 0; i < spl->splitVector.spl_nleft; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], false);
if (penalty == 0.0)
{
spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
len++;
}
}
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE);
for (i = 0; i < spl->splitVector.spl_nright; i++) {
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], false);
if ( penalty == 0.0 ) {
for (i = 0; i < spl->splitVector.spl_nright; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], false);
if (penalty == 0.0)
{
spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
len++;
}
@ -113,24 +123,32 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
}
static void
cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
int curlen,i;
OffsetNumber *curwpos;
cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
{
int curlen,
i;
OffsetNumber *curwpos;
curlen = *len;
curwpos = a;
for (i = 0; i < *len; i++) {
if ( equiv[ a[i] ] == FALSE ) {
for (i = 0; i < *len; i++)
{
if (equiv[a[i]] == FALSE)
{
*curwpos = a[i];
curwpos++;
} else {
}
else
{
/* corner case: we shouldn't make void array */
if ( curlen==1 ) {
equiv[ a[i] ] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */
if (curlen == 1)
{
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */
*LenEquiv -= 1;
continue;
} else
}
else
curlen--;
}
}
@ -139,33 +157,37 @@ cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
}
static void
placeOne( Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno ) {
placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno)
{
GISTENTRY identry[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
bool toLeft = true;
bool toLeft = true;
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
for(;attno<giststate->tupdesc->natts;attno++) {
float lpenalty, rpenalty;
for (; attno < giststate->tupdesc->natts; attno++)
{
float lpenalty,
rpenalty;
GISTENTRY entry;
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry+attno, isnull[ attno ]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry+attno, isnull[ attno ]);
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry + attno, isnull[attno]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
if ( lpenalty != rpenalty ) {
if ( lpenalty > rpenalty )
if (lpenalty != rpenalty)
{
if (lpenalty > rpenalty)
toLeft = false;
break;
}
}
if ( toLeft )
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = off;
if (toLeft)
v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
else
v->splitVector.spl_right[ v->splitVector.spl_nright++ ] = off;
v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
}
#define SWAPVAR( s, d, t ) \
@ -176,71 +198,83 @@ do { \
} while(0)
/*
* adjust left and right unions according to splits by previous
* split by firsts columns. This function is called only in case
* adjust left and right unions according to splits by previous
* split by firsts columns. This function is called only in case
* when pickSplit doesn't support subspplit.
*/
static void
supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR ) {
bool leaveOnLeft = true, tmpBool;
GISTENTRY entryL, entryR, entrySL, entrySR;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
{
bool leaveOnLeft = true,
tmpBool;
GISTENTRY entryL,
entryR,
entrySL,
entrySR;
if ( sv->spl_ldatum_exists && sv->spl_rdatum_exists ) {
float penalty1, penalty2;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
{
float penalty1,
penalty2;
penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) +
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
if ( penalty1 > penalty2 )
if (penalty1 > penalty2)
leaveOnLeft = false;
} else {
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1, penalty2;
}
else
{
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1,
penalty2;
/*
* there is only one previously defined union,
* so we just choose swap or not by lowest penalty
* there is only one previously defined union, so we just choose swap
* or not by lowest penalty
*/
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
if ( penalty1 < penalty2 )
leaveOnLeft = ( sv->spl_ldatum_exists ) ? true : false;
if (penalty1 < penalty2)
leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
else
leaveOnLeft = ( sv->spl_rdatum_exists ) ? true : false;
leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
}
if ( leaveOnLeft == false ) {
if (leaveOnLeft == false)
{
/*
* swap left and right
* swap left and right
*/
OffsetNumber *off, noff;
Datum datum;
OffsetNumber *off,
noff;
Datum datum;
SWAPVAR( sv->spl_left, sv->spl_right, off );
SWAPVAR( sv->spl_nleft, sv->spl_nright, noff );
SWAPVAR( sv->spl_ldatum, sv->spl_rdatum, datum );
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
SWAPVAR(sv->spl_left, sv->spl_right, off);
SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
}
if ( sv->spl_ldatum_exists )
if (sv->spl_ldatum_exists)
gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false,
&sv->spl_ldatum, &tmpBool);
&sv->spl_ldatum, &tmpBool);
if ( sv->spl_rdatum_exists )
if (sv->spl_rdatum_exists)
gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false,
&sv->spl_rdatum, &tmpBool);
&sv->spl_rdatum, &tmpBool);
sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
}
@ -251,20 +285,21 @@ supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVE
* get better split.
* Returns TRUE and v->spl_equiv = NULL if left and right unions of attno columns are the same,
* so caller may find better split
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
*/
static bool
gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v,
IndexTuple *itup, int len, GISTSTATE *giststate)
{
GIST_SPLITVEC *sv = &v->splitVector;
/*
* now let the user-defined picksplit function set up the split vector; in
* entryvec have no null value!!
*/
sv->spl_ldatum_exists = ( v->spl_lisnull[ attno ] ) ? false : true;
sv->spl_rdatum_exists = ( v->spl_risnull[ attno ] ) ? false : true;
sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
sv->spl_ldatum = v->spl_lattr[attno];
sv->spl_rdatum = v->spl_rattr[attno];
@ -278,11 +313,12 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
if( sv->spl_ldatum_exists || sv->spl_rdatum_exists ) {
elog(LOG,"PickSplit method of %d columns of index '%s' doesn't support secondary split",
attno + 1, RelationGetRelationName(r) );
if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
{
elog(LOG, "PickSplit method of %d columns of index '%s' doesn't support secondary split",
attno + 1, RelationGetRelationName(r));
supportSecondarySplit( r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno] );
supportSecondarySplit(r, giststate, attno, sv, v->spl_lattr[attno], v->spl_rattr[attno]);
}
v->spl_lattr[attno] = sv->spl_ldatum;
@ -296,53 +332,64 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
*/
v->spl_equiv = NULL;
if (giststate->tupdesc->natts > 1 && attno+1 != giststate->tupdesc->natts)
if (giststate->tupdesc->natts > 1 && attno + 1 != giststate->tupdesc->natts)
{
if ( gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum) ) {
if (gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum))
{
/*
* Left and right key's unions are equial, so
* we can get better split by following columns. Note,
* unions for attno columns are already done.
* Left and right key's unions are equial, so we can get better
* split by following columns. Note, unions for attno columns are
* already done.
*/
return true;
} else {
}
else
{
int LenEquiv;
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n+1));
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno);
/*
* if possible, we should distribute equivalent tuples
*/
if (LenEquiv == 0 ) {
* if possible, we should distribute equivalent tuples
*/
if (LenEquiv == 0)
{
gistunionsubkey(giststate, itup, v, attno + 1);
} else {
cleanupOffsets( sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv );
cleanupOffsets( sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv );
}
else
{
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
gistunionsubkey(giststate, itup, v, attno + 1);
if (LenEquiv == 1 ) {
if (LenEquiv == 1)
{
/*
* In case with one tuple we just choose left-right
* by penalty. It's simplify user-defined pickSplit
* In case with one tuple we just choose left-right by
* penalty. It's simplify user-defined pickSplit
*/
OffsetNumber toMove = InvalidOffsetNumber;
for(toMove=FirstOffsetNumber;toMove<entryvec->n;toMove++)
if ( v->spl_equiv[ toMove ] )
for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
if (v->spl_equiv[toMove])
break;
Assert( toMove < entryvec->n );
placeOne( r, giststate, v, itup[ toMove-1 ], toMove, attno+1 );
/* redo gistunionsubkey(): it will not degradate performance,
* because it's very rarely */
Assert(toMove < entryvec->n);
placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
/*
* redo gistunionsubkey(): it will not degradate
* performance, because it's very rarely
*/
v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno + 1);
return false;
} else if ( LenEquiv > 1 )
}
else if (LenEquiv > 1)
return true;
}
}
@ -352,60 +399,65 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
}
/*
* simple split page
* simple split page
*/
static void
gistSplitHalf(GIST_SPLITVEC *v, int len) {
int i;
gistSplitHalf(GIST_SPLITVEC *v, int len)
{
int i;
v->spl_nright = v->spl_nleft = 0;
v->spl_nright = v->spl_nleft = 0;
v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->spl_right= (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for(i = 1; i <= len; i++)
if ( i<len/2 )
v->spl_right[ v->spl_nright++ ] = i;
v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for (i = 1; i <= len; i++)
if (i < len / 2)
v->spl_right[v->spl_nright++] = i;
else
v->spl_left[ v->spl_nleft++ ] = i;
v->spl_left[v->spl_nleft++] = i;
}
/*
* if it was invalid tuple then we need special processing.
* We move all invalid tuples on right page.
* We move all invalid tuples on right page.
*
* if there is no place on left page, gistSplit will be called one more
* if there is no place on left page, gistSplit will be called one more
* time for left page.
*
* Normally, we never exec this code, but after crash replay it's possible
* to get 'invalid' tuples (probability is low enough)
*/
static void
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len) {
int i;
static OffsetNumber offInvTuples[ MaxOffsetNumber ];
int nOffInvTuples = 0;
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len)
{
int i;
static OffsetNumber offInvTuples[MaxOffsetNumber];
int nOffInvTuples = 0;
for (i = 1; i <= len; i++)
if ( GistTupleIsInvalid(itup[i - 1]) )
offInvTuples[ nOffInvTuples++ ] = i;
if (GistTupleIsInvalid(itup[i - 1]))
offInvTuples[nOffInvTuples++] = i;
if ( nOffInvTuples == len ) {
if (nOffInvTuples == len)
{
/* corner case, all tuples are invalid */
v->spl_rightvalid= v->spl_leftvalid = false;
gistSplitHalf( &v->splitVector, len );
} else {
GistSplitUnion gsvp;
v->spl_rightvalid = v->spl_leftvalid = false;
gistSplitHalf(&v->splitVector, len);
}
else
{
GistSplitUnion gsvp;
v->splitVector.spl_right = offInvTuples;
v->splitVector.spl_nright = nOffInvTuples;
v->spl_rightvalid = false;
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++)
if ( !GistTupleIsInvalid(itup[i - 1]) )
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
for (i = 1; i <= len; i++)
if (!GistTupleIsInvalid(itup[i - 1]))
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_leftvalid = true;
gsvp.equiv = NULL;
gsvp.attr = v->spl_lattr;
gsvp.len = v->splitVector.spl_nleft;
@ -418,52 +470,58 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
/*
* trys to split page by attno key, in a case of null
* values move its to separate page.
* values move its to separate page.
*/
void
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, int attno) {
int i;
static OffsetNumber offNullTuples[ MaxOffsetNumber ];
int nOffNullTuples = 0;
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, int attno)
{
int i;
static OffsetNumber offNullTuples[MaxOffsetNumber];
int nOffNullTuples = 0;
for (i = 1; i <= len; i++) {
Datum datum;
bool IsNull;
for (i = 1; i <= len; i++)
{
Datum datum;
bool IsNull;
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1])) {
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1]))
{
gistSplitByInvalid(giststate, v, itup, len);
return;
}
datum = index_getattr(itup[i - 1], attno+1, giststate->tupdesc, &IsNull);
datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc, &IsNull);
gistdentryinit(giststate, attno, &(entryvec->vector[i]),
datum, r, page, i,
FALSE, IsNull);
if ( IsNull )
offNullTuples[ nOffNullTuples++ ] = i;
if (IsNull)
offNullTuples[nOffNullTuples++] = i;
}
v->spl_leftvalid = v->spl_rightvalid = true;
if ( nOffNullTuples == len ) {
/*
if (nOffNullTuples == len)
{
/*
* Corner case: All keys in attno column are null, we should try to
* split by keys in next column. It all keys in all columns
* are NULL just split page half by half
* split by keys in next column. It all keys in all columns are NULL
* just split page half by half
*/
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
if ( attno+1 == r->rd_att->natts )
gistSplitHalf( &v->splitVector, len );
else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
} else if ( nOffNullTuples > 0 ) {
int j=0;
/*
* We don't want to mix NULLs and not-NULLs keys
* on one page, so move nulls to right page
if (attno + 1 == r->rd_att->natts)
gistSplitHalf(&v->splitVector, len);
else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else if (nOffNullTuples > 0)
{
int j = 0;
/*
* We don't want to mix NULLs and not-NULLs keys on one page, so move
* nulls to right page
*/
v->splitVector.spl_right = offNullTuples;
v->splitVector.spl_nright = nOffNullTuples;
@ -471,61 +529,71 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++)
if ( j<v->splitVector.spl_nright && offNullTuples[j] == i )
for (i = 1; i <= len; i++)
if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
j++;
else
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno);
} else {
}
else
{
/*
* all keys are not-null
*/
entryvec->n = len+1;
entryvec->n = len + 1;
if ( gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno+1 != r->rd_att->natts ) {
if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate) && attno + 1 != r->rd_att->natts)
{
/*
* Splitting on attno column is not optimized: there is a tuples which can be freely
* left or right page, we will try to split page by
* following columns
* Splitting on attno column is not optimized: there is a tuples
* which can be freely left or right page, we will try to split
* page by following columns
*/
if ( v->spl_equiv == NULL ) {
/* simple case: left and right keys for attno column are equial */
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
} else {
if (v->spl_equiv == NULL)
{
/*
* simple case: left and right keys for attno column are
* equial
*/
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else
{
/* we should clean up vector from already distributed tuples */
IndexTuple *newitup = (IndexTuple*)palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber*)palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0;
IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0;
GIST_SPLITVEC backupSplit = v->splitVector;
for(i=0; i<len; i++)
if ( v->spl_equiv[i+1] ) {
map[ newlen ] = i+1;
newitup[ newlen++ ] = itup[i];
for (i = 0; i < len; i++)
if (v->spl_equiv[i + 1])
{
map[newlen] = i + 1;
newitup[newlen++] = itup[i];
}
Assert( newlen>0 );
Assert(newlen > 0);
backupSplit.spl_left = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
memcpy( backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber)*v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
memcpy( backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber)*v->splitVector.spl_nright);
backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno+1);
gistSplitByKey(r, page, newitup, newlen, giststate, v, entryvec, attno + 1);
/* merge result of subsplit */
for(i=0;i<v->splitVector.spl_nleft;i++)
backupSplit.spl_left[ backupSplit.spl_nleft++ ] = map[ v->splitVector.spl_left[i]-1 ];
for(i=0;i<v->splitVector.spl_nright;i++)
backupSplit.spl_right[ backupSplit.spl_nright++ ] = map[ v->splitVector.spl_right[i]-1 ];
for (i = 0; i < v->splitVector.spl_nleft; i++)
backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
for (i = 0; i < v->splitVector.spl_nright; i++)
backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
v->splitVector = backupSplit;
/* reunion left and right datums */
gistunionsubkey(giststate, itup, v, attno);
}
}
}
}
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.19 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.20 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -22,8 +22,8 @@
* static *S used for temrorary storage (saves stack and palloc() call)
*/
static Datum attrS[INDEX_MAX_KEYS];
static bool isnullS[INDEX_MAX_KEYS];
static Datum attrS[INDEX_MAX_KEYS];
static bool isnullS[INDEX_MAX_KEYS];
/*
* Write itup vector to page, has no control of free space
@ -57,14 +57,17 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
bool
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
{
unsigned int size = freespace, deleted = 0;
unsigned int size = freespace,
deleted = 0;
int i;
for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
if ( todelete != InvalidOffsetNumber ) {
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
if (todelete != InvalidOffsetNumber)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
}
@ -72,11 +75,12 @@ gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size f
}
bool
gistfitpage(IndexTuple *itvec, int len) {
int i;
Size size=0;
gistfitpage(IndexTuple *itvec, int len)
{
int i;
Size size = 0;
for(i=0;i<len;i++)
for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
/* TODO: Consider fillfactor */
@ -119,56 +123,64 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
*/
IndexTupleData *
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
char *ptr, *ret;
int i;
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
{
char *ptr,
*ret;
int i;
*memlen = 0;
*memlen=0;
for (i = 0; i < veclen; i++)
*memlen += IndexTupleSize(vec[i]);
ptr = ret = palloc(*memlen);
for (i = 0; i < veclen; i++) {
for (i = 0; i < veclen; i++)
{
memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
ptr += IndexTupleSize(vec[i]);
}
return (IndexTupleData*)ret;
return (IndexTupleData *) ret;
}
/*
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
* invalid tuple. Resulting Datums aren't compressed.
*/
bool
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
Datum *attr, bool *isnull ) {
bool
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
Datum *attr, bool *isnull)
{
int i;
GistEntryVector *evec;
int attrsize;
int attrsize;
evec = (GistEntryVector *) palloc( ( len + 2 ) * sizeof(GISTENTRY) + GEVHDRSZ);
evec = (GistEntryVector *) palloc((len + 2) * sizeof(GISTENTRY) + GEVHDRSZ);
for (i = startkey; i < giststate->tupdesc->natts; i++) {
int j;
for (i = startkey; i < giststate->tupdesc->natts; i++)
{
int j;
evec->n = 0;
if ( !isnull[i] ) {
gistentryinit( evec->vector[evec->n], attr[i],
NULL, NULL, (OffsetNumber) 0,
FALSE);
if (!isnull[i])
{
gistentryinit(evec->vector[evec->n], attr[i],
NULL, NULL, (OffsetNumber) 0,
FALSE);
evec->n++;
}
for (j = 0; j < len; j++) {
Datum datum;
bool IsNull;
for (j = 0; j < len; j++)
{
Datum datum;
bool IsNull;
if (GistTupleIsInvalid(itvec[j]))
return FALSE; /* signals that union with invalid tuple => result is invalid */
if (GistTupleIsInvalid(itvec[j]))
return FALSE; /* signals that union with invalid tuple =>
* result is invalid */
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
if (IsNull)
@ -183,19 +195,23 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startke
}
/* If this tuple vector was all NULLs, the union is NULL */
if ( evec->n == 0 ) {
if (evec->n == 0)
{
attr[i] = (Datum) 0;
isnull[i] = TRUE;
} else {
if (evec->n == 1) {
}
else
{
if (evec->n == 1)
{
evec->n = 2;
evec->vector[1] = evec->vector[0];
}
}
/* Make union and store in attr array */
attr[i] = FunctionCall2(&giststate->unionFn[i],
PointerGetDatum(evec),
PointerGetDatum(&attrsize));
PointerGetDatum(evec),
PointerGetDatum(&attrsize));
isnull[i] = FALSE;
}
@ -213,57 +229,67 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
{
memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts);
if ( !gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS ) )
return gist_form_invalid_tuple(InvalidBlockNumber);
if (!gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS))
return gist_form_invalid_tuple(InvalidBlockNumber);
return gistFormTuple(giststate, r, attrS, isnullS, false);
return gistFormTuple(giststate, r, attrS, isnullS, false);
}
/*
/*
* makes union of two key
*/
void
gistMakeUnionKey( GISTSTATE *giststate, int attno,
GISTENTRY *entry1, bool isnull1,
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull ) {
gistMakeUnionKey(GISTSTATE *giststate, int attno,
GISTENTRY *entry1, bool isnull1,
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull)
{
int dstsize;
int dstsize;
static char storage[ 2 * sizeof(GISTENTRY) + GEVHDRSZ ];
GistEntryVector *evec = (GistEntryVector*)storage;
static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ];
GistEntryVector *evec = (GistEntryVector *) storage;
evec->n = 2;
if ( isnull1 && isnull2 ) {
if (isnull1 && isnull2)
{
*dstisnull = TRUE;
*dst = (Datum)0;
} else {
if ( isnull1 == FALSE && isnull2 == FALSE ) {
*dst = (Datum) 0;
}
else
{
if (isnull1 == FALSE && isnull2 == FALSE)
{
evec->vector[0] = *entry1;
evec->vector[1] = *entry2;
} else if ( isnull1 == FALSE ) {
}
else if (isnull1 == FALSE)
{
evec->vector[0] = *entry1;
evec->vector[1] = *entry1;
} else {
}
else
{
evec->vector[0] = *entry2;
evec->vector[1] = *entry2;
}
*dstisnull = FALSE;
*dst = FunctionCall2(&giststate->unionFn[attno],
PointerGetDatum(evec),
PointerGetDatum(&dstsize));
PointerGetDatum(evec),
PointerGetDatum(&dstsize));
}
}
bool
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) {
bool result;
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
{
bool result;
FunctionCall3(&giststate->equalFn[attno],
a, b,
PointerGetDatum(&result));
a, b,
PointerGetDatum(&result));
return result;
}
@ -309,22 +335,24 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
gistDeCompressAtt(giststate, r, addtup, NULL,
(OffsetNumber) 0, addentries, addisnull);
for(i = 0; i < r->rd_att->natts; i++) {
gistMakeUnionKey( giststate, i,
oldentries + i, oldisnull[i],
addentries + i, addisnull[i],
attrS + i, isnullS + i );
for (i = 0; i < r->rd_att->natts; i++)
{
gistMakeUnionKey(giststate, i,
oldentries + i, oldisnull[i],
addentries + i, addisnull[i],
attrS + i, isnullS + i);
if ( neednew )
if (neednew)
/* we already need new key, so we can skip check */
continue;
if ( isnullS[i] )
if (isnullS[i])
/* union of key may be NULL if and only if both keys are NULL */
continue;
if ( !addisnull[i] ) {
if ( oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i])==false )
if (!addisnull[i])
{
if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
neednew = true;
}
}
@ -363,8 +391,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
it, NULL, (OffsetNumber) 0,
identry, isnull);
Assert( maxoff >= FirstOffsetNumber );
Assert( !GistPageIsLeaf(p) );
Assert(maxoff >= FirstOffsetNumber);
Assert(!GistPageIsLeaf(p));
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
{
@ -484,7 +512,7 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
{
gistcentryinit(giststate, i, &centry[i], attdata[i],
r, NULL, (OffsetNumber) 0,
newValues,
newValues,
FALSE);
compatt[i] = centry[i].key;
}
@ -500,18 +528,19 @@ gistpenalty(GISTSTATE *giststate, int attno,
GISTENTRY *orig, bool isNullOrig,
GISTENTRY *add, bool isNullAdd)
{
float penalty = 0.0;
float penalty = 0.0;
if ( giststate->penaltyFn[attno].fn_strict==FALSE || ( isNullOrig == FALSE && isNullAdd == FALSE ) )
if (giststate->penaltyFn[attno].fn_strict == FALSE || (isNullOrig == FALSE && isNullAdd == FALSE))
FunctionCall3(&giststate->penaltyFn[attno],
PointerGetDatum(orig),
PointerGetDatum(add),
PointerGetDatum(&penalty));
else if ( isNullOrig && isNullAdd )
else if (isNullOrig && isNullAdd)
penalty = 0.0;
else
penalty = 1e10; /* try to prevent to mix null and non-null value */
penalty = 1e10; /* try to prevent to mix null and non-null
* value */
return penalty;
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.27 2006/09/21 20:31:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.28 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,19 +45,24 @@ typedef struct
} ArrayTuple;
/*
* Make union of keys on page
* Make union of keys on page
*/
static IndexTuple
PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
Page page = BufferGetPage( buffer );
PageMakeUnionKey(GistVacuum *gv, Buffer buffer)
{
Page page = BufferGetPage(buffer);
IndexTuple *vec,
tmp, res;
tmp,
res;
int veclen = 0;
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(page, &veclen);
/* we call gistunion() in temprorary context because user-defined functions called in gistunion()
may do not free all memory */
/*
* we call gistunion() in temprorary context because user-defined
* functions called in gistunion() may do not free all memory
*/
tmp = gistunion(gv->index, vec, veclen, &(gv->giststate));
MemoryContextSwitchTo(oldCtx);
@ -73,21 +78,25 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
}
static void
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
Buffer buffer;
Page page;
gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
{
Buffer buffer;
Page page;
buffer = ReadBuffer(gv->index, blkno);
LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer);
if ( !GistPageIsLeaf(page) ) {
int i;
if (!GistPageIsLeaf(page))
{
int i;
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i)) {
ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i))
{
ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
}
}
@ -103,7 +112,7 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
{
XLogRecData rdata[2];
XLogRecPtr recptr;
gistxlogPageDelete xlrec;
gistxlogPageDelete xlrec;
xlrec.node = gv->index->rd_node;
xlrec.blkno = blkno;
@ -125,31 +134,34 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
}
else
PageSetLSN(page, XLogRecPtrForTemp);
END_CRIT_SECTION();
UnlockReleaseBuffer(buffer);
}
static Page
GistPageGetCopyPage( Page page ) {
Size pageSize = PageGetPageSize( page );
Page tmppage;
static Page
GistPageGetCopyPage(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;
}
static ArrayTuple
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon) {
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon)
{
ArrayTuple res = {NULL, 0, false};
IndexTuple *vec;
SplitedPageLayout *dist = NULL,
*ptr;
int i, veclen=0;
BlockNumber blkno = BufferGetBlockNumber(buffer);
*ptr;
int i,
veclen = 0;
BlockNumber blkno = BufferGetBlockNumber(buffer);
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(tempPage, &veclen);
@ -158,67 +170,73 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
MemoryContextSwitchTo(oldCtx);
if (blkno != GIST_ROOT_BLKNO) {
if (blkno != GIST_ROOT_BLKNO)
{
/* if non-root split then we should not allocate new buffer */
dist->buffer = buffer;
dist->page = tempPage;
/* during vacuum we never split leaf page */
GistPageGetOpaque(dist->page)->flags = 0;
} else
}
else
pfree(tempPage);
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen);
res.ituplen = 0;
/* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) {
char *data;
for (ptr = dist; ptr; ptr = ptr->next)
{
char *data;
if ( ptr->buffer == InvalidBuffer ) {
ptr->buffer = gistNewBuffer( gv->index );
GISTInitBuffer( ptr->buffer, 0 );
if (ptr->buffer == InvalidBuffer)
{
ptr->buffer = gistNewBuffer(gv->index);
GISTInitBuffer(ptr->buffer, 0);
ptr->page = BufferGetPage(ptr->buffer);
}
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
data = (char*)(ptr->list);
for(i=0;i<ptr->block.num;i++) {
if ( PageAddItem(ptr->page, (Item)data, IndexTupleSize((IndexTuple)data), i+FirstOffsetNumber, LP_USED) == InvalidOffsetNumber )
data = (char *) (ptr->list);
for (i = 0; i < ptr->block.num; i++)
{
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(gv->index));
data += IndexTupleSize((IndexTuple)data);
data += IndexTupleSize((IndexTuple) data);
}
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
res.itup[ res.ituplen ] = (IndexTuple)palloc(IndexTupleSize(ptr->itup));
memcpy( res.itup[ res.ituplen ], ptr->itup, IndexTupleSize(ptr->itup) );
res.itup[res.ituplen] = (IndexTuple) palloc(IndexTupleSize(ptr->itup));
memcpy(res.itup[res.ituplen], ptr->itup, IndexTupleSize(ptr->itup));
res.ituplen++;
}
START_CRIT_SECTION();
for (ptr = dist; ptr; ptr = ptr->next) {
for (ptr = dist; ptr; ptr = ptr->next)
{
MarkBufferDirty(ptr->buffer);
GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber;
}
/* restore splitted non-root page */
if (blkno != GIST_ROOT_BLKNO) {
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
dist->page = BufferGetPage( dist->buffer );
if (blkno != GIST_ROOT_BLKNO)
{
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
}
if (!gv->index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData *rdata;
ItemPointerData key; /* set key for incomplete
* insert */
ItemPointerData key; /* set key for incomplete insert */
char *xlinfo;
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
rdata = formSplitRdata(gv->index->rd_node, blkno,
false, &key, dist);
false, &key, dist);
xlinfo = rdata->data;
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
@ -241,13 +259,12 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
{
/* we must keep the buffer pin on the head page */
if (BufferGetBlockNumber(ptr->buffer) != blkno)
UnlockReleaseBuffer( ptr->buffer );
UnlockReleaseBuffer(ptr->buffer);
}
if (blkno == GIST_ROOT_BLKNO)
{
ItemPointerData key; /* set key for incomplete
* insert */
ItemPointerData key; /* set key for incomplete insert */
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
@ -266,7 +283,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
{
ArrayTuple res = {NULL, 0, false};
Buffer buffer;
Page page, tempPage = NULL;
Page page,
tempPage = NULL;
OffsetNumber i,
maxoff;
ItemId iid;
@ -278,7 +296,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
*addon = NULL;
bool needwrite = false;
OffsetNumber offToDelete[MaxOffsetNumber];
BlockNumber blkToDelete[MaxOffsetNumber];
BlockNumber blkToDelete[MaxOffsetNumber];
ItemPointerData *completed = NULL;
int ncompleted = 0,
lencompleted = 16;
@ -322,7 +340,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen || chldtuple.emptypage)
{
/* update tuple or/and inserts new */
if ( chldtuple.emptypage )
if (chldtuple.emptypage)
blkToDelete[nBlkToDelete++] = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
offToDelete[nOffToDelete++] = i;
PageIndexTupleDelete(tempPage, i);
@ -333,7 +351,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen)
{
Assert( chldtuple.emptypage == false );
Assert(chldtuple.emptypage == false);
while (curlenaddon + chldtuple.ituplen >= lenaddon)
{
lenaddon *= 2;
@ -367,56 +385,63 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
}
}
}
Assert( maxoff == PageGetMaxOffsetNumber(tempPage) );
Assert(maxoff == PageGetMaxOffsetNumber(tempPage));
if (curlenaddon)
{
/* insert updated tuples */
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
{
/* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
tempPage=NULL; /* vacuumSplitPage() free tempPage */
needwrite = needunion = false; /* gistSplit already forms unions and writes pages */
} else
tempPage = NULL; /* vacuumSplitPage() free tempPage */
needwrite = needunion = false; /* gistSplit already forms
* unions and writes pages */
}
else
/* enough free space */
gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
}
}
/*
* If page is empty, we should remove pointer to it before
* deleting page (except root)
/*
* If page is empty, we should remove pointer to it before deleting page
* (except root)
*/
if ( blkno != GIST_ROOT_BLKNO && ( PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage)) ) ) {
if (blkno != GIST_ROOT_BLKNO && (PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage))))
{
/*
* New version of page is empty, so leave it unchanged,
* upper call will mark our page as deleted.
* In case of page split we never will be here...
* New version of page is empty, so leave it unchanged, upper call
* will mark our page as deleted. In case of page split we never will
* be here...
*
* If page was empty it can't become non-empty during processing
* If page was empty it can't become non-empty during processing
*/
res.emptypage = true;
UnlockReleaseBuffer(buffer);
} else {
}
else
{
/* write page and remove its childs if it need */
START_CRIT_SECTION();
if ( tempPage && needwrite ) {
if (tempPage && needwrite)
{
PageRestoreTempPage(tempPage, page);
tempPage = NULL;
}
/* Empty index */
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO )
/* Empty index */
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO)
{
needwrite = true;
GistPageSetLeaf(page);
}
if (needwrite)
{
MarkBufferDirty(buffer);
@ -446,7 +471,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
END_CRIT_SECTION();
if ( needunion && !PageIsEmpty(page) )
if (needunion && !PageIsEmpty(page))
{
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
res.ituplen = 1;
@ -456,7 +481,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
UnlockReleaseBuffer(buffer);
/* delete empty children, now we havn't any links to pointed subtrees */
for(i=0;i<nBlkToDelete;i++)
for (i = 0; i < nBlkToDelete; i++)
gistDeleteSubtree(gv, blkToDelete[i]);
if (ncompleted && !gv->index->rd_istemp)
@ -506,9 +531,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
/* use heap's tuple count */
Assert(info->num_heap_tuples >= 0);
stats->std.num_index_tuples = info->num_heap_tuples;
/*
* XXX the above is wrong if index is partial. Would it be OK to
* just return NULL, or is there work we must do below?
* XXX the above is wrong if index is partial. Would it be OK to just
* return NULL, or is there work we must do below?
*/
}
@ -545,8 +571,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
RelationGetRelationName(rel))));
/*
* 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;
@ -725,7 +751,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
if (callback(&(idxtuple->t_tid), callback_state))
{
todelete[ntodelete] = i-ntodelete;
todelete[ntodelete] = i - ntodelete;
ntodelete++;
stats->std.tuples_removed += 1;
}
@ -739,7 +765,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
MarkBufferDirty(buffer);
for(i=0;i<ntodelete;i++)
for (i = 0; i < ntodelete; i++)
PageIndexTupleDelete(page, todelete[i]);
GistMarkTuplesDeleted(page);
@ -750,7 +776,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
gistxlogPageUpdate *xlinfo;
rdata = formUpdateRdata(rel->rd_node, buffer,
todelete, ntodelete,
todelete, ntodelete,
NULL, 0,
NULL);
xlinfo = (gistxlogPageUpdate *) rdata->next->data;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.23 2006/08/07 16:57:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.24 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -55,11 +55,11 @@ typedef struct gistIncompleteInsert
static MemoryContext opCtx; /* working memory for operations */
static MemoryContext insertCtx; /* holds incomplete_inserts list */
static MemoryContext insertCtx; /* holds incomplete_inserts list */
static List *incomplete_inserts;
#define ItemPointerEQ(a, b) \
#define ItemPointerEQ(a, b) \
( ItemPointerGetOffsetNumber(a) == ItemPointerGetOffsetNumber(b) && \
ItemPointerGetBlockNumber (a) == ItemPointerGetBlockNumber(b) )
@ -72,8 +72,9 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
MemoryContext oldCxt;
gistIncompleteInsert *ninsert;
if ( !ItemPointerIsValid(&key) )
/*
if (!ItemPointerIsValid(&key))
/*
* if key is null then we should not store insertion as incomplete,
* because it's a vacuum operation..
*/
@ -108,8 +109,8 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
/*
* Stick the new incomplete insert onto the front of the list, not the
* back. This is so that gist_xlog_cleanup will process incompletions
* in last-in-first-out order.
* back. This is so that gist_xlog_cleanup will process incompletions in
* last-in-first-out order.
*/
incomplete_inserts = lcons(ninsert, incomplete_inserts);
@ -121,10 +122,10 @@ forgetIncompleteInsert(RelFileNode node, ItemPointerData key)
{
ListCell *l;
if ( !ItemPointerIsValid(&key) )
if (!ItemPointerIsValid(&key))
return;
if (incomplete_inserts==NIL)
if (incomplete_inserts == NIL)
return;
foreach(l, incomplete_inserts)
@ -241,9 +242,12 @@ gistRedoPageUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0)
GistClearTuplesDeleted(page);
if ( !GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO )
/* all links on non-leaf root page was deleted by vacuum full,
so root page becomes a leaf */
if (!GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO)
/*
* all links on non-leaf root page was deleted by vacuum full, so root
* page becomes a leaf
*/
GistPageSetLeaf(page);
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
@ -432,11 +436,11 @@ static void
out_target(StringInfo buf, RelFileNode node, ItemPointerData key)
{
appendStringInfo(buf, "rel %u/%u/%u",
node.spcNode, node.dbNode, node.relNode);
if ( ItemPointerIsValid( &key ) )
node.spcNode, node.dbNode, node.relNode);
if (ItemPointerIsValid(&key))
appendStringInfo(buf, "; tid %u/%u",
ItemPointerGetBlockNumber(&key),
ItemPointerGetOffsetNumber(&key));
ItemPointerGetBlockNumber(&key),
ItemPointerGetOffsetNumber(&key));
}
static void
@ -450,8 +454,8 @@ static void
out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
{
appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno);
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno);
}
static void
@ -460,7 +464,7 @@ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
appendStringInfo(buf, "page_split: ");
out_target(buf, xlrec->node, xlrec->key);
appendStringInfo(buf, "; block number %u splits to %d pages",
xlrec->origblkno, xlrec->npage);
xlrec->origblkno, xlrec->npage);
}
void
@ -486,15 +490,15 @@ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
break;
case XLOG_GIST_CREATE_INDEX:
appendStringInfo(buf, "create_index: rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
case XLOG_GIST_INSERT_COMPLETE:
appendStringInfo(buf, "complete_insert: rel %u/%u/%u",
((gistxlogInsertComplete *) rec)->node.spcNode,
((gistxlogInsertComplete *) rec)->node.dbNode,
((gistxlogInsertComplete *) rec)->node.relNode);
((gistxlogInsertComplete *) rec)->node.spcNode,
((gistxlogInsertComplete *) rec)->node.dbNode,
((gistxlogInsertComplete *) rec)->node.relNode);
break;
default:
appendStringInfo(buf, "unknown gist op code %u", info);
@ -547,22 +551,25 @@ gistxlogFindPath(Relation index, gistIncompleteInsert *insert)
elog(ERROR, "lost parent for block %u", insert->origblkno);
}
static SplitedPageLayout*
gistMakePageLayout(Buffer *buffers, int nbuffers) {
SplitedPageLayout *res=NULL, *resptr;
static SplitedPageLayout *
gistMakePageLayout(Buffer *buffers, int nbuffers)
{
SplitedPageLayout *res = NULL,
*resptr;
while( nbuffers-- > 0 ) {
Page page = BufferGetPage( buffers[ nbuffers ] );
IndexTuple* vec;
int veclen;
while (nbuffers-- > 0)
{
Page page = BufferGetPage(buffers[nbuffers]);
IndexTuple *vec;
int veclen;
resptr = (SplitedPageLayout*)palloc0( sizeof(SplitedPageLayout) );
resptr = (SplitedPageLayout *) palloc0(sizeof(SplitedPageLayout));
resptr->block.blkno = BufferGetBlockNumber( buffers[ nbuffers ] );
resptr->block.num = PageGetMaxOffsetNumber( page );
resptr->block.blkno = BufferGetBlockNumber(buffers[nbuffers]);
resptr->block.num = PageGetMaxOffsetNumber(page);
vec = gistextractpage( page, &veclen );
resptr->list = gistfillitupvec( vec, veclen, &(resptr->lenlist) );
vec = gistextractpage(page, &veclen);
resptr->list = gistfillitupvec(vec, veclen, &(resptr->lenlist));
resptr->next = res;
res = resptr;
@ -580,7 +587,7 @@ gistMakePageLayout(Buffer *buffers, int nbuffers) {
* Note that we assume the index is now in a valid state, except for the
* unfinished insertion. In particular it's safe to invoke gistFindPath();
* there shouldn't be any garbage pages for it to run into.
*
*
* To complete insert we can't use basic insertion algorithm because
* during insertion we can't call user-defined support functions of opclass.
* So, we insert 'invalid' tuples without real key and do it by separate algorithm.
@ -607,7 +614,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
itup[i] = gist_form_invalid_tuple(insert->blkno[i]);
/*
* any insertion of itup[] should make LOG message about
* any insertion of itup[] should make LOG message about
*/
if (insert->origblkno == GIST_ROOT_BLKNO)
@ -626,7 +633,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
Buffer *buffers;
Page *pages;
int numbuffer;
OffsetNumber *todelete;
OffsetNumber *todelete;
/* construct path */
gistxlogFindPath(index, insert);
@ -642,21 +649,22 @@ gistContinueInsert(gistIncompleteInsert *insert)
int j,
k,
pituplen = 0;
XLogRecData *rdata;
XLogRecPtr recptr;
Buffer tempbuffer = InvalidBuffer;
int ntodelete = 0;
XLogRecData *rdata;
XLogRecPtr recptr;
Buffer tempbuffer = InvalidBuffer;
int ntodelete = 0;
numbuffer = 1;
buffers[0] = ReadBuffer(index, insert->path[i]);
LockBuffer(buffers[0], GIST_EXCLUSIVE);
/*
* we check buffer, because we restored page earlier
*/
gistcheckpage(index, buffers[0]);
pages[0] = BufferGetPage(buffers[0]);
Assert( !GistPageIsLeaf(pages[0]) );
Assert(!GistPageIsLeaf(pages[0]));
pituplen = PageGetMaxOffsetNumber(pages[0]);
@ -678,12 +686,12 @@ gistContinueInsert(gistIncompleteInsert *insert)
}
}
if ( ntodelete == 0 )
elog(PANIC,"gistContinueInsert: can't find pointer to page(s)");
if (ntodelete == 0)
elog(PANIC, "gistContinueInsert: can't find pointer to page(s)");
/*
* we check space with subtraction only first tuple to delete, hope,
* that wiil be enough space....
* we check space with subtraction only first tuple to delete,
* hope, that wiil be enough space....
*/
if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
@ -699,7 +707,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
{
Buffer tmp;
Buffer tmp;
/*
* we split root, just copy content from root to new page
@ -713,44 +721,48 @@ gistContinueInsert(gistIncompleteInsert *insert)
/* fill new page, root will be changed later */
tempbuffer = ReadBuffer(index, P_NEW);
LockBuffer(tempbuffer, GIST_EXCLUSIVE);
memcpy( BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer) );
memcpy(BufferGetPage(tempbuffer), pages[0], BufferGetPageSize(tempbuffer));
/* swap buffers[0] (was root) and temp buffer */
tmp = buffers[0];
buffers[0] = tempbuffer;
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO, it is still unchanged */
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO,
* it is still unchanged */
pages[0] = BufferGetPage(buffers[0]);
}
START_CRIT_SECTION();
for(j=0;j<ntodelete;j++)
for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]);
rdata = formSplitRdata(index->rd_node, insert->path[i],
false, &(insert->key),
gistMakePageLayout( buffers, numbuffer ) );
false, &(insert->key),
gistMakePageLayout(buffers, numbuffer));
} else {
}
else
{
START_CRIT_SECTION();
for(j=0;j<ntodelete;j++)
for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]);
gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber);
rdata = formUpdateRdata(index->rd_node, buffers[0],
todelete, ntodelete,
itup, lenitup, &(insert->key));
rdata = formUpdateRdata(index->rd_node, buffers[0],
todelete, ntodelete,
itup, lenitup, &(insert->key));
}
/*
* use insert->key as mark for completion of insert (form*Rdata() above)
* for following possible replays
/*
* use insert->key as mark for completion of insert (form*Rdata()
* above) for following possible replays
*/
/* write pages, we should mark it dirty befor XLogInsert() */
for (j = 0; j < numbuffer; j++) {
for (j = 0; j < numbuffer; j++)
{
GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
MarkBufferDirty(buffers[j]);
}
@ -764,12 +776,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
END_CRIT_SECTION();
lenitup = numbuffer;
for (j = 0; j < numbuffer; j++) {
for (j = 0; j < numbuffer; j++)
{
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
UnlockReleaseBuffer(buffers[j]);
}
if ( tempbuffer != InvalidBuffer ) {
if (tempbuffer != InvalidBuffer)
{
/*
* it was a root split, so fill it by new values
*/
@ -780,9 +794,9 @@ gistContinueInsert(gistIncompleteInsert *insert)
}
ereport(LOG,
(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
(errmsg("index %u/%u/%u needs VACUUM FULL or REINDEX to finish crash recovery",
insert->node.spcNode, insert->node.dbNode, insert->node.relNode),
errdetail("Incomplete insertion detected during crash replay.")));
errdetail("Incomplete insertion detected during crash replay.")));
}
void