Clean up the representation of special snapshots by including a "method

pointer" in every Snapshot struct.  This allows removal of the case-by-case
tests in HeapTupleSatisfiesVisibility, which should make it a bit faster
(I didn't try any performance tests though).  More importantly, we are no
longer violating portable C practices by assuming that small integers are
distinct from all pointer values, and HeapTupleSatisfiesDirty no longer
has a non-reentrant API involving side-effects on a global variable.

There were a couple of places calling HeapTupleSatisfiesXXX routines
directly rather than through the HeapTupleSatisfiesVisibility macro.
Since these places had to be changed anyway, I chose to make them go
through the macro for uniformity.

Along the way I renamed HeapTupleSatisfiesSnapshot to HeapTupleSatisfiesMVCC
to emphasize that it's only used with MVCC-type snapshots.  I was sorely
tempted to rename HeapTupleSatisfiesVisibility to HeapTupleSatisfiesSnapshot,
but forebore for the moment to avoid confusion and reduce the likelihood that
this patch breaks some of the pending patches.  Might want to reconsider
doing that later.
This commit is contained in:
Tom Lane 2007-03-25 19:45:14 +00:00
parent 75c6519ff6
commit e85a01df67
10 changed files with 148 additions and 121 deletions

View file

@ -1,5 +1,5 @@
/*
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.25 2006/10/04 00:29:46 momjian Exp $
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.26 2007/03/25 19:45:13 tgl Exp $
*
* Copyright (c) 2001,2002 Tatsuo Ishii
*
@ -256,10 +256,10 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
/* scan the relation */
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
{
/* must hold a buffer lock to call HeapTupleSatisfiesNow */
/* must hold a buffer lock to call HeapTupleSatisfiesVisibility */
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
if (HeapTupleSatisfiesNow(tuple->t_data, scan->rs_cbuf))
if (HeapTupleSatisfiesVisibility(tuple, SnapshotNow, scan->rs_cbuf))
{
stat.tuple_len += tuple->t_len;
stat.tuple_count++;

View file

@ -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;
}

View file

@ -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);

View file

@ -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));

View file

@ -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;

View file

@ -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 */
}

View file

@ -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

View file

@ -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);
/*

View file

@ -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))
{
@ -422,6 +426,16 @@ HeapTupleSatisfiesNow(HeapTupleHeader tuple, Buffer buffer)
return false;
}
/*
* 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;

View file

@ -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,