]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix bug with page deletion. If inner page is removed and it tries to
authorTeodor Sigaev <teodor@sigaev.ru>
Thu, 30 Nov 2006 16:22:32 +0000 (16:22 +0000)
committerTeodor Sigaev <teodor@sigaev.ru>
Thu, 30 Nov 2006 16:22:32 +0000 (16:22 +0000)
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...

src/backend/access/gin/ginvacuum.c

index c3415ffe44ff2f30c57943a75d05aef215f1abb1..225dbc6047787e6a1239d8bbc097852e5adb18e0 100644 (file)
@@ -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();