/*------------------------------------------------------------------------- * snapmgr.c * PostgreSQL snapshot manager * * 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/snapmgr.c,v 1.1 2008/03/26 18:48:59 alvherre Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include "access/xact.h" #include "access/transam.h" #include "storage/procarray.h" #include "utils/snapmgr.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 */ }