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