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,
3232static void
3333killtuple (Relation r ,GISTScanOpaque so ,ItemPointer iptr )
3434{
35- Buffer buffer = so -> curbuf ;
36-
37- for (;;)
38- {
39- Page p ;
40- BlockNumber blkno ;
41- OffsetNumber offset ,
42- maxoff ;
43-
44- LockBuffer (buffer ,GIST_SHARE );
45- gistcheckpage (r ,buffer );
46- p = (Page )BufferGetPage (buffer );
35+ Page p ;
36+ OffsetNumber offset ;
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+ OffsetNumber maxoff = PageGetMaxOffsetNumber (p );
5952
6053for (offset = FirstOffsetNumber ;offset <=maxoff ;offset = OffsetNumberNext (offset ))
6154{
62- IndexTuple ituple = (IndexTuple )PageGetItem (p ,PageGetItemId (p ,offset ));
55+ IndexTuple ituple = (IndexTuple )PageGetItem (p ,PageGetItemId (p ,offset ));
6356
6457if (ItemPointerEquals (& (ituple -> t_tid ),iptr ))
6558{
6659/* found */
6760ItemIdMarkDead (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)
154130GISTSearchStack * stk ;
155131IndexTuple it ;
156132GISTPageOpaque opaque ;
157- bool resetoffset = false;
158133int64 ntids = 0 ;
159134
160135so = (GISTScanOpaque )scan -> opaque ;
@@ -179,6 +154,50 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
179154return 0 ;
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+ return 1 ;
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+ return 0 ;
193+ }
194+
195+ so -> curbuf = ReleaseAndReadBuffer (so -> curbuf ,
196+ scan -> indexRelation ,
197+ stk -> block );
198+ }
199+ }
200+
182201for (;;)
183202{
184203CHECK_FOR_INTERRUPTS ();
@@ -189,30 +208,25 @@ gistnext(IndexScanDesc scan, ScanDirection dir, TIDBitmap *tbm)
189208gistcheckpage (scan -> indexRelation ,so -> curbuf );
190209p = BufferGetPage (so -> curbuf );
191210opaque = 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)
235249continue ;
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 );
246254else
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
258260for (;;)
259261{
260262n = gistfindnext (scan ,n ,dir );
261263
262264if (!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+ return gistnext (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)
306320tbm_add_tuples (tbm ,& it -> t_tid ,1 ,scan -> xs_recheck );
307321else
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- return ntids ;/* 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}