hbache_v6.patch
application/octet-stream
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v6
| File | + | − |
|---|---|---|
| src/backend/utils/time/tqual.c | 447 | 30 |
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