mirror of https://github.com/postgres/postgres
snapmgmt.c file for the former. The header files have also been reorganized in three parts: the most basic snapshot definitions are now in a new file snapshot.h, and the also new snapmgmt.h keeps the definitions for snapmgmt.c. tqual.h has been reduced to the bare minimum. This patch is just a first step towards managing live snapshots within a transaction; there is no functionality change. Per my proposal to pgsql-patches on 20080318191940.GB27458@alvh.no-ip.org and subsequent discussion.REL8_5_ALPHA1_BRANCH
parent
2d7705e85e
commit
d43b085d57
@ -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 */ |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* snapmgmt.h |
||||||
|
* POSTGRES snapshot management definitions |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* $PostgreSQL: pgsql/src/include/utils/snapmgmt.h,v 1.1 2008/03/26 16:20:48 alvherre Exp $ |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#ifndef SNAPMGMT_H |
||||||
|
#define SNAPMGMT_H |
||||||
|
|
||||||
|
#include "utils/snapshot.h" |
||||||
|
|
||||||
|
|
||||||
|
extern PGDLLIMPORT Snapshot SerializableSnapshot; |
||||||
|
extern PGDLLIMPORT Snapshot LatestSnapshot; |
||||||
|
extern PGDLLIMPORT Snapshot ActiveSnapshot; |
||||||
|
|
||||||
|
extern TransactionId TransactionXmin; |
||||||
|
extern TransactionId RecentXmin; |
||||||
|
extern TransactionId RecentGlobalXmin; |
||||||
|
|
||||||
|
extern Snapshot GetTransactionSnapshot(void); |
||||||
|
extern Snapshot GetLatestSnapshot(void); |
||||||
|
extern Snapshot CopySnapshot(Snapshot snapshot); |
||||||
|
extern void FreeSnapshot(Snapshot snapshot); |
||||||
|
extern void FreeXactSnapshot(void); |
||||||
|
|
||||||
|
#endif /* SNAPMGMT_H */ |
@ -0,0 +1,62 @@ |
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
* |
||||||
|
* snapshot.h |
||||||
|
* POSTGRES snapshot definition |
||||||
|
* |
||||||
|
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group |
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California |
||||||
|
* |
||||||
|
* $PostgreSQL: pgsql/src/include/utils/snapshot.h,v 1.1 2008/03/26 16:20:48 alvherre Exp $ |
||||||
|
* |
||||||
|
*------------------------------------------------------------------------- |
||||||
|
*/ |
||||||
|
#ifndef SNAPSHOT_H |
||||||
|
#define SNAPSHOT_H |
||||||
|
|
||||||
|
#include "access/htup.h" |
||||||
|
#include "storage/buf.h" |
||||||
|
|
||||||
|
|
||||||
|
typedef struct SnapshotData *Snapshot; |
||||||
|
|
||||||
|
#define InvalidSnapshot ((Snapshot) NULL) |
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 bool (*SnapshotSatisfiesFunc) (HeapTupleHeader tuple, |
||||||
|
Snapshot snapshot, Buffer buffer); |
||||||
|
|
||||||
|
typedef struct SnapshotData |
||||||
|
{ |
||||||
|
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 */ |
||||||
|
int32 subxcnt; /* # of xact ids in subxip[], -1 if overflow */ |
||||||
|
TransactionId *subxip; /* array of subxact IDs in progress */ |
||||||
|
|
||||||
|
/*
|
||||||
|
* note: all ids in subxip[] are >= xmin, but we don't bother filtering |
||||||
|
* out any that are >= xmax |
||||||
|
*/ |
||||||
|
CommandId curcid; /* in my xact, CID < curcid are visible */ |
||||||
|
} SnapshotData; |
||||||
|
|
||||||
|
#endif /* SNAPSHOT_H */ |
Loading…
Reference in new issue