Avoid repeated CLOG access from heap_hot_search_buffer.

At the time we check whether the tuple is dead to all running
transactions, we've already verified that it isn't visible to our
scan, setting hint bits if appropriate.  So there's no need to
recheck CLOG for the all-dead test we do just a moment later.
So, add HeapTupleIsSurelyDead() to test the appropriate condition
under the assumption that all relevant hit bits are already set.

Review by Tom Lane.
This commit is contained in:
Robert Haas 2012-05-02 12:40:07 -04:00
parent 1b4998fd44
commit 0038110421
3 changed files with 43 additions and 2 deletions

View File

@ -1609,8 +1609,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
* transactions.
*/
if (all_dead && *all_dead &&
HeapTupleSatisfiesVacuum(heapTuple->t_data, RecentGlobalXmin,
buffer) != HEAPTUPLE_DEAD)
!HeapTupleIsSurelyDead(heapTuple->t_data, RecentGlobalXmin))
*all_dead = false;
/*

View File

@ -1219,6 +1219,46 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
return HEAPTUPLE_DEAD;
}
/*
* HeapTupleIsSurelyDead
*
* Determine whether a tuple is surely dead. We sometimes use this
* in lieu of HeapTupleSatisifesVacuum when the tuple has just been
* tested by HeapTupleSatisfiesMVCC and, therefore, any hint bits that
* can be set should already be set. We assume that if no hint bits
* either for xmin or xmax, the transaction is still running. This is
* therefore faster than HeapTupleSatisfiesVacuum, because we don't
* consult CLOG (and also because we don't need to give an exact answer,
* just whether or not the tuple is surely dead).
*/
bool
HeapTupleIsSurelyDead(HeapTupleHeader tuple, TransactionId OldestXmin)
{
/*
* If the inserting transaction is marked invalid, then it aborted,
* and the tuple is definitely dead. If it's marked neither committed
* nor invalid, then we assume it's still alive (since the presumption
* is that all relevant hint bits were just set moments ago).
*/
if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
return (tuple->t_infomask & HEAP_XMIN_INVALID) != 0 ? true : false;
/*
* If the inserting transaction committed, but any deleting transaction
* aborted, the tuple is still alive. Likewise, if XMAX is a lock rather
* than a delete, the tuple is still alive.
*/
if (tuple->t_infomask &
(HEAP_XMAX_INVALID | HEAP_IS_LOCKED | HEAP_XMAX_IS_MULTI))
return false;
/* If deleter isn't known to have committed, assume it's still running. */
if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
return false;
/* Deleter committed, so tuple is dead if the XID is old enough. */
return TransactionIdPrecedes(HeapTupleHeaderGetXmax(tuple), OldestXmin);
}
/*
* XidInMVCCSnapshot

View File

@ -83,6 +83,8 @@ extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTupleHeader tuple,
CommandId curcid, Buffer buffer);
extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple,
TransactionId OldestXmin, Buffer buffer);
extern bool HeapTupleIsSurelyDead(HeapTupleHeader tuple,
TransactionId OldestXmin);
extern void HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
uint16 infomask, TransactionId xid);