Commit 5eb15c99 authored by Joe Conway's avatar Joe Conway

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.
parent 262c71ab
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -2173,7 +2173,7 @@ l1: ...@@ -2173,7 +2173,7 @@ l1:
if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) 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)) if (!HeapTupleSatisfiesVisibility(&tp, crosscheck, buffer))
result = HeapTupleUpdated; result = HeapTupleUpdated;
} }
...@@ -2525,7 +2525,7 @@ l2: ...@@ -2525,7 +2525,7 @@ l2:
if (crosscheck != InvalidSnapshot && result == HeapTupleMayBeUpdated) 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)) if (!HeapTupleSatisfiesVisibility(&oldtup, crosscheck, buffer))
result = HeapTupleUpdated; result = HeapTupleUpdated;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -2049,7 +2049,7 @@ IndexCheckExclusion(Relation heapRelation, ...@@ -2049,7 +2049,7 @@ IndexCheckExclusion(Relation heapRelation,
* *
* After completing validate_index(), we wait until all transactions that * After completing validate_index(), we wait until all transactions that
* were alive at the time of the reference snapshot are gone; this is * 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 * older than the reference (and hence possibly able to see tuples we did
* not index). Then we mark the index "indisvalid" and commit. Subsequent * not index). Then we mark the index "indisvalid" and commit. Subsequent
* transactions will be able to use it for queries. * transactions will be able to use it for queries.
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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:; ...@@ -2387,7 +2387,7 @@ ltrmark:;
case HeapTupleUpdated: case HeapTupleUpdated:
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update"))); errmsg("could not serialize access due to concurrent update")));
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -1554,7 +1554,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
case HeapTupleUpdated: case HeapTupleUpdated:
ReleaseBuffer(buffer); ReleaseBuffer(buffer);
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update"))); errmsg("could not serialize access due to concurrent update")));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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: ...@@ -130,7 +130,7 @@ lnext:
break; break;
case HeapTupleUpdated: case HeapTupleUpdated:
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update"))); errmsg("could not serialize access due to concurrent update")));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -310,7 +310,7 @@ ExecDelete(ItemPointer tupleid,
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that * 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- * 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 * 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:; ldelete:;
result = heap_delete(resultRelationDesc, tupleid, result = heap_delete(resultRelationDesc, tupleid,
...@@ -328,7 +328,7 @@ ldelete:; ...@@ -328,7 +328,7 @@ ldelete:;
break; break;
case HeapTupleUpdated: case HeapTupleUpdated:
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update"))); errmsg("could not serialize access due to concurrent update")));
...@@ -499,7 +499,7 @@ lreplace:; ...@@ -499,7 +499,7 @@ lreplace:;
* Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that * 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- * 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 * 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, result = heap_update(resultRelationDesc, tupleid, tuple,
&update_ctid, &update_xmax, &update_ctid, &update_xmax,
...@@ -516,7 +516,7 @@ lreplace:; ...@@ -516,7 +516,7 @@ lreplace:;
break; break;
case HeapTupleUpdated: case HeapTupleUpdated:
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to concurrent update"))); errmsg("could not serialize access due to concurrent update")));
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -2802,7 +2802,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason) ...@@ -2802,7 +2802,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason)
* *
* PROCSIG_RECOVERY_CONFLICT_SNAPSHOT if no snapshots are held * PROCSIG_RECOVERY_CONFLICT_SNAPSHOT if no snapshots are held
* by parent transactions and the transaction is not * by parent transactions and the transaction is not
* serializable * transaction-snapshot mode
* *
* PROCSIG_RECOVERY_CONFLICT_TABLESPACE if no temp files or * PROCSIG_RECOVERY_CONFLICT_TABLESPACE if no temp files or
* cursors open in parent transactions * cursors open in parent transactions
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -1163,8 +1163,8 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
* Set snapshot if utility stmt needs one. Most reliable way to do this * 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 * 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 * list. Transaction control, LOCK, and SET must *not* set a snapshot
* since they need to be executable at the start of a serializable * since they need to be executable at the start of a transaction-snapshot
* transaction without freezing a snapshot. By extension we allow SHOW * mode transaction without freezing a snapshot. By extension we allow SHOW
* not to set a snapshot. The other stmts listed are just efficiency * not to set a snapshot. The other stmts listed are just efficiency
* hacks. Beware of listing anything that can modify the database --- if, * hacks. Beware of listing anything that can modify the database --- if,
* say, it has to update an index with expressions that invoke * say, it has to update an index with expressions that invoke
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * 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) ...@@ -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 * Run the plan. For safety we force a current snapshot to be used. (In
* serializable mode, this arguably violates serializability, but we * transaction-snapshot mode, this arguably violates transaction
* really haven't got much choice.) We don't need to register the * isolation rules, but we really haven't got much choice.)
* snapshot, because SPI_execute_snapshot will see to it. We need at most * We don't need to register the snapshot, because SPI_execute_snapshot
* one tuple returned, so pass limit = 1. * will see to it. We need at most one tuple returned, so pass limit = 1.
*/ */
spi_result = SPI_execute_snapshot(qplan, spi_result = SPI_execute_snapshot(qplan,
NULL, NULL, NULL, NULL,
...@@ -3332,15 +3332,15 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, ...@@ -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 * 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 * snapshot, and we will see all rows that could be interesting. But in
* SERIALIZABLE mode, we can't change the transaction snapshot. If the * transaction-snapshot mode, we can't change the transaction snapshot.
* caller passes detectNewRows == false then it's okay to do the query * 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 * 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 * 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 * snapshot that wouldn't be visible per the transaction snapshot. Note
* that SPI_execute_snapshot will register the snapshots, so we don't need * that SPI_execute_snapshot will register the snapshots, so we don't need
* to bother here. * to bother here.
*/ */
if (IsXactIsoLevelSerializable && detectNewRows) if (IsolationUsesXactSnapshot() && detectNewRows)
{ {
CommandCounterIncrement(); /* be sure all my own work is visible */ CommandCounterIncrement(); /* be sure all my own work is visible */
test_snapshot = GetLatestSnapshot(); test_snapshot = GetLatestSnapshot();
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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 @@ ...@@ -37,10 +37,10 @@
/* /*
* CurrentSnapshot points to the only snapshot taken in a serializable * CurrentSnapshot points to the only snapshot taken in transaction-snapshot
* transaction, and to the latest one taken in a read-committed transaction. * 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 * 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.) * special-purpose code (say, RI checking.)
* *
* These SnapshotData structs are static to simplify memory allocation * These SnapshotData structs are static to simplify memory allocation
...@@ -97,11 +97,11 @@ static int RegisteredSnapshots = 0; ...@@ -97,11 +97,11 @@ static int RegisteredSnapshots = 0;
bool FirstSnapshotSet = false; 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 * 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); static Snapshot CopySnapshot(Snapshot snapshot);
...@@ -130,21 +130,21 @@ GetTransactionSnapshot(void) ...@@ -130,21 +130,21 @@ GetTransactionSnapshot(void)
FirstSnapshotSet = true; FirstSnapshotSet = true;
/* /*
* In serializable mode, the first snapshot must live until end of * In transaction-snapshot mode, the first snapshot must live until
* xact regardless of what the caller does with it, so we must * 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. * register it internally here and unregister it at end of xact.
*/ */
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
{ {
CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot, CurrentSnapshot = RegisterSnapshotOnOwner(CurrentSnapshot,
TopTransactionResourceOwner); TopTransactionResourceOwner);
registered_serializable = true; registered_xact_snapshot = true;
} }
return CurrentSnapshot; return CurrentSnapshot;
} }
if (IsXactIsoLevelSerializable) if (IsolationUsesXactSnapshot())
return CurrentSnapshot; return CurrentSnapshot;
CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData);
...@@ -155,7 +155,7 @@ GetTransactionSnapshot(void) ...@@ -155,7 +155,7 @@ GetTransactionSnapshot(void)
/* /*
* GetLatestSnapshot * GetLatestSnapshot
* Get a snapshot that is up-to-date as of the current instant, * 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 Snapshot
GetLatestSnapshot(void) GetLatestSnapshot(void)
...@@ -515,13 +515,13 @@ void ...@@ -515,13 +515,13 @@ void
AtEarlyCommit_Snapshot(void) AtEarlyCommit_Snapshot(void)
{ {
/* /*
* On a serializable transaction we must unregister our private refcount * In transaction-snapshot mode we must unregister our private refcount
* to the serializable snapshot. * to the transaction-snapshot.
*/ */
if (registered_serializable) if (registered_xact_snapshot)
UnregisterSnapshotFromOwner(CurrentSnapshot, UnregisterSnapshotFromOwner(CurrentSnapshot,
TopTransactionResourceOwner); TopTransactionResourceOwner);
registered_serializable = false; registered_xact_snapshot = false;
} }
...@@ -557,5 +557,5 @@ AtEOXact_Snapshot(bool isCommit) ...@@ -557,5 +557,5 @@ AtEOXact_Snapshot(bool isCommit)
SecondarySnapshot = NULL; SecondarySnapshot = NULL;
FirstSnapshotSet = false; FirstSnapshotSet = false;
registered_serializable = false; registered_xact_snapshot = false;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; ...@@ -35,7 +35,7 @@ extern int XactIsoLevel;
* We only implement two isolation levels internally. This macro should * We only implement two isolation levels internally. This macro should
* be used to check which one is selected. * be used to check which one is selected.
*/ */
#define IsXactIsoLevelSerializable (XactIsoLevel >= XACT_REPEATABLE_READ) #define IsolationUsesXactSnapshot() (XactIsoLevel >= XACT_REPEATABLE_READ)
/* Xact read-only state */ /* Xact read-only state */
extern bool DefaultXactReadOnly; extern bool DefaultXactReadOnly;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment