Re: Make HeapTupleSatisfiesMVCC more concurrent - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Re: Make HeapTupleSatisfiesMVCC more concurrent |
Date | |
Msg-id | 5722.1439944573@sss.pgh.pa.us Whole thread Raw |
In response to | Re: Make HeapTupleSatisfiesMVCC more concurrent (Tom Lane <tgl@sss.pgh.pa.us>) |
Responses |
Re: Make HeapTupleSatisfiesMVCC more concurrent
Re: Make HeapTupleSatisfiesMVCC more concurrent Re: Make HeapTupleSatisfiesMVCC more concurrent Re: Make HeapTupleSatisfiesMVCC more concurrent |
List | pgsql-hackers |
I wrote: > Just thinking about this ... I wonder why we need to call > TransactionIdIsInProgress() at all rather than believing the answer from > the snapshot? Under what circumstances could TransactionIdIsInProgress() > return true where XidInMVCCSnapshot() had not? I experimented with the attached patch, which replaces HeapTupleSatisfiesMVCC's calls of TransactionIdIsInProgress with XidInMVCCSnapshot, and then as a cross-check has all the "return false" exits from XidInMVCCSnapshot assert !TransactionIdIsInProgress(). The asserts did not fire in the standard regression tests nor in a pgbench run, which is surely not proof of anything but it suggests that I'm not totally nuts. I wouldn't commit the changes in XidInMVCCSnapshot for real, but otherwise this is a possibly committable patch. regards, tom lane diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index de7b3fc..c8f59f7 100644 *** a/src/backend/utils/time/tqual.c --- b/src/backend/utils/time/tqual.c *************** *** 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. * ! * NOTE: must check TransactionIdIsInProgress (which looks in PGXACT array) * before TransactionIdDidCommit/TransactionIdDidAbort (which look in * pg_clog). Otherwise we have a race condition: we might decide that a * just-committed transaction crashed, because none of the tests succeed. * xact.c is careful to record commit/abort in pg_clog before it unsets ! * MyPgXact->xid in PGXACT array. That fixes that problem, but it also * means there is a window where TransactionIdIsInProgress and * TransactionIdDidCommit will both return true. If we check only * TransactionIdDidCommit, we could consider a tuple committed when a --- 10,22 ---- * 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. * ! * NOTE: When using a non-MVCC snapshot, we must check ! * TransactionIdIsInProgress (which looks in the PGXACT array) * before TransactionIdDidCommit/TransactionIdDidAbort (which look in * pg_clog). Otherwise we have a race condition: we might decide that a * just-committed transaction crashed, because none of the tests succeed. * xact.c is careful to record commit/abort in pg_clog before it unsets ! * MyPgXact->xid in the PGXACT array. That fixes that problem, but it also * means there is a window where TransactionIdIsInProgress and * TransactionIdDidCommit will both return true. If we check only * TransactionIdDidCommit, we could consider a tuple committed when a *************** *** 26,31 **** --- 27,37 ---- * subtransactions of our own main transaction and so there can't be any * race condition. * + * When using an MVCC snapshot, we rely on XidInMVCCSnapshot rather than + * TransactionIdIsInProgress, but the logic is otherwise the same: do not + * check pg_clog until after deciding that the xact is no longer in progress. + * + * * Summary of visibility functions: * * HeapTupleSatisfiesMVCC() *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 961,967 **** if (TransactionIdIsCurrentTransactionId(xvac)) return false; ! if (!TransactionIdIsInProgress(xvac)) { if (TransactionIdDidCommit(xvac)) { --- 967,973 ---- if (TransactionIdIsCurrentTransactionId(xvac)) return false; ! if (!XidInMVCCSnapshot(xvac, snapshot)) { if (TransactionIdDidCommit(xvac)) { *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 980,986 **** if (!TransactionIdIsCurrentTransactionId(xvac)) { ! if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, --- 986,992 ---- if (!TransactionIdIsCurrentTransactionId(xvac)) { ! if (XidInMVCCSnapshot(xvac, snapshot)) return false; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 1035,1041 **** else return false; /* deleted before scan started */ } ! else if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, --- 1041,1047 ---- else return false; /* deleted before scan started */ } ! else if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot)) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetRawXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 1048,1061 **** return false; } } ! /* ! * By here, the inserting transaction has committed - have to check ! * when... ! */ ! if (!HeapTupleHeaderXminFrozen(tuple) ! && XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot)) ! return false; /* treat as still in progress */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; --- 1054,1068 ---- return false; } } + else + { + /* xmin is committed, but maybe not according to our snapshot */ + if (!HeapTupleHeaderXminFrozen(tuple) && + XidInMVCCSnapshot(HeapTupleHeaderGetRawXmin(tuple), snapshot)) + return false; /* treat as still in progress */ + } ! /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 1082,1096 **** else return false; /* deleted before scan started */ } ! if (TransactionIdIsInProgress(xmax)) return true; if (TransactionIdDidCommit(xmax)) ! { ! /* updating transaction committed, but when? */ ! if (XidInMVCCSnapshot(xmax, snapshot)) ! return true; /* treat as still in progress */ ! return false; ! } /* it must have aborted or crashed */ return true; } --- 1089,1098 ---- else return false; /* deleted before scan started */ } ! if (XidInMVCCSnapshot(xmax, snapshot)) return true; if (TransactionIdDidCommit(xmax)) ! return false; /* updating transaction committed */ /* it must have aborted or crashed */ return true; } *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 1105,1111 **** return false; /* deleted before scan started */ } ! if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple))) return true; if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) --- 1107,1113 ---- return false; /* deleted before scan started */ } ! if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) return true; if (!TransactionIdDidCommit(HeapTupleHeaderGetRawXmax(tuple))) *************** HeapTupleSatisfiesMVCC(HeapTuple htup, S *** 1120,1131 **** SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); } ! /* ! * OK, the deleting transaction committed too ... but when? ! */ ! if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) ! return true; /* treat as still in progress */ return false; } --- 1122,1135 ---- SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetRawXmax(tuple)); } + else + { + /* xmax is committed, but maybe not according to our snapshot */ + if (XidInMVCCSnapshot(HeapTupleHeaderGetRawXmax(tuple), snapshot)) + return true; /* treat as still in progress */ + } ! /* xmax transaction committed */ return false; } *************** XidInMVCCSnapshot(TransactionId xid, Sna *** 1461,1467 **** --- 1465,1474 ---- /* Any xid < xmin is not in-progress */ if (TransactionIdPrecedes(xid, snapshot->xmin)) + { + Assert(!TransactionIdIsInProgress(xid)); return false; + } /* Any xid >= xmax is in-progress */ if (TransactionIdFollowsOrEquals(xid, snapshot->xmax)) return true; *************** XidInMVCCSnapshot(TransactionId xid, Sna *** 1503,1509 **** --- 1510,1519 ---- * xmax. */ if (TransactionIdPrecedes(xid, snapshot->xmin)) + { + Assert(!TransactionIdIsInProgress(xid)); return false; + } } for (i = 0; i < snapshot->xcnt; i++) *************** XidInMVCCSnapshot(TransactionId xid, Sna *** 1534,1540 **** --- 1544,1553 ---- * xmax. */ if (TransactionIdPrecedes(xid, snapshot->xmin)) + { + Assert(!TransactionIdIsInProgress(xid)); return false; + } } /* *************** XidInMVCCSnapshot(TransactionId xid, Sna *** 1549,1554 **** --- 1562,1568 ---- } } + Assert(!TransactionIdIsInProgress(xid)); return false; }
pgsql-hackers by date: