From ef148d6b8592e19cfeb9e2bee4255ddadc2ae3dd Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Thu, 30 Nov 2006 16:22:32 +0000 Subject: [PATCH] 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 Suppose, we need rc2 before release... --- src/backend/access/gin/ginvacuum.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index c3415ffe44..225dbc6047 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(); -- 2.40.0