hbcache_v2.patch
application/octet-stream
Filename: hbcache_v2.patch
Type: application/octet-stream
Part: 0
Message:
Re: Process local hint bit cache
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 v2
| File | + | − |
|---|---|---|
| src/backend/utils/time/tqual.c | 189 | 2 |
diff -x '*.sql' -x '*.o' -x '*.txt' -rupN postgresql-9.1alpha4/src/backend/utils/time/tqual.c postgresql-9.1alpha4_hbcache/src/backend/utils/time/tqual.c
--- postgresql-9.1alpha4/src/backend/utils/time/tqual.c 2011-03-09 08:19:24.000000000 -0600
+++ postgresql-9.1alpha4_hbcache/src/backend/utils/time/tqual.c 2011-04-01 11:16:03.095195001 -0500
@@ -122,6 +122,24 @@ SetHintBits(HeapTupleHeader tuple, Buffe
}
/*
+ * SetHintBitsCached()
+ *
+ * When hint bits have been read from a process local cache that is presumed
+ * to be as fast as the in tuple hint bit, the page is not marked as dirty to
+ * give the cache an opportunity to reduce i/o caused by writing out pages for
+ * which only the hint bits have been modified.
+ *
+ * The XLogNeedsFlush check is made when setting up the cache, so it does not
+ * have to be done again here.
+ */
+static inline void
+SetHintBitsCached(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
@@ -887,6 +905,157 @@ HeapTupleSatisfiesDirty(HeapTupleHeader
return false; /* updated by other */
}
+
+#define COMMIT_CACHE_BUCKET_COUNT 4
+#define COMMIT_CACHE_BUCKET_BLOCKSZ BLCKSZ
+#define COMMIT_CACHE_ROLLUPSZ 100
+#define COMMIT_CACHE_HIT_THRESHOLD 5
+
+typedef struct
+{
+ int XidBucket;
+ int HitCount;
+ bool Clear;
+} CommitCacheBucketHeader;
+
+static CommitCacheBucketHeader CommitCacheBucketList[COMMIT_CACHE_BUCKET_COUNT]
+ = {{-1, 0, false}, {-1, 0, false}, {-1, 0, false}, {-1, 0, false}};
+static char CommitCacheData[COMMIT_CACHE_BUCKET_COUNT][COMMIT_CACHE_BUCKET_BLOCKSZ];
+static TransactionId CommitCacheXidRollupList[COMMIT_CACHE_ROLLUPSZ];
+static int CommitCacheMissCount = 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;
+}
+
+static void RollUpCommitCache()
+{
+ TransactionId LastId = CommitCacheXidRollupList[0];
+ int XidIdx;
+ int HitCount = 0;
+ int Bucket;
+ int BucketMinHits = COMMIT_CACHE_ROLLUPSZ + 1;
+ int BucketMinIdx;
+ int XidBucket;
+
+ qsort(CommitCacheXidRollupList, COMMIT_CACHE_ROLLUPSZ, sizeof(int), xid_cmp);
+
+ for (XidIdx = 0; XidIdx < COMMIT_CACHE_ROLLUPSZ; XidIdx++)
+ {
+ if(CommitCacheXidRollupList[XidIdx] == LastId)
+ HitCount++;
+ else
+ {
+ if (HitCount >= COMMIT_CACHE_HIT_THRESHOLD)
+ {
+CheckLastXidBlock:
+ for (Bucket = 0; Bucket < COMMIT_CACHE_BUCKET_COUNT; Bucket++)
+ {
+ if (CommitCacheBucketList[Bucket].HitCount < BucketMinHits)
+ {
+ BucketMinIdx = Bucket;
+ BucketMinHits = CommitCacheBucketList[Bucket].HitCount;
+ }
+ }
+ if (HitCount > BucketMinHits)
+ {
+ XidBucket = LastId / COMMIT_CACHE_BUCKET_BLOCKSZ;
+ if(XidBucket != CommitCacheBucketList[BucketMinIdx].XidBucket)
+ {
+ CommitCacheBucketList[BucketMinIdx].XidBucket = XidBucket;
+ CommitCacheBucketList[BucketMinIdx].HitCount = HitCount;
+ CommitCacheBucketList[BucketMinIdx].Clear = true;
+ }
+ }
+
+ }
+ HitCount = 1;
+ LastId = CommitCacheXidRollupList[XidIdx];
+ }
+ }
+
+ if(HitCount >= COMMIT_CACHE_HIT_THRESHOLD)
+ {
+ XidIdx--;
+ goto CheckLastXidBlock;
+ }
+
+ for (Bucket = 0; Bucket < COMMIT_CACHE_BUCKET_COUNT; Bucket++)
+ {
+ if(CommitCacheBucketList[BucketMinIdx].Clear)
+ memset(CommitCacheData[Bucket], 0, COMMIT_CACHE_BUCKET_BLOCKSZ);
+
+ CommitCacheBucketList[BucketMinIdx].Clear = 0;
+ CommitCacheBucketList[BucketMinIdx].HitCount = 0;
+ }
+
+ CommitCacheMissCount = 0;
+ return;
+}
+
+static int log_count=0;
+static inline bool
+IsXidInCommitCache(TransactionId xid)
+{
+ int XidBucket = xid / COMMIT_CACHE_BUCKET_BLOCKSZ;
+ int Bucket;
+
+ for(Bucket = 0; Bucket < COMMIT_CACHE_BUCKET_COUNT; Bucket++)
+ {
+ if(CommitCacheBucketList[Bucket].XidBucket == XidBucket)
+ {
+ int ByteOffset = xid / BITS_PER_BYTE;
+ int BitOffset = xid % BITS_PER_BYTE;
+ if (CommitCacheData[Bucket][ByteOffset] & (1 << BitOffset))
+ {
+ CommitCacheBucketList[Bucket].HitCount++;
+ return true;
+ }
+
+ break;
+
+ }
+ }
+
+ CommitCacheXidRollupList[CommitCacheMissCount++] = xid;
+
+ if (CommitCacheMissCount == COMMIT_CACHE_ROLLUPSZ)
+ RollUpCommitCache();
+
+ return false;
+}
+
+
+static inline void
+SetXidInCommitCache(TransactionId xid)
+{
+ int XidBucket = xid / COMMIT_CACHE_BUCKET_BLOCKSZ;
+ int Bucket;
+
+ for(Bucket = 0; Bucket < COMMIT_CACHE_BUCKET_COUNT; Bucket++)
+ {
+ if(XidBucket == Bucket)
+ {
+ int ByteOffset = xid / BITS_PER_BYTE;
+ int BitOffset = xid % BITS_PER_BYTE;
+ CommitCacheData[Bucket][ByteOffset] |= (1 << BitOffset);
+ break;
+ }
+ }
+
+ return;
+}
+
/*
* HeapTupleSatisfiesMVCC
* True iff heap tuple is valid for the given MVCC snapshot.
@@ -916,9 +1085,14 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader t
{
if (tuple->t_infomask & HEAP_XMIN_INVALID)
return false;
-
+ /* Check the commit cache we store. If the transaction is
+ * set there, we set the hint bits but don't dirty the page.
+ */
+ if(IsXidInCommitCache(HeapTupleHeaderGetXmin(tuple)))
+ SetHintBitsCached(tuple, buffer, HEAP_XMIN_COMMITTED,
+ HeapTupleHeaderGetXmin(tuple));
/* Used by pre-9.0 binary upgrades */
- if (tuple->t_infomask & HEAP_MOVED_OFF)
+ else if (tuple->t_infomask & HEAP_MOVED_OFF)
{
TransactionId xvac = HeapTupleHeaderGetXvac(tuple);
@@ -985,8 +1159,21 @@ HeapTupleSatisfiesMVCC(HeapTupleHeader t
else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple)))
return false;
else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple)))
+ {
+ /* Only cache this transaction as committed if it's safe
+ * in the xlog so as to avoid making unnecessary repeated
+ * repeated checks to XLogNeedsFlush()
+ */
+ if (TransactionIdIsValid(HeapTupleHeaderGetXmin(tuple)))
+ {
+ XLogRecPtr commitLSN = TransactionIdGetCommitLSN(HeapTupleHeaderGetXmin(tuple));
+
+ if (!XLogNeedsFlush(commitLSN))
+ SetXidInCommitCache(HeapTupleHeaderGetXmin(tuple));
+ }
SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED,
HeapTupleHeaderGetXmin(tuple));
+ }
else
{
/* it must have aborted or crashed */