Modify keys_are_unique optimization to release buffer pins before it
returns NULL. This avoids out-of-buffers failures during many-way indexscans, as in Shraibman's complaint of 21-Mar.
This commit is contained in:
parent
346182ca92
commit
fddc2d94ce
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.37 2003/01/08 19:41:40 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/genam.c,v 1.38 2003/03/24 21:42:33 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* many of the old access method routines have been turned into
|
* many of the old access method routines have been turned into
|
||||||
@ -91,7 +91,7 @@ RelationGetIndexScan(Relation indexRelation,
|
|||||||
|
|
||||||
scan->kill_prior_tuple = false;
|
scan->kill_prior_tuple = false;
|
||||||
scan->ignore_killed_tuples = true; /* default setting */
|
scan->ignore_killed_tuples = true; /* default setting */
|
||||||
scan->keys_are_unique = false; /* may be set by amrescan */
|
scan->keys_are_unique = false; /* may be set by index AM */
|
||||||
scan->got_tuple = false;
|
scan->got_tuple = false;
|
||||||
|
|
||||||
scan->opaque = NULL;
|
scan->opaque = NULL;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.65 2003/03/23 23:01:03 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.66 2003/03/24 21:42:33 tgl Exp $
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* index_open - open an index relation by relation OID
|
* index_open - open an index relation by relation OID
|
||||||
@ -311,7 +311,7 @@ index_rescan(IndexScanDesc scan, ScanKey key)
|
|||||||
GET_SCAN_PROCEDURE(rescan, amrescan);
|
GET_SCAN_PROCEDURE(rescan, amrescan);
|
||||||
|
|
||||||
scan->kill_prior_tuple = false; /* for safety */
|
scan->kill_prior_tuple = false; /* for safety */
|
||||||
scan->keys_are_unique = false; /* may be set by amrescan */
|
scan->keys_are_unique = false; /* may be set by index AM */
|
||||||
scan->got_tuple = false;
|
scan->got_tuple = false;
|
||||||
scan->unique_tuple_pos = 0;
|
scan->unique_tuple_pos = 0;
|
||||||
scan->unique_tuple_mark = 0;
|
scan->unique_tuple_mark = 0;
|
||||||
@ -413,32 +413,6 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||||||
|
|
||||||
SCAN_CHECKS;
|
SCAN_CHECKS;
|
||||||
|
|
||||||
/*
|
|
||||||
* Can skip entering the index AM if we already got a tuple and it
|
|
||||||
* must be unique. Instead, we need a "short circuit" path that
|
|
||||||
* just keeps track of logical scan position (before/on/after tuple).
|
|
||||||
*
|
|
||||||
* Note that we hold the pin on the single tuple's buffer throughout
|
|
||||||
* the scan once we are in this state.
|
|
||||||
*/
|
|
||||||
if (scan->keys_are_unique && scan->got_tuple)
|
|
||||||
{
|
|
||||||
if (ScanDirectionIsForward(direction))
|
|
||||||
{
|
|
||||||
if (scan->unique_tuple_pos <= 0)
|
|
||||||
scan->unique_tuple_pos++;
|
|
||||||
}
|
|
||||||
else if (ScanDirectionIsBackward(direction))
|
|
||||||
{
|
|
||||||
if (scan->unique_tuple_pos >= 0)
|
|
||||||
scan->unique_tuple_pos--;
|
|
||||||
}
|
|
||||||
if (scan->unique_tuple_pos == 0)
|
|
||||||
return heapTuple;
|
|
||||||
else
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Release any previously held pin */
|
/* Release any previously held pin */
|
||||||
if (BufferIsValid(scan->xs_cbuf))
|
if (BufferIsValid(scan->xs_cbuf))
|
||||||
{
|
{
|
||||||
@ -446,6 +420,65 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||||||
scan->xs_cbuf = InvalidBuffer;
|
scan->xs_cbuf = InvalidBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we already got a tuple and it must be unique, there's no need
|
||||||
|
* to make the index AM look through any additional tuples. (This can
|
||||||
|
* save a useful amount of work in scenarios where there are many dead
|
||||||
|
* tuples due to heavy update activity.)
|
||||||
|
*
|
||||||
|
* To do this we must keep track of the logical scan position
|
||||||
|
* (before/on/after tuple). Also, we have to be sure to release scan
|
||||||
|
* resources before returning NULL; if we fail to do so then a multi-index
|
||||||
|
* scan can easily run the system out of free buffers. We can release
|
||||||
|
* index-level resources fairly cheaply by calling index_rescan. This
|
||||||
|
* means there are two persistent states as far as the index AM is
|
||||||
|
* concerned: on-tuple and rescanned. If we are actually asked to
|
||||||
|
* re-fetch the single tuple, we have to go through a fresh indexscan
|
||||||
|
* startup, which penalizes that (infrequent) case.
|
||||||
|
*/
|
||||||
|
if (scan->keys_are_unique && scan->got_tuple)
|
||||||
|
{
|
||||||
|
int new_tuple_pos = scan->unique_tuple_pos;
|
||||||
|
|
||||||
|
if (ScanDirectionIsForward(direction))
|
||||||
|
{
|
||||||
|
if (new_tuple_pos <= 0)
|
||||||
|
new_tuple_pos++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new_tuple_pos >= 0)
|
||||||
|
new_tuple_pos--;
|
||||||
|
}
|
||||||
|
if (new_tuple_pos == 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are moving onto the unique tuple from having been off it.
|
||||||
|
* We just fall through and let the index AM do the work. Note
|
||||||
|
* we should get the right answer regardless of scan direction.
|
||||||
|
*/
|
||||||
|
scan->unique_tuple_pos = 0; /* need to update position */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Moving off the tuple; must do amrescan to release index-level
|
||||||
|
* pins before we return NULL. Since index_rescan will reset
|
||||||
|
* my state, must save and restore...
|
||||||
|
*/
|
||||||
|
int unique_tuple_mark = scan->unique_tuple_mark;
|
||||||
|
|
||||||
|
index_rescan(scan, NULL /* no change to key */);
|
||||||
|
|
||||||
|
scan->keys_are_unique = true;
|
||||||
|
scan->got_tuple = true;
|
||||||
|
scan->unique_tuple_pos = new_tuple_pos;
|
||||||
|
scan->unique_tuple_mark = unique_tuple_mark;
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* just make sure this is false... */
|
/* just make sure this is false... */
|
||||||
scan->kill_prior_tuple = false;
|
scan->kill_prior_tuple = false;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user