Skip to content

Commit 3f4d488

Browse files
committed
Mark index entries "killed" when they are no longer visible to any
transaction, so as to avoid returning them out of the index AM. Saves repeated heap_fetch operations on frequently-updated rows. Also detect queries on unique keys (equality to all columns of a unique index), and don't bother continuing scan once we have found first match. Killing is implemented in the btree and hash AMs, but not yet in rtree or gist, because there isn't an equally convenient place to do it in those AMs (the outer amgetnext routine can't do it without re-pinning the index page). Did some small cleanup on APIs of HeapTupleSatisfies, heap_fetch, and index_insert to make this a little easier.
1 parent 2f2d057 commit 3f4d488

File tree

30 files changed

+498
-273
lines changed

30 files changed

+498
-273
lines changed

src/backend/access/gist/gist.c

Lines changed: 4 additions & 2 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-
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.92 2002/05/20 23:51:40 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/gist/gist.c,v 1.93 2002/05/24 18:57:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -294,9 +294,9 @@ gistinsert(PG_FUNCTION_ARGS)
294294
Datum *datum = (Datum *) PG_GETARG_POINTER(1);
295295
char *nulls = (char *) PG_GETARG_POINTER(2);
296296
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
297-
298297
#ifdef NOT_USED
299298
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
299+
bool checkUnique = PG_GETARG_BOOL(5);
300300
#endif
301301
InsertIndexResult res;
302302
IndexTuple itup;
@@ -1607,6 +1607,8 @@ gistbulkdelete(PG_FUNCTION_ARGS)
16071607

16081608
/* walk through the entire index */
16091609
iscan = index_beginscan(NULL, rel, SnapshotAny, 0, (ScanKey) NULL);
1610+
/* including killed tuples */
1611+
iscan->ignore_killed_tuples = false;
16101612

16111613
while (index_getnext_indexitem(iscan, ForwardScanDirection))
16121614
{

src/backend/access/hash/hash.c

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.57 2002/05/20 23:51:41 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/hash/hash.c,v 1.58 2002/05/24 18:57:55 tgl Exp $
1212
*
1313
* NOTES
1414
* This file contains only the public interface routines.
@@ -166,8 +166,8 @@ hashinsert(PG_FUNCTION_ARGS)
166166
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
167167
#ifdef NOT_USED
168168
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
169+
bool checkUnique = PG_GETARG_BOOL(5);
169170
#endif
170-
171171
InsertIndexResult res;
172172
HashItem hitem;
173173
IndexTuple itup;
@@ -210,19 +210,59 @@ hashgettuple(PG_FUNCTION_ARGS)
210210
{
211211
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
212212
ScanDirection dir = (ScanDirection) PG_GETARG_INT32(1);
213+
HashScanOpaque so = (HashScanOpaque) scan->opaque;
214+
Page page;
215+
OffsetNumber offnum;
213216
bool res;
214217

215218
/*
216219
* If we've already initialized this scan, we can just advance it in
217220
* the appropriate direction. If we haven't done so yet, we call a
218221
* routine to get the first item in the scan.
219222
*/
220-
221223
if (ItemPointerIsValid(&(scan->currentItemData)))
224+
{
225+
/*
226+
* Check to see if we should kill the previously-fetched tuple.
227+
*/
228+
if (scan->kill_prior_tuple)
229+
{
230+
/*
231+
* Yes, so mark it by setting the LP_DELETE bit in the item flags.
232+
*/
233+
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
234+
page = BufferGetPage(so->hashso_curbuf);
235+
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
236+
/*
237+
* Since this can be redone later if needed, it's treated the
238+
* same as a commit-hint-bit status update for heap tuples:
239+
* we mark the buffer dirty but don't make a WAL log entry.
240+
*/
241+
SetBufferCommitInfoNeedsSave(so->hashso_curbuf);
242+
}
243+
/*
244+
* Now continue the scan.
245+
*/
222246
res = _hash_next(scan, dir);
247+
}
223248
else
224249
res = _hash_first(scan, dir);
225250

251+
/*
252+
* Skip killed tuples if asked to.
253+
*/
254+
if (scan->ignore_killed_tuples)
255+
{
256+
while (res)
257+
{
258+
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
259+
page = BufferGetPage(so->hashso_curbuf);
260+
if (!ItemIdDeleted(PageGetItemId(page, offnum)))
261+
break;
262+
res = _hash_next(scan, dir);
263+
}
264+
}
265+
226266
PG_RETURN_BOOL(res);
227267
}
228268

@@ -418,6 +458,8 @@ hashbulkdelete(PG_FUNCTION_ARGS)
418458

419459
/* walk through the entire index */
420460
iscan = index_beginscan(NULL, rel, SnapshotAny, 0, (ScanKey) NULL);
461+
/* including killed tuples */
462+
iscan->ignore_killed_tuples = false;
421463

422464
while (index_getnext_indexitem(iscan, ForwardScanDirection))
423465
{

src/backend/access/hash/hashscan.c

Lines changed: 36 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.26 2002/05/20 23:51:41 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashscan.c,v 1.27 2002/05/24 18:57:55 tgl Exp $
1212
*
1313
* NOTES
1414
* Because we can be doing an index scan on a relation while we
@@ -32,8 +32,6 @@
3232

3333
#include "access/hash.h"
3434

35-
static void _hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
36-
static bool _hash_scantouched(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno);
3735

3836
typedef struct HashScanListData
3937
{
@@ -46,6 +44,10 @@ typedef HashScanListData *HashScanList;
4644
static HashScanList HashScans = (HashScanList) NULL;
4745

4846

47+
static void _hash_scandel(IndexScanDesc scan,
48+
BlockNumber blkno, OffsetNumber offno);
49+
50+
4951
/*
5052
* AtEOXact_hash() --- clean up hash subsystem at xact abort or commit.
5153
*
@@ -129,63 +131,51 @@ static void
129131
_hash_scandel(IndexScanDesc scan, BlockNumber blkno, OffsetNumber offno)
130132
{
131133
ItemPointer current;
134+
ItemPointer mark;
132135
Buffer buf;
133136
Buffer metabuf;
134137
HashScanOpaque so;
135138

136-
if (!_hash_scantouched(scan, blkno, offno))
137-
return;
138-
139-
metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
140-
141139
so = (HashScanOpaque) scan->opaque;
142-
buf = so->hashso_curbuf;
143-
144140
current = &(scan->currentItemData);
141+
mark = &(scan->currentMarkData);
142+
145143
if (ItemPointerIsValid(current)
146144
&& ItemPointerGetBlockNumber(current) == blkno
147145
&& ItemPointerGetOffsetNumber(current) >= offno)
148146
{
147+
metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
148+
buf = so->hashso_curbuf;
149149
_hash_step(scan, &buf, BackwardScanDirection, metabuf);
150-
so->hashso_curbuf = buf;
151150
}
152151

153-
current = &(scan->currentMarkData);
154-
if (ItemPointerIsValid(current)
155-
&& ItemPointerGetBlockNumber(current) == blkno
156-
&& ItemPointerGetOffsetNumber(current) >= offno)
152+
if (ItemPointerIsValid(mark)
153+
&& ItemPointerGetBlockNumber(mark) == blkno
154+
&& ItemPointerGetOffsetNumber(mark) >= offno)
157155
{
158-
ItemPointerData tmp;
159-
160-
tmp = *current;
161-
*current = scan->currentItemData;
162-
scan->currentItemData = tmp;
156+
/*
157+
* The idea here is to exchange the current and mark positions,
158+
* then step backwards (affecting current), then exchange again.
159+
*/
160+
ItemPointerData tmpitem;
161+
Buffer tmpbuf;
162+
163+
tmpitem = *mark;
164+
*mark = *current;
165+
*current = tmpitem;
166+
tmpbuf = so->hashso_mrkbuf;
167+
so->hashso_mrkbuf = so->hashso_curbuf;
168+
so->hashso_curbuf = tmpbuf;
169+
170+
metabuf = _hash_getbuf(scan->indexRelation, HASH_METAPAGE, HASH_READ);
171+
buf = so->hashso_curbuf;
163172
_hash_step(scan, &buf, BackwardScanDirection, metabuf);
164-
so->hashso_mrkbuf = buf;
165-
tmp = *current;
166-
*current = scan->currentItemData;
167-
scan->currentItemData = tmp;
168-
}
169-
}
170173

171-
static bool
172-
_hash_scantouched(IndexScanDesc scan,
173-
BlockNumber blkno,
174-
OffsetNumber offno)
175-
{
176-
ItemPointer current;
177-
178-
current = &(scan->currentItemData);
179-
if (ItemPointerIsValid(current)
180-
&& ItemPointerGetBlockNumber(current) == blkno
181-
&& ItemPointerGetOffsetNumber(current) >= offno)
182-
return true;
183-
184-
current = &(scan->currentMarkData);
185-
if (ItemPointerIsValid(current)
186-
&& ItemPointerGetBlockNumber(current) == blkno
187-
&& ItemPointerGetOffsetNumber(current) >= offno)
188-
return true;
189-
190-
return false;
174+
tmpitem = *mark;
175+
*mark = *current;
176+
*current = tmpitem;
177+
tmpbuf = so->hashso_mrkbuf;
178+
so->hashso_mrkbuf = so->hashso_curbuf;
179+
so->hashso_curbuf = tmpbuf;
180+
}
191181
}

src/backend/access/hash/hashsearch.c

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.28 2002/05/20 23:51:41 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashsearch.c,v 1.29 2002/05/24 18:57:55 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -54,10 +54,10 @@ _hash_search(Relation rel,
5454
* _hash_next() -- Get the next item in a scan.
5555
*
5656
* On entry, we have a valid currentItemData in the scan, and a
57-
* read lock on the page that contains that item. We do not have
58-
* the page pinned. We return the next item in the scan. On
59-
* exit, we have the page containing the next item locked but not
60-
* pinned.
57+
* pin and read lock on the page that contains that item.
58+
* We find the next item in the scan, if any.
59+
* On success exit, we have the page containing the next item
60+
* pinned and locked.
6161
*/
6262
bool
6363
_hash_next(IndexScanDesc scan, ScanDirection dir)
@@ -74,25 +74,12 @@ _hash_next(IndexScanDesc scan, ScanDirection dir)
7474

7575
rel = scan->indexRelation;
7676
so = (HashScanOpaque) scan->opaque;
77-
current = &(scan->currentItemData);
78-
79-
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
80-
81-
/*
82-
* XXX 10 may 91: somewhere there's a bug in our management of the
83-
* cached buffer for this scan. wei discovered it. the following is
84-
* a workaround so he can work until i figure out what's going on.
85-
*/
86-
87-
if (!BufferIsValid(so->hashso_curbuf))
88-
{
89-
so->hashso_curbuf = _hash_getbuf(rel,
90-
ItemPointerGetBlockNumber(current),
91-
HASH_READ);
92-
}
9377

9478
/* we still have the buffer pinned and locked */
9579
buf = so->hashso_curbuf;
80+
Assert(BufferIsValid(buf));
81+
82+
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
9683

9784
/*
9885
* step to next valid tuple. note that _hash_step releases our lock

0 commit comments

Comments
 (0)