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