diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index a36c806..83913de 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -662,6 +662,15 @@ TransactionIdIsCurrentTransactionId(TransactionId xid) TransactionState s; /* + * Optimise for read only transactions. This test gives an O(1) + * response for virtual transactions that haven't yet assigned an xid, + * no matter how deep the tree of subtransactions goes. We reuse the + * PgXact data again later, so the extra memory fetch is amortised. + */ + if (!TransactionIdIsValid(MyPgXact->xid)) + return false; + + /* * We always say that BootstrapTransactionId is "not my transaction ID" * even when it is (ie, during bootstrap). Along with the fact that * transam.c always treats BootstrapTransactionId as already committed, @@ -673,8 +682,18 @@ TransactionIdIsCurrentTransactionId(TransactionId xid) * Likewise, InvalidTransactionId and FrozenTransactionId are certainly * not my transaction ID, so we can just return "false" immediately for * any non-normal XID. - */ - if (!TransactionIdIsNormal(xid)) + * + * But rather than test specifically for non-normal XIDs we just test + * whether the tested xid is less than our top-level xid. Again, this + * is an O(1) test in case of a deep tree of subtransactions and just + * reuses the data we just cached from the above test. You might think + * this test would remove about 50% of xids from search space, but + * fast transactions are short lived, so this removes a greater proportion + * of the search space in a fast transaction. For longer running trans- + * actions the test reduces in effectiveness, eventually falling back to + * being equivalent to just !TransactionIdIsNormal(xid) + */ + if (TransactionIdPrecedes(xid, MyPgXact->xid)) return false; /* @@ -682,20 +701,26 @@ TransactionIdIsCurrentTransactionId(TransactionId xid) * its subcommitted children, any of its parents, or any of their * previously subcommitted children. However, a transaction being aborted * is no longer "current", even though it may still have an entry on the - * state stack. + * state stack. Walk the tree upwards from current subtransaction. */ for (s = CurrentTransactionState; s != NULL; s = s->parent) { int low, high; - if (s->state == TRANS_ABORT) - continue; if (!TransactionIdIsValid(s->transactionId)) continue; /* it can't have any child XIDs either */ + if (s->state == TRANS_ABORT) + continue; /* make unlikely test for correctness later */ if (TransactionIdEquals(xid, s->transactionId)) return true; - /* As the childXids array is ordered, we can use binary search */ + /* + * Search through the array of committed child subtransactions. + * As the childXids array is ordered, we can use binary search. + * By their nature, these xids are earlier work in an extended + * transaction, so they likely span most of the remaining search + * space, leaving little room for specific optimisations here. + */ low = 0; high = s->nChildXids - 1; while (low <= high)