1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-06 07:49:08 +03:00

Separate snapshot management code from tuple visibility code, create a

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.
This commit is contained in:
Alvaro Herrera
2008-03-26 16:20:48 +00:00
parent 2d7705e85e
commit d43b085d57
41 changed files with 345 additions and 258 deletions

View File

@@ -4,7 +4,7 @@
# Makefile for utils/time
#
# IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/utils/time/Makefile,v 1.13 2008/02/19 10:30:09 petere Exp $
# $PostgreSQL: pgsql/src/backend/utils/time/Makefile,v 1.14 2008/03/26 16:20:47 alvherre Exp $
#
#-------------------------------------------------------------------------
@@ -12,6 +12,6 @@ subdir = src/backend/utils/time
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = combocid.o tqual.o
OBJS = combocid.o tqual.o snapmgmt.o
include $(top_srcdir)/src/backend/common.mk

View File

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

View File

@@ -31,7 +31,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.109 2008/01/01 19:45:55 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/time/tqual.c,v 1.110 2008/03/26 16:20:47 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,33 +53,6 @@ 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 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;
/* local functions */
static bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot);
@@ -1235,130 +1208,6 @@ HeapTupleSatisfiesVacuum(HeapTupleHeader tuple, TransactionId OldestXmin,
}
/*
* 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 */
}
/*
* XidInMVCCSnapshot
* Is the given XID still-in-progress according to the snapshot?