1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Fix bundle bugs of GIN:

- Fix possible deadlock between UPDATE and VACUUM queries. Bug never was
  observed in 8.2, but it still exist there. HEAD is more sensitive to
  bug after recent "ring" of buffer improvements.
- Fix WAL creation: if parent page is stored as is after split then
  incomplete split isn't removed during replay. This happens rather rare, only
  on large tables with a lot of updates/inserts.
- Fix WAL replay: there was wrong test of XLR_BKP_BLOCK_* for left
  page after deletion of page. That causes wrong rightlink field: it pointed
  to deleted page.
- add checking of match of clearing incomplete split
- cleanup incomplete split list after proceeding

All of this chages doesn't change on-disk storage, so backpatch...
But second point may be an issue for replaying logs from previous version.
This commit is contained in:
Teodor Sigaev
2007-06-04 15:56:28 +00:00
parent aae5403278
commit 853d1c3103
5 changed files with 146 additions and 54 deletions

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.7 2007/02/01 04:16:08 neilc Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.8 2007/06/04 15:56:28 teodor Exp $
*-------------------------------------------------------------------------
*/
@ -17,22 +17,71 @@
#include "catalog/index.h"
#include "utils/memutils.h"
static OffsetNumber
findItemInPage(Page page, ItemPointer item, OffsetNumber off)
static bool
findItemInPage(Page page, ItemPointer item, OffsetNumber *off)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
int res;
for (; off <= maxoff; off++)
{
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, off));
Assert(res >= 0);
if ( GinPageGetOpaque(page)->flags & GIN_DELETED )
/* page was deleted by concurrent vacuum */
return false;
if (res == 0)
return off;
if ( *off > maxoff || *off == InvalidOffsetNumber )
res = -1;
else
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
if ( res == 0 )
{
/* page isn't changed */
return true;
}
else if ( res > 0 )
{
/*
* some items was added before our position, look further to find
* it or first greater
*/
(*off)++;
for (; *off <= maxoff; (*off)++)
{
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
if (res == 0)
return true;
if (res < 0)
{
(*off)--;
return true;
}
}
}
else
{
/*
* some items was deleted before our position, look from begining
* to find it or first greater
*/
for(*off = FirstOffsetNumber; *off<= maxoff; (*off)++)
{
res = compareItemPointers(item, (ItemPointer) GinDataPageGetItem(page, *off));
if ( res == 0 )
return true;
if (res < 0)
{
(*off)--;
return true;
}
}
}
return InvalidOffsetNumber;
return false;
}
/*
@ -111,7 +160,7 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firs
}
else if (entry->buffer != InvalidBuffer)
{
/* we should find place were we was stopped */
/* we should find place where we was stopped */
BlockNumber blkno;
Page page;
@ -125,7 +174,7 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firs
page = BufferGetPage(entry->buffer);
/* try to find curItem in current buffer */
if ((entry->offset = findItemInPage(page, &entry->curItem, entry->offset)) != InvalidOffsetNumber)
if ( findItemInPage(page, &entry->curItem, &entry->offset) )
return;
/* walk to right */
@ -136,11 +185,15 @@ startScanEntry(Relation index, GinState *ginstate, GinScanEntry entry, bool firs
LockBuffer(entry->buffer, GIN_SHARE);
page = BufferGetPage(entry->buffer);
if ((entry->offset = findItemInPage(page, &entry->curItem, FirstOffsetNumber)) != InvalidOffsetNumber)
entry->offset = InvalidOffsetNumber;
if ( findItemInPage(page, &entry->curItem, &entry->offset) )
return;
}
elog(ERROR, "Logic error: lost previously founded ItemId");
/*
* curItem and any greated items was deleted by concurrent vacuum,
* so we finished scan with currrent entry
*/
}
}