diff options
Diffstat (limited to 'src/backend/utils/time/snapmgmt.c')
-rw-r--r-- | src/backend/utils/time/snapmgmt.c | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/src/backend/utils/time/snapmgmt.c b/src/backend/utils/time/snapmgmt.c new file mode 100644 index 00000000000..b406b4bc69e --- /dev/null +++ b/src/backend/utils/time/snapmgmt.c @@ -0,0 +1,172 @@ +/*------------------------------------------------------------------------- + * snapmgmt.c + * PostgreSQL snapshot management code. + * + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/utils/time/snapmgmt.c,v 1.1 2008/03/26 16:20:47 alvherre Exp $ + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "access/xact.h" +#include "access/transam.h" +#include "storage/procarray.h" +#include "utils/snapmgmt.h" +#include "utils/tqual.h" + + +/* + * These SnapshotData structs are static to simplify memory allocation + * (see the hack in GetSnapshotData to avoid repeated malloc/free). + */ +static SnapshotData SerializableSnapshotData = {HeapTupleSatisfiesMVCC}; +static SnapshotData LatestSnapshotData = {HeapTupleSatisfiesMVCC}; + +/* Externally visible pointers to valid snapshots: */ +Snapshot SerializableSnapshot = NULL; +Snapshot LatestSnapshot = NULL; + +/* + * This pointer is not maintained by this module, but it's convenient + * to declare it here anyway. Callers typically assign a copy of + * GetTransactionSnapshot's result to ActiveSnapshot. + */ +Snapshot ActiveSnapshot = NULL; + +/* + * These are updated by GetSnapshotData. We initialize them this way + * for the convenience of TransactionIdIsInProgress: even in bootstrap + * mode, we don't want it to say that BootstrapTransactionId is in progress. + */ +TransactionId TransactionXmin = FirstNormalTransactionId; +TransactionId RecentXmin = FirstNormalTransactionId; +TransactionId RecentGlobalXmin = FirstNormalTransactionId; + + +/* + * GetTransactionSnapshot + * Get the appropriate snapshot for a new query in a transaction. + * + * The SerializableSnapshot is the first one taken in a transaction. + * In serializable mode we just use that one throughout the transaction. + * In read-committed mode, we take a new snapshot each time we are called. + * + * Note that the return value points at static storage that will be modified + * by future calls and by CommandCounterIncrement(). Callers should copy + * the result with CopySnapshot() if it is to be used very long. + */ +Snapshot +GetTransactionSnapshot(void) +{ + /* First call in transaction? */ + if (SerializableSnapshot == NULL) + { + SerializableSnapshot = GetSnapshotData(&SerializableSnapshotData, true); + return SerializableSnapshot; + } + + if (IsXactIsoLevelSerializable) + return SerializableSnapshot; + + LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false); + + return LatestSnapshot; +} + +/* + * GetLatestSnapshot + * Get a snapshot that is up-to-date as of the current instant, + * even if we are executing in SERIALIZABLE mode. + */ +Snapshot +GetLatestSnapshot(void) +{ + /* Should not be first call in transaction */ + if (SerializableSnapshot == NULL) + elog(ERROR, "no snapshot has been set"); + + LatestSnapshot = GetSnapshotData(&LatestSnapshotData, false); + + return LatestSnapshot; +} + +/* + * CopySnapshot + * Copy the given snapshot. + * + * The copy is palloc'd in the current memory context. + */ +Snapshot +CopySnapshot(Snapshot snapshot) +{ + Snapshot newsnap; + Size subxipoff; + Size size; + + /* We allocate any XID arrays needed in the same palloc block. */ + size = subxipoff = sizeof(SnapshotData) + + snapshot->xcnt * sizeof(TransactionId); + if (snapshot->subxcnt > 0) + size += snapshot->subxcnt * sizeof(TransactionId); + + newsnap = (Snapshot) palloc(size); + memcpy(newsnap, snapshot, sizeof(SnapshotData)); + + /* setup XID array */ + if (snapshot->xcnt > 0) + { + newsnap->xip = (TransactionId *) (newsnap + 1); + memcpy(newsnap->xip, snapshot->xip, + snapshot->xcnt * sizeof(TransactionId)); + } + else + newsnap->xip = NULL; + + /* setup subXID array */ + if (snapshot->subxcnt > 0) + { + newsnap->subxip = (TransactionId *) ((char *) newsnap + subxipoff); + memcpy(newsnap->subxip, snapshot->subxip, + snapshot->subxcnt * sizeof(TransactionId)); + } + else + newsnap->subxip = NULL; + + return newsnap; +} + +/* + * FreeSnapshot + * Free a snapshot previously copied with CopySnapshot. + * + * This is currently identical to pfree, but is provided for cleanliness. + * + * Do *not* apply this to the results of GetTransactionSnapshot or + * GetLatestSnapshot, since those are just static structs. + */ +void +FreeSnapshot(Snapshot snapshot) +{ + pfree(snapshot); +} + +/* + * FreeXactSnapshot + * Free snapshot(s) at end of transaction. + */ +void +FreeXactSnapshot(void) +{ + /* + * We do not free the xip arrays for the static snapshot structs; they + * will be reused soon. So this is now just a state change to prevent + * outside callers from accessing the snapshots. + */ + SerializableSnapshot = NULL; + LatestSnapshot = NULL; + ActiveSnapshot = NULL; /* just for cleanliness */ +} |