Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit1dcf6fd

Browse files
committed
Fix possible duplicate tuples while GiST scan. Now page is processed
at once and ItemPointers are collected in memory.Remove tuple's killing by killtuple() if tuple was moved to anotherpage - it could produce unaceptable overhead.Backpatch up to 8.1 because the bug was introduced by GiST's concurrency support.
1 parent42d313f commit1dcf6fd

File tree

3 files changed

+128
-91
lines changed

3 files changed

+128
-91
lines changed

‎src/backend/access/gist/gistget.c

Lines changed: 101 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.74 2008/06/19 00:46:03 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.75 2008/08/23 10:37:24 teodor Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -32,63 +32,39 @@ static bool gistindex_keytest(IndexTuple tuple, IndexScanDesc scan,
3232
staticvoid
3333
killtuple(Relationr,GISTScanOpaqueso,ItemPointeriptr)
3434
{
35-
Bufferbuffer=so->curbuf;
36-
37-
for (;;)
38-
{
39-
Pagep;
40-
BlockNumberblkno;
41-
OffsetNumberoffset,
42-
maxoff;
43-
44-
LockBuffer(buffer,GIST_SHARE);
45-
gistcheckpage(r,buffer);
46-
p= (Page)BufferGetPage(buffer);
35+
Pagep;
36+
OffsetNumberoffset;
4737

48-
if (buffer==so->curbuf&&XLByteEQ(so->stack->lsn,PageGetLSN(p)))
49-
{
50-
/* page unchanged, so all is simple */
51-
offset=ItemPointerGetOffsetNumber(iptr);
52-
ItemIdMarkDead(PageGetItemId(p,offset));
53-
SetBufferCommitInfoNeedsSave(buffer);
54-
LockBuffer(buffer,GIST_UNLOCK);
55-
break;
56-
}
38+
LockBuffer(so->curbuf,GIST_SHARE);
39+
gistcheckpage(r,so->curbuf);
40+
p= (Page)BufferGetPage(so->curbuf);
5741

58-
maxoff=PageGetMaxOffsetNumber(p);
42+
if (XLByteEQ(so->stack->lsn,PageGetLSN(p)))
43+
{
44+
/* page unchanged, so all is simple */
45+
offset=ItemPointerGetOffsetNumber(iptr);
46+
ItemIdMarkDead(PageGetItemId(p,offset));
47+
SetBufferCommitInfoNeedsSave(so->curbuf);
48+
}
49+
else
50+
{
51+
OffsetNumbermaxoff=PageGetMaxOffsetNumber(p);
5952

6053
for (offset=FirstOffsetNumber;offset <=maxoff;offset=OffsetNumberNext(offset))
6154
{
62-
IndexTupleituple= (IndexTuple)PageGetItem(p,PageGetItemId(p,offset));
55+
IndexTupleituple= (IndexTuple)PageGetItem(p,PageGetItemId(p,offset));
6356

6457
if (ItemPointerEquals(&(ituple->t_tid),iptr))
6558
{
6659
/* found */
6760
ItemIdMarkDead(PageGetItemId(p,offset));
68-
SetBufferCommitInfoNeedsSave(buffer);
69-
LockBuffer(buffer,GIST_UNLOCK);
70-
if (buffer!=so->curbuf)
71-
ReleaseBuffer(buffer);
72-
return;
61+
SetBufferCommitInfoNeedsSave(so->curbuf);
62+
break;
7363
}
7464
}
75-
76-
/* follow right link */
77-
78-
/*
79-
* ??? is it good? if tuple dropped by concurrent vacuum, we will read
80-
* all leaf pages...
81-
*/
82-
blkno=GistPageGetOpaque(p)->rightlink;
83-
LockBuffer(buffer,GIST_UNLOCK);
84-
if (buffer!=so->curbuf)
85-
ReleaseBuffer(buffer);
86-
87-
if (blkno==InvalidBlockNumber)
88-
/* can't found, dropped by somebody else */
89-
return;
90-
buffer=ReadBuffer(r,blkno);
9165
}
66+
67+
LockBuffer(so->curbuf,GIST_UNLOCK);
9268
}
9369

9470
/*
@@ -154,7 +130,6 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
154130
GISTSearchStack*stk;
155131
IndexTupleit;
156132
GISTPageOpaqueopaque;
157-
boolresetoffset= false;
158133
int64ntids=0;
159134

160135
so= (GISTScanOpaque)scan->opaque;
@@ -179,6 +154,50 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
179154
return0;
180155
}
181156

157+
/*
158+
* check stored pointers from last visit
159+
*/
160+
if (so->nPageData>0 )
161+
{
162+
/*
163+
* gistgetmulti never should go here
164+
*/
165+
Assert(tbm==NULL );
166+
167+
if (so->curPageData<so->nPageData )
168+
{
169+
/*
170+
* pageData is already ordered for scan's direction
171+
*/
172+
scan->xs_ctup.t_self=so->pageData[so->curPageData ].iptr;
173+
scan->xs_recheck=so->pageData[so->curPageData ].recheck;
174+
so->curPageData++;
175+
176+
return1;
177+
}
178+
else
179+
{
180+
/*
181+
* Go to the next page
182+
*/
183+
stk=so->stack->next;
184+
pfree(so->stack);
185+
so->stack=stk;
186+
187+
/* If we're out of stack entries, we're done */
188+
if (so->stack==NULL)
189+
{
190+
ReleaseBuffer(so->curbuf);
191+
so->curbuf=InvalidBuffer;
192+
return0;
193+
}
194+
195+
so->curbuf=ReleaseAndReadBuffer(so->curbuf,
196+
scan->indexRelation,
197+
stk->block);
198+
}
199+
}
200+
182201
for (;;)
183202
{
184203
CHECK_FOR_INTERRUPTS();
@@ -189,30 +208,25 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
189208
gistcheckpage(scan->indexRelation,so->curbuf);
190209
p=BufferGetPage(so->curbuf);
191210
opaque=GistPageGetOpaque(p);
192-
resetoffset= false;
193211

194-
if (XLogRecPtrIsInvalid(so->stack->lsn)|| !XLByteEQ(so->stack->lsn,PageGetLSN(p)))
195-
{
196-
/* first visit or page changed from last visit, reset offset */
197-
so->stack->lsn=PageGetLSN(p);
198-
resetoffset= true;
199-
200-
/* check page split, occured from last visit or visit to parent */
201-
if (!XLogRecPtrIsInvalid(so->stack->parentlsn)&&
202-
XLByteLT(so->stack->parentlsn,opaque->nsn)&&
203-
opaque->rightlink!=InvalidBlockNumber/* sanity check */&&
204-
(so->stack->next==NULL||so->stack->next->block!=opaque->rightlink)/* check if already
205-
added */ )
206-
{
207-
/* detect page split, follow right link to add pages */
212+
/* remember lsn to identify page changed for tuple's killing */
213+
so->stack->lsn=PageGetLSN(p);
208214

209-
stk= (GISTSearchStack*)palloc(sizeof(GISTSearchStack));
210-
stk->next=so->stack->next;
211-
stk->block=opaque->rightlink;
212-
stk->parentlsn=so->stack->parentlsn;
213-
memset(&(stk->lsn),0,sizeof(GistNSN));
214-
so->stack->next=stk;
215-
}
215+
/* check page split, occured since visit to parent */
216+
if (!XLogRecPtrIsInvalid(so->stack->parentlsn)&&
217+
XLByteLT(so->stack->parentlsn,opaque->nsn)&&
218+
opaque->rightlink!=InvalidBlockNumber/* sanity check */&&
219+
(so->stack->next==NULL||so->stack->next->block!=opaque->rightlink)/* check if already
220+
added */ )
221+
{
222+
/* detect page split, follow right link to add pages */
223+
224+
stk= (GISTSearchStack*)palloc(sizeof(GISTSearchStack));
225+
stk->next=so->stack->next;
226+
stk->block=opaque->rightlink;
227+
stk->parentlsn=so->stack->parentlsn;
228+
memset(&(stk->lsn),0,sizeof(GistNSN));
229+
so->stack->next=stk;
216230
}
217231

218232
/* if page is empty, then just skip it */
@@ -235,32 +249,32 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
235249
continue;
236250
}
237251

238-
if (!GistPageIsLeaf(p)||resetoffset||
239-
!ItemPointerIsValid(&so->curpos))
240-
{
241-
if (ScanDirectionIsBackward(dir))
242-
n=PageGetMaxOffsetNumber(p);
243-
else
244-
n=FirstOffsetNumber;
245-
}
252+
if (ScanDirectionIsBackward(dir))
253+
n=PageGetMaxOffsetNumber(p);
246254
else
247-
{
248-
n=ItemPointerGetOffsetNumber(&(so->curpos));
249-
250-
if (ScanDirectionIsBackward(dir))
251-
n=OffsetNumberPrev(n);
252-
else
253-
n=OffsetNumberNext(n);
254-
}
255+
n=FirstOffsetNumber;
255256

256257
/* wonderful, we can look at page */
258+
so->nPageData=so->curPageData=0;
257259

258260
for (;;)
259261
{
260262
n=gistfindnext(scan,n,dir);
261263

262264
if (!OffsetNumberIsValid(n))
263265
{
266+
/*
267+
* If we was called from gistgettuple and current buffer contains
268+
* something matched then make a recursive call - it will return
269+
* ItemPointer from so->pageData. But we save buffer pinned to
270+
* support tuple's killing
271+
*/
272+
if ( !tbm&&so->nPageData>0 )
273+
{
274+
LockBuffer(so->curbuf,GIST_UNLOCK);
275+
returngistnext(scan,dir,NULL);
276+
}
277+
264278
/*
265279
* We ran out of matching index entries on the current page,
266280
* so pop the top stack entry and use it to continue the
@@ -306,11 +320,9 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
306320
tbm_add_tuples(tbm,&it->t_tid,1,scan->xs_recheck);
307321
else
308322
{
309-
scan->xs_ctup.t_self=it->t_tid;
310-
/* scan->xs_recheck is already set */
311-
312-
LockBuffer(so->curbuf,GIST_UNLOCK);
313-
returnntids;/* always 1 */
323+
so->pageData[so->nPageData ].iptr=it->t_tid;
324+
so->pageData[so->nPageData ].recheck=scan->xs_recheck;
325+
so->nPageData++;
314326
}
315327
}
316328
}

‎src/backend/access/gist/gistscan.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.70 2008/06/19 00:46:03 alvherre Exp $
11+
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.71 2008/08/23 10:37:24 teodor Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -63,6 +63,7 @@ gistrescan(PG_FUNCTION_ARGS)
6363
ReleaseBuffer(so->markbuf);
6464
so->markbuf=InvalidBuffer;
6565
}
66+
6667
}
6768
else
6869
{
@@ -83,6 +84,7 @@ gistrescan(PG_FUNCTION_ARGS)
8384
*/
8485
ItemPointerSetInvalid(&so->curpos);
8586
ItemPointerSetInvalid(&so->markpos);
87+
so->nPageData=so->curPageData=0;
8688

8789
/* Update scan key, if a new one is given */
8890
if (key&&scan->numberOfKeys>0)
@@ -150,6 +152,11 @@ gistmarkpos(PG_FUNCTION_ARGS)
150152
so->markbuf=so->curbuf;
151153
}
152154

155+
so->markNPageData=so->nPageData;
156+
so->markCurPageData=so->curPageData;
157+
if (so->markNPageData>0 )
158+
memcpy(so->markPageData,so->pageData,sizeof(ItemResult)*so->markNPageData );
159+
153160
PG_RETURN_VOID();
154161
}
155162

@@ -199,6 +206,11 @@ gistrestrpos(PG_FUNCTION_ARGS)
199206
so->curbuf=so->markbuf;
200207
}
201208

209+
so->nPageData=so->markNPageData;
210+
so->curPageData=so->markNPageData;
211+
if (so->markNPageData>0 )
212+
memcpy(so->pageData,so->markPageData,sizeof(ItemResult)*so->markNPageData );
213+
202214
PG_RETURN_VOID();
203215
}
204216

‎src/include/access/gist_private.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.31 2008/06/19 00:46:05 alvherre Exp $
10+
* $PostgreSQL: pgsql/src/include/access/gist_private.h,v 1.32 2008/08/23 10:37:24 teodor Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -58,6 +58,12 @@ typedef struct GISTSTATE
5858
TupleDesctupdesc;
5959
}GISTSTATE;
6060

61+
typedefstructItemResult
62+
{
63+
ItemPointerDataiptr;
64+
boolrecheck;
65+
}ItemResult;
66+
6167
/*
6268
*When we're doing a scan, we need to keep track of the parent stack
6369
*for the marked and current items.
@@ -73,6 +79,13 @@ typedef struct GISTScanOpaqueData
7379
ItemPointerDatacurpos;
7480
Buffermarkbuf;
7581
ItemPointerDatamarkpos;
82+
83+
ItemResultpageData[BLCKSZ/sizeof(IndexTupleData)];
84+
OffsetNumbernPageData;
85+
OffsetNumbercurPageData;
86+
ItemResultmarkPageData[BLCKSZ/sizeof(IndexTupleData)];
87+
OffsetNumbermarkNPageData;
88+
OffsetNumbermarkCurPageData;
7689
}GISTScanOpaqueData;
7790

7891
typedefGISTScanOpaqueData*GISTScanOpaque;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp