From 003811042139790a5a479c8264271a3248eda36f Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Wed, 2 May 2012 12:40:07 -0400 Subject: [PATCH] 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. --- src/backend/access/heap/heapam.c | 3 +-- src/backend/utils/time/tqual.c | 40 ++++++++++++++++++++++++++++++++ src/include/utils/tqual.h | 2 ++ 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 3259354d5e..7e4c8f52ab 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -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; /* diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index c1c78c389c..727e0bf91b 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -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 diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 0f8a7f8c2d..3d8a480d81 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -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); -- 2.40.0