diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c
old mode 100644
new mode 100755
index 2fd32e0..62ed2fe
--- a/src/backend/utils/time/tqual.c
+++ b/src/backend/utils/time/tqual.c
@@ -10,6 +10,21 @@
  * the passed-in buffer.  The caller must hold not only a pin, but at least
  * shared buffer content lock on the buffer containing the tuple.
  *
+ * Hint bits are maintained directly on the tuple itself and on a separate
+ * in-memory cache.  If the hint bit is found from the cache, the hint bit
+ * is set on the tuple but the page is not marked dirty.  This is done to
+ * reduce i/o resulting from hint bit only changes.  The cache itself is
+ * exactly like the clog page, and uses a similar page size, but does not
+ * have to.  Cache maintenance occurs every Nth (typically 100) cache miss
+ * that successfully fetches the transaction status from clog.
+ *
+ * It's tempting to try and expand the simple last transaction status in
+ * transam.c but this check happens too late in the critical visibility
+ * routines to provide much benefit.  For the fastest possible cache
+ * performance with the least amount of impact on scan heavy cases, you have
+ * to maintain the cache here if you want to avoid dirtying the page
+ * based on interaction with the cache.
+ *
  * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
  * before TransactionIdDidCommit/TransactionIdDidAbort (which look in
  * pg_clog).  Otherwise we have a race condition: we might decide that a
@@ -64,6 +79,7 @@
 #include "storage/bufmgr.h"
 #include "storage/procarray.h"
 #include "utils/tqual.h"
+#include "utils/memutils.h"
 
 
 /* Static variables representing various special snapshot semantics */
@@ -72,9 +88,332 @@ SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf};
 SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny};
 SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast};
 
+/* hint bit cache definitions and structures */
+
+#define HBCACHE_PAGESZ 8192
+/* 8192 bytes of stororage in each hint bit cache page */
+#define HBCACHE_PAGE_COUNT 4		/* how many pages to keep */
+#define HBCACHE_ROLLUPSZ 100
+/* 100 cache misses are stored in array before re-filling cache */
+#define HBCACHE_HIT_THRESHOLD 5
+/* cache pagees with less than 5 interesting transactions per cache re-fill
+ * are not considered interesting
+ */
+
+#define HBCACHE_BITS_PER_XACT	1
+#define HBCACHE_XACTS_PER_BYTE	8
+#define HBCACHE_XACTS_PER_PAGE	(HBCACHE_PAGESZ * HBCACHE_XACTS_PER_BYTE)
+#define HBCACHE_XACT_BITMASK	((1 << HBCACHE_BITS_PER_XACT) - 1)
+
+#define HBCACHE_COMITTED 1
+/* The hint bit cache only tracks commit bits */
+
+
+#define HBCache_TransactionIdToPage(xid)	((xid) / (TransactionId) HBCACHE_XACTS_PER_PAGE)
+#define HBCache_TransactionIdToPgIndex(xid) ((xid) % (TransactionId) HBCACHE_XACTS_PER_PAGE)
+#define HBCache_TransactionIdToByte(xid)	(HBCache_TransactionIdToPgIndex(xid) / HBCACHE_XACTS_PER_BYTE)
+#define HBCache_TransactionIdToBIndex(xid)	((xid) % (TransactionId) HBCACHE_XACTS_PER_BYTE)
+
+
+/* describes a hint bit page in memory */
+typedef struct
+{
+	TransactionId XidPage;  /* this page describes a range of transaction ids */
+	int HitCount;	/* number of cache hits on this page */
+	bool Clear;
+	char *Data;
+	/* during rollup, signals the page is changing and cache data needs to
+	 * be cleared
+	 */
+} HintBitCachePageHeader;
+
 /* local functions */
 static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
 
+static inline void SetHintBitsNonDirty(HeapTupleHeader tuple, Buffer buffer,
+			uint16 infomask, TransactionId xid);
+
+static HintBitCachePageHeader *HintBitCachePageList = NULL;
+static char *HintBitCachePageData = NULL;
+static TransactionId *HintBitCachePageRollupList = NULL;
+static int HintBitCacheMissCount = 0;
+
+/* qsort comparison function */
+static int
+xid_cmp(const void *p1, const void *p2)
+{
+	TransactionId v1 = *((const TransactionId *) p1);
+	TransactionId v2 = *((const TransactionId *) p2);
+
+	if (v1 < v2)
+		return -1;
+	if (v1 > v2)
+		return 1;
+	return 0;
+}
+
+/*
+ * InitializeHintbitCache
+ *		Initialize the hint bit cache.
+ */
+static void
+InitializeHintBitCache(void)
+{
+ 	int cachepage;
+	int cachesz = sizeof(char) * HBCACHE_PAGE_COUNT * HBCACHE_PAGESZ;
+
+	HintBitCachePageData = MemoryContextAlloc(CacheMemoryContext, cachesz);
+	MemSet(HintBitCachePageData, 0, cachesz);
+
+	HintBitCachePageList = MemoryContextAlloc(CacheMemoryContext,
+		sizeof(HintBitCachePageHeader) * HBCACHE_PAGE_COUNT);
+
+	for(cachepage = 0; cachepage < HBCACHE_PAGE_COUNT; cachepage++)
+	{
+		/* initialize cache page to a valid that is impossible to see in the
+		 * wild -- since bits are always divided out to calculate a page,
+		 * a value with the top bits set is impossible to see and cant't
+		 * represent an invalid page.
+		 */
+		TransactionId invalid_page = (TransactionId) 0xFFFFFFFF;
+
+		Assert(sizeof(TransactionId) == 4);
+
+		HintBitCachePageList[cachepage].XidPage = invalid_page;
+		HintBitCachePageList[cachepage].HitCount = 0;
+		HintBitCachePageList[cachepage].Clear = false;
+		HintBitCachePageList[cachepage].Data =
+			&HintBitCachePageData[HBCACHE_PAGESZ * cachepage];
+	}
+
+
+	HintBitCachePageRollupList = MemoryContextAlloc(CacheMemoryContext,
+		sizeof(int) * HBCACHE_ROLLUPSZ);
+}
+
+/*
+ * RollUpHintBitCache()
+ *
+ * Whenever a transaction is checked against the hint bit cache and the status
+ * is not there (a cache miss), the transaction's page is added to the
+ * rollup array. When that array fills, the rollup array is processed into
+ * a new set of cache pages.
+ *
+ * The algorithm is to sort the rollup array and iterate it counting the
+ * number of identical pages as we go.  When we hit a new page (or the
+ * end of the array) and the number of counted pages is over a minimum
+ * threshold, the page is moved into the cache if it has more cache hits
+ * than any page that is already in the cache.
+ */
+static void RollUpHintBitCache()
+{
+	TransactionId LastPage = HintBitCachePageRollupList[0];
+	/* The page we are duplicate tracking. */
+
+	int PageIdx;
+	int HitCount = 0;
+	/* effectively initializes to 1: the first iteration of the loop will
+	 * always match LastPage and increment this value
+	 */
+
+	int Page;
+	int PageMinHits = HBCACHE_ROLLUPSZ + 1;
+	/* The smallest number of hits for a page currently in the cache. It's
+	 * scanned comparing as we go, so initialize it to an impossibly high
+	 * value here */
+
+	int PageMinIdx;
+	/* The cache page index of the page with the smallest number of hits.
+	 * if a new cache page higher number of hits with this one, it is
+	 * swapped in its place.
+	 */
+	TransactionId XidPage;
+
+	bool AlreadyInCache;
+
+	/* sort the list in order to make counting identical pages easier */
+	qsort(HintBitCachePageRollupList, HBCACHE_ROLLUPSZ, sizeof(int), xid_cmp);
+
+	for (PageIdx = 0; PageIdx < HBCACHE_ROLLUPSZ; PageIdx++)
+	{
+		/* If page is the same as the last one, increment the hitcount
+		 * or reset it and do cache management based on the number of hits
+		 */
+		XidPage = HintBitCachePageRollupList[PageIdx];
+
+		if(XidPage == LastPage)
+		        HitCount++;
+		else
+		{
+			/* Now check the page represented by LastPage to see if its
+			 * interesting for cache purposes.  To avoid thrashing cache pages
+			 * in and out, a minimum threshold of hits has to be met before
+			 * putting a page in the cache.
+			 */
+			if (HitCount >= HBCACHE_HIT_THRESHOLD)
+			{
+CheckLastXidBlock:
+				/* Look through the pages, find the one with the smallest
+				 * hit count, and save off the index.
+				 */
+				AlreadyInCache = false;
+
+				for (Page = 0; Page < HBCACHE_PAGE_COUNT; Page++)
+				{
+					if (HintBitCachePageList[Page].HitCount < PageMinHits)
+					{
+						PageMinIdx = Page;
+						PageMinHits = HintBitCachePageList[Page].HitCount;
+					}
+
+					/* If this page is alredy in the cache, we can leave it
+					 * an without clearing it.
+					 */
+					if (HintBitCachePageList[Page].XidPage == LastPage)
+						AlreadyInCache = true;
+				}
+
+				/* does the page we are examining have a higher number of
+				 * cache hits than any page currently in the cache?
+				 */
+				if (!AlreadyInCache && HitCount > PageMinHits)
+				{
+					/* mark the cache buffer with the new page, hint count
+					 * and clear flag.
+					 */
+					HintBitCachePageList[PageMinIdx].XidPage = LastPage;
+					HintBitCachePageList[PageMinIdx].HitCount = HitCount;
+					HintBitCachePageList[PageMinIdx].Clear = true;
+				}
+			}
+
+			/* reset the hit count, since we've already technically already
+			 * seen this page in this iteration, HitCount is initialized
+			 * to 1, and this page is now the one tracked via LastPage.
+			 */
+			HitCount = 1;
+			LastPage = XidPage;
+		}
+	}
+
+	/* When the loop is exited, the last block of identical pages may have
+	 * never gotten checked via the XidPage == LastPage condition.
+	 * Sneakily jump back into the loop if necessary.
+	 *
+	 * jump back into the loop to check it but decrement PageIdx first so
+	 * that the final LastPage assignment does't look outside the array.
+	 */
+	if(HitCount >= HBCACHE_HIT_THRESHOLD)
+	{
+		/* Since HitCount is reset when a page is processed, checking it
+		 * is enough to guarantee the last page in the loop was never
+		 * processed.
+		 */
+		goto CheckLastXidBlock;
+	}
+
+	/* Cache pages that are new have to be cleared.  Look for ones marked as
+	 * such and reset the hit count for all pages.
+	 */
+	for (Page = 0; Page < HBCACHE_PAGE_COUNT; Page++)
+	{
+		if(HintBitCachePageList[PageMinIdx].Clear)
+			MemSet(HintBitCachePageList[PageMinIdx].Data, 0, HBCACHE_PAGESZ);
+
+		HintBitCachePageList[PageMinIdx].Clear = 0;
+		HintBitCachePageList[PageMinIdx].HitCount = 0;
+	}
+
+	HintBitCacheMissCount = 0;
+	return;
+}
+
+/*
+ * HintBitCacheXidStatus()
+ *
+ * Compute the page for a TransactionId, and compare it against the pages
+ * currently in the cache.  If the page is found, resolve the hint bit
+ * status's position in the block and return it.
+ */
+static inline int
+HintBitCacheXidStatus(HeapTupleHeader tuple, Buffer buffer,
+				uint16 infomask, TransactionId xid)
+{
+	TransactionId XidPage = HBCache_TransactionIdToPage(xid);
+	int Page;
+
+	if(HintBitCachePageList == NULL)
+		InitializeHintBitCache();
+
+	for(Page = 0; Page < HBCACHE_PAGE_COUNT; Page++)
+	{
+		/* is the transaction status in the range defined by the page? */
+		if(HintBitCachePageList[Page].XidPage == XidPage)
+		{
+			int	byteno = HBCache_TransactionIdToByte(xid);
+			int bshift = HBCache_TransactionIdToBIndex(xid) * HBCACHE_BITS_PER_XACT;
+			char *byteptr = HintBitCachePageList[Page].Data + byteno;
+
+			int hbcache_status = (*byteptr >> bshift) & HBCACHE_XACT_BITMASK;
+
+			if (hbcache_status == HBCACHE_COMITTED)
+				SetHintBitsNonDirty(tuple, buffer, infomask, xid);
+
+			return hbcache_status;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * SetXidInHintBitCache()
+ *
+ * Compute the page for a TransactionId, and compare it against the pages
+ * currently in the cache.  If the page is found, compute the bit position
+ * and set it to 1 (true).  If it is not found, put the TransactionId in the
+ * array that holds cache misses.  If that array fills, rebuild the cache.
+ */
+static inline void
+SetXidInHintBitCache(TransactionId xid, int hbcache_status)
+{
+	TransactionId XidPage = HBCache_TransactionIdToPage(xid);
+	int Page;
+
+	Assert(HintBitCachePageList != NULL);
+
+	for(Page = 0; Page < HBCACHE_PAGE_COUNT; Page++)
+	{
+	    if(XidPage == HintBitCachePageList[Page].XidPage)
+	    {
+			int	byteno = HBCache_TransactionIdToByte(xid);
+			int bshift = HBCache_TransactionIdToBIndex(xid) * HBCACHE_BITS_PER_XACT;
+			char *byteptr = HintBitCachePageList[Page].Data + byteno;
+			char byteval = *byteptr;
+
+			byteval &= ~(((1 << HBCACHE_BITS_PER_XACT) - 1) << bshift);
+			byteval |= (hbcache_status << bshift);
+			*byteptr = byteval;
+
+			/* there is a minute chance of overflow here, but it doesn't
+			 * seem worthwhile to test for it
+			 */
+			HintBitCachePageList[Page].HitCount++;
+			break;
+		}
+	}
+
+	HintBitCachePageRollupList[HintBitCacheMissCount++] = XidPage;
+
+	/* Enough transactions have fallen through the cache that it's time to
+	 * rebuild it.  Hopefully we don't have to do this too often
+	 */
+	if (HintBitCacheMissCount == HBCACHE_ROLLUPSZ)
+		RollUpHintBitCache();
+
+	return;
+}
+
 
 /*
  * SetHintBits()
@@ -122,6 +461,51 @@ SetHintBits(HeapTupleHeader tuple, Buffer buffer,
 }
 
 /*
+ * SetHintBitsCache()
+ *
+ * Do the same action as SetHintBits(), but also set the commit bit in the
+ * cache. Since only commit bits are cached, that is what they are assumed
+ * to be.
+ *
+ */
+static inline void
+SetHintBitsCache(HeapTupleHeader tuple, Buffer buffer,
+				uint16 infomask, TransactionId xid)
+{
+	if (TransactionIdIsValid(xid))
+	{
+		/* NB: xid must be known committed here! */
+		XLogRecPtr	commitLSN = TransactionIdGetCommitLSN(xid);
+
+		if (XLogNeedsFlush(commitLSN))
+			return;			/* not flushed yet, so don't set hint */
+	}
+
+	tuple->t_infomask |= infomask;
+	SetBufferCommitInfoNeedsSave(buffer);
+
+	SetXidInHintBitCache(xid, HBCACHE_COMITTED);
+
+	return;
+}
+
+/*
+ * SetHintBitsNonDirty()
+ *
+ * Set the hint bits on the tuple only but don't dirty the page. This is done
+ * when a hit bint is found in the cache.  There's no reason not to set it
+ * anyways, because if the page is dirty for another reason it will get
+ * written out.
+ *
+ */
+static inline void
+SetHintBitsNonDirty(HeapTupleHeader tuple, Buffer buffer,
+				uint16 infomask, TransactionId xid)
+{
+	tuple->t_infomask |= infomask;
+}
+
+/*
  * HeapTupleSetHintBits --- exported version of SetHintBits()
  *
  * This must be separate because of C99's brain-dead notions about how to
@@ -162,7 +546,9 @@ HeapTupleSetHintBits(HeapTupleHeader tuple, Buffer buffer,
 bool
 HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 {
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return false;
@@ -229,7 +615,7 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
 			return false;
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 						HeapTupleHeaderGetXmin(tuple));
 		else
 		{
@@ -245,7 +631,9 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
 		return true;
 
-	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	if (tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple)))
 	{
 		if (tuple->t_infomask & HEAP_IS_LOCKED)
 			return true;
@@ -286,7 +674,7 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 		return true;
 	}
 
-	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
+	SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
 				HeapTupleHeaderGetXmax(tuple));
 	return false;
 }
@@ -335,7 +723,9 @@ HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 bool
 HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 {
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return false;
@@ -408,7 +798,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
 			return false;
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 						HeapTupleHeaderGetXmin(tuple));
 		else
 		{
@@ -424,7 +814,9 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
 		return true;
 
-	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	if (tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple)))
 	{
 		if (tuple->t_infomask & HEAP_IS_LOCKED)
 			return true;
@@ -468,7 +860,7 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer)
 		return true;
 	}
 
-	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
+	SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
 				HeapTupleHeaderGetXmax(tuple));
 	return false;
 }
@@ -501,7 +893,9 @@ bool
 HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
 						Buffer buffer)
 {
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return false;
@@ -535,7 +929,7 @@ HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot,
 				if (TransactionIdIsInProgress(xvac))
 					return false;
 				if (TransactionIdDidCommit(xvac))
-					SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+					SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 								InvalidTransactionId);
 				else
 				{
@@ -582,7 +976,9 @@ HTSU_Result
 HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
 						 Buffer buffer)
 {
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return HeapTupleInvisible;
@@ -655,7 +1051,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
 		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
 			return HeapTupleInvisible;
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 						HeapTupleHeaderGetXmin(tuple));
 		else
 		{
@@ -671,7 +1067,9 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
 	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
 		return HeapTupleMayBeUpdated;
 
-	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	if (tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple)))
 	{
 		if (tuple->t_infomask & HEAP_IS_LOCKED)
 			return HeapTupleMayBeUpdated;
@@ -720,7 +1118,7 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid,
 		return HeapTupleMayBeUpdated;
 	}
 
-	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
+	SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
 				HeapTupleHeaderGetXmax(tuple));
 	return HeapTupleUpdated;	/* updated by other */
 }
@@ -751,7 +1149,9 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
 {
 	snapshot->xmin = snapshot->xmax = InvalidTransactionId;
 
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return false;
@@ -822,7 +1222,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
 			return true;		/* in insertion by other */
 		}
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 						HeapTupleHeaderGetXmin(tuple));
 		else
 		{
@@ -838,7 +1238,9 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
 	if (tuple->t_infomask & HEAP_XMAX_INVALID)	/* xid invalid or aborted */
 		return true;
 
-	if (tuple->t_infomask & HEAP_XMAX_COMMITTED)
+	if (tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple)))
 	{
 		if (tuple->t_infomask & HEAP_IS_LOCKED)
 			return true;
@@ -882,7 +1284,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot,
 		return true;
 	}
 
-	SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
+	SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
 				HeapTupleHeaderGetXmax(tuple));
 	return false;				/* updated by other */
 }
@@ -912,7 +1314,9 @@ bool
 HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
 					   Buffer buffer)
 {
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return false;
@@ -985,8 +1389,14 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
 		else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
 			return false;
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
-						HeapTupleHeaderGetXmin(tuple));
+		{
+			/* Set the hint bit on the tuple, and put it in the cache
+			 * if it was actually set.
+			 */
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple));
+
+		}
 		else
 		{
 			/* it must have aborted or crashed */
@@ -1016,7 +1426,9 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
 		return true;
 	}
 
-	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple))))
 	{
 		if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple)))
 		{
@@ -1038,8 +1450,8 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot,
 		}
 
 		/* xmax transaction committed */
-		SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
-					HeapTupleHeaderGetXmax(tuple));
+		SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple));
 	}
 
 	/*
@@ -1074,7 +1486,9 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
 	 * If the inserting transaction aborted, then the tuple was never visible
 	 * to any other transaction, so we can delete it immediately.
 	 */
-	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMIN_COMMITTED,
+				HeapTupleHeaderGetXmin(tuple))))
 	{
 		if (tuple->t_infomask & HEAP_XMIN_INVALID)
 			return HEAPTUPLE_DEAD;
@@ -1125,7 +1539,7 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
 			return HEAPTUPLE_DELETE_IN_PROGRESS;
 		}
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
+			SetHintBitsCache(tuple, buffer, HEAP_XMIN_COMMITTED,
 						HeapTupleHeaderGetXmin(tuple));
 		else
 		{
@@ -1192,13 +1606,17 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
 		return HEAPTUPLE_LIVE;
 	}
 
-	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED))
+	if (!(tuple->t_infomask & HEAP_XMAX_COMMITTED
+		|| HintBitCacheXidStatus(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple))))
 	{
 		if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple)))
 			return HEAPTUPLE_DELETE_IN_PROGRESS;
 		else if (TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple)))
-			SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED,
-						HeapTupleHeaderGetXmax(tuple));
+		{
+			SetHintBitsCache(tuple, buffer, HEAP_XMAX_COMMITTED,
+				HeapTupleHeaderGetXmax(tuple));
+		}
 		else
 		{
 			/*
@@ -1208,7 +1626,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
 						InvalidTransactionId);
 			return HEAPTUPLE_LIVE;
 		}
-
 		/*
 		 * At this point the xmax is known committed, but we might not have
 		 * been able to set the hint bit yet; so we can no longer Assert that