From f2696dc29bdb46de62e8aab3cf4685fe53de9f3a Mon Sep 17 00:00:00 2001 From: Sokolov Yura Date: Mon, 10 Jul 2017 12:34:48 +0000 Subject: [PATCH] Make hash table for xip in XidInMVCCSnapshot --- src/backend/storage/ipc/procarray.c | 21 +++++++++- src/backend/utils/time/tqual.c | 81 +++++++++++++++++++++++++++---------- src/include/access/transam.h | 5 +++ src/include/utils/snapshot.h | 3 ++ 4 files changed, 87 insertions(+), 23 deletions(-) diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index a7e8cf2..2a5e3ac 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -1533,23 +1533,34 @@ GetSnapshotData(Snapshot snapshot) */ if (snapshot->xip == NULL) { + uint32 cap, max; /* * First call for this snapshot. Snapshot is same size whether or not * we are in recovery, see later comments. */ + max = GetMaxSnapshotXidCount(); + cap = 1; + while (cap < max * 2) cap *= 2; snapshot->xip = (TransactionId *) - malloc(GetMaxSnapshotXidCount() * sizeof(TransactionId)); + malloc((max + cap + 1) * sizeof(TransactionId)); if (snapshot->xip == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); + snapshot->xiphash = snapshot->xip + max; + snapshot->xiphash[0] = cap - 1; Assert(snapshot->subxip == NULL); + max = GetMaxSnapshotSubxidCount(); + cap = 1; + while (cap < max * 2) cap *= 2; snapshot->subxip = (TransactionId *) - malloc(GetMaxSnapshotSubxidCount() * sizeof(TransactionId)); + malloc((max + cap + 1) * sizeof(TransactionId)); if (snapshot->subxip == NULL) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); + snapshot->subxiphash = snapshot->subxip + max; + snapshot->subxiphash[0] = cap - 1; } /* @@ -1757,6 +1768,12 @@ GetSnapshotData(Snapshot snapshot) snapshot->active_count = 0; snapshot->regd_count = 0; snapshot->copied = false; + if (snapshot->xiphash != NULL) + { + /* set "unbuilt" bit */ + snapshot->xiphash[0] |= SnapshotHashNotBuilt; + snapshot->subxiphash[0] |= SnapshotHashNotBuilt; + } if (old_snapshot_threshold < 0) { diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index f9da9e1..fdf0a1c 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -1450,6 +1450,59 @@ HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin) return TransactionIdPrecedes(HeapTupleHeaderGetRawXmax(tuple), OldestXmin); } +static bool +XidInXip(TransactionId xid, TransactionId *xip, TransactionId *xiphash, uint32 xcnt) +{ + uint32 i = 0; + uint32 j, k, d, mask; + if (!TransactionIdIsNormal(xid)) + return false; + if (xcnt < 60 || xiphash == NULL) + { + /* full scan for small snapshots and if xiphash is not allocated */ + for (; i < xcnt; i++) + if (TransactionIdEquals(xid, xip[i])) + return true; + return false; + } + mask = xiphash[0]; + xiphash += 1; + if ((mask & SnapshotHashNotBuilt) == 0) + { + d = xid >> 6; + j = k = xid & mask; + while (xiphash[j] != InvalidTransactionId) + { + if (TransactionIdEquals(xiphash[j], xid)) + return true; + j = (k + d) & mask; + d = d*5 + 1; + } + return false; + } + else + { + /* build hash */ + int found = 0; + mask &= ~SnapshotHashNotBuilt; + xiphash[-1] = mask; + memset(xiphash, 0, (mask + 1) * sizeof(TransactionId)); + for (i = 0; i < xcnt; i++) + { + found += TransactionIdEquals(xip[i], xid); + d = xip[i] >> 6; + j = k = xip[i] & mask; + while (xiphash[j] != InvalidTransactionId) + { + j = (k + d) & mask; + d = d*5 + 1; + } + xiphash[j] = xip[i]; + } + return found != 0; + } +} + /* * XidInMVCCSnapshot * Is the given XID still-in-progress according to the snapshot? @@ -1463,8 +1516,6 @@ HeapTupleIsSurelyDead(HeapTuple htup, TransactionId OldestXmin) static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) { - uint32 i; - /* * Make a quick range check to eliminate most XIDs without looking at the * xip arrays. Note that this is OK even if we convert a subxact XID to @@ -1496,13 +1547,8 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) if (!snapshot->suboverflowed) { /* we have full data, so search subxip */ - int32 j; - - for (j = 0; j < snapshot->subxcnt; j++) - { - if (TransactionIdEquals(xid, snapshot->subxip[j])) - return true; - } + if (XidInXip(xid, snapshot->subxip, snapshot->subxiphash, snapshot->subxcnt)) + return true; /* not there, fall through to search xip[] */ } @@ -1523,16 +1569,12 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) return false; } - for (i = 0; i < snapshot->xcnt; i++) - { - if (TransactionIdEquals(xid, snapshot->xip[i])) - return true; - } + + if (XidInXip(xid, snapshot->xip, snapshot->xiphash, snapshot->xcnt)) + return true; } else { - int32 j; - /* * In recovery we store all xids in the subxact array because it is by * far the bigger array, and we mostly don't know which xids are @@ -1562,11 +1604,8 @@ XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) * indeterminate xid. We don't know whether it's top level or subxact * but it doesn't matter. If it's present, the xid is visible. */ - for (j = 0; j < snapshot->subxcnt; j++) - { - if (TransactionIdEquals(xid, snapshot->subxip[j])) - return true; - } + if (XidInXip(xid, snapshot->subxip, snapshot->subxiphash, snapshot->subxcnt)) + return true; } return false; diff --git a/src/include/access/transam.h b/src/include/access/transam.h index 86076de..b60126c 100644 --- a/src/include/access/transam.h +++ b/src/include/access/transam.h @@ -68,6 +68,11 @@ (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ (int32) ((id1) - (id2)) > 0) +/* compare two XIDs already known to be normal; this is a macro for speed */ +#define NormalTransactionIdCompare(id1, id2) \ + (AssertMacro(TransactionIdIsNormal(id1) && TransactionIdIsNormal(id2)), \ + (int32) ((id1) - (id2))) + /* ---------- * Object ID (OID) zero is InvalidOid. * diff --git a/src/include/utils/snapshot.h b/src/include/utils/snapshot.h index 074cc81..e0a3b11 100644 --- a/src/include/utils/snapshot.h +++ b/src/include/utils/snapshot.h @@ -23,6 +23,7 @@ typedef struct SnapshotData *Snapshot; #define InvalidSnapshot ((Snapshot) NULL) +#define SnapshotHashNotBuilt (0x80000000u) /* * We use SnapshotData structures to represent both "regular" (MVCC) @@ -75,6 +76,7 @@ typedef struct SnapshotData * note: all ids in xip[] satisfy xmin <= xip[i] < xmax */ TransactionId *xip; + TransactionId *xiphash; uint32 xcnt; /* # of xact ids in xip[] */ /* @@ -87,6 +89,7 @@ typedef struct SnapshotData * out any that are >= xmax */ TransactionId *subxip; + TransactionId *subxiphash; int32 subxcnt; /* # of xact ids in subxip[] */ bool suboverflowed; /* has the subxip array overflowed? */ -- 1.8.3.1