aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTeodor Sigaev <teodor@sigaev.ru>2006-11-30 16:22:32 +0000
committerTeodor Sigaev <teodor@sigaev.ru>2006-11-30 16:22:32 +0000
commitef148d6b8592e19cfeb9e2bee4255ddadc2ae3dd (patch)
treee0a802a58aba4201b0fb997420ceab8011ebdac1
parentcf06c2e5d43bbc96ce31cd37125d17125c6c2f9a (diff)
downloadpostgresql-ef148d6b8592e19cfeb9e2bee4255ddadc2ae3dd.tar.gz
postgresql-ef148d6b8592e19cfeb9e2bee4255ddadc2ae3dd.zip
Fix bug with page deletion. If inner page is removed and it tries to
remove page on next level linked from next inner page, ginScanToDelete() wrongly sets parent page. Bug reveals when many item pointers from index was deleted ( several hundred thousands). Bug is discovered by hubert depesz lubaczewski <depesz@gmail.com> Suppose, we need rc2 before release...
-rw-r--r--src/backend/access/gin/ginvacuum.c22
1 files changed, 15 insertions, 7 deletions
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index c3415ffe44f..225dbc60477 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.8 2006/11/12 06:55:53 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginvacuum.c,v 1.9 2006/11/30 16:22:32 teodor Exp $
*-------------------------------------------------------------------------
*/
@@ -265,6 +265,12 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
}
parentPage = BufferGetPage(pBuffer);
+#ifdef USE_ASSERT_CHECKING
+ do {
+ PostingItem *tod=(PostingItem *) GinDataPageGetItem(parentPage, myoff);
+ Assert( PostingItemGetBlockNumber(tod) == deleteBlkno );
+ } while(0);
+#endif
PageDeletePostingItem(parentPage, myoff);
page = BufferGetPage(dBuffer);
@@ -351,7 +357,8 @@ typedef struct DataPageDeleteStack
struct DataPageDeleteStack *child;
struct DataPageDeleteStack *parent;
- BlockNumber blkno;
+ BlockNumber blkno; /* current block number */
+ BlockNumber leftBlkno; /* rightest non-deleted page on left */
bool isRoot;
} DataPageDeleteStack;
@@ -377,7 +384,7 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
me = (DataPageDeleteStack *) palloc0(sizeof(DataPageDeleteStack));
me->parent = parent;
parent->child = me;
- me->blkno = InvalidBlockNumber;
+ me->leftBlkno = InvalidBlockNumber;
}
else
me = parent->child;
@@ -392,6 +399,7 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
{
OffsetNumber i;
+ me->blkno = blkno;
for (i = FirstOffsetNumber; i <= GinPageGetOpaque(page)->maxoff; i++)
{
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, i);
@@ -403,13 +411,13 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
{
- if (!(me->blkno == InvalidBlockNumber && GinPageRightMost(page)))
+ if (!(me->leftBlkno == 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);
+ ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);
meDelete = TRUE;
}
}
@@ -418,7 +426,7 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
ReleaseBuffer(buffer);
if (!meDelete)
- me->blkno = blkno;
+ me->leftBlkno = blkno;
return meDelete;
}
@@ -438,7 +446,7 @@ ginVacuumPostingTree(GinVacuumState *gvs, BlockNumber rootBlkno)
}
memset(&root, 0, sizeof(DataPageDeleteStack));
- root.blkno = rootBlkno;
+ root.leftBlkno = InvalidBlockNumber;
root.isRoot = TRUE;
vacuum_delay_point();