diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/heap/heapam.c | 6 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtinsert.c | 11 | ||||
-rw-r--r-- | src/backend/catalog/catalog.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 7 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 12 | ||||
-rw-r--r-- | src/backend/storage/ipc/procarray.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/ri_triggers.c | 10 | ||||
-rw-r--r-- | src/backend/utils/time/tqual.c | 89 | ||||
-rw-r--r-- | src/include/utils/tqual.h | 117 |
9 files changed, 145 insertions, 118 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index d46308863fe..367831a515a 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.228 2007/02/09 03:35:33 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.229 2007/03/25 19:45:13 tgl Exp $ * * * INTERFACE ROUTINES @@ -1706,7 +1706,7 @@ l1: if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) { /* Perform additional check for serializable RI updates */ - if (!HeapTupleSatisfiesSnapshot(tp.t_data, crosscheck, buffer)) + if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer)) result = HeapTupleUpdated; } @@ -2025,7 +2025,7 @@ l2: if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) { /* Perform additional check for serializable RI updates */ - if (!HeapTupleSatisfiesSnapshot(oldtup.t_data, crosscheck, buffer)) + if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer)) result = HeapTupleUpdated; } diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index d2992374e97..c1671ce333c 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.154 2007/03/05 14:13:12 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.155 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -176,11 +176,14 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel, { TupleDesc itupdesc = RelationGetDescr(rel); int natts = rel->rd_rel->relnatts; + SnapshotData SnapshotDirty; OffsetNumber maxoff; Page page; BTPageOpaque opaque; Buffer nbuf = InvalidBuffer; + InitDirtySnapshot(SnapshotDirty); + page = BufferGetPage(buf); opaque = (BTPageOpaque) PageGetSpecialPointer(page); maxoff = PageGetMaxOffsetNumber(page); @@ -232,13 +235,13 @@ _bt_check_unique(Relation rel, IndexTuple itup, Relation heapRel, /* okay, we gotta fetch the heap tuple ... */ curitup = (IndexTuple) PageGetItem(page, curitemid); htup.t_self = curitup->t_tid; - if (heap_fetch(heapRel, SnapshotDirty, &htup, &hbuffer, + if (heap_fetch(heapRel, &SnapshotDirty, &htup, &hbuffer, true, NULL)) { /* it is a duplicate */ TransactionId xwait = - (TransactionIdIsValid(SnapshotDirty->xmin)) ? - SnapshotDirty->xmin : SnapshotDirty->xmax; + (TransactionIdIsValid(SnapshotDirty.xmin)) ? + SnapshotDirty.xmin : SnapshotDirty.xmax; ReleaseBuffer(hbuffer); diff --git a/src/backend/catalog/catalog.c b/src/backend/catalog/catalog.c index 4d4a851130b..049d216a787 100644 --- a/src/backend/catalog/catalog.c +++ b/src/backend/catalog/catalog.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.69 2007/01/05 22:19:24 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.70 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -361,10 +361,13 @@ Oid GetNewOidWithIndex(Relation relation, Relation indexrel) { Oid newOid; + SnapshotData SnapshotDirty; IndexScanDesc scan; ScanKeyData key; bool collides; + InitDirtySnapshot(SnapshotDirty); + /* Generate new OIDs until we find one not in the table */ do { @@ -377,7 +380,7 @@ GetNewOidWithIndex(Relation relation, Relation indexrel) /* see notes above about using SnapshotDirty */ scan = index_beginscan(relation, indexrel, - SnapshotDirty, 1, &key); + &SnapshotDirty, 1, &key); collides = HeapTupleIsValid(index_getnext(scan, ForwardScanDirection)); diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 092a8d8de38..b660a94aabc 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.280 2007/03/03 20:08:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.281 2007/03/25 19:45:14 tgl Exp $ * * * INTERFACE ROUTINES @@ -1828,10 +1828,11 @@ validate_index_heapscan(Relation heapRelation, */ if (indexInfo->ii_Unique) { - /* must hold a buffer lock to call HeapTupleSatisfiesNow */ + /* must lock buffer to call HeapTupleSatisfiesVisibility */ LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE); - if (HeapTupleSatisfiesNow(heapTuple->t_data, scan->rs_cbuf)) + if (HeapTupleSatisfiesVisibility(heapTuple, SnapshotNow, + scan->rs_cbuf)) check_unique = true; else check_unique = false; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 239656dd06b..b2f7159e8c0 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -26,7 +26,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.290 2007/03/06 02:06:13 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.291 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1893,6 +1893,7 @@ EvalPlanQual(EState *estate, Index rti, Relation relation; HeapTupleData tuple; HeapTuple copyTuple = NULL; + SnapshotData SnapshotDirty; bool endNode; Assert(rti != 0); @@ -1925,12 +1926,13 @@ EvalPlanQual(EState *estate, Index rti, * * Loop here to deal with updated or busy tuples */ + InitDirtySnapshot(SnapshotDirty); tuple.t_self = *tid; for (;;) { Buffer buffer; - if (heap_fetch(relation, SnapshotDirty, &tuple, &buffer, true, NULL)) + if (heap_fetch(relation, &SnapshotDirty, &tuple, &buffer, true, NULL)) { /* * If xmin isn't what we're expecting, the slot must have been @@ -1948,17 +1950,17 @@ EvalPlanQual(EState *estate, Index rti, } /* otherwise xmin should not be dirty... */ - if (TransactionIdIsValid(SnapshotDirty->xmin)) + if (TransactionIdIsValid(SnapshotDirty.xmin)) elog(ERROR, "t_xmin is uncommitted in tuple to be updated"); /* * If tuple is being updated by other transaction then we have to * wait for its commit/abort. */ - if (TransactionIdIsValid(SnapshotDirty->xmax)) + if (TransactionIdIsValid(SnapshotDirty.xmax)) { ReleaseBuffer(buffer); - XactLockTableWait(SnapshotDirty->xmax); + XactLockTableWait(SnapshotDirty.xmax); continue; /* loop back to repeat heap_fetch */ } diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index d2d39770c5b..12e61c89263 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -23,7 +23,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.22 2007/03/23 03:16:39 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.23 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -484,7 +484,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum) * limited cache area for subxact XIDs, full information may not be * available. If we find any overflowed subxid arrays, we have to mark * the snapshot's subxid data as overflowed, and extra work will need to - * be done to determine what's running (see XidInSnapshot() in tqual.c). + * be done to determine what's running (see XidInMVCCSnapshot() in tqual.c). * * We also update the following backend-global variables: * TransactionXmin: the oldest xmin of any snapshot in use in the diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 72200ced9dc..af363f4acff 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -15,7 +15,7 @@ * * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.92 2007/03/15 23:12:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.93 2007/03/25 19:45:14 tgl Exp $ * * ---------- */ @@ -277,11 +277,11 @@ RI_FKey_check(PG_FUNCTION_ARGS) * We should not even consider checking the row if it is no longer valid, * since it was either deleted (so the deferred check should be skipped) * or updated (in which case only the latest version of the row should be - * checked). Test its liveness with HeapTupleSatisfiesItself. + * checked). Test its liveness according to SnapshotSelf. * * NOTE: The normal coding rule is that one must acquire the buffer - * content lock to call HeapTupleSatisfiesFOO. We can skip that here - * because we know that AfterTriggerExecute just fetched the tuple + * content lock to call HeapTupleSatisfiesVisibility. We can skip that + * here because we know that AfterTriggerExecute just fetched the tuple * successfully, so there cannot be a VACUUM compaction in progress on the * page (either heap_fetch would have waited for the VACUUM, or the * VACUUM's LockBufferForCleanup would be waiting for us to drop pin). @@ -289,7 +289,7 @@ RI_FKey_check(PG_FUNCTION_ARGS) * can be entitled to change its xmin/xmax. */ Assert(new_row_buf != InvalidBuffer); - if (!HeapTupleSatisfiesItself(new_row->t_data, new_row_buf)) + if (!HeapTupleSatisfiesVisibility(new_row, SnapshotSelf, new_row_buf)) return PointerGetDatum(NULL); /* diff --git a/src/backend/utils/time/tqual.c b/src/backend/utils/time/tqual.c index 13cc211b5db..429005a843a 100644 --- a/src/backend/utils/time/tqual.c +++ b/src/backend/utils/time/tqual.c @@ -1,15 +1,14 @@ /*------------------------------------------------------------------------- * * tqual.c - * POSTGRES "time" qualification code, ie, tuple visibility rules. - * - * The caller must hold at least a shared buffer context lock on the buffer - * containing the tuple. (VACUUM FULL assumes it's sufficient to have - * exclusive lock on the containing relation, instead.) + * POSTGRES "time qualification" code, ie, tuple visibility rules. * * NOTE: all the HeapTupleSatisfies routines will update the tuple's * "hint" status bits if we see that the inserting or deleting transaction - * has now committed or aborted. + * has now committed or aborted. If the hint bits are changed, + * SetBufferCommitInfoNeedsSave is called on the passed-in buffer. + * The caller must hold at least a shared buffer context lock on the buffer + * containing the tuple. * * NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array) * before TransactionIdDidCommit/TransactionIdDidAbort (which look in @@ -32,7 +31,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.101 2007/01/05 22:19:47 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.102 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,16 +46,21 @@ #include "storage/procarray.h" #include "utils/tqual.h" + +/* Static variables representing various special snapshot semantics */ +SnapshotData SnapshotNowData = {HeapTupleSatisfiesNow}; +SnapshotData SnapshotSelfData = {HeapTupleSatisfiesSelf}; +SnapshotData SnapshotAnyData = {HeapTupleSatisfiesAny}; +SnapshotData SnapshotToastData = {HeapTupleSatisfiesToast}; + /* * These SnapshotData structs are static to simplify memory allocation * (see the hack in GetSnapshotData to avoid repeated malloc/free). */ -static SnapshotData SnapshotDirtyData; -static SnapshotData SerializableSnapshotData; -static SnapshotData LatestSnapshotData; +static SnapshotData SerializableSnapshotData = {HeapTupleSatisfiesMVCC}; +static SnapshotData LatestSnapshotData = {HeapTupleSatisfiesMVCC}; /* Externally visible pointers to valid snapshots: */ -Snapshot SnapshotDirty = &SnapshotDirtyData; Snapshot SerializableSnapshot = NULL; Snapshot LatestSnapshot = NULL; @@ -73,11 +77,11 @@ TransactionId RecentXmin = InvalidTransactionId; TransactionId RecentGlobalXmin = InvalidTransactionId; /* local functions */ -static bool XidInSnapshot(TransactionId xid, Snapshot snapshot); +static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot); /* - * HeapTupleSatisfiesItself + * HeapTupleSatisfiesSelf * True iff heap tuple is valid "for itself". * * Here, we consider the effects of: @@ -101,7 +105,7 @@ static bool XidInSnapshot(TransactionId xid, Snapshot snapshot); * Xmax is not committed))) that has not been committed */ bool -HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer) +HeapTupleSatisfiesSelf(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -278,7 +282,7 @@ HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer) * that do catalog accesses. this is unfortunate, but not critical. */ bool -HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer) +HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -423,6 +427,16 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer) } /* + * HeapTupleSatisfiesAny + * Dummy "satisfies" routine: any tuple satisfies SnapshotAny. + */ +bool +HeapTupleSatisfiesAny(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) +{ + return true; +} + +/* * HeapTupleSatisfiesToast * True iff heap tuple is valid as a TOAST row. * @@ -437,7 +451,8 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer) * table. */ bool -HeapTupleSatisfiesToast(HeapTupleHeader tuple, Buffer buffer) +HeapTupleSatisfiesToast(HeapTupleHeader tuple, Snapshot snapshot, + Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -676,20 +691,22 @@ HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid, * previous commands of this transaction * changes made by the current command * - * This is essentially like HeapTupleSatisfiesItself as far as effects of + * This is essentially like HeapTupleSatisfiesSelf as far as effects of * the current transaction and committed/aborted xacts are concerned. * However, we also include the effects of other xacts still in progress. * - * Returns extra information in the global variable SnapshotDirty, namely - * xids of concurrent xacts that affected the tuple. SnapshotDirty->xmin - * is set to InvalidTransactionId if xmin is either committed good or - * committed dead; or to xmin if that transaction is still in progress. - * Similarly for SnapshotDirty->xmax. + * A special hack is that the passed-in snapshot struct is used as an + * output argument to return the xids of concurrent xacts that affected the + * tuple. snapshot->xmin is set to the tuple's xmin if that is another + * transaction that's still in progress; or to InvalidTransactionId if the + * tuple's xmin is committed good, committed dead, or my own xact. Similarly + * for snapshot->xmax and the tuple's xmax. */ bool -HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) +HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Snapshot snapshot, + Buffer buffer) { - SnapshotDirty->xmin = SnapshotDirty->xmax = InvalidTransactionId; + snapshot->xmin = snapshot->xmax = InvalidTransactionId; if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -759,7 +776,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) { - SnapshotDirty->xmin = HeapTupleHeaderGetXmin(tuple); + snapshot->xmin = HeapTupleHeaderGetXmin(tuple); /* XXX shouldn't we fall through to look at xmax? */ return true; /* in insertion by other */ } @@ -805,7 +822,7 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) { - SnapshotDirty->xmax = HeapTupleHeaderGetXmax(tuple); + snapshot->xmax = HeapTupleHeaderGetXmax(tuple); return true; } @@ -832,8 +849,8 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) } /* - * HeapTupleSatisfiesSnapshot - * True iff heap tuple is valid for the given snapshot. + * HeapTupleSatisfiesMVCC + * True iff heap tuple is valid for the given MVCC snapshot. * * Here, we consider the effects of: * all transactions committed as of the time of the given snapshot @@ -853,8 +870,8 @@ HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer) * can't see it.) */ bool -HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot, - Buffer buffer) +HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, Snapshot snapshot, + Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { @@ -949,7 +966,7 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot, * By here, the inserting transaction has committed - have to check * when... */ - if (XidInSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot)) + if (XidInMVCCSnapshot(HeapTupleHeaderGetXmin(tuple), snapshot)) return false; /* treat as still in progress */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ @@ -994,7 +1011,7 @@ HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, Snapshot snapshot, /* * OK, the deleting transaction committed too ... but when? */ - if (XidInSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot)) + if (XidInMVCCSnapshot(HeapTupleHeaderGetXmax(tuple), snapshot)) return true; /* treat as still in progress */ return false; @@ -1241,8 +1258,6 @@ GetLatestSnapshot(void) * Copy the given snapshot. * * The copy is palloc'd in the current memory context. - * - * Note that this will not work on "special" snapshots. */ Snapshot CopySnapshot(Snapshot snapshot) @@ -1290,7 +1305,7 @@ CopySnapshot(Snapshot snapshot) * This is currently identical to pfree, but is provided for cleanliness. * * Do *not* apply this to the results of GetTransactionSnapshot or - * GetLatestSnapshot. + * GetLatestSnapshot, since those are just static structs. */ void FreeSnapshot(Snapshot snapshot) @@ -1316,7 +1331,7 @@ FreeXactSnapshot(void) } /* - * XidInSnapshot + * XidInMVCCSnapshot * Is the given XID still-in-progress according to the snapshot? * * Note: GetSnapshotData never stores either top xid or subxids of our own @@ -1325,7 +1340,7 @@ FreeXactSnapshot(void) * apply this for known-committed XIDs. */ static bool -XidInSnapshot(TransactionId xid, Snapshot snapshot) +XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot) { uint32 i; diff --git a/src/include/utils/tqual.h b/src/include/utils/tqual.h index 0b3ef50ac34..e3596e2d507 100644 --- a/src/include/utils/tqual.h +++ b/src/include/utils/tqual.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.65 2007/01/05 22:19:59 momjian Exp $ + * $PostgreSQL: pgsql/src/include/utils/tqual.h,v 1.66 2007/03/25 19:45:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,23 +20,31 @@ /* - * "Regular" snapshots are pointers to a SnapshotData structure. - * - * We also have some "special" snapshot values that have fixed meanings - * and don't need any backing SnapshotData. These are encoded by small - * integer values, which of course is a gross violation of ANSI C, but - * it works fine on all known platforms. - * - * SnapshotDirty is an even more special case: its semantics are fixed, - * but there is a backing SnapshotData struct for it. That struct is - * actually used as *output* data from tqual.c, not input into it. - * (But hey, SnapshotDirty ought to have a dirty implementation, no? ;-)) + * We use SnapshotData structures to represent both "regular" (MVCC) + * snapshots and "special" snapshots that have non-MVCC semantics. + * The specific semantics of a snapshot are encoded by the "satisfies" + * function. */ +typedef struct SnapshotData *Snapshot; + +typedef bool (*SnapshotSatisfiesFunc) (HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); typedef struct SnapshotData { - TransactionId xmin; /* XID < xmin are visible to me */ - TransactionId xmax; /* XID >= xmax are invisible to me */ + SnapshotSatisfiesFunc satisfies; /* tuple test function */ + /* + * The remaining fields are used only for MVCC snapshots, and are + * normally just zeroes in special snapshots. (But xmin and xmax + * are used specially by HeapTupleSatisfiesDirty.) + * + * An MVCC snapshot can never see the effects of XIDs >= xmax. + * It can see the effects of all older XIDs except those listed in + * the snapshot. xmin is stored as an optimization to avoid needing + * to search the XID arrays for most tuples. + */ + TransactionId xmin; /* all XID < xmin are visible to me */ + TransactionId xmax; /* all XID >= xmax are invisible to me */ uint32 xcnt; /* # of xact ids in xip[] */ TransactionId *xip; /* array of xact IDs in progress */ /* note: all ids in xip[] satisfy xmin <= xip[i] < xmax */ @@ -50,24 +58,30 @@ typedef struct SnapshotData CommandId curcid; /* in my xact, CID < curcid are visible */ } SnapshotData; -typedef SnapshotData *Snapshot; +#define InvalidSnapshot ((Snapshot) NULL) -/* Special snapshot values: */ -#define InvalidSnapshot ((Snapshot) 0x0) /* same as NULL */ -#define SnapshotNow ((Snapshot) 0x1) -#define SnapshotSelf ((Snapshot) 0x2) -#define SnapshotAny ((Snapshot) 0x3) -#define SnapshotToast ((Snapshot) 0x4) +/* Static variables representing various special snapshot semantics */ +extern DLLIMPORT SnapshotData SnapshotNowData; +extern DLLIMPORT SnapshotData SnapshotSelfData; +extern DLLIMPORT SnapshotData SnapshotAnyData; +extern DLLIMPORT SnapshotData SnapshotToastData; -extern DLLIMPORT Snapshot SnapshotDirty; +#define SnapshotNow (&SnapshotNowData) +#define SnapshotSelf (&SnapshotSelfData) +#define SnapshotAny (&SnapshotAnyData) +#define SnapshotToast (&SnapshotToastData) + +/* + * We don't provide a static SnapshotDirty variable because it would be + * non-reentrant. Instead, users of that snapshot type should declare a + * local variable of type SnapshotData, and initialize it with this macro. + */ +#define InitDirtySnapshot(snapshotdata) \ + ((snapshotdata).satisfies = HeapTupleSatisfiesDirty) /* This macro encodes the knowledge of which snapshots are MVCC-safe */ #define IsMVCCSnapshot(snapshot) \ - ((snapshot) != SnapshotNow && \ - (snapshot) != SnapshotSelf && \ - (snapshot) != SnapshotAny && \ - (snapshot) != SnapshotToast && \ - (snapshot) != SnapshotDirty) + ((snapshot)->satisfies == HeapTupleSatisfiesMVCC) extern DLLIMPORT Snapshot SerializableSnapshot; @@ -78,7 +92,6 @@ extern TransactionId TransactionXmin; extern TransactionId RecentXmin; extern TransactionId RecentGlobalXmin; - /* * HeapTupleSatisfiesVisibility * True iff heap tuple satisfies a time qual. @@ -86,30 +99,11 @@ extern TransactionId RecentGlobalXmin; * Notes: * Assumes heap tuple is valid. * Beware of multiple evaluations of snapshot argument. - * Hint bits in the HeapTuple's t_infomask may be updated as a side effect. + * Hint bits in the HeapTuple's t_infomask may be updated as a side effect; + * if so, the indicated buffer is marked dirty. */ #define HeapTupleSatisfiesVisibility(tuple, snapshot, buffer) \ -((snapshot) == SnapshotNow ? \ - HeapTupleSatisfiesNow((tuple)->t_data, buffer) \ -: \ - ((snapshot) == SnapshotSelf ? \ - HeapTupleSatisfiesItself((tuple)->t_data, buffer) \ - : \ - ((snapshot) == SnapshotAny ? \ - true \ - : \ - ((snapshot) == SnapshotToast ? \ - HeapTupleSatisfiesToast((tuple)->t_data, buffer) \ - : \ - ((snapshot) == SnapshotDirty ? \ - HeapTupleSatisfiesDirty((tuple)->t_data, buffer) \ - : \ - HeapTupleSatisfiesSnapshot((tuple)->t_data, snapshot, buffer) \ - ) \ - ) \ - ) \ - ) \ -) + ((*(snapshot)->satisfies) ((tuple)->t_data, snapshot, buffer)) /* Result codes for HeapTupleSatisfiesUpdate */ typedef enum @@ -127,16 +121,25 @@ typedef enum HEAPTUPLE_DEAD, /* tuple is dead and deletable */ HEAPTUPLE_LIVE, /* tuple is live (committed, no deleter) */ HEAPTUPLE_RECENTLY_DEAD, /* tuple is dead, but not deletable yet */ - HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ + HEAPTUPLE_INSERT_IN_PROGRESS, /* inserting xact is still in progress */ HEAPTUPLE_DELETE_IN_PROGRESS /* deleting xact is still in progress */ } HTSV_Result; -extern bool HeapTupleSatisfiesItself(HeapTupleHeader tuple, Buffer buffer); -extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer); -extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple, Buffer buffer); -extern bool HeapTupleSatisfiesToast(HeapTupleHeader tuple, Buffer buffer); -extern bool HeapTupleSatisfiesSnapshot(HeapTupleHeader tuple, - Snapshot snapshot, Buffer buffer); +/* These are the "satisfies" test routines for the various snapshot types */ +extern bool HeapTupleSatisfiesMVCC(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); +extern bool HeapTupleSatisfiesNow(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); +extern bool HeapTupleSatisfiesSelf(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); +extern bool HeapTupleSatisfiesAny(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); +extern bool HeapTupleSatisfiesToast(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); +extern bool HeapTupleSatisfiesDirty(HeapTupleHeader tuple, + Snapshot snapshot, Buffer buffer); + +/* Special "satisfies" routines with different APIs */ extern HTSU_Result HeapTupleSatisfiesUpdate(HeapTupleHeader tuple, CommandId curcid, Buffer buffer); extern HTSV_Result HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, |