mirror of
https://github.com/postgres/postgres.git
synced 2025-06-06 00:02:36 -04:00
pgindent new GIST index code, per request from Tom.
This commit is contained in:
parent
08817bdb76
commit
b3364fc81b
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.125 2005/06/30 17:52:13 teodor Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.126 2005/09/22 20:44:36 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -92,8 +92,8 @@ gistbuild(PG_FUNCTION_ARGS)
|
|||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We expect to be called exactly once for any index relation. If
|
* We expect to be called exactly once for any index relation. If that's
|
||||||
* that's not the case, big trouble's what we have.
|
* not the case, big trouble's what we have.
|
||||||
*/
|
*/
|
||||||
if (RelationGetNumberOfBlocks(index) != 0)
|
if (RelationGetNumberOfBlocks(index) != 0)
|
||||||
elog(ERROR, "index \"%s\" already contains data",
|
elog(ERROR, "index \"%s\" already contains data",
|
||||||
@ -105,7 +105,8 @@ gistbuild(PG_FUNCTION_ARGS)
|
|||||||
/* initialize the root page */
|
/* initialize the root page */
|
||||||
buffer = gistNewBuffer(index);
|
buffer = gistNewBuffer(index);
|
||||||
GISTInitBuffer(buffer, F_LEAF);
|
GISTInitBuffer(buffer, F_LEAF);
|
||||||
if ( !index->rd_istemp ) {
|
if (!index->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
XLogRecData rdata;
|
XLogRecData rdata;
|
||||||
Page page;
|
Page page;
|
||||||
@ -124,7 +125,8 @@ gistbuild(PG_FUNCTION_ARGS)
|
|||||||
PageSetTLI(page, ThisTimeLineID);
|
PageSetTLI(page, ThisTimeLineID);
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
PageSetLSN(BufferGetPage(buffer), XLogRecPtrForTemp);
|
PageSetLSN(BufferGetPage(buffer), XLogRecPtrForTemp);
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
@ -132,9 +134,10 @@ gistbuild(PG_FUNCTION_ARGS)
|
|||||||
/* build the index */
|
/* build the index */
|
||||||
buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
|
buildstate.numindexattrs = indexInfo->ii_NumIndexAttrs;
|
||||||
buildstate.indtuples = 0;
|
buildstate.indtuples = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a temporary memory context that is reset once for each
|
* create a temporary memory context that is reset once for each tuple
|
||||||
* tuple inserted into the index
|
* inserted into the index
|
||||||
*/
|
*/
|
||||||
buildstate.tmpCtx = createTempGistContext();
|
buildstate.tmpCtx = createTempGistContext();
|
||||||
|
|
||||||
@ -195,11 +198,11 @@ gistbuildCallback(Relation index,
|
|||||||
itup->t_tid = htup->t_self;
|
itup->t_tid = htup->t_self;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since we already have the index relation locked, we call
|
* Since we already have the index relation locked, we call gistdoinsert
|
||||||
* gistdoinsert directly. Normal access method calls dispatch through
|
* directly. Normal access method calls dispatch through gistinsert,
|
||||||
* gistinsert, which locks the relation for write. This is the right
|
* which locks the relation for write. This is the right thing to do if
|
||||||
* thing to do if you're inserting single tups, but not when you're
|
* you're inserting single tups, but not when you're initializing the
|
||||||
* initializing the whole index at once.
|
* whole index at once.
|
||||||
*/
|
*/
|
||||||
gistdoinsert(index, itup, &buildstate->giststate);
|
gistdoinsert(index, itup, &buildstate->giststate);
|
||||||
|
|
||||||
@ -221,6 +224,7 @@ gistinsert(PG_FUNCTION_ARGS)
|
|||||||
Datum *values = (Datum *) PG_GETARG_POINTER(1);
|
Datum *values = (Datum *) PG_GETARG_POINTER(1);
|
||||||
bool *isnull = (bool *) PG_GETARG_POINTER(2);
|
bool *isnull = (bool *) PG_GETARG_POINTER(2);
|
||||||
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
|
||||||
|
|
||||||
#ifdef NOT_USED
|
#ifdef NOT_USED
|
||||||
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
|
||||||
bool checkUnique = PG_GETARG_BOOL(5);
|
bool checkUnique = PG_GETARG_BOOL(5);
|
||||||
@ -296,17 +300,18 @@ gistdoinsert(Relation r, IndexTuple itup, GISTSTATE *giststate)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
|
||||||
|
{
|
||||||
bool is_splitted = false;
|
bool is_splitted = false;
|
||||||
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
|
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
|
||||||
|
|
||||||
|
|
||||||
if (!is_leaf)
|
if (!is_leaf)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This node's key has been modified, either because a child
|
* This node's key has been modified, either because a child split
|
||||||
* split occurred or because we needed to adjust our key for
|
* occurred or because we needed to adjust our key for an insert in a
|
||||||
* an insert in a child node. Therefore, remove the old
|
* child node. Therefore, remove the old version of this node's key.
|
||||||
* version of this node's key.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);
|
PageIndexTupleDelete(state->stack->page, state->stack->childoffnum);
|
||||||
@ -316,8 +321,10 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
/* no space for insertion */
|
/* no space for insertion */
|
||||||
IndexTuple *itvec,
|
IndexTuple *itvec,
|
||||||
*newitup;
|
*newitup;
|
||||||
int tlen,olen;
|
int tlen,
|
||||||
SplitedPageLayout *dist=NULL, *ptr;
|
olen;
|
||||||
|
SplitedPageLayout *dist = NULL,
|
||||||
|
*ptr;
|
||||||
|
|
||||||
is_splitted = true;
|
is_splitted = true;
|
||||||
itvec = gistextractbuffer(state->stack->buffer, &tlen);
|
itvec = gistextractbuffer(state->stack->buffer, &tlen);
|
||||||
@ -325,7 +332,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
|
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
|
||||||
newitup = gistSplit(state->r, state->stack->buffer, itvec, &tlen, &dist, giststate);
|
newitup = gistSplit(state->r, state->stack->buffer, itvec, &tlen, &dist, giststate);
|
||||||
|
|
||||||
if ( !state->r->rd_istemp ) {
|
if (!state->r->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
|
|
||||||
@ -336,16 +344,20 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
|
|
||||||
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
PageSetLSN(BufferGetPage(ptr->buffer), recptr);
|
PageSetLSN(BufferGetPage(ptr->buffer), recptr);
|
||||||
PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);
|
PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
|
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
@ -354,12 +366,15 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
state->itup = newitup;
|
state->itup = newitup;
|
||||||
state->ituplen = tlen; /* now tlen >= 2 */
|
state->ituplen = tlen; /* now tlen >= 2 */
|
||||||
|
|
||||||
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));
|
gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
|
||||||
state->needInsertComplete = false;
|
state->needInsertComplete = false;
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
Page page = (Page) BufferGetPage(ptr->buffer);
|
Page page = (Page) BufferGetPage(ptr->buffer);
|
||||||
|
|
||||||
GistPageGetOpaque(page)->rightlink = (ptr->next) ?
|
GistPageGetOpaque(page)->rightlink = (ptr->next) ?
|
||||||
ptr->next->block.blkno : InvalidBlockNumber;
|
ptr->next->block.blkno : InvalidBlockNumber;
|
||||||
GistPageGetOpaque(page)->nsn = PageGetLSN(page);
|
GistPageGetOpaque(page)->nsn = PageGetLSN(page);
|
||||||
@ -367,7 +382,9 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
WriteBuffer(ptr->buffer);
|
WriteBuffer(ptr->buffer);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Page page;
|
Page page;
|
||||||
BlockNumber rightrightlink = InvalidBlockNumber;
|
BlockNumber rightrightlink = InvalidBlockNumber;
|
||||||
SplitedPageLayout *ourpage = NULL;
|
SplitedPageLayout *ourpage = NULL;
|
||||||
@ -375,10 +392,13 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
GISTPageOpaque opaque;
|
GISTPageOpaque opaque;
|
||||||
|
|
||||||
/* move origpage to first in chain */
|
/* move origpage to first in chain */
|
||||||
if ( dist->block.blkno != state->stack->blkno ) {
|
if (dist->block.blkno != state->stack->blkno)
|
||||||
|
{
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr->next) {
|
while (ptr->next)
|
||||||
if ( ptr->next->block.blkno == state->stack->blkno ) {
|
{
|
||||||
|
if (ptr->next->block.blkno == state->stack->blkno)
|
||||||
|
{
|
||||||
ourpage = ptr->next;
|
ourpage = ptr->next;
|
||||||
ptr->next = ptr->next->next;
|
ptr->next = ptr->next->next;
|
||||||
ourpage->next = dist;
|
ourpage->next = dist;
|
||||||
@ -388,7 +408,8 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
Assert(ourpage != NULL);
|
Assert(ourpage != NULL);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ourpage = dist;
|
ourpage = dist;
|
||||||
|
|
||||||
|
|
||||||
@ -400,11 +421,13 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
opaque->nsn = PageGetLSN(page);
|
opaque->nsn = PageGetLSN(page);
|
||||||
opaque->rightlink = ourpage->next->block.blkno;
|
opaque->rightlink = ourpage->next->block.blkno;
|
||||||
|
|
||||||
/* fills and write all new pages.
|
/*
|
||||||
They isn't linked into tree yet */
|
* fills and write all new pages. They isn't linked into tree yet
|
||||||
|
*/
|
||||||
|
|
||||||
ptr = ourpage->next;
|
ptr = ourpage->next;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
page = (Page) BufferGetPage(ptr->buffer);
|
page = (Page) BufferGetPage(ptr->buffer);
|
||||||
GistPageGetOpaque(page)->rightlink = (ptr->next) ?
|
GistPageGetOpaque(page)->rightlink = (ptr->next) ?
|
||||||
ptr->next->block.blkno : rightrightlink;
|
ptr->next->block.blkno : rightrightlink;
|
||||||
@ -427,12 +450,15 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
gistfillbuffer(state->r, state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);
|
gistfillbuffer(state->r, state->stack->page, state->itup, state->ituplen, InvalidOffsetNumber);
|
||||||
|
|
||||||
oldlsn = PageGetLSN(state->stack->page);
|
oldlsn = PageGetLSN(state->stack->page);
|
||||||
if ( !state->r->rd_istemp ) {
|
if (!state->r->rd_istemp)
|
||||||
OffsetNumber noffs=0, offs[ MAXALIGN( sizeof(OffsetNumber) ) / sizeof(OffsetNumber) ];
|
{
|
||||||
|
OffsetNumber noffs = 0,
|
||||||
|
offs[MAXALIGN(sizeof(OffsetNumber)) / sizeof(OffsetNumber)];
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
|
|
||||||
if ( !is_leaf ) {
|
if (!is_leaf)
|
||||||
|
{
|
||||||
/* only on inner page we should delete previous version */
|
/* only on inner page we should delete previous version */
|
||||||
offs[0] = state->stack->childoffnum;
|
offs[0] = state->stack->childoffnum;
|
||||||
noffs = 1;
|
noffs = 1;
|
||||||
@ -449,30 +475,38 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
PageSetTLI(state->stack->page, ThisTimeLineID);
|
PageSetTLI(state->stack->page, ThisTimeLineID);
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
PageSetLSN(state->stack->page, XLogRecPtrForTemp);
|
PageSetLSN(state->stack->page, XLogRecPtrForTemp);
|
||||||
|
|
||||||
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
||||||
state->needInsertComplete = false;
|
state->needInsertComplete = false;
|
||||||
WriteNoReleaseBuffer(state->stack->buffer);
|
WriteNoReleaseBuffer(state->stack->buffer);
|
||||||
|
|
||||||
if (!is_leaf) /* small optimization: inform scan ablout deleting... */
|
if (!is_leaf) /* small optimization: inform scan ablout
|
||||||
|
* deleting... */
|
||||||
gistadjscans(state->r, GISTOP_DEL, state->stack->blkno,
|
gistadjscans(state->r, GISTOP_DEL, state->stack->blkno,
|
||||||
state->stack->childoffnum, PageGetLSN(state->stack->page), oldlsn);
|
state->stack->childoffnum, PageGetLSN(state->stack->page), oldlsn);
|
||||||
|
|
||||||
if (state->ituplen > 1)
|
if (state->ituplen > 1)
|
||||||
{ /* previous is_splitted==true */
|
{ /* previous is_splitted==true */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* child was splited, so we must form union for insertion in
|
* child was splited, so we must form union for insertion in
|
||||||
* parent
|
* parent
|
||||||
*/
|
*/
|
||||||
IndexTuple newtup = gistunion(state->r, state->itup, state->ituplen, giststate);
|
IndexTuple newtup = gistunion(state->r, state->itup, state->ituplen, giststate);
|
||||||
|
|
||||||
ItemPointerSetBlockNumber(&(newtup->t_tid), state->stack->blkno);
|
ItemPointerSetBlockNumber(&(newtup->t_tid), state->stack->blkno);
|
||||||
state->itup[0] = newtup;
|
state->itup[0] = newtup;
|
||||||
state->ituplen = 1;
|
state->ituplen = 1;
|
||||||
} else if (is_leaf) {
|
}
|
||||||
/* itup[0] store key to adjust parent, we set it to valid
|
else if (is_leaf)
|
||||||
to correct check by GistTupleIsInvalid macro in gistgetadjusted() */
|
{
|
||||||
|
/*
|
||||||
|
* itup[0] store key to adjust parent, we set it to valid to
|
||||||
|
* correct check by GistTupleIsInvalid macro in gistgetadjusted()
|
||||||
|
*/
|
||||||
ItemPointerSetBlockNumber(&(state->itup[0]->t_tid), state->stack->blkno);
|
ItemPointerSetBlockNumber(&(state->itup[0]->t_tid), state->stack->blkno);
|
||||||
GistTupleSetValid(state->itup[0]);
|
GistTupleSetValid(state->itup[0]);
|
||||||
}
|
}
|
||||||
@ -492,10 +526,13 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
|||||||
IndexTuple idxtuple;
|
IndexTuple idxtuple;
|
||||||
GISTPageOpaque opaque;
|
GISTPageOpaque opaque;
|
||||||
|
|
||||||
/* walk down, We don't lock page for a long time, but so
|
/*
|
||||||
we should be ready to recheck path in a bad case...
|
* walk down, We don't lock page for a long time, but so we should be
|
||||||
We remember, that page->lsn should never be invalid. */
|
* ready to recheck path in a bad case... We remember, that page->lsn
|
||||||
while( true ) {
|
* should never be invalid.
|
||||||
|
*/
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
|
||||||
if (XLogRecPtrIsInvalid(state->stack->lsn))
|
if (XLogRecPtrIsInvalid(state->stack->lsn))
|
||||||
state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);
|
state->stack->buffer = ReadBuffer(state->r, state->stack->blkno);
|
||||||
@ -508,8 +545,12 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
|||||||
Assert(state->r->rd_istemp || !XLogRecPtrIsInvalid(state->stack->lsn));
|
Assert(state->r->rd_istemp || !XLogRecPtrIsInvalid(state->stack->lsn));
|
||||||
|
|
||||||
if (state->stack->blkno != GIST_ROOT_BLKNO &&
|
if (state->stack->blkno != GIST_ROOT_BLKNO &&
|
||||||
XLByteLT( state->stack->parent->lsn, opaque->nsn) ) {
|
XLByteLT(state->stack->parent->lsn, opaque->nsn))
|
||||||
/* caused split non-root page is detected, go up to parent to choose best child */
|
{
|
||||||
|
/*
|
||||||
|
* caused split non-root page is detected, go up to parent to
|
||||||
|
* choose best child
|
||||||
|
*/
|
||||||
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(state->stack->buffer);
|
ReleaseBuffer(state->stack->buffer);
|
||||||
state->stack = state->stack->parent;
|
state->stack = state->stack->parent;
|
||||||
@ -520,13 +561,12 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
|||||||
if (!GistPageIsLeaf(state->stack->page))
|
if (!GistPageIsLeaf(state->stack->page))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is an internal page, so continue to walk down the
|
* This is an internal page, so continue to walk down the tree. We
|
||||||
* tree. We find the child node that has the minimum insertion
|
* find the child node that has the minimum insertion penalty and
|
||||||
* penalty and recursively invoke ourselves to modify that
|
* recursively invoke ourselves to modify that node. Once the
|
||||||
* node. Once the recursive call returns, we may need to
|
* recursive call returns, we may need to adjust the parent node
|
||||||
* adjust the parent node for two reasons: the child node
|
* for two reasons: the child node split, or the key in this node
|
||||||
* split, or the key in this node needs to be adjusted for the
|
* needs to be adjusted for the newly inserted key below us.
|
||||||
* newly inserted key below us.
|
|
||||||
*/
|
*/
|
||||||
GISTInsertStack *item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
GISTInsertStack *item = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
||||||
|
|
||||||
@ -542,28 +582,43 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
|||||||
if (state->stack)
|
if (state->stack)
|
||||||
state->stack->child = item;
|
state->stack->child = item;
|
||||||
state->stack = item;
|
state->stack = item;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* be carefull, during unlock/lock page may be changed... */
|
/* be carefull, during unlock/lock page may be changed... */
|
||||||
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
||||||
LockBuffer(state->stack->buffer, GIST_EXCLUSIVE);
|
LockBuffer(state->stack->buffer, GIST_EXCLUSIVE);
|
||||||
state->stack->page = (Page) BufferGetPage(state->stack->buffer);
|
state->stack->page = (Page) BufferGetPage(state->stack->buffer);
|
||||||
opaque = GistPageGetOpaque(state->stack->page);
|
opaque = GistPageGetOpaque(state->stack->page);
|
||||||
|
|
||||||
if ( state->stack->blkno == GIST_ROOT_BLKNO ) {
|
if (state->stack->blkno == GIST_ROOT_BLKNO)
|
||||||
/* the only page can become inner instead of leaf is a root page,
|
{
|
||||||
so for root we should recheck it */
|
/*
|
||||||
if ( !GistPageIsLeaf(state->stack->page) ) {
|
* the only page can become inner instead of leaf is a root
|
||||||
/* very rarely situation: during unlock/lock index
|
* page, so for root we should recheck it
|
||||||
with number of pages = 1 was increased */
|
*/
|
||||||
|
if (!GistPageIsLeaf(state->stack->page))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* very rarely situation: during unlock/lock index with
|
||||||
|
* number of pages = 1 was increased
|
||||||
|
*/
|
||||||
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* we don't need to check root split, because checking
|
|
||||||
leaf/inner is enough to recognize split for root */
|
|
||||||
|
|
||||||
} else if ( XLByteLT( state->stack->parent->lsn, opaque->nsn) ) {
|
/*
|
||||||
/* detecting split during unlock/lock, so we should
|
* we don't need to check root split, because checking
|
||||||
find better child on parent*/
|
* leaf/inner is enough to recognize split for root
|
||||||
|
*/
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (XLByteLT(state->stack->parent->lsn, opaque->nsn))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* detecting split during unlock/lock, so we should find
|
||||||
|
* better child on parent
|
||||||
|
*/
|
||||||
|
|
||||||
/* forget buffer */
|
/* forget buffer */
|
||||||
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
||||||
@ -587,8 +642,10 @@ gistfindleaf(GISTInsertState *state, GISTSTATE *giststate)
|
|||||||
* Should have the same interface as XLogReadBuffer
|
* Should have the same interface as XLogReadBuffer
|
||||||
*/
|
*/
|
||||||
static Buffer
|
static Buffer
|
||||||
gistReadAndLockBuffer( Relation r, BlockNumber blkno ) {
|
gistReadAndLockBuffer(Relation r, BlockNumber blkno)
|
||||||
|
{
|
||||||
Buffer buffer = ReadBuffer(r, blkno);
|
Buffer buffer = ReadBuffer(r, blkno);
|
||||||
|
|
||||||
LockBuffer(buffer, GIST_SHARE);
|
LockBuffer(buffer, GIST_SHARE);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@ -601,23 +658,29 @@ gistReadAndLockBuffer( Relation r, BlockNumber blkno ) {
|
|||||||
* returns from the begining of closest parent;
|
* returns from the begining of closest parent;
|
||||||
*/
|
*/
|
||||||
GISTInsertStack *
|
GISTInsertStack *
|
||||||
gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, BlockNumber) ) {
|
gistFindPath(Relation r, BlockNumber child, Buffer (*myReadBuffer) (Relation, BlockNumber))
|
||||||
|
{
|
||||||
Page page;
|
Page page;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
OffsetNumber i, maxoff;
|
OffsetNumber i,
|
||||||
|
maxoff;
|
||||||
ItemId iid;
|
ItemId iid;
|
||||||
IndexTuple idxtuple;
|
IndexTuple idxtuple;
|
||||||
GISTInsertStack *top, *tail, *ptr;
|
GISTInsertStack *top,
|
||||||
|
*tail,
|
||||||
|
*ptr;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
|
|
||||||
top = tail = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
top = tail = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
||||||
top->blkno = GIST_ROOT_BLKNO;
|
top->blkno = GIST_ROOT_BLKNO;
|
||||||
|
|
||||||
while( top && top->blkno != child ) {
|
while (top && top->blkno != child)
|
||||||
|
{
|
||||||
buffer = myReadBuffer(r, top->blkno); /* buffer locked */
|
buffer = myReadBuffer(r, top->blkno); /* buffer locked */
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if ( GistPageIsLeaf(page) ) {
|
if (GistPageIsLeaf(page))
|
||||||
|
{
|
||||||
/* we can safety go away, follows only leaf pages */
|
/* we can safety go away, follows only leaf pages */
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
@ -627,7 +690,8 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, B
|
|||||||
top->lsn = PageGetLSN(page);
|
top->lsn = PageGetLSN(page);
|
||||||
|
|
||||||
if (top->parent && XLByteLT(top->parent->lsn, GistPageGetOpaque(page)->nsn) &&
|
if (top->parent && XLByteLT(top->parent->lsn, GistPageGetOpaque(page)->nsn) &&
|
||||||
GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */) {
|
GistPageGetOpaque(page)->rightlink != InvalidBlockNumber /* sanity check */ )
|
||||||
|
{
|
||||||
/* page splited while we thinking of... */
|
/* page splited while we thinking of... */
|
||||||
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
||||||
ptr->blkno = GistPageGetOpaque(page)->rightlink;
|
ptr->blkno = GistPageGetOpaque(page)->rightlink;
|
||||||
@ -640,25 +704,32 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, B
|
|||||||
|
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
for(i = FirstOffsetNumber; i<= maxoff; i = OffsetNumberNext(i)) {
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
|
{
|
||||||
iid = PageGetItemId(page, i);
|
iid = PageGetItemId(page, i);
|
||||||
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||||
blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
|
blkno = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
|
||||||
if ( blkno == child ) {
|
if (blkno == child)
|
||||||
|
{
|
||||||
OffsetNumber poff = InvalidOffsetNumber;
|
OffsetNumber poff = InvalidOffsetNumber;
|
||||||
|
|
||||||
/* make childs links */
|
/* make childs links */
|
||||||
ptr = top;
|
ptr = top;
|
||||||
while( ptr->parent ) {
|
while (ptr->parent)
|
||||||
|
{
|
||||||
/* set child link */
|
/* set child link */
|
||||||
ptr->parent->child = ptr;
|
ptr->parent->child = ptr;
|
||||||
/* move childoffnum.. */
|
/* move childoffnum.. */
|
||||||
if ( ptr == top ) {
|
if (ptr == top)
|
||||||
|
{
|
||||||
/* first iteration */
|
/* first iteration */
|
||||||
poff = ptr->parent->childoffnum;
|
poff = ptr->parent->childoffnum;
|
||||||
ptr->parent->childoffnum = ptr->childoffnum;
|
ptr->parent->childoffnum = ptr->childoffnum;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
OffsetNumber tmp = ptr->parent->childoffnum;
|
OffsetNumber tmp = ptr->parent->childoffnum;
|
||||||
|
|
||||||
ptr->parent->childoffnum = poff;
|
ptr->parent->childoffnum = poff;
|
||||||
poff = tmp;
|
poff = tmp;
|
||||||
}
|
}
|
||||||
@ -668,11 +739,14 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, B
|
|||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return top;
|
return top;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Install next inner page to the end of stack */
|
/* Install next inner page to the end of stack */
|
||||||
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
ptr = (GISTInsertStack *) palloc0(sizeof(GISTInsertStack));
|
||||||
ptr->blkno = blkno;
|
ptr->blkno = blkno;
|
||||||
ptr->childoffnum = i; /* set offsetnumber of child to child !!! */
|
ptr->childoffnum = i; /* set offsetnumber of child to child
|
||||||
|
* !!! */
|
||||||
ptr->parent = top;
|
ptr->parent = top;
|
||||||
ptr->next = NULL;
|
ptr->next = NULL;
|
||||||
tail->next = ptr;
|
tail->next = ptr;
|
||||||
@ -694,7 +768,8 @@ gistFindPath( Relation r, BlockNumber child, Buffer (*myReadBuffer)(Relation, B
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gistFindCorrectParent( Relation r, GISTInsertStack *child ) {
|
gistFindCorrectParent(Relation r, GISTInsertStack *child)
|
||||||
|
{
|
||||||
GISTInsertStack *parent = child->parent;
|
GISTInsertStack *parent = child->parent;
|
||||||
|
|
||||||
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
|
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
|
||||||
@ -702,19 +777,24 @@ gistFindCorrectParent( Relation r, GISTInsertStack *child ) {
|
|||||||
|
|
||||||
|
|
||||||
/* here we don't need to distinguish between split and page update */
|
/* here we don't need to distinguish between split and page update */
|
||||||
if ( parent->childoffnum == InvalidOffsetNumber || !XLByteEQ( parent->lsn, PageGetLSN(parent->page) ) ) {
|
if (parent->childoffnum == InvalidOffsetNumber || !XLByteEQ(parent->lsn, PageGetLSN(parent->page)))
|
||||||
|
{
|
||||||
/* parent is changed, look child in right links until found */
|
/* parent is changed, look child in right links until found */
|
||||||
OffsetNumber i, maxoff;
|
OffsetNumber i,
|
||||||
|
maxoff;
|
||||||
ItemId iid;
|
ItemId iid;
|
||||||
IndexTuple idxtuple;
|
IndexTuple idxtuple;
|
||||||
GISTInsertStack *ptr;
|
GISTInsertStack *ptr;
|
||||||
|
|
||||||
while(true) {
|
while (true)
|
||||||
|
{
|
||||||
maxoff = PageGetMaxOffsetNumber(parent->page);
|
maxoff = PageGetMaxOffsetNumber(parent->page);
|
||||||
for(i = FirstOffsetNumber; i<= maxoff; i = OffsetNumberNext(i)) {
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
|
{
|
||||||
iid = PageGetItemId(parent->page, i);
|
iid = PageGetItemId(parent->page, i);
|
||||||
idxtuple = (IndexTuple) PageGetItem(parent->page, iid);
|
idxtuple = (IndexTuple) PageGetItem(parent->page, iid);
|
||||||
if ( ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno ) {
|
if (ItemPointerGetBlockNumber(&(idxtuple->t_tid)) == child->blkno)
|
||||||
|
{
|
||||||
/* yes!!, found */
|
/* yes!!, found */
|
||||||
parent->childoffnum = i;
|
parent->childoffnum = i;
|
||||||
return;
|
return;
|
||||||
@ -725,19 +805,26 @@ gistFindCorrectParent( Relation r, GISTInsertStack *child ) {
|
|||||||
LockBuffer(parent->buffer, GIST_UNLOCK);
|
LockBuffer(parent->buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(parent->buffer);
|
ReleaseBuffer(parent->buffer);
|
||||||
if (parent->blkno == InvalidBlockNumber)
|
if (parent->blkno == InvalidBlockNumber)
|
||||||
/* end of chain and still didn't found parent,
|
|
||||||
It's very-very rare situation when root splited */
|
/*
|
||||||
|
* end of chain and still didn't found parent, It's very-very
|
||||||
|
* rare situation when root splited
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
parent->buffer = ReadBuffer(r, parent->blkno);
|
parent->buffer = ReadBuffer(r, parent->blkno);
|
||||||
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
|
LockBuffer(parent->buffer, GIST_EXCLUSIVE);
|
||||||
parent->page = (Page) BufferGetPage(parent->buffer);
|
parent->page = (Page) BufferGetPage(parent->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* awful!!, we need search tree to find parent ... ,
|
/*
|
||||||
but before we should release all old parent */
|
* awful!!, we need search tree to find parent ... , but before we
|
||||||
|
* should release all old parent
|
||||||
|
*/
|
||||||
|
|
||||||
ptr = child->parent->parent; /* child->parent already released above */
|
ptr = child->parent->parent; /* child->parent already released
|
||||||
while(ptr) {
|
* above */
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
ReleaseBuffer(ptr->buffer);
|
ReleaseBuffer(ptr->buffer);
|
||||||
ptr = ptr->parent;
|
ptr = ptr->parent;
|
||||||
}
|
}
|
||||||
@ -747,7 +834,8 @@ gistFindCorrectParent( Relation r, GISTInsertStack *child ) {
|
|||||||
Assert(ptr != NULL);
|
Assert(ptr != NULL);
|
||||||
|
|
||||||
/* read all buffers as supposed in caller */
|
/* read all buffers as supposed in caller */
|
||||||
while( ptr ) {
|
while (ptr)
|
||||||
|
{
|
||||||
ptr->buffer = ReadBuffer(r, ptr->blkno);
|
ptr->buffer = ReadBuffer(r, ptr->blkno);
|
||||||
ptr->page = (Page) BufferGetPage(ptr->buffer);
|
ptr->page = (Page) BufferGetPage(ptr->buffer);
|
||||||
ptr = ptr->parent;
|
ptr = ptr->parent;
|
||||||
@ -765,22 +853,28 @@ gistFindCorrectParent( Relation r, GISTInsertStack *child ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
gistmakedeal(GISTInsertState *state, GISTSTATE *giststate)
|
||||||
|
{
|
||||||
int is_splitted;
|
int is_splitted;
|
||||||
ItemId iid;
|
ItemId iid;
|
||||||
IndexTuple oldtup, newtup;
|
IndexTuple oldtup,
|
||||||
|
newtup;
|
||||||
|
|
||||||
/* walk up */
|
/* walk up */
|
||||||
while( true ) {
|
while (true)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* After this call: 1. if child page was splited, then itup
|
* After this call: 1. if child page was splited, then itup contains
|
||||||
* contains keys for each page 2. if child page wasn't splited,
|
* keys for each page 2. if child page wasn't splited, then itup
|
||||||
* then itup contains additional for adjustment of current key
|
* contains additional for adjustment of current key
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( state->stack->parent ) {
|
if (state->stack->parent)
|
||||||
/* X-lock parent page before proceed child,
|
{
|
||||||
gistFindCorrectParent should find and lock it */
|
/*
|
||||||
|
* X-lock parent page before proceed child, gistFindCorrectParent
|
||||||
|
* should find and lock it
|
||||||
|
*/
|
||||||
gistFindCorrectParent(state->r, state->stack);
|
gistFindCorrectParent(state->r, state->stack);
|
||||||
}
|
}
|
||||||
is_splitted = gistplacetopage(state, giststate);
|
is_splitted = gistplacetopage(state, giststate);
|
||||||
@ -796,7 +890,10 @@ gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
if (!state->stack)
|
if (!state->stack)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* child did not split, so we can check is it needed to update parent tuple */
|
/*
|
||||||
|
* child did not split, so we can check is it needed to update parent
|
||||||
|
* tuple
|
||||||
|
*/
|
||||||
if (!is_splitted)
|
if (!is_splitted)
|
||||||
{
|
{
|
||||||
/* parent's tuple */
|
/* parent's tuple */
|
||||||
@ -804,7 +901,8 @@ gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);
|
oldtup = (IndexTuple) PageGetItem(state->stack->page, iid);
|
||||||
newtup = gistgetadjusted(state->r, oldtup, state->itup[0], giststate);
|
newtup = gistgetadjusted(state->r, oldtup, state->itup[0], giststate);
|
||||||
|
|
||||||
if (!newtup) { /* not need to update key */
|
if (!newtup)
|
||||||
|
{ /* not need to update key */
|
||||||
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
LockBuffer(state->stack->buffer, GIST_UNLOCK);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -814,7 +912,8 @@ gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
} /* while */
|
} /* while */
|
||||||
|
|
||||||
/* release all parent buffers */
|
/* release all parent buffers */
|
||||||
while( state->stack ) {
|
while (state->stack)
|
||||||
|
{
|
||||||
ReleaseBuffer(state->stack->buffer);
|
ReleaseBuffer(state->stack->buffer);
|
||||||
state->stack = state->stack->parent;
|
state->stack = state->stack->parent;
|
||||||
}
|
}
|
||||||
@ -825,7 +924,8 @@ gistmakedeal(GISTInsertState *state, GISTSTATE *giststate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gistToRealOffset(OffsetNumber *arr, int len, OffsetNumber *reasloffset) {
|
gistToRealOffset(OffsetNumber *arr, int len, OffsetNumber *reasloffset)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
@ -856,7 +956,8 @@ gistSplit(Relation r,
|
|||||||
GISTPageOpaque opaque;
|
GISTPageOpaque opaque;
|
||||||
GIST_SPLITVEC v;
|
GIST_SPLITVEC v;
|
||||||
GistEntryVector *entryvec;
|
GistEntryVector *entryvec;
|
||||||
int i, fakeoffset,
|
int i,
|
||||||
|
fakeoffset,
|
||||||
nlen;
|
nlen;
|
||||||
OffsetNumber *realoffset;
|
OffsetNumber *realoffset;
|
||||||
IndexTuple *cleaneditup = itup;
|
IndexTuple *cleaneditup = itup;
|
||||||
@ -867,8 +968,8 @@ gistSplit(Relation r,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The root of the tree is the first block in the relation. If we're
|
* The root of the tree is the first block in the relation. If we're
|
||||||
* about to split the root, we need to do some hocus-pocus to enforce
|
* about to split the root, we need to do some hocus-pocus to enforce this
|
||||||
* this guarantee.
|
* guarantee.
|
||||||
*/
|
*/
|
||||||
if (BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO)
|
if (BufferGetBlockNumber(buffer) == GIST_ROOT_BLKNO)
|
||||||
{
|
{
|
||||||
@ -901,7 +1002,8 @@ gistSplit(Relation r,
|
|||||||
Datum datum;
|
Datum datum;
|
||||||
bool IsNull;
|
bool IsNull;
|
||||||
|
|
||||||
if (!GistPageIsLeaf(p) && GistTupleIsInvalid( itup[i - 1] )) {
|
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(itup[i - 1]))
|
||||||
|
{
|
||||||
entryvec->n--;
|
entryvec->n--;
|
||||||
/* remember position of invalid tuple */
|
/* remember position of invalid tuple */
|
||||||
realoffset[entryvec->n] = i;
|
realoffset[entryvec->n] = i;
|
||||||
@ -918,30 +1020,34 @@ gistSplit(Relation r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if it was invalid tuple then we need special processing. If
|
* if it was invalid tuple then we need special processing. If it's
|
||||||
* it's possible, we move all invalid tuples on right page.
|
* possible, we move all invalid tuples on right page. We should remember,
|
||||||
* We should remember, that union with invalid tuples
|
* that union with invalid tuples is a invalid tuple.
|
||||||
* is a invalid tuple.
|
|
||||||
*/
|
*/
|
||||||
if ( entryvec->n != *len + 1 ) {
|
if (entryvec->n != *len + 1)
|
||||||
|
{
|
||||||
lencleaneditup = entryvec->n - 1;
|
lencleaneditup = entryvec->n - 1;
|
||||||
cleaneditup = (IndexTuple *) palloc(lencleaneditup * sizeof(IndexTuple));
|
cleaneditup = (IndexTuple *) palloc(lencleaneditup * sizeof(IndexTuple));
|
||||||
for (i = 1; i < entryvec->n; i++)
|
for (i = 1; i < entryvec->n; i++)
|
||||||
cleaneditup[i - 1] = itup[realoffset[i] - 1];
|
cleaneditup[i - 1] = itup[realoffset[i] - 1];
|
||||||
|
|
||||||
if ( gistnospace( left, cleaneditup, lencleaneditup ) ) {
|
if (gistnospace(left, cleaneditup, lencleaneditup))
|
||||||
|
{
|
||||||
/* no space on left to put all good tuples, so picksplit */
|
/* no space on left to put all good tuples, so picksplit */
|
||||||
gistUserPicksplit(r, entryvec, &v, cleaneditup, lencleaneditup, giststate);
|
gistUserPicksplit(r, entryvec, &v, cleaneditup, lencleaneditup, giststate);
|
||||||
v.spl_leftvalid = true;
|
v.spl_leftvalid = true;
|
||||||
v.spl_rightvalid = false;
|
v.spl_rightvalid = false;
|
||||||
gistToRealOffset(v.spl_left, v.spl_nleft, realoffset);
|
gistToRealOffset(v.spl_left, v.spl_nleft, realoffset);
|
||||||
gistToRealOffset(v.spl_right, v.spl_nright, realoffset);
|
gistToRealOffset(v.spl_right, v.spl_nright, realoffset);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* we can try to store all valid tuples on one page */
|
/* we can try to store all valid tuples on one page */
|
||||||
v.spl_right = (OffsetNumber *) palloc(entryvec->n * sizeof(OffsetNumber));
|
v.spl_right = (OffsetNumber *) palloc(entryvec->n * sizeof(OffsetNumber));
|
||||||
v.spl_left = (OffsetNumber *) palloc(entryvec->n * sizeof(OffsetNumber));
|
v.spl_left = (OffsetNumber *) palloc(entryvec->n * sizeof(OffsetNumber));
|
||||||
|
|
||||||
if ( lencleaneditup==0 ) {
|
if (lencleaneditup == 0)
|
||||||
|
{
|
||||||
/* all tuples are invalid, so moves half of its to right */
|
/* all tuples are invalid, so moves half of its to right */
|
||||||
v.spl_leftvalid = v.spl_rightvalid = false;
|
v.spl_leftvalid = v.spl_rightvalid = false;
|
||||||
v.spl_nright = 0;
|
v.spl_nright = 0;
|
||||||
@ -951,9 +1057,13 @@ gistSplit(Relation r,
|
|||||||
v.spl_left[v.spl_nleft++] = i;
|
v.spl_left[v.spl_nleft++] = i;
|
||||||
else
|
else
|
||||||
v.spl_right[v.spl_nright++] = i;
|
v.spl_right[v.spl_nright++] = i;
|
||||||
} else {
|
}
|
||||||
/* we will not call gistUserPicksplit, just put good
|
else
|
||||||
tuples on left and invalid on right */
|
{
|
||||||
|
/*
|
||||||
|
* we will not call gistUserPicksplit, just put good tuples on
|
||||||
|
* left and invalid on right
|
||||||
|
*/
|
||||||
v.spl_nleft = lencleaneditup;
|
v.spl_nleft = lencleaneditup;
|
||||||
v.spl_nright = 0;
|
v.spl_nright = 0;
|
||||||
for (i = 1; i < entryvec->n; i++)
|
for (i = 1; i < entryvec->n; i++)
|
||||||
@ -968,7 +1078,9 @@ gistSplit(Relation r,
|
|||||||
v.spl_rightvalid = false;
|
v.spl_rightvalid = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* there is no invalid tuples, so usial processing */
|
/* there is no invalid tuples, so usial processing */
|
||||||
gistUserPicksplit(r, entryvec, &v, itup, *len, giststate);
|
gistUserPicksplit(r, entryvec, &v, itup, *len, giststate);
|
||||||
v.spl_leftvalid = v.spl_rightvalid = true;
|
v.spl_leftvalid = v.spl_rightvalid = true;
|
||||||
@ -986,7 +1098,8 @@ gistSplit(Relation r,
|
|||||||
rvectup[i] = itup[v.spl_right[i] - 1];
|
rvectup[i] = itup[v.spl_right[i] - 1];
|
||||||
|
|
||||||
/* place invalid tuples on right page if itsn't done yet */
|
/* place invalid tuples on right page if itsn't done yet */
|
||||||
for (fakeoffset = entryvec->n; fakeoffset < *len+1 && lencleaneditup; fakeoffset++) {
|
for (fakeoffset = entryvec->n; fakeoffset < *len + 1 && lencleaneditup; fakeoffset++)
|
||||||
|
{
|
||||||
rvectup[v.spl_nright++] = itup[realoffset[fakeoffset] - 1];
|
rvectup[v.spl_nright++] = itup[realoffset[fakeoffset] - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,7 +1121,8 @@ gistSplit(Relation r,
|
|||||||
(*dist)->block.num = v.spl_nright;
|
(*dist)->block.num = v.spl_nright;
|
||||||
(*dist)->list = (IndexTupleData *) palloc(BLCKSZ);
|
(*dist)->list = (IndexTupleData *) palloc(BLCKSZ);
|
||||||
ptr = (char *) ((*dist)->list);
|
ptr = (char *) ((*dist)->list);
|
||||||
for(i=0;i<v.spl_nright;i++) {
|
for (i = 0; i < v.spl_nright; i++)
|
||||||
|
{
|
||||||
memcpy(ptr, rvectup[i], IndexTupleSize(rvectup[i]));
|
memcpy(ptr, rvectup[i], IndexTupleSize(rvectup[i]));
|
||||||
ptr += IndexTupleSize(rvectup[i]);
|
ptr += IndexTupleSize(rvectup[i]);
|
||||||
}
|
}
|
||||||
@ -1043,7 +1157,8 @@ gistSplit(Relation r,
|
|||||||
(*dist)->block.num = v.spl_nleft;
|
(*dist)->block.num = v.spl_nleft;
|
||||||
(*dist)->list = (IndexTupleData *) palloc(BLCKSZ);
|
(*dist)->list = (IndexTupleData *) palloc(BLCKSZ);
|
||||||
ptr = (char *) ((*dist)->list);
|
ptr = (char *) ((*dist)->list);
|
||||||
for(i=0;i<v.spl_nleft;i++) {
|
for (i = 0; i < v.spl_nleft; i++)
|
||||||
|
{
|
||||||
memcpy(ptr, lvectup[i], IndexTupleSize(lvectup[i]));
|
memcpy(ptr, lvectup[i], IndexTupleSize(lvectup[i]));
|
||||||
ptr += IndexTupleSize(lvectup[i]);
|
ptr += IndexTupleSize(lvectup[i]);
|
||||||
}
|
}
|
||||||
@ -1076,7 +1191,8 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
|
|||||||
GISTInitBuffer(buffer, 0);
|
GISTInitBuffer(buffer, 0);
|
||||||
|
|
||||||
gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
|
gistfillbuffer(r, page, itup, len, FirstOffsetNumber);
|
||||||
if ( !r->rd_istemp ) {
|
if (!r->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
|
|
||||||
@ -1090,7 +1206,8 @@ gistnewroot(Relation r, Buffer buffer, IndexTuple *itup, int len, ItemPointer ke
|
|||||||
PageSetTLI(page, ThisTimeLineID);
|
PageSetTLI(page, ThisTimeLineID);
|
||||||
|
|
||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
PageSetLSN(page, XLogRecPtrForTemp);
|
PageSetLSN(page, XLogRecPtrForTemp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1136,4 +1253,3 @@ freeGISTstate(GISTSTATE *giststate)
|
|||||||
{
|
{
|
||||||
/* no work */
|
/* no work */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.50 2005/06/27 12:45:22 teodor Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.51 2005/09/22 20:44:36 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -26,18 +26,22 @@ static bool gistindex_keytest(IndexTuple tuple, IndexScanDesc scan,
|
|||||||
OffsetNumber offset);
|
OffsetNumber offset);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr) {
|
killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr)
|
||||||
|
{
|
||||||
Buffer buffer = so->curbuf;
|
Buffer buffer = so->curbuf;
|
||||||
|
|
||||||
for(;;) {
|
for (;;)
|
||||||
|
{
|
||||||
Page p;
|
Page p;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
OffsetNumber offset, maxoff;
|
OffsetNumber offset,
|
||||||
|
maxoff;
|
||||||
|
|
||||||
LockBuffer(buffer, GIST_SHARE);
|
LockBuffer(buffer, GIST_SHARE);
|
||||||
p = (Page) BufferGetPage(buffer);
|
p = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if ( buffer == so->curbuf && XLByteEQ( so->stack->lsn, PageGetLSN(p) ) ) {
|
if (buffer == so->curbuf && XLByteEQ(so->stack->lsn, PageGetLSN(p)))
|
||||||
|
{
|
||||||
/* page unchanged, so all is simple */
|
/* page unchanged, so all is simple */
|
||||||
offset = ItemPointerGetOffsetNumber(iptr);
|
offset = ItemPointerGetOffsetNumber(iptr);
|
||||||
PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
|
PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
|
||||||
@ -48,10 +52,12 @@ killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr) {
|
|||||||
|
|
||||||
maxoff = PageGetMaxOffsetNumber(p);
|
maxoff = PageGetMaxOffsetNumber(p);
|
||||||
|
|
||||||
for(offset = FirstOffsetNumber; offset<= maxoff; offset = OffsetNumberNext(offset)) {
|
for (offset = FirstOffsetNumber; offset <= maxoff; offset = OffsetNumberNext(offset))
|
||||||
|
{
|
||||||
IndexTuple ituple = (IndexTuple) PageGetItem(p, PageGetItemId(p, offset));
|
IndexTuple ituple = (IndexTuple) PageGetItem(p, PageGetItemId(p, offset));
|
||||||
|
|
||||||
if ( ItemPointerEquals( &(ituple->t_tid), iptr ) ) {
|
if (ItemPointerEquals(&(ituple->t_tid), iptr))
|
||||||
|
{
|
||||||
/* found */
|
/* found */
|
||||||
PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
|
PageGetItemId(p, offset)->lp_flags |= LP_DELETE;
|
||||||
SetBufferCommitInfoNeedsSave(buffer);
|
SetBufferCommitInfoNeedsSave(buffer);
|
||||||
@ -63,9 +69,10 @@ killtuple(Relation r, GISTScanOpaque so, ItemPointer iptr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* follow right link */
|
/* follow right link */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ??? is it good? if tuple dropped by concurrent vacuum,
|
* ??? is it good? if tuple dropped by concurrent vacuum, we will read
|
||||||
* we will read all leaf pages...
|
* all leaf pages...
|
||||||
*/
|
*/
|
||||||
blkno = GistPageGetOpaque(p)->rightlink;
|
blkno = GistPageGetOpaque(p)->rightlink;
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
@ -94,16 +101,16 @@ gistgettuple(PG_FUNCTION_ARGS)
|
|||||||
so = (GISTScanOpaque) scan->opaque;
|
so = (GISTScanOpaque) scan->opaque;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have produced an index tuple in the past and the executor
|
* If we have produced an index tuple in the past and the executor has
|
||||||
* has informed us we need to mark it as "killed", do so now.
|
* informed us we need to mark it as "killed", do so now.
|
||||||
*/
|
*/
|
||||||
if (scan->kill_prior_tuple && ItemPointerIsValid(&(scan->currentItemData)))
|
if (scan->kill_prior_tuple && ItemPointerIsValid(&(scan->currentItemData)))
|
||||||
killtuple(scan->indexRelation, so, &(scan->currentItemData));
|
killtuple(scan->indexRelation, so, &(scan->currentItemData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the next tuple that matches the search key. If asked to
|
* Get the next tuple that matches the search key. If asked to skip killed
|
||||||
* skip killed tuples, continue looping until we find a non-killed
|
* tuples, continue looping until we find a non-killed tuple that matches
|
||||||
* tuple that matches the search key.
|
* the search key.
|
||||||
*/
|
*/
|
||||||
res = (gistnext(scan, dir, &tid, 1, scan->ignore_killed_tuples)) ? true : false;
|
res = (gistnext(scan, dir, &tid, 1, scan->ignore_killed_tuples)) ? true : false;
|
||||||
|
|
||||||
@ -154,11 +161,14 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
|
|
||||||
stk->next = NULL;
|
stk->next = NULL;
|
||||||
stk->block = GIST_ROOT_BLKNO;
|
stk->block = GIST_ROOT_BLKNO;
|
||||||
} else if ( so->curbuf == InvalidBuffer ) {
|
}
|
||||||
|
else if (so->curbuf == InvalidBuffer)
|
||||||
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;) {
|
for (;;)
|
||||||
|
{
|
||||||
/* First of all, we need lock buffer */
|
/* First of all, we need lock buffer */
|
||||||
Assert(so->curbuf != InvalidBuffer);
|
Assert(so->curbuf != InvalidBuffer);
|
||||||
LockBuffer(so->curbuf, GIST_SHARE);
|
LockBuffer(so->curbuf, GIST_SHARE);
|
||||||
@ -166,7 +176,8 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
opaque = GistPageGetOpaque(p);
|
opaque = GistPageGetOpaque(p);
|
||||||
resetoffset = false;
|
resetoffset = false;
|
||||||
|
|
||||||
if ( XLogRecPtrIsInvalid( so->stack->lsn ) || !XLByteEQ( so->stack->lsn, PageGetLSN(p) ) ) {
|
if (XLogRecPtrIsInvalid(so->stack->lsn) || !XLByteEQ(so->stack->lsn, PageGetLSN(p)))
|
||||||
|
{
|
||||||
/* page changed from last visit or visit first time , reset offset */
|
/* page changed from last visit or visit first time , reset offset */
|
||||||
so->stack->lsn = PageGetLSN(p);
|
so->stack->lsn = PageGetLSN(p);
|
||||||
resetoffset = true;
|
resetoffset = true;
|
||||||
@ -175,7 +186,9 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
if (!XLogRecPtrIsInvalid(so->stack->parentlsn) &&
|
if (!XLogRecPtrIsInvalid(so->stack->parentlsn) &&
|
||||||
XLByteLT(so->stack->parentlsn, opaque->nsn) &&
|
XLByteLT(so->stack->parentlsn, opaque->nsn) &&
|
||||||
opaque->rightlink != InvalidBlockNumber /* sanity check */ &&
|
opaque->rightlink != InvalidBlockNumber /* sanity check */ &&
|
||||||
(so->stack->next==NULL || so->stack->next->block != opaque->rightlink) /* check if already added */) {
|
(so->stack->next == NULL || so->stack->next->block != opaque->rightlink) /* check if already
|
||||||
|
added */ )
|
||||||
|
{
|
||||||
/* detect page split, follow right link to add pages */
|
/* detect page split, follow right link to add pages */
|
||||||
|
|
||||||
stk = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
|
stk = (GISTSearchStack *) palloc(sizeof(GISTSearchStack));
|
||||||
@ -188,13 +201,15 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* if page is empty, then just skip it */
|
/* if page is empty, then just skip it */
|
||||||
if ( PageIsEmpty(p) ) {
|
if (PageIsEmpty(p))
|
||||||
|
{
|
||||||
LockBuffer(so->curbuf, GIST_UNLOCK);
|
LockBuffer(so->curbuf, GIST_UNLOCK);
|
||||||
stk = so->stack->next;
|
stk = so->stack->next;
|
||||||
pfree(so->stack);
|
pfree(so->stack);
|
||||||
so->stack = stk;
|
so->stack = stk;
|
||||||
|
|
||||||
if (so->stack == NULL) {
|
if (so->stack == NULL)
|
||||||
|
{
|
||||||
ReleaseBuffer(so->curbuf);
|
ReleaseBuffer(so->curbuf);
|
||||||
so->curbuf = InvalidBuffer;
|
so->curbuf = InvalidBuffer;
|
||||||
return ntids;
|
return ntids;
|
||||||
@ -231,9 +246,9 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
if (!OffsetNumberIsValid(n))
|
if (!OffsetNumberIsValid(n))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We ran out of matching index entries on the current
|
* We ran out of matching index entries on the current page,
|
||||||
* page, so pop the top stack entry and use it to continue
|
* so pop the top stack entry and use it to continue the
|
||||||
* the search.
|
* search.
|
||||||
*/
|
*/
|
||||||
LockBuffer(so->curbuf, GIST_UNLOCK);
|
LockBuffer(so->curbuf, GIST_UNLOCK);
|
||||||
stk = so->stack->next;
|
stk = so->stack->next;
|
||||||
@ -259,19 +274,21 @@ gistnext(IndexScanDesc scan, ScanDirection dir, ItemPointer tids, int maxtids, b
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We've found a matching index entry in a leaf page, so
|
* We've found a matching index entry in a leaf page, so
|
||||||
* return success. Note that we keep "curbuf" pinned so
|
* return success. Note that we keep "curbuf" pinned so that
|
||||||
* that we can efficiently resume the index scan later.
|
* we can efficiently resume the index scan later.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ItemPointerSet(&(scan->currentItemData),
|
ItemPointerSet(&(scan->currentItemData),
|
||||||
BufferGetBlockNumber(so->curbuf), n);
|
BufferGetBlockNumber(so->curbuf), n);
|
||||||
|
|
||||||
if ( ! ( ignore_killed_tuples && ItemIdDeleted(PageGetItemId(p, n)) ) ) {
|
if (!(ignore_killed_tuples && ItemIdDeleted(PageGetItemId(p, n))))
|
||||||
|
{
|
||||||
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
|
it = (IndexTuple) PageGetItem(p, PageGetItemId(p, n));
|
||||||
tids[ntids] = scan->xs_ctup.t_self = it->t_tid;
|
tids[ntids] = scan->xs_ctup.t_self = it->t_tid;
|
||||||
ntids++;
|
ntids++;
|
||||||
|
|
||||||
if ( ntids == maxtids ) {
|
if (ntids == maxtids)
|
||||||
|
{
|
||||||
LockBuffer(so->curbuf, GIST_UNLOCK);
|
LockBuffer(so->curbuf, GIST_UNLOCK);
|
||||||
return ntids;
|
return ntids;
|
||||||
}
|
}
|
||||||
@ -334,7 +351,8 @@ gistindex_keytest(IndexTuple tuple,
|
|||||||
IncrIndexProcessed();
|
IncrIndexProcessed();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Tuple doesn't restore after crash recovery because of inclomplete insert
|
* Tuple doesn't restore after crash recovery because of inclomplete
|
||||||
|
* insert
|
||||||
*/
|
*/
|
||||||
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
|
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
|
||||||
return true;
|
return true;
|
||||||
@ -366,13 +384,12 @@ gistindex_keytest(IndexTuple tuple,
|
|||||||
FALSE, isNull);
|
FALSE, isNull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call the Consistent function to evaluate the test. The
|
* Call the Consistent function to evaluate the test. The arguments
|
||||||
* arguments are the index datum (as a GISTENTRY*), the comparison
|
* are the index datum (as a GISTENTRY*), the comparison datum, and
|
||||||
* datum, and the comparison operator's strategy number and
|
* the comparison operator's strategy number and subtype from pg_amop.
|
||||||
* subtype from pg_amop.
|
|
||||||
*
|
*
|
||||||
* (Presently there's no need to pass the subtype since it'll always
|
* (Presently there's no need to pass the subtype since it'll always be
|
||||||
* be zero, but might as well pass it for possible future use.)
|
* zero, but might as well pass it for possible future use.)
|
||||||
*/
|
*/
|
||||||
test = FunctionCall4(&key->sk_func,
|
test = FunctionCall4(&key->sk_func,
|
||||||
PointerGetDatum(&de),
|
PointerGetDatum(&de),
|
||||||
@ -410,15 +427,15 @@ gistfindnext(IndexScanDesc scan, OffsetNumber n, ScanDirection dir)
|
|||||||
maxoff = PageGetMaxOffsetNumber(p);
|
maxoff = PageGetMaxOffsetNumber(p);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure we're in a short-lived memory context when we invoke
|
* Make sure we're in a short-lived memory context when we invoke a
|
||||||
* a user-supplied GiST method in gistindex_keytest(), so we don't
|
* user-supplied GiST method in gistindex_keytest(), so we don't leak
|
||||||
* leak memory
|
* memory
|
||||||
*/
|
*/
|
||||||
oldcxt = MemoryContextSwitchTo(so->tempCxt);
|
oldcxt = MemoryContextSwitchTo(so->tempCxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we modified the index during the scan, we may have a pointer to
|
* If we modified the index during the scan, we may have a pointer to a
|
||||||
* a ghost tuple, before the scan. If this is the case, back up one.
|
* ghost tuple, before the scan. If this is the case, back up one.
|
||||||
*/
|
*/
|
||||||
if (so->flags & GS_CURBEFORE)
|
if (so->flags & GS_CURBEFORE)
|
||||||
{
|
{
|
||||||
@ -442,9 +459,8 @@ gistfindnext(IndexScanDesc scan, OffsetNumber n, ScanDirection dir)
|
|||||||
MemoryContextReset(so->tempCxt);
|
MemoryContextReset(so->tempCxt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we found a matching entry, return its offset; otherwise
|
* If we found a matching entry, return its offset; otherwise return
|
||||||
* return InvalidOffsetNumber to inform the caller to go to the
|
* InvalidOffsetNumber to inform the caller to go to the next page.
|
||||||
* next page.
|
|
||||||
*/
|
*/
|
||||||
if (n >= FirstOffsetNumber && n <= maxoff)
|
if (n >= FirstOffsetNumber && n <= maxoff)
|
||||||
return n;
|
return n;
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.1 2005/07/01 19:19:02 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.2 2005/09/22 20:44:36 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -621,8 +621,8 @@ gist_poly_consistent(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the operators are marked lossy anyway, we can just use
|
* Since the operators are marked lossy anyway, we can just use
|
||||||
* rtree_internal_consistent even at leaf nodes. (This works
|
* rtree_internal_consistent even at leaf nodes. (This works in part
|
||||||
* in part because the index entries are bounding boxes not polygons.)
|
* because the index entries are bounding boxes not polygons.)
|
||||||
*/
|
*/
|
||||||
result = rtree_internal_consistent(DatumGetBoxP(entry->key),
|
result = rtree_internal_consistent(DatumGetBoxP(entry->key),
|
||||||
&(query->boundbox), strategy);
|
&(query->boundbox), strategy);
|
||||||
@ -693,8 +693,8 @@ gist_circle_consistent(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Since the operators are marked lossy anyway, we can just use
|
* Since the operators are marked lossy anyway, we can just use
|
||||||
* rtree_internal_consistent even at leaf nodes. (This works
|
* rtree_internal_consistent even at leaf nodes. (This works in part
|
||||||
* in part because the index entries are bounding boxes not circles.)
|
* because the index entries are bounding boxes not circles.)
|
||||||
*/
|
*/
|
||||||
bbox.high.x = query->center.x + query->radius;
|
bbox.high.x = query->center.x + query->radius;
|
||||||
bbox.low.x = query->center.x - query->radius;
|
bbox.low.x = query->center.x - query->radius;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.60 2005/09/22 18:49:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.61 2005/09/22 20:44:36 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -120,11 +120,11 @@ gistrescan(PG_FUNCTION_ARGS)
|
|||||||
scan->numberOfKeys * sizeof(ScanKeyData));
|
scan->numberOfKeys * sizeof(ScanKeyData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Modify the scan key so that all the Consistent method is
|
* Modify the scan key so that all the Consistent method is called for
|
||||||
* called for all comparisons. The original operator is passed
|
* all comparisons. The original operator is passed to the Consistent
|
||||||
* to the Consistent function in the form of its strategy
|
* function in the form of its strategy number, which is available
|
||||||
* number, which is available from the sk_strategy field, and
|
* from the sk_strategy field, and its subtype from the sk_subtype
|
||||||
* its subtype from the sk_subtype field.
|
* field.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < scan->numberOfKeys; i++)
|
for (i = 0; i < scan->numberOfKeys; i++)
|
||||||
scan->keyData[i].sk_func = so->giststate->consistentFn[scan->keyData[i].sk_attno - 1];
|
scan->keyData[i].sk_func = so->giststate->consistentFn[scan->keyData[i].sk_attno - 1];
|
||||||
@ -308,9 +308,9 @@ ReleaseResources_gist(void)
|
|||||||
GISTScanList next;
|
GISTScanList next;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: this should be a no-op during normal query shutdown. However,
|
* Note: this should be a no-op during normal query shutdown. However, in
|
||||||
* in an abort situation ExecutorEnd is not called and so there may be
|
* an abort situation ExecutorEnd is not called and so there may be open
|
||||||
* open index scans to clean up.
|
* index scans to clean up.
|
||||||
*/
|
*/
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
|
|
||||||
@ -399,7 +399,8 @@ adjustiptr(IndexScanDesc scan,
|
|||||||
{
|
{
|
||||||
case GISTOP_DEL:
|
case GISTOP_DEL:
|
||||||
/* back up one if we need to */
|
/* back up one if we need to */
|
||||||
if (curoff >= offnum && XLByteEQ(stk->lsn, oldlsn) ) /* the same vesrion of page */
|
if (curoff >= offnum && XLByteEQ(stk->lsn, oldlsn)) /* the same vesrion of
|
||||||
|
* page */
|
||||||
{
|
{
|
||||||
if (curoff > FirstOffsetNumber)
|
if (curoff > FirstOffsetNumber)
|
||||||
{
|
{
|
||||||
@ -409,8 +410,7 @@ adjustiptr(IndexScanDesc scan,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* remember that we're before the current
|
* remember that we're before the current tuple
|
||||||
* tuple
|
|
||||||
*/
|
*/
|
||||||
ItemPointerSet(iptr, blkno, FirstOffsetNumber);
|
ItemPointerSet(iptr, blkno, FirstOffsetNumber);
|
||||||
if (iptr == &(scan->currentItemData))
|
if (iptr == &(scan->currentItemData))
|
||||||
@ -435,6 +435,7 @@ gistfreestack(GISTSearchStack *s)
|
|||||||
while (s != NULL)
|
while (s != NULL)
|
||||||
{
|
{
|
||||||
GISTSearchStack *p = s->next;
|
GISTSearchStack *p = s->next;
|
||||||
|
|
||||||
pfree(s);
|
pfree(s);
|
||||||
s = p;
|
s = p;
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.6 2005/09/22 18:49:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.7 2005/09/22 20:44:36 momjian Exp $
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -47,8 +47,7 @@
|
|||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void gistpenalty(GISTSTATE *giststate, int attno,
|
||||||
gistpenalty(GISTSTATE *giststate, int attno,
|
|
||||||
GISTENTRY *key1, bool isNull1,
|
GISTENTRY *key1, bool isNull1,
|
||||||
GISTENTRY *key2, bool isNull2, float *penalty);
|
GISTENTRY *key2, bool isNull2, float *penalty);
|
||||||
|
|
||||||
@ -155,6 +154,7 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
|
|||||||
for (j = 0; j < len; j++)
|
for (j = 0; j < len; j++)
|
||||||
{
|
{
|
||||||
bool IsNull;
|
bool IsNull;
|
||||||
|
|
||||||
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
|
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &IsNull);
|
||||||
if (IsNull)
|
if (IsNull)
|
||||||
continue;
|
continue;
|
||||||
@ -402,8 +402,8 @@ gistfindgroup(GISTSTATE *giststate, GISTENTRY *valvec, GIST_SPLITVEC *spl)
|
|||||||
int curid = 1;
|
int curid = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* first key is always not null (see gistinsert), so we may not check
|
* first key is always not null (see gistinsert), so we may not check for
|
||||||
* for nulls
|
* nulls
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < spl->spl_nleft; i++)
|
for (i = 0; i < spl->spl_nleft; i++)
|
||||||
{
|
{
|
||||||
@ -555,8 +555,7 @@ gistadjsubkey(Relation r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add
|
* add XXX: refactor this to avoid duplicating code
|
||||||
* XXX: refactor this to avoid duplicating code
|
|
||||||
*/
|
*/
|
||||||
if (lpenalty < rpenalty)
|
if (lpenalty < rpenalty)
|
||||||
{
|
{
|
||||||
@ -644,7 +643,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
|
|||||||
int j;
|
int j;
|
||||||
IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
|
IndexTuple itup = (IndexTuple) PageGetItem(p, PageGetItemId(p, i));
|
||||||
|
|
||||||
if ( !GistPageIsLeaf(p) && GistTupleIsInvalid(itup) ) {
|
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(itup))
|
||||||
|
{
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("index \"%s\" needs VACUUM or REINDEX to finish crash recovery",
|
(errmsg("index \"%s\" needs VACUUM or REINDEX to finish crash recovery",
|
||||||
RelationGetRelationName(r))));
|
RelationGetRelationName(r))));
|
||||||
@ -776,6 +776,7 @@ gistDeCompressAtt(GISTSTATE *giststate, Relation r, IndexTuple tuple, Page p,
|
|||||||
for (i = 0; i < r->rd_att->natts; i++)
|
for (i = 0; i < r->rd_att->natts; i++)
|
||||||
{
|
{
|
||||||
Datum datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
|
Datum datum = index_getattr(tuple, i + 1, giststate->tupdesc, &isnull[i]);
|
||||||
|
|
||||||
gistdentryinit(giststate, i, &attdata[i],
|
gistdentryinit(giststate, i, &attdata[i],
|
||||||
datum, r, p, o,
|
datum, r, p, o,
|
||||||
ATTSIZE(datum, giststate->tupdesc, i + 1, isnull[i]),
|
ATTSIZE(datum, giststate->tupdesc, i + 1, isnull[i]),
|
||||||
@ -816,10 +817,11 @@ GISTInitBuffer(Buffer b, uint32 f)
|
|||||||
|
|
||||||
void
|
void
|
||||||
gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
||||||
IndexTuple *itup, int len, GISTSTATE *giststate) {
|
IndexTuple *itup, int len, GISTSTATE *giststate)
|
||||||
|
{
|
||||||
/*
|
/*
|
||||||
* now let the user-defined picksplit function set up the split
|
* now let the user-defined picksplit function set up the split vector; in
|
||||||
* vector; in entryvec have no null value!!
|
* entryvec have no null value!!
|
||||||
*/
|
*/
|
||||||
FunctionCall2(&giststate->picksplitFn[0],
|
FunctionCall2(&giststate->picksplitFn[0],
|
||||||
PointerGetDatum(entryvec),
|
PointerGetDatum(entryvec),
|
||||||
@ -837,8 +839,8 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
|||||||
v->spl_risnull[0] = false;
|
v->spl_risnull[0] = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if index is multikey, then we must to try get smaller bounding box
|
* if index is multikey, then we must to try get smaller bounding box for
|
||||||
* for subkey(s)
|
* subkey(s)
|
||||||
*/
|
*/
|
||||||
if (r->rd_att->natts > 1)
|
if (r->rd_att->natts > 1)
|
||||||
{
|
{
|
||||||
@ -854,8 +856,8 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
|||||||
gistunionsubkey(r, giststate, itup, v, false);
|
gistunionsubkey(r, giststate, itup, v, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if possible, we insert equivalent tuples with control by
|
* if possible, we insert equivalent tuples with control by penalty
|
||||||
* penalty for a subkey(s)
|
* for a subkey(s)
|
||||||
*/
|
*/
|
||||||
if (MaxGrpId > 1)
|
if (MaxGrpId > 1)
|
||||||
gistadjsubkey(r, itup, len, v, giststate);
|
gistadjsubkey(r, itup, len, v, giststate);
|
||||||
@ -863,22 +865,29 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, GIST_SPLITVEC *v,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Buffer
|
Buffer
|
||||||
gistNewBuffer(Relation r) {
|
gistNewBuffer(Relation r)
|
||||||
|
{
|
||||||
Buffer buffer = InvalidBuffer;
|
Buffer buffer = InvalidBuffer;
|
||||||
bool needLock;
|
bool needLock;
|
||||||
|
|
||||||
while(true) {
|
while (true)
|
||||||
|
{
|
||||||
BlockNumber blkno = GetFreeIndexPage(&r->rd_node);
|
BlockNumber blkno = GetFreeIndexPage(&r->rd_node);
|
||||||
|
|
||||||
if (blkno == InvalidBlockNumber)
|
if (blkno == InvalidBlockNumber)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buffer = ReadBuffer(r, blkno);
|
buffer = ReadBuffer(r, blkno);
|
||||||
if ( ConditionalLockBuffer(buffer) ) {
|
if (ConditionalLockBuffer(buffer))
|
||||||
|
{
|
||||||
Page page = BufferGetPage(buffer);
|
Page page = BufferGetPage(buffer);
|
||||||
if ( GistPageIsDeleted( page ) ) {
|
|
||||||
|
if (GistPageIsDeleted(page))
|
||||||
|
{
|
||||||
GistPageSetNonDeleted(page);
|
GistPageSetNonDeleted(page);
|
||||||
return buffer;
|
return buffer;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.8 2005/09/22 18:49:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.9 2005/09/22 20:44:36 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -29,47 +29,60 @@
|
|||||||
static bool needFullVacuum = false;
|
static bool needFullVacuum = false;
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
GISTSTATE giststate;
|
GISTSTATE giststate;
|
||||||
Relation index;
|
Relation index;
|
||||||
MemoryContext opCtx;
|
MemoryContext opCtx;
|
||||||
IndexBulkDeleteResult *result;
|
IndexBulkDeleteResult *result;
|
||||||
} GistVacuum;
|
} GistVacuum;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
IndexTuple *itup;
|
IndexTuple *itup;
|
||||||
int ituplen;
|
int ituplen;
|
||||||
bool emptypage;
|
bool emptypage;
|
||||||
} ArrayTuple;
|
} ArrayTuple;
|
||||||
|
|
||||||
static ArrayTuple
|
static ArrayTuple
|
||||||
gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
|
||||||
|
{
|
||||||
ArrayTuple res = {NULL, 0, false};
|
ArrayTuple res = {NULL, 0, false};
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
Page page;
|
Page page;
|
||||||
OffsetNumber i, maxoff;
|
OffsetNumber i,
|
||||||
|
maxoff;
|
||||||
ItemId iid;
|
ItemId iid;
|
||||||
int lenaddon=4, curlenaddon=0, ntodelete=0;
|
int lenaddon = 4,
|
||||||
IndexTuple idxtuple, *addon=NULL;
|
curlenaddon = 0,
|
||||||
|
ntodelete = 0;
|
||||||
|
IndexTuple idxtuple,
|
||||||
|
*addon = NULL;
|
||||||
bool needwrite = false;
|
bool needwrite = false;
|
||||||
OffsetNumber todelete[MaxOffsetNumber];
|
OffsetNumber todelete[MaxOffsetNumber];
|
||||||
ItemPointerData *completed = NULL;
|
ItemPointerData *completed = NULL;
|
||||||
int ncompleted=0, lencompleted=16;
|
int ncompleted = 0,
|
||||||
|
lencompleted = 16;
|
||||||
|
|
||||||
buffer = ReadBuffer(gv->index, blkno);
|
buffer = ReadBuffer(gv->index, blkno);
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
if ( GistPageIsLeaf(page) ) {
|
if (GistPageIsLeaf(page))
|
||||||
if ( GistTuplesDeleted(page) ) {
|
{
|
||||||
|
if (GistTuplesDeleted(page))
|
||||||
|
{
|
||||||
needunion = needwrite = true;
|
needunion = needwrite = true;
|
||||||
GistClearTuplesDeleted(page);
|
GistClearTuplesDeleted(page);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
completed = (ItemPointerData *) palloc(sizeof(ItemPointerData) * lencompleted);
|
completed = (ItemPointerData *) palloc(sizeof(ItemPointerData) * lencompleted);
|
||||||
addon = (IndexTuple *) palloc(sizeof(IndexTuple) * lenaddon);
|
addon = (IndexTuple *) palloc(sizeof(IndexTuple) * lenaddon);
|
||||||
|
|
||||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
|
{
|
||||||
ArrayTuple chldtuple;
|
ArrayTuple chldtuple;
|
||||||
bool needchildunion;
|
bool needchildunion;
|
||||||
|
|
||||||
@ -83,14 +96,18 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
|
|
||||||
chldtuple = gistVacuumUpdate(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)),
|
chldtuple = gistVacuumUpdate(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)),
|
||||||
needchildunion);
|
needchildunion);
|
||||||
if ( chldtuple.ituplen || chldtuple.emptypage ) {
|
if (chldtuple.ituplen || chldtuple.emptypage)
|
||||||
|
{
|
||||||
PageIndexTupleDelete(page, i);
|
PageIndexTupleDelete(page, i);
|
||||||
todelete[ntodelete++] = i;
|
todelete[ntodelete++] = i;
|
||||||
i--; maxoff--;
|
i--;
|
||||||
|
maxoff--;
|
||||||
needwrite = needunion = true;
|
needwrite = needunion = true;
|
||||||
|
|
||||||
if ( chldtuple.ituplen ) {
|
if (chldtuple.ituplen)
|
||||||
while( curlenaddon + chldtuple.ituplen >= lenaddon ) {
|
{
|
||||||
|
while (curlenaddon + chldtuple.ituplen >= lenaddon)
|
||||||
|
{
|
||||||
lenaddon *= 2;
|
lenaddon *= 2;
|
||||||
addon = (IndexTuple *) repalloc(addon, sizeof(IndexTuple) * lenaddon);
|
addon = (IndexTuple *) repalloc(addon, sizeof(IndexTuple) * lenaddon);
|
||||||
}
|
}
|
||||||
@ -99,15 +116,21 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
|
|
||||||
curlenaddon += chldtuple.ituplen;
|
curlenaddon += chldtuple.ituplen;
|
||||||
|
|
||||||
if ( chldtuple.ituplen > 1 ) {
|
if (chldtuple.ituplen > 1)
|
||||||
/* child was splitted, so we need mark completion insert(split) */
|
{
|
||||||
|
/*
|
||||||
|
* child was splitted, so we need mark completion
|
||||||
|
* insert(split)
|
||||||
|
*/
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
while( ncompleted + chldtuple.ituplen > lencompleted ) {
|
while (ncompleted + chldtuple.ituplen > lencompleted)
|
||||||
|
{
|
||||||
lencompleted *= 2;
|
lencompleted *= 2;
|
||||||
completed = (ItemPointerData *) repalloc(completed, sizeof(ItemPointerData) * lencompleted);
|
completed = (ItemPointerData *) repalloc(completed, sizeof(ItemPointerData) * lencompleted);
|
||||||
}
|
}
|
||||||
for(j=0;j<chldtuple.ituplen;j++) {
|
for (j = 0; j < chldtuple.ituplen; j++)
|
||||||
|
{
|
||||||
ItemPointerCopy(&(chldtuple.itup[j]->t_tid), completed + ncompleted);
|
ItemPointerCopy(&(chldtuple.itup[j]->t_tid), completed + ncompleted);
|
||||||
ncompleted++;
|
ncompleted++;
|
||||||
}
|
}
|
||||||
@ -117,12 +140,15 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( curlenaddon ) {
|
if (curlenaddon)
|
||||||
|
{
|
||||||
/* insert updated tuples */
|
/* insert updated tuples */
|
||||||
if (gistnospace(page, addon, curlenaddon)) {
|
if (gistnospace(page, addon, curlenaddon))
|
||||||
|
{
|
||||||
/* there is no space on page to insert tuples */
|
/* there is no space on page to insert tuples */
|
||||||
IndexTuple *vec;
|
IndexTuple *vec;
|
||||||
SplitedPageLayout *dist=NULL,*ptr;
|
SplitedPageLayout *dist = NULL,
|
||||||
|
*ptr;
|
||||||
int i;
|
int i;
|
||||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||||
|
|
||||||
@ -132,16 +158,19 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
MemoryContextSwitchTo(oldCtx);
|
MemoryContextSwitchTo(oldCtx);
|
||||||
|
|
||||||
vec = (IndexTuple *) palloc(sizeof(IndexTuple) * res.ituplen);
|
vec = (IndexTuple *) palloc(sizeof(IndexTuple) * res.ituplen);
|
||||||
for(i=0;i<res.ituplen;i++) {
|
for (i = 0; i < res.ituplen; i++)
|
||||||
|
{
|
||||||
vec[i] = (IndexTuple) palloc(IndexTupleSize(res.itup[i]));
|
vec[i] = (IndexTuple) palloc(IndexTupleSize(res.itup[i]));
|
||||||
memcpy(vec[i], res.itup[i], IndexTupleSize(res.itup[i]));
|
memcpy(vec[i], res.itup[i], IndexTupleSize(res.itup[i]));
|
||||||
}
|
}
|
||||||
res.itup = vec;
|
res.itup = vec;
|
||||||
|
|
||||||
if ( !gv->index->rd_istemp ) {
|
if (!gv->index->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
ItemPointerData key; /* set key for incomplete insert */
|
ItemPointerData key; /* set key for incomplete
|
||||||
|
* insert */
|
||||||
char *xlinfo;
|
char *xlinfo;
|
||||||
|
|
||||||
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||||
@ -154,7 +183,8 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
|
|
||||||
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
recptr = XLogInsert(RM_GIST_ID, XLOG_GIST_PAGE_SPLIT, rdata);
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
PageSetLSN(BufferGetPage(ptr->buffer), recptr);
|
PageSetLSN(BufferGetPage(ptr->buffer), recptr);
|
||||||
PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);
|
PageSetTLI(BufferGetPage(ptr->buffer), ThisTimeLineID);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
@ -163,24 +193,30 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
END_CRIT_SECTION();
|
END_CRIT_SECTION();
|
||||||
pfree(xlinfo);
|
pfree(xlinfo);
|
||||||
pfree(rdata);
|
pfree(rdata);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
|
PageSetLSN(BufferGetPage(ptr->buffer), XLogRecPtrForTemp);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
if (BufferGetBlockNumber(ptr->buffer) != blkno)
|
if (BufferGetBlockNumber(ptr->buffer) != blkno)
|
||||||
LockBuffer(ptr->buffer, GIST_UNLOCK);
|
LockBuffer(ptr->buffer, GIST_UNLOCK);
|
||||||
WriteBuffer(ptr->buffer);
|
WriteBuffer(ptr->buffer);
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( blkno == GIST_ROOT_BLKNO ) {
|
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);
|
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
|
||||||
|
|
||||||
@ -196,27 +232,37 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
MemoryContextReset(gv->opCtx);
|
MemoryContextReset(gv->opCtx);
|
||||||
|
|
||||||
needunion = false; /* gistSplit already forms unions */
|
needunion = false; /* gistSplit already forms unions */
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* enough free space */
|
/* enough free space */
|
||||||
gistfillbuffer(gv->index, page, addon, curlenaddon, InvalidOffsetNumber);
|
gistfillbuffer(gv->index, page, addon, curlenaddon, InvalidOffsetNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( needunion ) {
|
if (needunion)
|
||||||
|
{
|
||||||
/* forms union for page or check empty */
|
/* forms union for page or check empty */
|
||||||
if ( PageIsEmpty(page) ) {
|
if (PageIsEmpty(page))
|
||||||
if ( blkno == GIST_ROOT_BLKNO ) {
|
{
|
||||||
|
if (blkno == GIST_ROOT_BLKNO)
|
||||||
|
{
|
||||||
needwrite = true;
|
needwrite = true;
|
||||||
GistPageSetLeaf(page);
|
GistPageSetLeaf(page);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
needwrite = true;
|
needwrite = true;
|
||||||
res.emptypage = true;
|
res.emptypage = true;
|
||||||
GistPageSetDeleted(page);
|
GistPageSetDeleted(page);
|
||||||
gv->result->pages_deleted++;
|
gv->result->pages_deleted++;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
IndexTuple *vec, tmp;
|
else
|
||||||
|
{
|
||||||
|
IndexTuple *vec,
|
||||||
|
tmp;
|
||||||
int veclen = 0;
|
int veclen = 0;
|
||||||
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
|
||||||
|
|
||||||
@ -236,8 +282,10 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( needwrite ) {
|
if (needwrite)
|
||||||
if ( !gv->index->rd_istemp ) {
|
{
|
||||||
|
if (!gv->index->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
char *xlinfo;
|
char *xlinfo;
|
||||||
@ -254,10 +302,12 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
|
|
||||||
pfree(xlinfo);
|
pfree(xlinfo);
|
||||||
pfree(rdata);
|
pfree(rdata);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
PageSetLSN(page, XLogRecPtrForTemp);
|
PageSetLSN(page, XLogRecPtrForTemp);
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
|
|
||||||
if (ncompleted && !gv->index->rd_istemp)
|
if (ncompleted && !gv->index->rd_istemp)
|
||||||
@ -265,8 +315,10 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
|
|
||||||
for (i = 0; i < curlenaddon; i++)
|
for (i = 0; i < curlenaddon; i++)
|
||||||
pfree(addon[i]);
|
pfree(addon[i]);
|
||||||
if (addon) pfree(addon);
|
if (addon)
|
||||||
if (completed) pfree(completed);
|
pfree(addon);
|
||||||
|
if (completed)
|
||||||
|
pfree(completed);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,17 +330,23 @@ gistVacuumUpdate( GistVacuum *gv, BlockNumber blkno, bool needunion ) {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
gistvacuumcleanup(PG_FUNCTION_ARGS) {
|
gistvacuumcleanup(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||||
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
|
IndexVacuumCleanupInfo *info = (IndexVacuumCleanupInfo *) PG_GETARG_POINTER(1);
|
||||||
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
|
IndexBulkDeleteResult *stats = (IndexBulkDeleteResult *) PG_GETARG_POINTER(2);
|
||||||
BlockNumber npages, blkno;
|
BlockNumber npages,
|
||||||
BlockNumber nFreePages, *freePages, maxFreePages;
|
blkno;
|
||||||
BlockNumber lastBlock = GIST_ROOT_BLKNO, lastFilledBlock = GIST_ROOT_BLKNO;
|
BlockNumber nFreePages,
|
||||||
|
*freePages,
|
||||||
|
maxFreePages;
|
||||||
|
BlockNumber lastBlock = GIST_ROOT_BLKNO,
|
||||||
|
lastFilledBlock = GIST_ROOT_BLKNO;
|
||||||
bool needLock;
|
bool needLock;
|
||||||
|
|
||||||
/* gistVacuumUpdate may cause hard work */
|
/* gistVacuumUpdate may cause hard work */
|
||||||
if ( info->vacuum_full ) {
|
if (info->vacuum_full)
|
||||||
|
{
|
||||||
GistVacuum gv;
|
GistVacuum gv;
|
||||||
ArrayTuple res;
|
ArrayTuple res;
|
||||||
|
|
||||||
@ -302,15 +360,18 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||||||
/* walk through the entire index for update tuples */
|
/* walk through the entire index for update tuples */
|
||||||
res = gistVacuumUpdate(&gv, GIST_ROOT_BLKNO, false);
|
res = gistVacuumUpdate(&gv, GIST_ROOT_BLKNO, false);
|
||||||
/* cleanup */
|
/* cleanup */
|
||||||
if (res.itup) {
|
if (res.itup)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < res.ituplen; i++)
|
for (i = 0; i < res.ituplen; i++)
|
||||||
pfree(res.itup[i]);
|
pfree(res.itup[i]);
|
||||||
pfree(res.itup);
|
pfree(res.itup);
|
||||||
}
|
}
|
||||||
freeGISTstate(&(gv.giststate));
|
freeGISTstate(&(gv.giststate));
|
||||||
MemoryContextDelete(gv.opCtx);
|
MemoryContextDelete(gv.opCtx);
|
||||||
} else if (needFullVacuum)
|
}
|
||||||
|
else if (needFullVacuum)
|
||||||
ereport(NOTICE,
|
ereport(NOTICE,
|
||||||
(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",
|
(errmsg("index \"%s\" needs VACUUM FULL or REINDEX to finish crash recovery",
|
||||||
RelationGetRelationName(rel))));
|
RelationGetRelationName(rel))));
|
||||||
@ -334,29 +395,36 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
nFreePages = 0;
|
nFreePages = 0;
|
||||||
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
|
freePages = (BlockNumber *) palloc(sizeof(BlockNumber) * maxFreePages);
|
||||||
for(blkno=GIST_ROOT_BLKNO+1;blkno<npages;blkno++) {
|
for (blkno = GIST_ROOT_BLKNO + 1; blkno < npages; blkno++)
|
||||||
|
{
|
||||||
Buffer buffer = ReadBuffer(rel, blkno);
|
Buffer buffer = ReadBuffer(rel, blkno);
|
||||||
Page page;
|
Page page;
|
||||||
|
|
||||||
LockBuffer(buffer, GIST_SHARE);
|
LockBuffer(buffer, GIST_SHARE);
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if ( GistPageIsDeleted(page) ) {
|
if (GistPageIsDeleted(page))
|
||||||
if (nFreePages < maxFreePages) {
|
{
|
||||||
|
if (nFreePages < maxFreePages)
|
||||||
|
{
|
||||||
freePages[nFreePages] = blkno;
|
freePages[nFreePages] = blkno;
|
||||||
nFreePages++;
|
nFreePages++;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
lastFilledBlock = blkno;
|
lastFilledBlock = blkno;
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
lastBlock = npages - 1;
|
lastBlock = npages - 1;
|
||||||
|
|
||||||
if ( info->vacuum_full && nFreePages>0 ) { /* try to truncate index */
|
if (info->vacuum_full && nFreePages > 0)
|
||||||
|
{ /* try to truncate index */
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < nFreePages; i++)
|
for (i = 0; i < nFreePages; i++)
|
||||||
if ( freePages[i] >= lastFilledBlock ) {
|
if (freePages[i] >= lastFilledBlock)
|
||||||
|
{
|
||||||
nFreePages = i;
|
nFreePages = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -383,22 +451,26 @@ gistvacuumcleanup(PG_FUNCTION_ARGS) {
|
|||||||
PG_RETURN_POINTER(stats);
|
PG_RETURN_POINTER(stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct GistBDItem {
|
typedef struct GistBDItem
|
||||||
|
{
|
||||||
GistNSN parentlsn;
|
GistNSN parentlsn;
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
struct GistBDItem *next;
|
struct GistBDItem *next;
|
||||||
} GistBDItem;
|
} GistBDItem;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
pushStackIfSplited(Page page, GistBDItem *stack) {
|
pushStackIfSplited(Page page, GistBDItem *stack)
|
||||||
|
{
|
||||||
GISTPageOpaque opaque = GistPageGetOpaque(page);
|
GISTPageOpaque opaque = GistPageGetOpaque(page);
|
||||||
|
|
||||||
if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
|
if (stack->blkno != GIST_ROOT_BLKNO && !XLogRecPtrIsInvalid(stack->parentlsn) &&
|
||||||
XLByteLT(stack->parentlsn, opaque->nsn) &&
|
XLByteLT(stack->parentlsn, opaque->nsn) &&
|
||||||
opaque->rightlink != InvalidBlockNumber /* sanity check */ ) {
|
opaque->rightlink != InvalidBlockNumber /* sanity check */ )
|
||||||
|
{
|
||||||
/* split page detected, install right link to the stack */
|
/* split page detected, install right link to the stack */
|
||||||
|
|
||||||
GistBDItem *ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
|
GistBDItem *ptr = (GistBDItem *) palloc(sizeof(GistBDItem));
|
||||||
|
|
||||||
ptr->blkno = opaque->rightlink;
|
ptr->blkno = opaque->rightlink;
|
||||||
ptr->parentlsn = stack->parentlsn;
|
ptr->parentlsn = stack->parentlsn;
|
||||||
ptr->next = stack->next;
|
ptr->next = stack->next;
|
||||||
@ -416,12 +488,14 @@ pushStackIfSplited(Page page, GistBDItem *stack) {
|
|||||||
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
* Result: a palloc'd struct containing statistical info for VACUUM displays.
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
gistbulkdelete(PG_FUNCTION_ARGS) {
|
gistbulkdelete(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
Relation rel = (Relation) PG_GETARG_POINTER(0);
|
||||||
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
|
IndexBulkDeleteCallback callback = (IndexBulkDeleteCallback) PG_GETARG_POINTER(1);
|
||||||
void *callback_state = (void *) PG_GETARG_POINTER(2);
|
void *callback_state = (void *) PG_GETARG_POINTER(2);
|
||||||
IndexBulkDeleteResult *result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
IndexBulkDeleteResult *result = (IndexBulkDeleteResult *) palloc0(sizeof(IndexBulkDeleteResult));
|
||||||
GistBDItem *stack, *ptr;
|
GistBDItem *stack,
|
||||||
|
*ptr;
|
||||||
bool needLock;
|
bool needLock;
|
||||||
|
|
||||||
stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
|
stack = (GistBDItem *) palloc0(sizeof(GistBDItem));
|
||||||
@ -429,17 +503,20 @@ gistbulkdelete(PG_FUNCTION_ARGS) {
|
|||||||
stack->blkno = GIST_ROOT_BLKNO;
|
stack->blkno = GIST_ROOT_BLKNO;
|
||||||
needFullVacuum = false;
|
needFullVacuum = false;
|
||||||
|
|
||||||
while( stack ) {
|
while (stack)
|
||||||
|
{
|
||||||
Buffer buffer = ReadBuffer(rel, stack->blkno);
|
Buffer buffer = ReadBuffer(rel, stack->blkno);
|
||||||
Page page;
|
Page page;
|
||||||
OffsetNumber i, maxoff;
|
OffsetNumber i,
|
||||||
|
maxoff;
|
||||||
IndexTuple idxtuple;
|
IndexTuple idxtuple;
|
||||||
ItemId iid;
|
ItemId iid;
|
||||||
|
|
||||||
LockBuffer(buffer, GIST_SHARE);
|
LockBuffer(buffer, GIST_SHARE);
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if ( GistPageIsLeaf(page) ) {
|
if (GistPageIsLeaf(page))
|
||||||
|
{
|
||||||
OffsetNumber todelete[MaxOffsetNumber];
|
OffsetNumber todelete[MaxOffsetNumber];
|
||||||
int ntodelete = 0;
|
int ntodelete = 0;
|
||||||
|
|
||||||
@ -447,7 +524,8 @@ gistbulkdelete(PG_FUNCTION_ARGS) {
|
|||||||
LockBuffer(buffer, GIST_EXCLUSIVE);
|
LockBuffer(buffer, GIST_EXCLUSIVE);
|
||||||
|
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
if ( stack->blkno==GIST_ROOT_BLKNO && !GistPageIsLeaf(page) ) {
|
if (stack->blkno == GIST_ROOT_BLKNO && !GistPageIsLeaf(page))
|
||||||
|
{
|
||||||
/* the only root can become non-leaf during relock */
|
/* the only root can become non-leaf during relock */
|
||||||
LockBuffer(buffer, GIST_UNLOCK);
|
LockBuffer(buffer, GIST_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
@ -455,30 +533,39 @@ gistbulkdelete(PG_FUNCTION_ARGS) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check for split proceeded after look at parent,
|
/*
|
||||||
we should check it after relock */
|
* check for split proceeded after look at parent, we should check
|
||||||
|
* it after relock
|
||||||
|
*/
|
||||||
pushStackIfSplited(page, stack);
|
pushStackIfSplited(page, stack);
|
||||||
|
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
for(i=FirstOffsetNumber;i<=maxoff;i=OffsetNumberNext(i)) {
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
|
{
|
||||||
iid = PageGetItemId(page, i);
|
iid = PageGetItemId(page, i);
|
||||||
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||||
|
|
||||||
if ( callback(&(idxtuple->t_tid), callback_state) ) {
|
if (callback(&(idxtuple->t_tid), callback_state))
|
||||||
|
{
|
||||||
PageIndexTupleDelete(page, i);
|
PageIndexTupleDelete(page, i);
|
||||||
todelete[ntodelete] = i;
|
todelete[ntodelete] = i;
|
||||||
i--; maxoff--; ntodelete++;
|
i--;
|
||||||
|
maxoff--;
|
||||||
|
ntodelete++;
|
||||||
result->tuples_removed += 1;
|
result->tuples_removed += 1;
|
||||||
Assert(maxoff == PageGetMaxOffsetNumber(page));
|
Assert(maxoff == PageGetMaxOffsetNumber(page));
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
result->num_index_tuples += 1;
|
result->num_index_tuples += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ntodelete ) {
|
if (ntodelete)
|
||||||
|
{
|
||||||
GistMarkTuplesDeleted(page);
|
GistMarkTuplesDeleted(page);
|
||||||
|
|
||||||
if (!rel->rd_istemp ) {
|
if (!rel->rd_istemp)
|
||||||
|
{
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
gistxlogEntryUpdate *xlinfo;
|
gistxlogEntryUpdate *xlinfo;
|
||||||
@ -495,17 +582,21 @@ gistbulkdelete(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
pfree(xlinfo);
|
pfree(xlinfo);
|
||||||
pfree(rdata);
|
pfree(rdata);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
PageSetLSN(page, XLogRecPtrForTemp);
|
PageSetLSN(page, XLogRecPtrForTemp);
|
||||||
WriteNoReleaseBuffer(buffer);
|
WriteNoReleaseBuffer(buffer);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* check for split proceeded after look at parent */
|
/* check for split proceeded after look at parent */
|
||||||
pushStackIfSplited(page, stack);
|
pushStackIfSplited(page, stack);
|
||||||
|
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
for(i=FirstOffsetNumber;i<=maxoff;i=OffsetNumberNext(i)) {
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
|
{
|
||||||
iid = PageGetItemId(page, i);
|
iid = PageGetItemId(page, i);
|
||||||
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
idxtuple = (IndexTuple) PageGetItem(page, iid);
|
||||||
|
|
||||||
@ -541,4 +632,3 @@ gistbulkdelete(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.8 2005/09/22 18:49:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.9 2005/09/22 20:44:36 momjian Exp $
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -23,26 +23,30 @@
|
|||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
gistxlogEntryUpdate *data;
|
gistxlogEntryUpdate *data;
|
||||||
int len;
|
int len;
|
||||||
IndexTuple *itup;
|
IndexTuple *itup;
|
||||||
OffsetNumber *todelete;
|
OffsetNumber *todelete;
|
||||||
} EntryUpdateRecord;
|
} EntryUpdateRecord;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
gistxlogPage *header;
|
gistxlogPage *header;
|
||||||
IndexTuple *itup;
|
IndexTuple *itup;
|
||||||
} NewPage;
|
} NewPage;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
gistxlogPageSplit *data;
|
gistxlogPageSplit *data;
|
||||||
NewPage *page;
|
NewPage *page;
|
||||||
} PageSplitRecord;
|
} PageSplitRecord;
|
||||||
|
|
||||||
/* track for incomplete inserts, idea was taken from nbtxlog.c */
|
/* track for incomplete inserts, idea was taken from nbtxlog.c */
|
||||||
|
|
||||||
typedef struct gistIncompleteInsert {
|
typedef struct gistIncompleteInsert
|
||||||
|
{
|
||||||
RelFileNode node;
|
RelFileNode node;
|
||||||
BlockNumber origblkno; /* for splits */
|
BlockNumber origblkno; /* for splits */
|
||||||
ItemPointerData key;
|
ItemPointerData key;
|
||||||
@ -68,7 +72,8 @@ static List *incomplete_inserts;
|
|||||||
static void
|
static void
|
||||||
pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
||||||
BlockNumber *blkno, int lenblk,
|
BlockNumber *blkno, int lenblk,
|
||||||
PageSplitRecord *xlinfo /* to extract blkno info */ ) {
|
PageSplitRecord *xlinfo /* to extract blkno info */ )
|
||||||
|
{
|
||||||
MemoryContext oldCxt = MemoryContextSwitchTo(insertCtx);
|
MemoryContext oldCxt = MemoryContextSwitchTo(insertCtx);
|
||||||
gistIncompleteInsert *ninsert = (gistIncompleteInsert *) palloc(sizeof(gistIncompleteInsert));
|
gistIncompleteInsert *ninsert = (gistIncompleteInsert *) palloc(sizeof(gistIncompleteInsert));
|
||||||
|
|
||||||
@ -76,12 +81,15 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
|||||||
ninsert->key = key;
|
ninsert->key = key;
|
||||||
ninsert->lsn = lsn;
|
ninsert->lsn = lsn;
|
||||||
|
|
||||||
if ( lenblk && blkno ) {
|
if (lenblk && blkno)
|
||||||
|
{
|
||||||
ninsert->lenblk = lenblk;
|
ninsert->lenblk = lenblk;
|
||||||
ninsert->blkno = (BlockNumber *) palloc(sizeof(BlockNumber) * ninsert->lenblk);
|
ninsert->blkno = (BlockNumber *) palloc(sizeof(BlockNumber) * ninsert->lenblk);
|
||||||
memcpy(ninsert->blkno, blkno, sizeof(BlockNumber) * ninsert->lenblk);
|
memcpy(ninsert->blkno, blkno, sizeof(BlockNumber) * ninsert->lenblk);
|
||||||
ninsert->origblkno = *blkno;
|
ninsert->origblkno = *blkno;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
Assert(xlinfo);
|
Assert(xlinfo);
|
||||||
@ -98,13 +106,16 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
forgetIncompleteInsert(RelFileNode node, ItemPointerData key) {
|
forgetIncompleteInsert(RelFileNode node, ItemPointerData key)
|
||||||
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
foreach(l, incomplete_inserts) {
|
foreach(l, incomplete_inserts)
|
||||||
|
{
|
||||||
gistIncompleteInsert *insert = (gistIncompleteInsert *) lfirst(l);
|
gistIncompleteInsert *insert = (gistIncompleteInsert *) lfirst(l);
|
||||||
|
|
||||||
if ( RelFileNodeEquals(node, insert->node) && ItemPointerEQ( &(insert->key), &(key) ) ) {
|
if (RelFileNodeEquals(node, insert->node) && ItemPointerEQ(&(insert->key), &(key)))
|
||||||
|
{
|
||||||
|
|
||||||
/* found */
|
/* found */
|
||||||
pfree(insert->blkno);
|
pfree(insert->blkno);
|
||||||
@ -116,21 +127,27 @@ forgetIncompleteInsert(RelFileNode node, ItemPointerData key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
decodeEntryUpdateRecord(EntryUpdateRecord *decoded, XLogRecord *record) {
|
decodeEntryUpdateRecord(EntryUpdateRecord *decoded, XLogRecord *record)
|
||||||
char *begin = XLogRecGetData(record), *ptr;
|
{
|
||||||
int i=0, addpath=0;
|
char *begin = XLogRecGetData(record),
|
||||||
|
*ptr;
|
||||||
|
int i = 0,
|
||||||
|
addpath = 0;
|
||||||
|
|
||||||
decoded->data = (gistxlogEntryUpdate *) begin;
|
decoded->data = (gistxlogEntryUpdate *) begin;
|
||||||
|
|
||||||
if ( decoded->data->ntodelete ) {
|
if (decoded->data->ntodelete)
|
||||||
|
{
|
||||||
decoded->todelete = (OffsetNumber *) (begin + sizeof(gistxlogEntryUpdate) + addpath);
|
decoded->todelete = (OffsetNumber *) (begin + sizeof(gistxlogEntryUpdate) + addpath);
|
||||||
addpath = MAXALIGN(sizeof(OffsetNumber) * decoded->data->ntodelete);
|
addpath = MAXALIGN(sizeof(OffsetNumber) * decoded->data->ntodelete);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
decoded->todelete = NULL;
|
decoded->todelete = NULL;
|
||||||
|
|
||||||
decoded->len = 0;
|
decoded->len = 0;
|
||||||
ptr = begin + sizeof(gistxlogEntryUpdate) + addpath;
|
ptr = begin + sizeof(gistxlogEntryUpdate) + addpath;
|
||||||
while( ptr - begin < record->xl_len ) {
|
while (ptr - begin < record->xl_len)
|
||||||
|
{
|
||||||
decoded->len++;
|
decoded->len++;
|
||||||
ptr += IndexTupleSize((IndexTuple) ptr);
|
ptr += IndexTupleSize((IndexTuple) ptr);
|
||||||
}
|
}
|
||||||
@ -138,7 +155,8 @@ decodeEntryUpdateRecord(EntryUpdateRecord *decoded, XLogRecord *record) {
|
|||||||
decoded->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * decoded->len);
|
decoded->itup = (IndexTuple *) palloc(sizeof(IndexTuple) * decoded->len);
|
||||||
|
|
||||||
ptr = begin + sizeof(gistxlogEntryUpdate) + addpath;
|
ptr = begin + sizeof(gistxlogEntryUpdate) + addpath;
|
||||||
while( ptr - begin < record->xl_len ) {
|
while (ptr - begin < record->xl_len)
|
||||||
|
{
|
||||||
decoded->itup[i] = (IndexTuple) ptr;
|
decoded->itup[i] = (IndexTuple) ptr;
|
||||||
ptr += IndexTupleSize(decoded->itup[i]);
|
ptr += IndexTupleSize(decoded->itup[i]);
|
||||||
i++;
|
i++;
|
||||||
@ -149,7 +167,8 @@ decodeEntryUpdateRecord(EntryUpdateRecord *decoded, XLogRecord *record) {
|
|||||||
* redo any page update (except page split)
|
* redo any page update (except page split)
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot)
|
||||||
|
{
|
||||||
EntryUpdateRecord xlrec;
|
EntryUpdateRecord xlrec;
|
||||||
Relation reln;
|
Relation reln;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
@ -165,23 +184,29 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
|||||||
elog(PANIC, "block %u unfound", xlrec.data->blkno);
|
elog(PANIC, "block %u unfound", xlrec.data->blkno);
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if ( isnewroot ) {
|
if (isnewroot)
|
||||||
if ( !PageIsNew((PageHeader) page) && XLByteLE(lsn, PageGetLSN(page)) ) {
|
{
|
||||||
|
if (!PageIsNew((PageHeader) page) && XLByteLE(lsn, PageGetLSN(page)))
|
||||||
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (PageIsNew((PageHeader) page))
|
if (PageIsNew((PageHeader) page))
|
||||||
elog(PANIC, "uninitialized page %u", xlrec.data->blkno);
|
elog(PANIC, "uninitialized page %u", xlrec.data->blkno);
|
||||||
if (XLByteLE(lsn, PageGetLSN(page))) {
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( xlrec.data->isemptypage ) {
|
if (xlrec.data->isemptypage)
|
||||||
|
{
|
||||||
while (!PageIsEmpty(page))
|
while (!PageIsEmpty(page))
|
||||||
PageIndexTupleDelete(page, FirstOffsetNumber);
|
PageIndexTupleDelete(page, FirstOffsetNumber);
|
||||||
|
|
||||||
@ -189,11 +214,15 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
|||||||
GistPageSetLeaf(page);
|
GistPageSetLeaf(page);
|
||||||
else
|
else
|
||||||
GistPageSetDeleted(page);
|
GistPageSetDeleted(page);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (isnewroot)
|
if (isnewroot)
|
||||||
GISTInitBuffer(buffer, 0);
|
GISTInitBuffer(buffer, 0);
|
||||||
else if ( xlrec.data->ntodelete ) {
|
else if (xlrec.data->ntodelete)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < xlrec.data->ntodelete; i++)
|
for (i = 0; i < xlrec.data->ntodelete; i++)
|
||||||
PageIndexTupleDelete(page, xlrec.todelete[i]);
|
PageIndexTupleDelete(page, xlrec.todelete[i]);
|
||||||
if (GistPageIsLeaf(page))
|
if (GistPageIsLeaf(page))
|
||||||
@ -204,8 +233,10 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
|||||||
if (xlrec.len > 0)
|
if (xlrec.len > 0)
|
||||||
gistfillbuffer(reln, page, xlrec.itup, xlrec.len, InvalidOffsetNumber);
|
gistfillbuffer(reln, page, xlrec.itup, xlrec.len, InvalidOffsetNumber);
|
||||||
|
|
||||||
/* special case: leafpage, nothing to insert, nothing to delete, then
|
/*
|
||||||
vacuum marks page */
|
* special case: leafpage, nothing to insert, nothing to delete, then
|
||||||
|
* vacuum marks page
|
||||||
|
*/
|
||||||
if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0)
|
if (GistPageIsLeaf(page) && xlrec.len == 0 && xlrec.data->ntodelete == 0)
|
||||||
GistClearTuplesDeleted(page);
|
GistClearTuplesDeleted(page);
|
||||||
}
|
}
|
||||||
@ -216,7 +247,8 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
|||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
|
|
||||||
if ( ItemPointerIsValid( &(xlrec.data->key) ) ) {
|
if (ItemPointerIsValid(&(xlrec.data->key)))
|
||||||
|
{
|
||||||
if (incomplete_inserts != NIL)
|
if (incomplete_inserts != NIL)
|
||||||
forgetIncompleteInsert(xlrec.data->node, xlrec.data->key);
|
forgetIncompleteInsert(xlrec.data->node, xlrec.data->key);
|
||||||
|
|
||||||
@ -228,15 +260,19 @@ gistRedoEntryUpdateRecord(XLogRecPtr lsn, XLogRecord *record, bool isnewroot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
decodePageSplitRecord(PageSplitRecord *decoded, XLogRecord *record) {
|
decodePageSplitRecord(PageSplitRecord *decoded, XLogRecord *record)
|
||||||
char *begin = XLogRecGetData(record), *ptr;
|
{
|
||||||
int j,i=0;
|
char *begin = XLogRecGetData(record),
|
||||||
|
*ptr;
|
||||||
|
int j,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
decoded->data = (gistxlogPageSplit *) begin;
|
decoded->data = (gistxlogPageSplit *) begin;
|
||||||
decoded->page = (NewPage *) palloc(sizeof(NewPage) * decoded->data->npage);
|
decoded->page = (NewPage *) palloc(sizeof(NewPage) * decoded->data->npage);
|
||||||
|
|
||||||
ptr = begin + sizeof(gistxlogPageSplit);
|
ptr = begin + sizeof(gistxlogPageSplit);
|
||||||
for(i=0;i<decoded->data->npage;i++) {
|
for (i = 0; i < decoded->data->npage; i++)
|
||||||
|
{
|
||||||
Assert(ptr - begin < record->xl_len);
|
Assert(ptr - begin < record->xl_len);
|
||||||
decoded->page[i].header = (gistxlogPage *) ptr;
|
decoded->page[i].header = (gistxlogPage *) ptr;
|
||||||
ptr += sizeof(gistxlogPage);
|
ptr += sizeof(gistxlogPage);
|
||||||
@ -244,7 +280,8 @@ decodePageSplitRecord(PageSplitRecord *decoded, XLogRecord *record) {
|
|||||||
decoded->page[i].itup = (IndexTuple *)
|
decoded->page[i].itup = (IndexTuple *)
|
||||||
palloc(sizeof(IndexTuple) * decoded->page[i].header->num);
|
palloc(sizeof(IndexTuple) * decoded->page[i].header->num);
|
||||||
j = 0;
|
j = 0;
|
||||||
while(j<decoded->page[i].header->num) {
|
while (j < decoded->page[i].header->num)
|
||||||
|
{
|
||||||
Assert(ptr - begin < record->xl_len);
|
Assert(ptr - begin < record->xl_len);
|
||||||
decoded->page[i].itup[j] = (IndexTuple) ptr;
|
decoded->page[i].itup[j] = (IndexTuple) ptr;
|
||||||
ptr += IndexTupleSize((IndexTuple) ptr);
|
ptr += IndexTupleSize((IndexTuple) ptr);
|
||||||
@ -254,7 +291,8 @@ decodePageSplitRecord(PageSplitRecord *decoded, XLogRecord *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record ) {
|
gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record)
|
||||||
|
{
|
||||||
PageSplitRecord xlrec;
|
PageSplitRecord xlrec;
|
||||||
Relation reln;
|
Relation reln;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
@ -280,7 +318,8 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record ) {
|
|||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
|
|
||||||
/* loop around all pages */
|
/* loop around all pages */
|
||||||
for(i=0;i<xlrec.data->npage;i++) {
|
for (i = 0; i < xlrec.data->npage; i++)
|
||||||
|
{
|
||||||
NewPage *newpage = xlrec.page + i;
|
NewPage *newpage = xlrec.page + i;
|
||||||
bool isorigpage = (xlrec.data->origblkno == newpage->header->blkno) ? true : false;
|
bool isorigpage = (xlrec.data->origblkno == newpage->header->blkno) ? true : false;
|
||||||
|
|
||||||
@ -289,7 +328,8 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record ) {
|
|||||||
elog(PANIC, "block %u unfound", newpage->header->blkno);
|
elog(PANIC, "block %u unfound", newpage->header->blkno);
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if (XLByteLE(lsn, PageGetLSN(page))) {
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
continue;
|
continue;
|
||||||
@ -307,7 +347,8 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record ) {
|
|||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ItemPointerIsValid( &(xlrec.data->key) ) ) {
|
if (ItemPointerIsValid(&(xlrec.data->key)))
|
||||||
|
{
|
||||||
if (incomplete_inserts != NIL)
|
if (incomplete_inserts != NIL)
|
||||||
forgetIncompleteInsert(xlrec.data->node, xlrec.data->key);
|
forgetIncompleteInsert(xlrec.data->node, xlrec.data->key);
|
||||||
|
|
||||||
@ -318,7 +359,8 @@ gistRedoPageSplitRecord(XLogRecPtr lsn, XLogRecord *record ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
|
gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record)
|
||||||
|
{
|
||||||
RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
|
RelFileNode *node = (RelFileNode *) XLogRecGetData(record);
|
||||||
Relation reln;
|
Relation reln;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
@ -332,7 +374,8 @@ gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
|
|||||||
elog(PANIC, "root block unfound");
|
elog(PANIC, "root block unfound");
|
||||||
page = (Page) BufferGetPage(buffer);
|
page = (Page) BufferGetPage(buffer);
|
||||||
|
|
||||||
if (!PageIsNew((PageHeader) page) && XLByteLE(lsn, PageGetLSN(page))) {
|
if (!PageIsNew((PageHeader) page) && XLByteLE(lsn, PageGetLSN(page)))
|
||||||
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return;
|
return;
|
||||||
@ -347,14 +390,17 @@ gistRedoCreateIndex(XLogRecPtr lsn, XLogRecord *record) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gistRedoCompleteInsert(XLogRecPtr lsn, XLogRecord *record) {
|
gistRedoCompleteInsert(XLogRecPtr lsn, XLogRecord *record)
|
||||||
char *begin = XLogRecGetData(record), *ptr;
|
{
|
||||||
|
char *begin = XLogRecGetData(record),
|
||||||
|
*ptr;
|
||||||
gistxlogInsertComplete *xlrec;
|
gistxlogInsertComplete *xlrec;
|
||||||
|
|
||||||
xlrec = (gistxlogInsertComplete *) begin;
|
xlrec = (gistxlogInsertComplete *) begin;
|
||||||
|
|
||||||
ptr = begin + sizeof(gistxlogInsertComplete);
|
ptr = begin + sizeof(gistxlogInsertComplete);
|
||||||
while( ptr - begin < record->xl_len ) {
|
while (ptr - begin < record->xl_len)
|
||||||
|
{
|
||||||
Assert(record->xl_len - (ptr - begin) >= sizeof(ItemPointerData));
|
Assert(record->xl_len - (ptr - begin) >= sizeof(ItemPointerData));
|
||||||
forgetIncompleteInsert(xlrec->node, *((ItemPointerData *) ptr));
|
forgetIncompleteInsert(xlrec->node, *((ItemPointerData *) ptr));
|
||||||
ptr += sizeof(ItemPointerData);
|
ptr += sizeof(ItemPointerData);
|
||||||
@ -367,8 +413,10 @@ gist_redo(XLogRecPtr lsn, XLogRecord *record)
|
|||||||
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
uint8 info = record->xl_info & ~XLR_INFO_MASK;
|
||||||
|
|
||||||
MemoryContext oldCxt;
|
MemoryContext oldCxt;
|
||||||
|
|
||||||
oldCxt = MemoryContextSwitchTo(opCtx);
|
oldCxt = MemoryContextSwitchTo(opCtx);
|
||||||
switch (info) {
|
switch (info)
|
||||||
|
{
|
||||||
case XLOG_GIST_ENTRY_UPDATE:
|
case XLOG_GIST_ENTRY_UPDATE:
|
||||||
case XLOG_GIST_ENTRY_DELETE:
|
case XLOG_GIST_ENTRY_DELETE:
|
||||||
gistRedoEntryUpdateRecord(lsn, record, false);
|
gistRedoEntryUpdateRecord(lsn, record, false);
|
||||||
@ -403,14 +451,16 @@ out_target(char *buf, RelFileNode node, ItemPointerData key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
out_gistxlogEntryUpdate(char *buf, gistxlogEntryUpdate *xlrec) {
|
out_gistxlogEntryUpdate(char *buf, gistxlogEntryUpdate *xlrec)
|
||||||
|
{
|
||||||
out_target(buf, xlrec->node, xlrec->key);
|
out_target(buf, xlrec->node, xlrec->key);
|
||||||
sprintf(buf + strlen(buf), "; block number %u",
|
sprintf(buf + strlen(buf), "; block number %u",
|
||||||
xlrec->blkno);
|
xlrec->blkno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
out_gistxlogPageSplit(char *buf, gistxlogPageSplit *xlrec) {
|
out_gistxlogPageSplit(char *buf, gistxlogPageSplit *xlrec)
|
||||||
|
{
|
||||||
strcat(buf, "page_split: ");
|
strcat(buf, "page_split: ");
|
||||||
out_target(buf, xlrec->node, xlrec->key);
|
out_target(buf, xlrec->node, xlrec->key);
|
||||||
sprintf(buf + strlen(buf), "; block number %u splits to %d pages",
|
sprintf(buf + strlen(buf), "; block number %u splits to %d pages",
|
||||||
@ -422,7 +472,8 @@ gist_desc(char *buf, uint8 xl_info, char *rec)
|
|||||||
{
|
{
|
||||||
uint8 info = xl_info & ~XLR_INFO_MASK;
|
uint8 info = xl_info & ~XLR_INFO_MASK;
|
||||||
|
|
||||||
switch (info) {
|
switch (info)
|
||||||
|
{
|
||||||
case XLOG_GIST_ENTRY_UPDATE:
|
case XLOG_GIST_ENTRY_UPDATE:
|
||||||
strcat(buf, "entry_update: ");
|
strcat(buf, "entry_update: ");
|
||||||
out_gistxlogEntryUpdate(buf, (gistxlogEntryUpdate *) rec);
|
out_gistxlogEntryUpdate(buf, (gistxlogEntryUpdate *) rec);
|
||||||
@ -456,9 +507,12 @@ gist_desc(char *buf, uint8 xl_info, char *rec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
IndexTuple
|
IndexTuple
|
||||||
gist_form_invalid_tuple(BlockNumber blkno) {
|
gist_form_invalid_tuple(BlockNumber blkno)
|
||||||
/* we don't alloc space for null's bitmap, this is invalid tuple,
|
{
|
||||||
be carefull in read and write code */
|
/*
|
||||||
|
* we don't alloc space for null's bitmap, this is invalid tuple, be
|
||||||
|
* carefull in read and write code
|
||||||
|
*/
|
||||||
Size size = IndexInfoFindDataOffset(0);
|
Size size = IndexInfoFindDataOffset(0);
|
||||||
IndexTuple tuple = (IndexTuple) palloc0(size);
|
IndexTuple tuple = (IndexTuple) palloc0(size);
|
||||||
|
|
||||||
@ -471,8 +525,10 @@ gist_form_invalid_tuple(BlockNumber blkno) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Buffer
|
static Buffer
|
||||||
gistXLogReadAndLockBuffer( Relation r, BlockNumber blkno ) {
|
gistXLogReadAndLockBuffer(Relation r, BlockNumber blkno)
|
||||||
|
{
|
||||||
Buffer buffer = XLogReadBuffer(false, r, blkno);
|
Buffer buffer = XLogReadBuffer(false, r, blkno);
|
||||||
|
|
||||||
if (!BufferIsValid(buffer))
|
if (!BufferIsValid(buffer))
|
||||||
elog(PANIC, "block %u unfound", blkno);
|
elog(PANIC, "block %u unfound", blkno);
|
||||||
if (PageIsNew((PageHeader) (BufferGetPage(buffer))))
|
if (PageIsNew((PageHeader) (BufferGetPage(buffer))))
|
||||||
@ -483,16 +539,20 @@ gistXLogReadAndLockBuffer( Relation r, BlockNumber blkno ) {
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gixtxlogFindPath( Relation index, gistIncompleteInsert *insert ) {
|
gixtxlogFindPath(Relation index, gistIncompleteInsert *insert)
|
||||||
|
{
|
||||||
GISTInsertStack *top;
|
GISTInsertStack *top;
|
||||||
|
|
||||||
insert->pathlen = 0;
|
insert->pathlen = 0;
|
||||||
insert->path = NULL;
|
insert->path = NULL;
|
||||||
|
|
||||||
if ( (top=gistFindPath(index, insert->origblkno, gistXLogReadAndLockBuffer)) != NULL ) {
|
if ((top = gistFindPath(index, insert->origblkno, gistXLogReadAndLockBuffer)) != NULL)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
GISTInsertStack *ptr = top;
|
GISTInsertStack *ptr = top;
|
||||||
while(ptr) {
|
|
||||||
|
while (ptr)
|
||||||
|
{
|
||||||
insert->pathlen++;
|
insert->pathlen++;
|
||||||
ptr = ptr->parent;
|
ptr = ptr->parent;
|
||||||
}
|
}
|
||||||
@ -501,12 +561,14 @@ gixtxlogFindPath( Relation index, gistIncompleteInsert *insert ) {
|
|||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
ptr = top;
|
ptr = top;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
insert->path[i] = ptr->blkno;
|
insert->path[i] = ptr->blkno;
|
||||||
i++;
|
i++;
|
||||||
ptr = ptr->parent;
|
ptr = ptr->parent;
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
elog(LOG, "lost parent for block %u", insert->origblkno);
|
elog(LOG, "lost parent for block %u", insert->origblkno);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -520,27 +582,34 @@ gixtxlogFindPath( Relation index, gistIncompleteInsert *insert ) {
|
|||||||
* lesser than stored lsn then changes in parent doesn't do yet.
|
* lesser than stored lsn then changes in parent doesn't do yet.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
gistContinueInsert(gistIncompleteInsert *insert) {
|
gistContinueInsert(gistIncompleteInsert *insert)
|
||||||
|
{
|
||||||
IndexTuple *itup;
|
IndexTuple *itup;
|
||||||
int i, lenitup;
|
int i,
|
||||||
|
lenitup;
|
||||||
Relation index;
|
Relation index;
|
||||||
|
|
||||||
index = XLogOpenRelation(insert->node);
|
index = XLogOpenRelation(insert->node);
|
||||||
if (!RelationIsValid(index))
|
if (!RelationIsValid(index))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* needed vector itup never will be more than initial lenblkno+2,
|
/*
|
||||||
because during this processing Indextuple can be only smaller */
|
* needed vector itup never will be more than initial lenblkno+2, because
|
||||||
|
* during this processing Indextuple can be only smaller
|
||||||
|
*/
|
||||||
lenitup = insert->lenblk;
|
lenitup = insert->lenblk;
|
||||||
itup = (IndexTuple *) palloc(sizeof(IndexTuple) * (lenitup + 2 /* guarantee root split */ ));
|
itup = (IndexTuple *) palloc(sizeof(IndexTuple) * (lenitup + 2 /* guarantee root split */ ));
|
||||||
|
|
||||||
for (i = 0; i < insert->lenblk; i++)
|
for (i = 0; i < insert->lenblk; i++)
|
||||||
itup[i] = gist_form_invalid_tuple(insert->blkno[i]);
|
itup[i] = gist_form_invalid_tuple(insert->blkno[i]);
|
||||||
|
|
||||||
if ( insert->origblkno==GIST_ROOT_BLKNO ) {
|
if (insert->origblkno == GIST_ROOT_BLKNO)
|
||||||
/*it was split root, so we should only make new root.
|
{
|
||||||
it can't be simple insert into root, look at call
|
/*
|
||||||
pushIncompleteInsert in gistRedoPageSplitRecord */
|
* it was split root, so we should only make new root. it can't be
|
||||||
|
* simple insert into root, look at call pushIncompleteInsert in
|
||||||
|
* gistRedoPageSplitRecord
|
||||||
|
*/
|
||||||
Buffer buffer = XLogReadBuffer(true, index, GIST_ROOT_BLKNO);
|
Buffer buffer = XLogReadBuffer(true, index, GIST_ROOT_BLKNO);
|
||||||
Page page;
|
Page page;
|
||||||
|
|
||||||
@ -548,7 +617,8 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
elog(PANIC, "root block unfound");
|
elog(PANIC, "root block unfound");
|
||||||
|
|
||||||
page = BufferGetPage(buffer);
|
page = BufferGetPage(buffer);
|
||||||
if (XLByteLE(insert->lsn, PageGetLSN(page))) {
|
if (XLByteLE(insert->lsn, PageGetLSN(page)))
|
||||||
|
{
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffer);
|
ReleaseBuffer(buffer);
|
||||||
return;
|
return;
|
||||||
@ -561,7 +631,9 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
PageSetTLI(page, ThisTimeLineID);
|
PageSetTLI(page, ThisTimeLineID);
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Buffer *buffers;
|
Buffer *buffers;
|
||||||
Page *pages;
|
Page *pages;
|
||||||
int numbuffer;
|
int numbuffer;
|
||||||
@ -574,8 +646,12 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
buffers = (Buffer *) palloc(sizeof(Buffer) * (insert->lenblk + 2 /* guarantee root split */ ));
|
buffers = (Buffer *) palloc(sizeof(Buffer) * (insert->lenblk + 2 /* guarantee root split */ ));
|
||||||
pages = (Page *) palloc(sizeof(Page) * (insert->lenblk + 2 /* guarantee root split */ ));
|
pages = (Page *) palloc(sizeof(Page) * (insert->lenblk + 2 /* guarantee root split */ ));
|
||||||
|
|
||||||
for(i=0;i<insert->pathlen;i++) {
|
for (i = 0; i < insert->pathlen; i++)
|
||||||
int j, k, pituplen=0, childfound=0;
|
{
|
||||||
|
int j,
|
||||||
|
k,
|
||||||
|
pituplen = 0,
|
||||||
|
childfound = 0;
|
||||||
|
|
||||||
numbuffer = 1;
|
numbuffer = 1;
|
||||||
buffers[numbuffer - 1] = XLogReadBuffer(false, index, insert->path[i]);
|
buffers[numbuffer - 1] = XLogReadBuffer(false, index, insert->path[i]);
|
||||||
@ -585,7 +661,8 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
if (PageIsNew((PageHeader) (pages[numbuffer - 1])))
|
if (PageIsNew((PageHeader) (pages[numbuffer - 1])))
|
||||||
elog(PANIC, "uninitialized page %u", insert->path[i]);
|
elog(PANIC, "uninitialized page %u", insert->path[i]);
|
||||||
|
|
||||||
if (XLByteLE(insert->lsn, PageGetLSN(pages[numbuffer-1]))) {
|
if (XLByteLE(insert->lsn, PageGetLSN(pages[numbuffer - 1])))
|
||||||
|
{
|
||||||
LockBuffer(buffers[numbuffer - 1], BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffers[numbuffer - 1], BUFFER_LOCK_UNLOCK);
|
||||||
ReleaseBuffer(buffers[numbuffer - 1]);
|
ReleaseBuffer(buffers[numbuffer - 1]);
|
||||||
return;
|
return;
|
||||||
@ -594,7 +671,8 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
pituplen = PageGetMaxOffsetNumber(pages[numbuffer - 1]);
|
pituplen = PageGetMaxOffsetNumber(pages[numbuffer - 1]);
|
||||||
|
|
||||||
/* remove old IndexTuples */
|
/* remove old IndexTuples */
|
||||||
for(j=0;j<pituplen && childfound<lenitup;j++) {
|
for (j = 0; j < pituplen && childfound < lenitup; j++)
|
||||||
|
{
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
ItemId iid = PageGetItemId(pages[numbuffer - 1], j + FirstOffsetNumber);
|
ItemId iid = PageGetItemId(pages[numbuffer - 1], j + FirstOffsetNumber);
|
||||||
IndexTuple idxtup = (IndexTuple) PageGetItem(pages[numbuffer - 1], iid);
|
IndexTuple idxtup = (IndexTuple) PageGetItem(pages[numbuffer - 1], iid);
|
||||||
@ -602,15 +680,18 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
blkno = ItemPointerGetBlockNumber(&(idxtup->t_tid));
|
blkno = ItemPointerGetBlockNumber(&(idxtup->t_tid));
|
||||||
|
|
||||||
for (k = 0; k < lenitup; k++)
|
for (k = 0; k < lenitup; k++)
|
||||||
if ( ItemPointerGetBlockNumber( &(itup[k]->t_tid) ) == blkno ) {
|
if (ItemPointerGetBlockNumber(&(itup[k]->t_tid)) == blkno)
|
||||||
|
{
|
||||||
PageIndexTupleDelete(pages[numbuffer - 1], j + FirstOffsetNumber);
|
PageIndexTupleDelete(pages[numbuffer - 1], j + FirstOffsetNumber);
|
||||||
j--; pituplen--;
|
j--;
|
||||||
|
pituplen--;
|
||||||
childfound++;
|
childfound++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( gistnospace(pages[numbuffer-1], itup, lenitup) ) {
|
if (gistnospace(pages[numbuffer - 1], itup, lenitup))
|
||||||
|
{
|
||||||
/* no space left on page, so we should split */
|
/* no space left on page, so we should split */
|
||||||
buffers[numbuffer] = XLogReadBuffer(true, index, P_NEW);
|
buffers[numbuffer] = XLogReadBuffer(true, index, P_NEW);
|
||||||
if (!BufferIsValid(buffers[numbuffer]))
|
if (!BufferIsValid(buffers[numbuffer]))
|
||||||
@ -620,10 +701,14 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
gistfillbuffer(index, pages[numbuffer], itup, lenitup, FirstOffsetNumber);
|
gistfillbuffer(index, pages[numbuffer], itup, lenitup, FirstOffsetNumber);
|
||||||
numbuffer++;
|
numbuffer++;
|
||||||
|
|
||||||
if ( BufferGetBlockNumber( buffers[0] ) == GIST_ROOT_BLKNO ) {
|
if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
|
||||||
|
{
|
||||||
IndexTuple *parentitup;
|
IndexTuple *parentitup;
|
||||||
|
|
||||||
/* we split root, just copy tuples from old root to new page */
|
/*
|
||||||
|
* we split root, just copy tuples from old root to new
|
||||||
|
* page
|
||||||
|
*/
|
||||||
parentitup = gistextractbuffer(buffers[numbuffer - 1], &pituplen);
|
parentitup = gistextractbuffer(buffers[numbuffer - 1], &pituplen);
|
||||||
|
|
||||||
/* sanity check */
|
/* sanity check */
|
||||||
@ -642,8 +727,10 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
|
|
||||||
/* fill root page */
|
/* fill root page */
|
||||||
GISTInitBuffer(buffers[0], 0);
|
GISTInitBuffer(buffers[0], 0);
|
||||||
for(j=1;j<numbuffer;j++) {
|
for (j = 1; j < numbuffer; j++)
|
||||||
|
{
|
||||||
IndexTuple tuple = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
IndexTuple tuple = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
||||||
|
|
||||||
if (PageAddItem(pages[0],
|
if (PageAddItem(pages[0],
|
||||||
(Item) tuple,
|
(Item) tuple,
|
||||||
IndexTupleSize(tuple),
|
IndexTupleSize(tuple),
|
||||||
@ -653,11 +740,13 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
RelationGetRelationName(index));
|
RelationGetRelationName(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
gistfillbuffer(index, pages[numbuffer - 1], itup, lenitup, InvalidOffsetNumber);
|
gistfillbuffer(index, pages[numbuffer - 1], itup, lenitup, InvalidOffsetNumber);
|
||||||
|
|
||||||
lenitup = numbuffer;
|
lenitup = numbuffer;
|
||||||
for(j=0;j<numbuffer;j++) {
|
for (j = 0; j < numbuffer; j++)
|
||||||
|
{
|
||||||
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
|
||||||
PageSetLSN(pages[j], insert->lsn);
|
PageSetLSN(pages[j], insert->lsn);
|
||||||
PageSetTLI(pages[j], ThisTimeLineID);
|
PageSetTLI(pages[j], ThisTimeLineID);
|
||||||
@ -675,7 +764,8 @@ gistContinueInsert(gistIncompleteInsert *insert) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gist_xlog_startup(void) {
|
gist_xlog_startup(void)
|
||||||
|
{
|
||||||
incomplete_inserts = NIL;
|
incomplete_inserts = NIL;
|
||||||
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
|
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
"GiST recovery temporary context",
|
"GiST recovery temporary context",
|
||||||
@ -686,7 +776,8 @@ gist_xlog_startup(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
gist_xlog_cleanup(void) {
|
gist_xlog_cleanup(void)
|
||||||
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
List *reverse = NIL;
|
List *reverse = NIL;
|
||||||
MemoryContext oldCxt = MemoryContextSwitchTo(insertCtx);
|
MemoryContext oldCxt = MemoryContextSwitchTo(insertCtx);
|
||||||
@ -697,8 +788,10 @@ gist_xlog_cleanup(void) {
|
|||||||
reverse = lappend(reverse, lfirst(l));
|
reverse = lappend(reverse, lfirst(l));
|
||||||
|
|
||||||
MemoryContextSwitchTo(opCtx);
|
MemoryContextSwitchTo(opCtx);
|
||||||
foreach(l, reverse) {
|
foreach(l, reverse)
|
||||||
|
{
|
||||||
gistIncompleteInsert *insert = (gistIncompleteInsert *) lfirst(l);
|
gistIncompleteInsert *insert = (gistIncompleteInsert *) lfirst(l);
|
||||||
|
|
||||||
gistContinueInsert(insert);
|
gistContinueInsert(insert);
|
||||||
MemoryContextReset(opCtx);
|
MemoryContextReset(opCtx);
|
||||||
}
|
}
|
||||||
@ -711,15 +804,18 @@ gist_xlog_cleanup(void) {
|
|||||||
|
|
||||||
XLogRecData *
|
XLogRecData *
|
||||||
formSplitRdata(RelFileNode node, BlockNumber blkno,
|
formSplitRdata(RelFileNode node, BlockNumber blkno,
|
||||||
ItemPointer key, SplitedPageLayout *dist ) {
|
ItemPointer key, SplitedPageLayout *dist)
|
||||||
|
{
|
||||||
|
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
gistxlogPageSplit *xlrec = (gistxlogPageSplit *) palloc(sizeof(gistxlogPageSplit));
|
gistxlogPageSplit *xlrec = (gistxlogPageSplit *) palloc(sizeof(gistxlogPageSplit));
|
||||||
SplitedPageLayout *ptr;
|
SplitedPageLayout *ptr;
|
||||||
int npage = 0, cur=1;
|
int npage = 0,
|
||||||
|
cur = 1;
|
||||||
|
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while( ptr ) {
|
while (ptr)
|
||||||
|
{
|
||||||
npage++;
|
npage++;
|
||||||
ptr = ptr->next;
|
ptr = ptr->next;
|
||||||
}
|
}
|
||||||
@ -740,7 +836,8 @@ formSplitRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
rdata[0].next = NULL;
|
rdata[0].next = NULL;
|
||||||
|
|
||||||
ptr = dist;
|
ptr = dist;
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
rdata[cur].buffer = InvalidBuffer;
|
rdata[cur].buffer = InvalidBuffer;
|
||||||
rdata[cur].data = (char *) &(ptr->block);
|
rdata[cur].data = (char *) &(ptr->block);
|
||||||
rdata[cur].len = sizeof(gistxlogPage);
|
rdata[cur].len = sizeof(gistxlogPage);
|
||||||
@ -763,7 +860,8 @@ formSplitRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
XLogRecData *
|
XLogRecData *
|
||||||
formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
||||||
OffsetNumber *todelete, int ntodelete, bool emptypage,
|
OffsetNumber *todelete, int ntodelete, bool emptypage,
|
||||||
IndexTuple *itup, int ituplen, ItemPointer key ) {
|
IndexTuple *itup, int ituplen, ItemPointer key)
|
||||||
|
{
|
||||||
XLogRecData *rdata;
|
XLogRecData *rdata;
|
||||||
gistxlogEntryUpdate *xlrec = (gistxlogEntryUpdate *) palloc(sizeof(gistxlogEntryUpdate));
|
gistxlogEntryUpdate *xlrec = (gistxlogEntryUpdate *) palloc(sizeof(gistxlogEntryUpdate));
|
||||||
|
|
||||||
@ -774,7 +872,8 @@ formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
else
|
else
|
||||||
ItemPointerSetInvalid(&(xlrec->key));
|
ItemPointerSetInvalid(&(xlrec->key));
|
||||||
|
|
||||||
if ( emptypage ) {
|
if (emptypage)
|
||||||
|
{
|
||||||
xlrec->isemptypage = true;
|
xlrec->isemptypage = true;
|
||||||
xlrec->ntodelete = 0;
|
xlrec->ntodelete = 0;
|
||||||
|
|
||||||
@ -783,8 +882,11 @@ formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
rdata->data = (char *) xlrec;
|
rdata->data = (char *) xlrec;
|
||||||
rdata->len = sizeof(gistxlogEntryUpdate);
|
rdata->len = sizeof(gistxlogEntryUpdate);
|
||||||
rdata->next = NULL;
|
rdata->next = NULL;
|
||||||
} else {
|
}
|
||||||
int cur=1,i;
|
else
|
||||||
|
{
|
||||||
|
int cur = 1,
|
||||||
|
i;
|
||||||
|
|
||||||
xlrec->isemptypage = false;
|
xlrec->isemptypage = false;
|
||||||
xlrec->ntodelete = ntodelete;
|
xlrec->ntodelete = ntodelete;
|
||||||
@ -796,7 +898,8 @@ formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
rdata->len = sizeof(gistxlogEntryUpdate);
|
rdata->len = sizeof(gistxlogEntryUpdate);
|
||||||
rdata->next = NULL;
|
rdata->next = NULL;
|
||||||
|
|
||||||
if ( ntodelete ) {
|
if (ntodelete)
|
||||||
|
{
|
||||||
rdata[cur - 1].next = &(rdata[cur]);
|
rdata[cur - 1].next = &(rdata[cur]);
|
||||||
rdata[cur].buffer = InvalidBuffer;
|
rdata[cur].buffer = InvalidBuffer;
|
||||||
rdata[cur].data = (char *) todelete;
|
rdata[cur].data = (char *) todelete;
|
||||||
@ -806,7 +909,8 @@ formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* new tuples */
|
/* new tuples */
|
||||||
for(i=0;i<ituplen;i++) {
|
for (i = 0; i < ituplen; i++)
|
||||||
|
{
|
||||||
rdata[cur].buffer = InvalidBuffer;
|
rdata[cur].buffer = InvalidBuffer;
|
||||||
rdata[cur].data = (char *) (itup[i]);
|
rdata[cur].data = (char *) (itup[i]);
|
||||||
rdata[cur].len = IndexTupleSize(itup[i]);
|
rdata[cur].len = IndexTupleSize(itup[i]);
|
||||||
@ -820,7 +924,8 @@ formUpdateRdata(RelFileNode node, BlockNumber blkno,
|
|||||||
}
|
}
|
||||||
|
|
||||||
XLogRecPtr
|
XLogRecPtr
|
||||||
gistxlogInsertCompletion(RelFileNode node, ItemPointerData *keys, int len) {
|
gistxlogInsertCompletion(RelFileNode node, ItemPointerData *keys, int len)
|
||||||
|
{
|
||||||
gistxlogInsertComplete xlrec;
|
gistxlogInsertComplete xlrec;
|
||||||
XLogRecData rdata[2];
|
XLogRecData rdata[2];
|
||||||
XLogRecPtr recptr;
|
XLogRecPtr recptr;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user