SERIALIZABLE transactions are actually implemented beneath the covers with

transaction snapshots, i.e. a snapshot registered at the beginning of
a transaction. Change variable naming and comments to reflect this reality
in preparation for a future, truly serializable mode, e.g.
Serializable Snapshot Isolation (SSI).

For the moment transaction snapshots are still used to implement
SERIALIZABLE, but hopefully not for too much longer. Patch by Kevin
Grittner and Dan Ports with review and some minor wording changes by me.
This commit is contained in:
Joe Conway 2010-09-11 18:38:58 +00:00
parent 262c71ab63
commit 5eb15c9942
11 changed files with 49 additions and 49 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.293 2010/07/29 16:14:36 rhaas Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.294 2010/09/11 18:38:55 joe Exp $
*
*
* INTERFACE ROUTINES
@ -2173,7 +2173,7 @@ l1:
if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated)
{
/* Perform additional check for serializable RI updates */
/* Perform additional check for transaction-snapshot mode RI updates */
if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
result = HeapTupleUpdated;
}
@ -2525,7 +2525,7 @@ l2:
if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated)
{
/* Perform additional check for serializable RI updates */
/* Perform additional check for transaction-snapshot mode RI updates */
if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer))
result = HeapTupleUpdated;
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.338 2010/08/13 20:10:50 rhaas Exp $
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.339 2010/09/11 18:38:56 joe Exp $
*
*
* INTERFACE ROUTINES
@ -2049,7 +2049,7 @@ IndexCheckExclusion(Relation heapRelation,
*
* After completing validate_index(), we wait until all transactions that
* were alive at the time of the reference snapshot are gone; this is
* necessary to be sure there are none left with a serializable snapshot
* necessary to be sure there are none left with a transaction snapshot
* older than the reference (and hence possibly able to see tuples we did
* not index). Then we mark the index "indisvalid" and commit. Subsequent
* transactions will be able to use it for queries.

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.265 2010/08/19 15:46:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.266 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -2387,7 +2387,7 @@ ltrmark:;
case HeapTupleUpdated:
ReleaseBuffer(buffer);
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));

View File

@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.354 2010/08/05 14:45:02 rhaas Exp $
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.355 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -1554,7 +1554,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
case HeapTupleUpdated:
ReleaseBuffer(buffer);
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.6 2010/07/28 17:21:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeLockRows.c,v 1.7 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -130,7 +130,7 @@ lnext:
break;
case HeapTupleUpdated:
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.9 2010/08/18 21:52:24 tgl Exp $
* $PostgreSQL: pgsql/src/backend/executor/nodeModifyTable.c,v 1.10 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -310,7 +310,7 @@ ExecDelete(ItemPointer tupleid,
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
* the row to be deleted is visible to that snapshot, and throw a can't-
* serialize error if not. This is a special-case behavior needed for
* referential integrity updates in serializable transactions.
* referential integrity updates in transaction-snapshot mode transactions.
*/
ldelete:;
result = heap_delete(resultRelationDesc, tupleid,
@ -328,7 +328,7 @@ ldelete:;
break;
case HeapTupleUpdated:
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));
@ -499,7 +499,7 @@ lreplace:;
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that
* the row to be updated is visible to that snapshot, and throw a can't-
* serialize error if not. This is a special-case behavior needed for
* referential integrity updates in serializable transactions.
* referential integrity updates in transaction-snapshot mode transactions.
*/
result = heap_update(resultRelationDesc, tupleid, tuple,
&update_ctid, &update_xmax,
@ -516,7 +516,7 @@ lreplace:;
break;
case HeapTupleUpdated:
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update")));

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.596 2010/08/12 23:24:54 rhaas Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.597 2010/09/11 18:38:56 joe Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -2802,7 +2802,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason)
*
* PROCSIG_RECOVERY_CONFLICT_SNAPSHOT if no snapshots are held
* by parent transactions and the transaction is not
* serializable
* transaction-snapshot mode
*
* PROCSIG_RECOVERY_CONFLICT_TABLESPACE if no temp files or
* cursors open in parent transactions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.137 2010/02/26 02:01:02 momjian Exp $
* $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.138 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -1163,8 +1163,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
* Set snapshot if utility stmt needs one. Most reliable way to do this
* seems to be to enumerate those that do not need one; this is a short
* list. Transaction control, LOCK, and SET must *not* set a snapshot
* since they need to be executable at the start of a serializable
* transaction without freezing a snapshot. By extension we allow SHOW
* since they need to be executable at the start of a transaction-snapshot
* mode transaction without freezing a snapshot. By extension we allow SHOW
* not to set a snapshot. The other stmts listed are just efficiency
* hacks. Beware of listing anything that can modify the database --- if,
* say, it has to update an index with expressions that invoke

View File

@ -15,7 +15,7 @@
*
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.120 2010/07/28 05:22:24 sriggs Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.121 2010/09/11 18:38:56 joe Exp $
*
* ----------
*/
@ -2784,10 +2784,10 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel)
/*
* Run the plan. For safety we force a current snapshot to be used. (In
* serializable mode, this arguably violates serializability, but we
* really haven't got much choice.) We don't need to register the
* snapshot, because SPI_execute_snapshot will see to it. We need at most
* one tuple returned, so pass limit = 1.
* transaction-snapshot mode, this arguably violates transaction
* isolation rules, but we really haven't got much choice.)
* We don't need to register the snapshot, because SPI_execute_snapshot
* will see to it. We need at most one tuple returned, so pass limit = 1.
*/
spi_result = SPI_execute_snapshot(qplan,
NULL, NULL,
@ -3332,15 +3332,15 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan,
/*
* In READ COMMITTED mode, we just need to use an up-to-date regular
* snapshot, and we will see all rows that could be interesting. But in
* SERIALIZABLE mode, we can't change the transaction snapshot. If the
* caller passes detectNewRows == false then it's okay to do the query
* transaction-snapshot mode, we can't change the transaction snapshot.
* If the caller passes detectNewRows == false then it's okay to do the query
* with the transaction snapshot; otherwise we use a current snapshot, and
* tell the executor to error out if it finds any rows under the current
* snapshot that wouldn't be visible per the transaction snapshot. Note
* that SPI_execute_snapshot will register the snapshots, so we don't need
* to bother here.
*/
if (IsXactIsoLevelSerializable && detectNewRows)
if (IsolationUsesXactSnapshot() && detectNewRows)
{
CommandCounterIncrement(); /* be sure all my own work is visible */
test_snapshot = GetLatestSnapshot();

View File

@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.15 2010/02/26 02:01:15 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.16 2010/09/11 18:38:56 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -37,10 +37,10 @@
/*
* CurrentSnapshot points to the only snapshot taken in a serializable
* transaction, and to the latest one taken in a read-committed transaction.
* CurrentSnapshot points to the only snapshot taken in transaction-snapshot
* mode, and to the latest one taken in a read-committed transaction.
* SecondarySnapshot is a snapshot that's always up-to-date as of the current
* instant, even on a serializable transaction. It should only be used for
* instant, even in transaction-snapshot mode. It should only be used for
* special-purpose code (say, RI checking.)
*
* These SnapshotData structs are static to simplify memory allocation
@ -97,11 +97,11 @@ static int RegisteredSnapshots = 0;
bool FirstSnapshotSet = false;
/*
* Remembers whether this transaction registered a serializable snapshot at
* Remembers whether this transaction registered a transaction snapshot at
* start. We cannot trust FirstSnapshotSet in combination with
* IsXactIsoLevelSerializable, because GUC may be reset before us.
* IsolationUsesXactSnapshot(), because GUC may be reset before us.
*/
static bool registered_serializable = false;
static bool registered_xact_snapshot = false;
static Snapshot CopySnapshot(Snapshot snapshot);
@ -130,21 +130,21 @@ GetTransactionSnapshot(void)
FirstSnapshotSet = true;
/*
* In serializable mode, the first snapshot must live until end of
* xact regardless of what the caller does with it, so we must
* In transaction-snapshot mode, the first snapshot must live until
* end of xact regardless of what the caller does with it, so we must
* register it internally here and unregister it at end of xact.
*/
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
{
CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
TopTransactionResourceOwner);
registered_serializable = true;
registered_xact_snapshot = true;
}
return CurrentSnapshot;
}
if (IsXactIsoLevelSerializable)
if (IsolationUsesXactSnapshot())
return CurrentSnapshot;
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
@ -155,7 +155,7 @@ GetTransactionSnapshot(void)
/*
* GetLatestSnapshot
* Get a snapshot that is up-to-date as of the current instant,
* even if we are executing in SERIALIZABLE mode.
* even if we are executing in transaction-snapshot mode.
*/
Snapshot
GetLatestSnapshot(void)
@ -515,13 +515,13 @@ void
AtEarlyCommit_Snapshot(void)
{
/*
* On a serializable transaction we must unregister our private refcount
* to the serializable snapshot.
* In transaction-snapshot mode we must unregister our private refcount
* to the transaction-snapshot.
*/
if (registered_serializable)
if (registered_xact_snapshot)
UnregisterSnapshotFromOwner(CurrentSnapshot,
TopTransactionResourceOwner);
registered_serializable = false;
registered_xact_snapshot = false;
}
@ -557,5 +557,5 @@ AtEOXact_Snapshot(bool isCommit)
SecondarySnapshot = NULL;
FirstSnapshotSet = false;
registered_serializable = false;
registered_xact_snapshot = false;
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.103 2010/02/26 02:01:21 momjian Exp $
* $PostgreSQL: pgsql/src/include/access/xact.h,v 1.104 2010/09/11 18:38:58 joe Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,7 +35,7 @@ extern int XactIsoLevel;
* We only implement two isolation levels internally. This macro should
* be used to check which one is selected.
*/
#define IsXactIsoLevelSerializable (XactIsoLevel >= XACT_REPEATABLE_READ)
#define IsolationUsesXactSnapshot() (XactIsoLevel >= XACT_REPEATABLE_READ)
/* Xact read-only state */
extern bool DefaultXactReadOnly;