mirror of
https://github.com/postgres/postgres.git
synced 2025-07-23 03:21:12 +03:00
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.
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.135 2002/05/21 22:05:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.136 2002/05/24 18:57:55 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -306,6 +306,8 @@ heapgettup(Relation relation,
|
||||
{
|
||||
if (ItemIdIsUsed(lpp))
|
||||
{
|
||||
bool valid;
|
||||
|
||||
tuple->t_datamcxt = NULL;
|
||||
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lpp);
|
||||
tuple->t_len = ItemIdGetLength(lpp);
|
||||
@ -315,8 +317,8 @@ heapgettup(Relation relation,
|
||||
* if current tuple qualifies, return it.
|
||||
*/
|
||||
HeapTupleSatisfies(tuple, relation, *buffer, (PageHeader) dp,
|
||||
snapshot, nkeys, key);
|
||||
if (tuple->t_data != NULL)
|
||||
snapshot, nkeys, key, valid);
|
||||
if (valid)
|
||||
{
|
||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||
return;
|
||||
@ -864,32 +866,37 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
|
||||
return ((scan->rs_ctup.t_data == NULL) ? NULL : &(scan->rs_ctup));
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
* heap_fetch - retrieve tuple with given tid
|
||||
/*
|
||||
* heap_fetch - retrieve tuple with given tid
|
||||
*
|
||||
* On entry, tuple->t_self is the TID to fetch.
|
||||
* On entry, tuple->t_self is the TID to fetch. We pin the buffer holding
|
||||
* the tuple, fill in the remaining fields of *tuple, and check the tuple
|
||||
* against the specified snapshot.
|
||||
*
|
||||
* If successful (ie, tuple found and passes snapshot time qual),
|
||||
* then the rest of *tuple is filled in, and *userbuf is set to the
|
||||
* buffer holding the tuple. A pin is obtained on the buffer; the
|
||||
* caller must BufferRelease the buffer when done with the tuple.
|
||||
* If successful (tuple passes snapshot time qual), then *userbuf is set to
|
||||
* the buffer holding the tuple and TRUE is returned. The caller must
|
||||
* unpin the buffer when done with the tuple.
|
||||
*
|
||||
* If not successful, tuple->t_data is set to NULL and *userbuf is set to
|
||||
* InvalidBuffer.
|
||||
* ----------------
|
||||
* If the tuple fails the time qual check, then FALSE will be returned.
|
||||
* When the caller specifies keep_buf = true, we retain the pin on the
|
||||
* buffer and return it in *userbuf (so the caller can still access the
|
||||
* tuple); when keep_buf = false, the pin is released and *userbuf is set
|
||||
* to InvalidBuffer.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
heap_fetch(Relation relation,
|
||||
Snapshot snapshot,
|
||||
HeapTuple tuple,
|
||||
Buffer *userbuf,
|
||||
bool keep_buf,
|
||||
PgStat_Info *pgstat_info)
|
||||
{
|
||||
ItemPointer tid = &(tuple->t_self);
|
||||
ItemId lp;
|
||||
Buffer buffer;
|
||||
PageHeader dp;
|
||||
ItemPointer tid = &(tuple->t_self);
|
||||
OffsetNumber offnum;
|
||||
bool valid;
|
||||
|
||||
/*
|
||||
* increment access statistics
|
||||
@ -901,14 +908,16 @@ heap_fetch(Relation relation,
|
||||
* get the buffer from the relation descriptor. Note that this does a
|
||||
* buffer pin.
|
||||
*/
|
||||
|
||||
buffer = ReadBuffer(relation, ItemPointerGetBlockNumber(tid));
|
||||
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(ERROR, "heap_fetch: %s relation: ReadBuffer(%ld) failed",
|
||||
elog(ERROR, "heap_fetch: ReadBuffer(%s, %lu) failed",
|
||||
RelationGetRelationName(relation),
|
||||
(long) ItemPointerGetBlockNumber(tid));
|
||||
(unsigned long) ItemPointerGetBlockNumber(tid));
|
||||
|
||||
/*
|
||||
* Need share lock on buffer to examine tuple commit status.
|
||||
*/
|
||||
LockBuffer(buffer, BUFFER_LOCK_SHARE);
|
||||
|
||||
/*
|
||||
@ -921,38 +930,34 @@ heap_fetch(Relation relation,
|
||||
/*
|
||||
* more sanity checks
|
||||
*/
|
||||
|
||||
if (!ItemIdIsUsed(lp))
|
||||
{
|
||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||
ReleaseBuffer(buffer);
|
||||
*userbuf = InvalidBuffer;
|
||||
tuple->t_datamcxt = NULL;
|
||||
tuple->t_data = NULL;
|
||||
return;
|
||||
|
||||
elog(ERROR, "heap_fetch: invalid tuple id (%s, %lu, %u)",
|
||||
RelationGetRelationName(relation),
|
||||
(unsigned long) ItemPointerGetBlockNumber(tid),
|
||||
offnum);
|
||||
}
|
||||
|
||||
/*
|
||||
* fill in *tuple fields
|
||||
*/
|
||||
tuple->t_datamcxt = NULL;
|
||||
tuple->t_data = (HeapTupleHeader) PageGetItem((Page) dp, lp);
|
||||
tuple->t_len = ItemIdGetLength(lp);
|
||||
tuple->t_tableOid = relation->rd_id;
|
||||
|
||||
/*
|
||||
* check time qualification of tid
|
||||
* check time qualification of tuple, then release lock
|
||||
*/
|
||||
|
||||
HeapTupleSatisfies(tuple, relation, buffer, dp,
|
||||
snapshot, 0, (ScanKey) NULL);
|
||||
snapshot, 0, (ScanKey) NULL, valid);
|
||||
|
||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||
|
||||
if (tuple->t_data == NULL)
|
||||
{
|
||||
/* Tuple failed time check, so we can release now. */
|
||||
ReleaseBuffer(buffer);
|
||||
*userbuf = InvalidBuffer;
|
||||
}
|
||||
else
|
||||
if (valid)
|
||||
{
|
||||
/*
|
||||
* All checks passed, so return the tuple as valid. Caller is now
|
||||
@ -968,13 +973,28 @@ heap_fetch(Relation relation,
|
||||
pgstat_count_heap_fetch(pgstat_info);
|
||||
else
|
||||
pgstat_count_heap_fetch(&relation->pgstat_info);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Tuple failed time qual, but maybe caller wants to see it anyway. */
|
||||
if (keep_buf)
|
||||
{
|
||||
*userbuf = buffer;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Okay to release pin on buffer. */
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
*userbuf = InvalidBuffer;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ----------------
|
||||
/*
|
||||
* heap_get_latest_tid - get the latest tid of a specified tuple
|
||||
*
|
||||
* ----------------
|
||||
*/
|
||||
ItemPointer
|
||||
heap_get_latest_tid(Relation relation,
|
||||
@ -989,7 +1009,8 @@ heap_get_latest_tid(Relation relation,
|
||||
HeapTupleHeader t_data;
|
||||
ItemPointerData ctid;
|
||||
bool invalidBlock,
|
||||
linkend;
|
||||
linkend,
|
||||
valid;
|
||||
|
||||
/*
|
||||
* get the buffer from the relation descriptor Note that this does a
|
||||
@ -1038,7 +1059,7 @@ heap_get_latest_tid(Relation relation,
|
||||
*/
|
||||
|
||||
HeapTupleSatisfies(&tp, relation, buffer, dp,
|
||||
snapshot, 0, (ScanKey) NULL);
|
||||
snapshot, 0, (ScanKey) NULL, valid);
|
||||
|
||||
linkend = true;
|
||||
if ((t_data->t_infomask & HEAP_XMIN_COMMITTED) != 0 &&
|
||||
@ -1048,7 +1069,7 @@ heap_get_latest_tid(Relation relation,
|
||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||
ReleaseBuffer(buffer);
|
||||
|
||||
if (tp.t_data == NULL)
|
||||
if (!valid)
|
||||
{
|
||||
if (linkend)
|
||||
return NULL;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.30 2002/05/21 22:05:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/tuptoaster.c,v 1.31 2002/05/24 18:57:55 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
@ -923,7 +923,7 @@ toast_save_datum(Relation rel, Datum value)
|
||||
*/
|
||||
idxres = index_insert(toastidx, t_values, t_nulls,
|
||||
&(toasttup->t_self),
|
||||
toastrel);
|
||||
toastrel, toastidx->rd_uniqueindex);
|
||||
if (idxres == NULL)
|
||||
elog(ERROR, "Failed to insert index entry for TOAST tuple");
|
||||
|
||||
|
Reference in New Issue
Block a user