Commit 5da9da71 authored by Alvaro Herrera's avatar Alvaro Herrera

Improve snapshot manager by keeping explicit track of snapshots.

There are two ways to track a snapshot: there's the "registered" list, which
is used for arbitrary long-lived snapshots; and there's the "active stack",
which is used for the snapshot that is considered "active" at any time.
This also allows users of snapshots to stop worrying about snapshot memory
allocation and freeing, and about using PG_TRY blocks around ActiveSnapshot
assignment.  This is all done automatically now.

As a consequence, this allows us to reset MyProc->xmin when there are no
more snapshots registered in the current backend, reducing the impact that
long-running transactions have on VACUUM.
parent aa82790f
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.263 2008/05/12 00:00:46 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.264 2008/05/12 20:01:58 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -622,12 +622,9 @@ CommandCounterIncrement(void) ...@@ -622,12 +622,9 @@ CommandCounterIncrement(void)
} }
currentCommandIdUsed = false; currentCommandIdUsed = false;
/* Propagate new command ID into static snapshots, if set */ /* Propagate new command ID into static snapshots */
if (SerializableSnapshot) SnapshotSetCommandId(currentCommandId);
SerializableSnapshot->curcid = currentCommandId;
if (LatestSnapshot)
LatestSnapshot->curcid = currentCommandId;
/* /*
* Make any catalog changes done by the just-completed command * Make any catalog changes done by the just-completed command
* visible in the local syscache. We obviously don't need to do * visible in the local syscache. We obviously don't need to do
...@@ -1509,9 +1506,8 @@ StartTransaction(void) ...@@ -1509,9 +1506,8 @@ StartTransaction(void)
s->transactionId = InvalidTransactionId; /* until assigned */ s->transactionId = InvalidTransactionId; /* until assigned */
/* /*
* Make sure we've freed any old snapshot, and reset xact state variables * Make sure we've reset xact state variables
*/ */
FreeXactSnapshot();
XactIsoLevel = DefaultXactIsoLevel; XactIsoLevel = DefaultXactIsoLevel;
XactReadOnly = DefaultXactReadOnly; XactReadOnly = DefaultXactReadOnly;
forceSyncCommit = false; forceSyncCommit = false;
...@@ -1753,6 +1749,7 @@ CommitTransaction(void) ...@@ -1753,6 +1749,7 @@ CommitTransaction(void)
AtEOXact_ComboCid(); AtEOXact_ComboCid();
AtEOXact_HashTables(true); AtEOXact_HashTables(true);
AtEOXact_PgStat(true); AtEOXact_PgStat(true);
AtEOXact_Snapshot(true);
pgstat_report_xact_timestamp(0); pgstat_report_xact_timestamp(0);
CurrentResourceOwner = NULL; CurrentResourceOwner = NULL;
...@@ -1985,6 +1982,7 @@ PrepareTransaction(void) ...@@ -1985,6 +1982,7 @@ PrepareTransaction(void)
AtEOXact_ComboCid(); AtEOXact_ComboCid();
AtEOXact_HashTables(true); AtEOXact_HashTables(true);
/* don't call AtEOXact_PgStat here */ /* don't call AtEOXact_PgStat here */
AtEOXact_Snapshot(true);
CurrentResourceOwner = NULL; CurrentResourceOwner = NULL;
ResourceOwnerDelete(TopTransactionResourceOwner); ResourceOwnerDelete(TopTransactionResourceOwner);
...@@ -2129,6 +2127,7 @@ AbortTransaction(void) ...@@ -2129,6 +2127,7 @@ AbortTransaction(void)
AtEOXact_ComboCid(); AtEOXact_ComboCid();
AtEOXact_HashTables(false); AtEOXact_HashTables(false);
AtEOXact_PgStat(false); AtEOXact_PgStat(false);
AtEOXact_Snapshot(false);
pgstat_report_xact_timestamp(0); pgstat_report_xact_timestamp(0);
/* /*
...@@ -3844,6 +3843,7 @@ CommitSubTransaction(void) ...@@ -3844,6 +3843,7 @@ CommitSubTransaction(void)
s->parent->subTransactionId); s->parent->subTransactionId);
AtEOSubXact_HashTables(true, s->nestingLevel); AtEOSubXact_HashTables(true, s->nestingLevel);
AtEOSubXact_PgStat(true, s->nestingLevel); AtEOSubXact_PgStat(true, s->nestingLevel);
AtSubCommit_Snapshot(s->nestingLevel);
/* /*
* We need to restore the upper transaction's read-only state, in case the * We need to restore the upper transaction's read-only state, in case the
...@@ -3963,6 +3963,7 @@ AbortSubTransaction(void) ...@@ -3963,6 +3963,7 @@ AbortSubTransaction(void)
s->parent->subTransactionId); s->parent->subTransactionId);
AtEOSubXact_HashTables(false, s->nestingLevel); AtEOSubXact_HashTables(false, s->nestingLevel);
AtEOSubXact_PgStat(false, s->nestingLevel); AtEOSubXact_PgStat(false, s->nestingLevel);
AtSubAbort_Snapshot(s->nestingLevel);
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.298 2008/05/12 00:00:47 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.299 2008/05/12 20:01:59 alvherre Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
...@@ -1507,7 +1507,7 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1507,7 +1507,7 @@ IndexBuildHeapScan(Relation heapRelation,
} }
else if (indexInfo->ii_Concurrent) else if (indexInfo->ii_Concurrent)
{ {
snapshot = CopySnapshot(GetTransactionSnapshot()); snapshot = RegisterSnapshot(GetTransactionSnapshot());
OldestXmin = InvalidTransactionId; /* not used */ OldestXmin = InvalidTransactionId; /* not used */
} }
else else
...@@ -1517,10 +1517,7 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1517,10 +1517,7 @@ IndexBuildHeapScan(Relation heapRelation,
OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared, true); OldestXmin = GetOldestXmin(heapRelation->rd_rel->relisshared, true);
} }
scan = heap_beginscan(heapRelation, /* relation */ scan = heap_beginscan(heapRelation, snapshot, 0, NULL);
snapshot, /* seeself */
0, /* number of keys */
NULL); /* scan key */
reltuples = 0; reltuples = 0;
...@@ -1793,6 +1790,10 @@ IndexBuildHeapScan(Relation heapRelation, ...@@ -1793,6 +1790,10 @@ IndexBuildHeapScan(Relation heapRelation,
heap_endscan(scan); heap_endscan(scan);
/* we can now forget our snapshot, if set */
if (indexInfo->ii_Concurrent)
UnregisterSnapshot(snapshot);
ExecDropSingleTupleTableSlot(slot); ExecDropSingleTupleTableSlot(slot);
FreeExecutorState(estate); FreeExecutorState(estate);
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.175 2008/05/12 00:00:47 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.176 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -212,6 +212,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel) ...@@ -212,6 +212,7 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
rvs = get_tables_to_cluster(cluster_context); rvs = get_tables_to_cluster(cluster_context);
/* Commit to get out of starting transaction */ /* Commit to get out of starting transaction */
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
/* Ok, now that we've got them all, cluster them one by one */ /* Ok, now that we've got them all, cluster them one by one */
...@@ -222,8 +223,9 @@ cluster(ClusterStmt *stmt, bool isTopLevel) ...@@ -222,8 +223,9 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
/* Start a new transaction for each relation. */ /* Start a new transaction for each relation. */
StartTransactionCommand(); StartTransactionCommand();
/* functions in indexes may want a snapshot set */ /* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
cluster_rel(rvtc, true); cluster_rel(rvtc, true);
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.298 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.299 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1044,21 +1044,18 @@ DoCopy(const CopyStmt *stmt, const char *queryString) ...@@ -1044,21 +1044,18 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
plan = planner(query, 0, NULL); plan = planner(query, 0, NULL);
/* /*
* Update snapshot command ID to ensure this query sees results of any * Use a snapshot with an updated command ID to ensure this query sees
* previously executed queries. (It's a bit cheesy to modify * results of any previously executed queries.
* ActiveSnapshot without making a copy, but for the limited ways in
* which COPY can be invoked, I think it's OK, because the active
* snapshot shouldn't be shared with anything else anyway.)
*/ */
ActiveSnapshot->curcid = GetCurrentCommandId(false); PushUpdatedSnapshot(GetActiveSnapshot());
/* Create dest receiver for COPY OUT */ /* Create dest receiver for COPY OUT */
dest = CreateDestReceiver(DestCopyOut, NULL); dest = CreateDestReceiver(DestCopyOut, NULL);
((DR_copy *) dest)->cstate = cstate; ((DR_copy *) dest)->cstate = cstate;
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
cstate->queryDesc = CreateQueryDesc(plan, cstate->queryDesc = CreateQueryDesc(plan, GetActiveSnapshot(),
ActiveSnapshot, InvalidSnapshot, InvalidSnapshot,
dest, NULL, false); dest, NULL, false);
/* /*
...@@ -1161,6 +1158,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString) ...@@ -1161,6 +1158,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
/* Close down the query and free resources. */ /* Close down the query and free resources. */
ExecutorEnd(cstate->queryDesc); ExecutorEnd(cstate->queryDesc);
FreeQueryDesc(cstate->queryDesc); FreeQueryDesc(cstate->queryDesc);
PopActiveSnapshot();
} }
/* Clean up storage (probably not really necessary) */ /* Clean up storage (probably not really necessary) */
...@@ -1390,7 +1388,7 @@ CopyTo(CopyState cstate) ...@@ -1390,7 +1388,7 @@ CopyTo(CopyState cstate)
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
nulls = (bool *) palloc(num_phys_attrs * sizeof(bool)); nulls = (bool *) palloc(num_phys_attrs * sizeof(bool));
scandesc = heap_beginscan(cstate->rel, ActiveSnapshot, 0, NULL); scandesc = heap_beginscan(cstate->rel, GetActiveSnapshot(), 0, NULL);
while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL) while ((tuple = heap_getnext(scandesc, ForwardScanDirection)) != NULL)
{ {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.173 2008/04/18 01:42:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.174 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -229,17 +229,14 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params, ...@@ -229,17 +229,14 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
int eflags; int eflags;
/* /*
* Update snapshot command ID to ensure this query sees results of any * Use a snapshot with an updated command ID to ensure this query sees
* previously executed queries. (It's a bit cheesy to modify * results of any previously executed queries.
* ActiveSnapshot without making a copy, but for the limited ways in which
* EXPLAIN can be invoked, I think it's OK, because the active snapshot
* shouldn't be shared with anything else anyway.)
*/ */
ActiveSnapshot->curcid = GetCurrentCommandId(false); PushUpdatedSnapshot(GetActiveSnapshot());
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(plannedstmt, queryDesc = CreateQueryDesc(plannedstmt,
ActiveSnapshot, InvalidSnapshot, GetActiveSnapshot(), InvalidSnapshot,
None_Receiver, params, None_Receiver, params,
stmt->analyze); stmt->analyze);
...@@ -324,6 +321,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params, ...@@ -324,6 +321,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
FreeQueryDesc(queryDesc); FreeQueryDesc(queryDesc);
PopActiveSnapshot();
/* We need a CCI just in case query expanded to multiple plans */ /* We need a CCI just in case query expanded to multiple plans */
if (stmt->analyze) if (stmt->analyze)
CommandCounterIncrement(); CommandCounterIncrement();
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.175 2008/05/12 00:00:47 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.176 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -484,6 +484,7 @@ DefineIndex(RangeVar *heapRelation, ...@@ -484,6 +484,7 @@ DefineIndex(RangeVar *heapRelation,
*/ */
LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock); LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
StartTransactionCommand(); StartTransactionCommand();
...@@ -542,7 +543,7 @@ DefineIndex(RangeVar *heapRelation, ...@@ -542,7 +543,7 @@ DefineIndex(RangeVar *heapRelation,
indexRelation = index_open(indexRelationId, RowExclusiveLock); indexRelation = index_open(indexRelationId, RowExclusiveLock);
/* Set ActiveSnapshot since functions in the indexes may need it */ /* Set ActiveSnapshot since functions in the indexes may need it */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
/* We have to re-build the IndexInfo struct, since it was lost in commit */ /* We have to re-build the IndexInfo struct, since it was lost in commit */
indexInfo = BuildIndexInfo(indexRelation); indexInfo = BuildIndexInfo(indexRelation);
...@@ -581,6 +582,9 @@ DefineIndex(RangeVar *heapRelation, ...@@ -581,6 +582,9 @@ DefineIndex(RangeVar *heapRelation,
heap_close(pg_index, RowExclusiveLock); heap_close(pg_index, RowExclusiveLock);
/* we can do away with our snapshot */
PopActiveSnapshot();
/* /*
* Commit this transaction to make the indisready update visible. * Commit this transaction to make the indisready update visible.
*/ */
...@@ -616,8 +620,8 @@ DefineIndex(RangeVar *heapRelation, ...@@ -616,8 +620,8 @@ DefineIndex(RangeVar *heapRelation,
* We also set ActiveSnapshot to this snap, since functions in indexes may * We also set ActiveSnapshot to this snap, since functions in indexes may
* need a snapshot. * need a snapshot.
*/ */
snapshot = CopySnapshot(GetTransactionSnapshot()); snapshot = RegisterSnapshot(GetTransactionSnapshot());
ActiveSnapshot = snapshot; PushActiveSnapshot(snapshot);
/* /*
* Scan the index and the heap, insert any missing index entries. * Scan the index and the heap, insert any missing index entries.
...@@ -645,7 +649,7 @@ DefineIndex(RangeVar *heapRelation, ...@@ -645,7 +649,7 @@ DefineIndex(RangeVar *heapRelation,
* Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
* check for that. * check for that.
*/ */
old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax, false, old_snapshots = GetCurrentVirtualXIDs(snapshot->xmax, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM); PROC_IS_AUTOVACUUM | PROC_IN_VACUUM);
while (VirtualTransactionIdIsValid(*old_snapshots)) while (VirtualTransactionIdIsValid(*old_snapshots))
...@@ -686,6 +690,12 @@ DefineIndex(RangeVar *heapRelation, ...@@ -686,6 +690,12 @@ DefineIndex(RangeVar *heapRelation,
*/ */
CacheInvalidateRelcacheByRelid(heaprelid.relId); CacheInvalidateRelcacheByRelid(heaprelid.relId);
/* we can now do away with our active snapshot */
PopActiveSnapshot();
/* And we can remove the validating snapshot too */
UnregisterSnapshot(snapshot);
/* /*
* Last thing to do is release the session-level lock on the parent table. * Last thing to do is release the session-level lock on the parent table.
*/ */
...@@ -1453,6 +1463,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) ...@@ -1453,6 +1463,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
heap_close(relationRelation, AccessShareLock); heap_close(relationRelation, AccessShareLock);
/* Now reindex each rel in a separate transaction */ /* Now reindex each rel in a separate transaction */
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
foreach(l, relids) foreach(l, relids)
{ {
...@@ -1460,11 +1471,12 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user) ...@@ -1460,11 +1471,12 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
StartTransactionCommand(); StartTransactionCommand();
/* functions in indexes may want a snapshot set */ /* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
if (reindex_relation(relid, true)) if (reindex_relation(relid, true))
ereport(NOTICE, ereport(NOTICE,
(errmsg("table \"%s\" was reindexed", (errmsg("table \"%s\" was reindexed",
get_rel_name(relid)))); get_rel_name(relid))));
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
} }
StartTransactionCommand(); StartTransactionCommand();
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.73 2008/04/02 18:31:50 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.74 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -121,7 +121,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params, ...@@ -121,7 +121,7 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
/* /*
* Start execution, inserting parameters if any. * Start execution, inserting parameters if any.
*/ */
PortalStart(portal, params, ActiveSnapshot); PortalStart(portal, params, GetActiveSnapshot());
Assert(portal->strategy == PORTAL_ONE_SELECT); Assert(portal->strategy == PORTAL_ONE_SELECT);
...@@ -293,7 +293,6 @@ PersistHoldablePortal(Portal portal) ...@@ -293,7 +293,6 @@ PersistHoldablePortal(Portal portal)
{ {
QueryDesc *queryDesc = PortalGetQueryDesc(portal); QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveActivePortal; Portal saveActivePortal;
Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner; ResourceOwner saveResourceOwner;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext oldcxt; MemoryContext oldcxt;
...@@ -334,18 +333,18 @@ PersistHoldablePortal(Portal portal) ...@@ -334,18 +333,18 @@ PersistHoldablePortal(Portal portal)
* Set up global portal context pointers. * Set up global portal context pointers.
*/ */
saveActivePortal = ActivePortal; saveActivePortal = ActivePortal;
saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner; saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PG_TRY(); PG_TRY();
{ {
ActivePortal = portal; ActivePortal = portal;
ActiveSnapshot = queryDesc->snapshot;
CurrentResourceOwner = portal->resowner; CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
MemoryContextSwitchTo(PortalContext); MemoryContextSwitchTo(PortalContext);
PushActiveSnapshot(queryDesc->snapshot);
/* /*
* Rewind the executor: we need to store the entire result set in the * Rewind the executor: we need to store the entire result set in the
* tuplestore, so that subsequent backward FETCHs can be processed. * tuplestore, so that subsequent backward FETCHs can be processed.
...@@ -411,7 +410,6 @@ PersistHoldablePortal(Portal portal) ...@@ -411,7 +410,6 @@ PersistHoldablePortal(Portal portal)
/* Restore global vars and propagate error */ /* Restore global vars and propagate error */
ActivePortal = saveActivePortal; ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
...@@ -425,10 +423,11 @@ PersistHoldablePortal(Portal portal) ...@@ -425,10 +423,11 @@ PersistHoldablePortal(Portal portal)
portal->status = PORTAL_READY; portal->status = PORTAL_READY;
ActivePortal = saveActivePortal; ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner; CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext; PortalContext = savePortalContext;
PopActiveSnapshot();
/* /*
* We can now release any subsidiary memory of the portal's heap context; * We can now release any subsidiary memory of the portal's heap context;
* we'll never use it again. The executor already dropped its context, * we'll never use it again. The executor already dropped its context,
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group * Copyright (c) 2002-2008, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.86 2008/05/12 00:00:47 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.87 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -263,7 +263,7 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString, ...@@ -263,7 +263,7 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
/* /*
* Run the portal to completion. * Run the portal to completion.
*/ */
PortalStart(portal, paramLI, ActiveSnapshot); PortalStart(portal, paramLI, GetActiveSnapshot());
(void) PortalRun(portal, FETCH_ALL, false, dest, dest, completionTag); (void) PortalRun(portal, FETCH_ALL, false, dest, dest, completionTag);
......
...@@ -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.232 2008/05/12 00:00:48 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.233 2008/05/12 20:01:59 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2976,6 +2976,7 @@ void ...@@ -2976,6 +2976,7 @@ void
AfterTriggerFireDeferred(void) AfterTriggerFireDeferred(void)
{ {
AfterTriggerEventList *events; AfterTriggerEventList *events;
bool snap_pushed = false;
/* Must be inside a transaction */ /* Must be inside a transaction */
Assert(afterTriggers != NULL); Assert(afterTriggers != NULL);
...@@ -2990,7 +2991,10 @@ AfterTriggerFireDeferred(void) ...@@ -2990,7 +2991,10 @@ AfterTriggerFireDeferred(void)
*/ */
events = &afterTriggers->events; events = &afterTriggers->events;
if (events->head != NULL) if (events->head != NULL)
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); {
PushActiveSnapshot(GetTransactionSnapshot());
snap_pushed = true;
}
/* /*
* Run all the remaining triggers. Loop until they are all gone, in case * Run all the remaining triggers. Loop until they are all gone, in case
...@@ -3003,6 +3007,9 @@ AfterTriggerFireDeferred(void) ...@@ -3003,6 +3007,9 @@ AfterTriggerFireDeferred(void)
afterTriggerInvokeEvents(events, firing_id, NULL, true); afterTriggerInvokeEvents(events, firing_id, NULL, true);
} }
if (snap_pushed)
PopActiveSnapshot();
Assert(events->head == NULL); Assert(events->head == NULL);
} }
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.372 2008/05/12 00:00:48 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.373 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -409,6 +409,10 @@ vacuum(VacuumStmt *vacstmt, List *relids, ...@@ -409,6 +409,10 @@ vacuum(VacuumStmt *vacstmt, List *relids,
*/ */
if (use_own_xacts) if (use_own_xacts)
{ {
/* ActiveSnapshot is not set by autovacuum */
if (ActiveSnapshotSet())
PopActiveSnapshot();
/* matches the StartTransaction in PostgresMain() */ /* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand(); CommitTransactionCommand();
} }
...@@ -446,7 +450,7 @@ vacuum(VacuumStmt *vacstmt, List *relids, ...@@ -446,7 +450,7 @@ vacuum(VacuumStmt *vacstmt, List *relids,
{ {
StartTransactionCommand(); StartTransactionCommand();
/* functions in indexes may want a snapshot set */ /* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
} }
else else
old_context = MemoryContextSwitchTo(anl_context); old_context = MemoryContextSwitchTo(anl_context);
...@@ -454,7 +458,10 @@ vacuum(VacuumStmt *vacstmt, List *relids, ...@@ -454,7 +458,10 @@ vacuum(VacuumStmt *vacstmt, List *relids,
analyze_rel(relid, vacstmt, vac_strategy); analyze_rel(relid, vacstmt, vac_strategy);
if (use_own_xacts) if (use_own_xacts)
{
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
}
else else
{ {
MemoryContextSwitchTo(old_context); MemoryContextSwitchTo(old_context);
...@@ -981,7 +988,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -981,7 +988,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (vacstmt->full) if (vacstmt->full)
{ {
/* functions in indexes may want a snapshot set */ /* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
} }
else else
{ {
...@@ -1038,6 +1045,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -1038,6 +1045,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (!onerel) if (!onerel)
{ {
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return; return;
} }
...@@ -1068,6 +1077,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -1068,6 +1077,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
(errmsg("skipping \"%s\" --- only table or database owner can vacuum it", (errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
RelationGetRelationName(onerel)))); RelationGetRelationName(onerel))));
relation_close(onerel, lmode); relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return; return;
} }
...@@ -1082,6 +1093,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -1082,6 +1093,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables", (errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
RelationGetRelationName(onerel)))); RelationGetRelationName(onerel))));
relation_close(onerel, lmode); relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return; return;
} }
...@@ -1096,6 +1109,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -1096,6 +1109,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (isOtherTempNamespace(RelationGetNamespace(onerel))) if (isOtherTempNamespace(RelationGetNamespace(onerel)))
{ {
relation_close(onerel, lmode); relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
return; return;
} }
...@@ -1143,6 +1158,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind, ...@@ -1143,6 +1158,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
/* /*
* Complete the transaction and free all temporary memory used. * Complete the transaction and free all temporary memory used.
*/ */
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand(); CommitTransactionCommand();
/* /*
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.127 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/variable.c,v 1.128 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -550,7 +550,7 @@ show_log_timezone(void) ...@@ -550,7 +550,7 @@ show_log_timezone(void)
const char * const char *
assign_XactIsoLevel(const char *value, bool doit, GucSource source) assign_XactIsoLevel(const char *value, bool doit, GucSource source)
{ {
if (SerializableSnapshot != NULL) if (FirstSnapshotSet)
{ {
ereport(GUC_complaint_elevel(source), ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.308 2008/05/12 00:00:48 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.309 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/memutils.h" #include "utils/memutils.h"
#include "utils/snapmgr.h"
#include "utils/tqual.h" #include "utils/tqual.h"
...@@ -185,8 +186,8 @@ ExecutorStart(QueryDesc *queryDesc, int eflags) ...@@ -185,8 +186,8 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
/* /*
* Copy other important information into the EState * Copy other important information into the EState
*/ */
estate->es_snapshot = queryDesc->snapshot; estate->es_snapshot = RegisterSnapshot(queryDesc->snapshot);
estate->es_crosscheck_snapshot = queryDesc->crosscheck_snapshot; estate->es_crosscheck_snapshot = RegisterSnapshot(queryDesc->crosscheck_snapshot);
estate->es_instrument = queryDesc->doInstrument; estate->es_instrument = queryDesc->doInstrument;
/* /*
...@@ -313,6 +314,10 @@ ExecutorEnd(QueryDesc *queryDesc) ...@@ -313,6 +314,10 @@ ExecutorEnd(QueryDesc *queryDesc)
if (estate->es_select_into) if (estate->es_select_into)
CloseIntoRel(queryDesc); CloseIntoRel(queryDesc);
/* do away with our snapshots */
UnregisterSnapshot(estate->es_snapshot);
UnregisterSnapshot(estate->es_crosscheck_snapshot);
/* /*
* Must switch out of context before destroying it * Must switch out of context before destroying it
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.124 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.125 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -295,15 +295,14 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -295,15 +295,14 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
* In a read-only function, use the surrounding query's snapshot; * In a read-only function, use the surrounding query's snapshot;
* otherwise take a new snapshot for each query. The snapshot should * otherwise take a new snapshot for each query. The snapshot should
* include a fresh command ID so that all work to date in this transaction * include a fresh command ID so that all work to date in this transaction
* is visible. We copy in both cases so that postquel_end can * is visible.
* unconditionally do FreeSnapshot.
*/ */
if (fcache->readonly_func) if (fcache->readonly_func)
snapshot = CopySnapshot(ActiveSnapshot); snapshot = GetActiveSnapshot();
else else
{ {
CommandCounterIncrement(); CommandCounterIncrement();
snapshot = CopySnapshot(GetTransactionSnapshot()); snapshot = GetTransactionSnapshot();
} }
if (IsA(es->stmt, PlannedStmt)) if (IsA(es->stmt, PlannedStmt))
...@@ -340,56 +339,44 @@ static TupleTableSlot * ...@@ -340,56 +339,44 @@ static TupleTableSlot *
postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache) postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
{ {
TupleTableSlot *result; TupleTableSlot *result;
Snapshot saveActiveSnapshot;
long count; long count;
/* Make our snapshot the active one for any called functions */ /* Make our snapshot the active one for any called functions */
saveActiveSnapshot = ActiveSnapshot; PushActiveSnapshot(es->qd->snapshot);
PG_TRY();
{
ActiveSnapshot = es->qd->snapshot;
if (es->qd->utilitystmt)
{
/* ProcessUtility needs the PlannedStmt for DECLARE CURSOR */
ProcessUtility((es->qd->plannedstmt ?
(Node *) es->qd->plannedstmt :
es->qd->utilitystmt),
fcache->src,
es->qd->params,
false, /* not top level */
es->qd->dest,
NULL);
result = NULL;
}
else
{
/*
* If it's the function's last command, and it's a SELECT, fetch
* one row at a time so we can return the results. Otherwise just
* run it to completion. (If we run to completion then
* ExecutorRun is guaranteed to return NULL.)
*/
if (LAST_POSTQUEL_COMMAND(es) &&
es->qd->operation == CMD_SELECT &&
es->qd->plannedstmt->utilityStmt == NULL &&
es->qd->plannedstmt->intoClause == NULL)
count = 1L;
else
count = 0L;
result = ExecutorRun(es->qd, ForwardScanDirection, count); if (es->qd->utilitystmt)
} {
/* ProcessUtility needs the PlannedStmt for DECLARE CURSOR */
ProcessUtility((es->qd->plannedstmt ?
(Node *) es->qd->plannedstmt :
es->qd->utilitystmt),
fcache->src,
es->qd->params,
false, /* not top level */
es->qd->dest,
NULL);
result = NULL;
} }
PG_CATCH(); else
{ {
/* Restore global vars and propagate error */ /*
ActiveSnapshot = saveActiveSnapshot; * If it's the function's last command, and it's a SELECT, fetch
PG_RE_THROW(); * one row at a time so we can return the results. Otherwise just
* run it to completion. (If we run to completion then
* ExecutorRun is guaranteed to return NULL.)
*/
if (LAST_POSTQUEL_COMMAND(es) &&
es->qd->operation == CMD_SELECT &&
es->qd->plannedstmt->utilityStmt == NULL &&
es->qd->plannedstmt->intoClause == NULL)
count = 1L;
else
count = 0L;
result = ExecutorRun(es->qd, ForwardScanDirection, count);
} }
PG_END_TRY();
ActiveSnapshot = saveActiveSnapshot; PopActiveSnapshot();
return result; return result;
} }
...@@ -397,8 +384,6 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache) ...@@ -397,8 +384,6 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
static void static void
postquel_end(execution_state *es) postquel_end(execution_state *es)
{ {
Snapshot saveActiveSnapshot;
/* mark status done to ensure we don't do ExecutorEnd twice */ /* mark status done to ensure we don't do ExecutorEnd twice */
es->status = F_EXEC_DONE; es->status = F_EXEC_DONE;
...@@ -406,26 +391,15 @@ postquel_end(execution_state *es) ...@@ -406,26 +391,15 @@ postquel_end(execution_state *es)
if (es->qd->utilitystmt == NULL) if (es->qd->utilitystmt == NULL)
{ {
/* Make our snapshot the active one for any called functions */ /* Make our snapshot the active one for any called functions */
saveActiveSnapshot = ActiveSnapshot; PushActiveSnapshot(es->qd->snapshot);
PG_TRY();
{
ActiveSnapshot = es->qd->snapshot;
if (es->qd->operation != CMD_SELECT) if (es->qd->operation != CMD_SELECT)
AfterTriggerEndQuery(es->qd->estate); AfterTriggerEndQuery(es->qd->estate);
ExecutorEnd(es->qd); ExecutorEnd(es->qd);
}
PG_CATCH(); PopActiveSnapshot();
{
/* Restore global vars and propagate error */
ActiveSnapshot = saveActiveSnapshot;
PG_RE_THROW();
}
PG_END_TRY();
ActiveSnapshot = saveActiveSnapshot;
} }
FreeSnapshot(es->qd->snapshot);
FreeQueryDesc(es->qd); FreeQueryDesc(es->qd);
es->qd = NULL; es->qd = NULL;
} }
......
This diff is collapsed.
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.43 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.44 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -660,8 +660,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum) ...@@ -660,8 +660,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
* *
* We also update the following backend-global variables: * We also update the following backend-global variables:
* TransactionXmin: the oldest xmin of any snapshot in use in the * TransactionXmin: the oldest xmin of any snapshot in use in the
* current transaction (this is the same as MyProc->xmin). This * current transaction (this is the same as MyProc->xmin).
* is just the xmin computed for the first, serializable snapshot.
* RecentXmin: the xmin computed for the most recent snapshot. XIDs * RecentXmin: the xmin computed for the most recent snapshot. XIDs
* older than this are known not running any more. * older than this are known not running any more.
* RecentGlobalXmin: the global xmin (oldest TransactionXmin across all * RecentGlobalXmin: the global xmin (oldest TransactionXmin across all
...@@ -669,7 +668,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum) ...@@ -669,7 +668,7 @@ GetOldestXmin(bool allDbs, bool ignoreVacuum)
* the same computation done by GetOldestXmin(true, true). * the same computation done by GetOldestXmin(true, true).
*/ */
Snapshot Snapshot
GetSnapshotData(Snapshot snapshot, bool serializable) GetSnapshotData(Snapshot snapshot)
{ {
ProcArrayStruct *arrayP = procArray; ProcArrayStruct *arrayP = procArray;
TransactionId xmin; TransactionId xmin;
...@@ -681,11 +680,6 @@ GetSnapshotData(Snapshot snapshot, bool serializable) ...@@ -681,11 +680,6 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
Assert(snapshot != NULL); Assert(snapshot != NULL);
/* Serializable snapshot must be computed before any other... */
Assert(serializable ?
!TransactionIdIsValid(MyProc->xmin) :
TransactionIdIsValid(MyProc->xmin));
/* /*
* Allocating space for maxProcs xids is usually overkill; numProcs would * Allocating space for maxProcs xids is usually overkill; numProcs would
* be sufficient. But it seems better to do the malloc while not holding * be sufficient. But it seems better to do the malloc while not holding
...@@ -806,7 +800,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable) ...@@ -806,7 +800,7 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
} }
} }
if (serializable) if (!TransactionIdIsValid(MyProc->xmin))
MyProc->xmin = TransactionXmin = xmin; MyProc->xmin = TransactionXmin = xmin;
LWLockRelease(ProcArrayLock); LWLockRelease(ProcArrayLock);
...@@ -830,6 +824,14 @@ GetSnapshotData(Snapshot snapshot, bool serializable) ...@@ -830,6 +824,14 @@ GetSnapshotData(Snapshot snapshot, bool serializable)
snapshot->curcid = GetCurrentCommandId(false); snapshot->curcid = GetCurrentCommandId(false);
/*
* This is a new snapshot, so set both refcounts are zero, and mark it
* as not copied in persistent memory.
*/
snapshot->active_count = 0;
snapshot->regd_count = 0;
snapshot->copied = false;
return snapshot; return snapshot;
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.132 2008/04/12 23:14:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.133 2008/05/12 20:02:00 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -246,12 +246,8 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt) ...@@ -246,12 +246,8 @@ inv_open(Oid lobjId, int flags, MemoryContext mcxt)
} }
else if (flags & INV_READ) else if (flags & INV_READ)
{ {
/* be sure to copy snap into mcxt */ retval->snapshot = RegisterSnapshot(GetActiveSnapshot());
MemoryContext oldContext = MemoryContextSwitchTo(mcxt);
retval->snapshot = CopySnapshot(ActiveSnapshot);
retval->flags = IFS_RDLOCK; retval->flags = IFS_RDLOCK;
MemoryContextSwitchTo(oldContext);
} }
else else
elog(ERROR, "invalid flags: %d", flags); elog(ERROR, "invalid flags: %d", flags);
...@@ -274,7 +270,7 @@ inv_close(LargeObjectDesc *obj_desc) ...@@ -274,7 +270,7 @@ inv_close(LargeObjectDesc *obj_desc)
{ {
Assert(PointerIsValid(obj_desc)); Assert(PointerIsValid(obj_desc));
if (obj_desc->snapshot != SnapshotNow) if (obj_desc->snapshot != SnapshotNow)
FreeSnapshot(obj_desc->snapshot); UnregisterSnapshot(obj_desc->snapshot);
pfree(obj_desc); pfree(obj_desc);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.99 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.100 2008/05/12 20:02:01 alvherre Exp $
* *
* NOTES * NOTES
* This cruft is the server side of PQfn. * This cruft is the server side of PQfn.
...@@ -309,7 +309,7 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -309,7 +309,7 @@ HandleFunctionRequest(StringInfo msgBuf)
* Now that we know we are in a valid transaction, set snapshot in case * Now that we know we are in a valid transaction, set snapshot in case
* needed by function itself or one of the datatype I/O routines. * needed by function itself or one of the datatype I/O routines.
*/ */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); PushActiveSnapshot(GetTransactionSnapshot());
/* /*
* Begin parsing the buffer contents. * Begin parsing the buffer contents.
...@@ -396,6 +396,9 @@ HandleFunctionRequest(StringInfo msgBuf) ...@@ -396,6 +396,9 @@ HandleFunctionRequest(StringInfo msgBuf)
SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat); SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
/* We no longer need the snapshot */
PopActiveSnapshot();
/* /*
* Emit duration logging if appropriate. * Emit duration logging if appropriate.
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.551 2008/05/12 00:00:50 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.552 2008/05/12 20:02:01 alvherre Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -732,49 +732,37 @@ List * ...@@ -732,49 +732,37 @@ List *
pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams, pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams,
bool needSnapshot) bool needSnapshot)
{ {
List * volatile stmt_list = NIL; List *stmt_list = NIL;
Snapshot saveActiveSnapshot = ActiveSnapshot; ListCell *query_list;
bool snapshot_set = false;
/* PG_TRY to ensure previous ActiveSnapshot is restored on error */ foreach(query_list, querytrees)
PG_TRY();
{ {
Snapshot mySnapshot = NULL; Query *query = (Query *) lfirst(query_list);
ListCell *query_list; Node *stmt;
foreach(query_list, querytrees) if (query->commandType == CMD_UTILITY)
{ {
Query *query = (Query *) lfirst(query_list); /* Utility commands have no plans. */
Node *stmt; stmt = query->utilityStmt;
}
if (query->commandType == CMD_UTILITY) else
{ {
/* Utility commands have no plans. */ if (needSnapshot && !snapshot_set)
stmt = query->utilityStmt;
}
else
{ {
if (needSnapshot && mySnapshot == NULL) PushActiveSnapshot(GetTransactionSnapshot());
{ snapshot_set = true;
mySnapshot = CopySnapshot(GetTransactionSnapshot());
ActiveSnapshot = mySnapshot;
}
stmt = (Node *) pg_plan_query(query, cursorOptions,
boundParams);
} }
stmt_list = lappend(stmt_list, stmt); stmt = (Node *) pg_plan_query(query, cursorOptions,
boundParams);
} }
if (mySnapshot) stmt_list = lappend(stmt_list, stmt);
FreeSnapshot(mySnapshot);
} }
PG_CATCH();
{ if (snapshot_set)
ActiveSnapshot = saveActiveSnapshot; PopActiveSnapshot();
PG_RE_THROW();
}
PG_END_TRY();
ActiveSnapshot = saveActiveSnapshot;
return stmt_list; return stmt_list;
} }
......
This diff is collapsed.
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.107 2008/03/26 21:10:39 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ri_triggers.c,v 1.108 2008/05/12 20:02:02 alvherre Exp $
* *
* ---------- * ----------
*/ */
...@@ -2756,12 +2756,13 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) ...@@ -2756,12 +2756,13 @@ 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 * serializable mode, this arguably violates serializability, but we
* really haven't got much choice.) We need at most one tuple returned, * really haven't got much choice.) We don't need to register the
* so pass limit = 1. * 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, spi_result = SPI_execute_snapshot(qplan,
NULL, NULL, NULL, NULL,
CopySnapshot(GetLatestSnapshot()), GetLatestSnapshot(),
InvalidSnapshot, InvalidSnapshot,
true, false, 1); true, false, 1);
...@@ -3311,13 +3312,15 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan, ...@@ -3311,13 +3312,15 @@ ri_PerformCheck(RI_QueryKey *qkey, SPIPlanPtr qplan,
* caller passes detectNewRows == false then it's okay to do the query * 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. * 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 (IsXactIsoLevelSerializable && detectNewRows)
{ {
CommandCounterIncrement(); /* be sure all my own work is visible */ CommandCounterIncrement(); /* be sure all my own work is visible */
test_snapshot = CopySnapshot(GetLatestSnapshot()); test_snapshot = GetLatestSnapshot();
crosscheck_snapshot = CopySnapshot(GetTransactionSnapshot()); crosscheck_snapshot = GetTransactionSnapshot();
} }
else else
{ {
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* Author: Jan Wieck, Afilias USA INC. * Author: Jan Wieck, Afilias USA INC.
* 64-bit txids: Marko Kreen, Skype Technologies * 64-bit txids: Marko Kreen, Skype Technologies
* *
* $PostgreSQL: pgsql/src/backend/utils/adt/txid.c,v 1.6 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/txid.c,v 1.7 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -362,9 +362,9 @@ txid_current_snapshot(PG_FUNCTION_ARGS) ...@@ -362,9 +362,9 @@ txid_current_snapshot(PG_FUNCTION_ARGS)
TxidEpoch state; TxidEpoch state;
Snapshot cur; Snapshot cur;
cur = ActiveSnapshot; cur = GetActiveSnapshot();
if (cur == NULL) if (cur == NULL)
elog(ERROR, "txid_current_snapshot: ActiveSnapshot == NULL"); elog(ERROR, "no active snapshot set");
load_xid_epoch(&state); load_xid_epoch(&state);
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,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/cache/plancache.c,v 1.17 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.18 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -71,7 +71,6 @@ static List *cached_plans_list = NIL; ...@@ -71,7 +71,6 @@ static List *cached_plans_list = NIL;
static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list, static void StoreCachedPlan(CachedPlanSource *plansource, List *stmt_list,
MemoryContext plan_context); MemoryContext plan_context);
static List *do_planning(List *querytrees, int cursorOptions);
static void AcquireExecutorLocks(List *stmt_list, bool acquire); static void AcquireExecutorLocks(List *stmt_list, bool acquire);
static void AcquirePlannerLocks(List *stmt_list, bool acquire); static void AcquirePlannerLocks(List *stmt_list, bool acquire);
static void LockRelid(Oid relid, LOCKMODE lockmode, void *arg); static void LockRelid(Oid relid, LOCKMODE lockmode, void *arg);
...@@ -481,8 +480,15 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner) ...@@ -481,8 +480,15 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
if (plansource->fully_planned) if (plansource->fully_planned)
{ {
/* Generate plans for queries */ /*
slist = do_planning(slist, plansource->cursor_options); * Generate plans for queries.
*
* If a snapshot is already set (the normal case), we can just use
* that for planning. But if it isn't, we have to tell
* pg_plan_queries to make a snap if it needs one.
*/
slist = pg_plan_queries(slist, plansource->cursor_options,
NULL, !ActiveSnapshotSet());
} }
/* /*
...@@ -537,49 +543,6 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner) ...@@ -537,49 +543,6 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner)
return plan; return plan;
} }
/*
* Invoke the planner on some rewritten queries. This is broken out of
* RevalidateCachedPlan just to avoid plastering "volatile" all over that
* function's variables.
*/
static List *
do_planning(List *querytrees, int cursorOptions)
{
List *stmt_list;
/*
* If a snapshot is already set (the normal case), we can just use that
* for planning. But if it isn't, we have to tell pg_plan_queries to make
* a snap if it needs one. In that case we should arrange to reset
* ActiveSnapshot afterward, to ensure that RevalidateCachedPlan has no
* caller-visible effects on the snapshot. Having to replan is an unusual
* case, and it seems a really bad idea for RevalidateCachedPlan to affect
* the snapshot only in unusual cases. (Besides, the snap might have been
* created in a short-lived context.)
*/
if (ActiveSnapshot != NULL)
stmt_list = pg_plan_queries(querytrees, cursorOptions, NULL, false);
else
{
PG_TRY();
{
stmt_list = pg_plan_queries(querytrees, cursorOptions, NULL, true);
}
PG_CATCH();
{
/* Restore global vars and propagate error */
ActiveSnapshot = NULL;
PG_RE_THROW();
}
PG_END_TRY();
ActiveSnapshot = NULL;
}
return stmt_list;
}
/* /*
* ReleaseCachedPlan: release active use of a cached plan. * ReleaseCachedPlan: release active use of a cached plan.
* *
......
This diff is collapsed.
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, 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/storage/procarray.h,v 1.21 2008/03/26 16:20:48 alvherre Exp $ * $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.22 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,7 +26,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid); ...@@ -26,7 +26,7 @@ extern void ProcArrayRemove(PGPROC *proc, TransactionId latestXid);
extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid); extern void ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid);
extern void ProcArrayClearTransaction(PGPROC *proc); extern void ProcArrayClearTransaction(PGPROC *proc);
extern Snapshot GetSnapshotData(Snapshot snapshot, bool serializable); extern Snapshot GetSnapshotData(Snapshot snapshot);
extern bool TransactionIdIsInProgress(TransactionId xid); extern bool TransactionIdIsInProgress(TransactionId xid);
extern bool TransactionIdIsActive(TransactionId xid); extern bool TransactionIdIsActive(TransactionId xid);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, 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/utils/snapmgr.h,v 1.1 2008/03/26 18:48:59 alvherre Exp $ * $PostgreSQL: pgsql/src/include/utils/snapmgr.h,v 1.2 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,9 +16,7 @@ ...@@ -16,9 +16,7 @@
#include "utils/snapshot.h" #include "utils/snapshot.h"
extern PGDLLIMPORT Snapshot SerializableSnapshot; extern bool FirstSnapshotSet;
extern PGDLLIMPORT Snapshot LatestSnapshot;
extern PGDLLIMPORT Snapshot ActiveSnapshot;
extern TransactionId TransactionXmin; extern TransactionId TransactionXmin;
extern TransactionId RecentXmin; extern TransactionId RecentXmin;
...@@ -26,8 +24,19 @@ extern TransactionId RecentGlobalXmin; ...@@ -26,8 +24,19 @@ extern TransactionId RecentGlobalXmin;
extern Snapshot GetTransactionSnapshot(void); extern Snapshot GetTransactionSnapshot(void);
extern Snapshot GetLatestSnapshot(void); extern Snapshot GetLatestSnapshot(void);
extern Snapshot CopySnapshot(Snapshot snapshot); extern void SnapshotSetCommandId(CommandId curcid);
extern void FreeSnapshot(Snapshot snapshot);
extern void FreeXactSnapshot(void); extern void PushActiveSnapshot(Snapshot snapshot);
extern void PushUpdatedSnapshot(Snapshot snapshot);
extern void PopActiveSnapshot(void);
extern Snapshot GetActiveSnapshot(void);
extern bool ActiveSnapshotSet(void);
extern Snapshot RegisterSnapshot(Snapshot snapshot);
extern void UnregisterSnapshot(Snapshot snapshot);
extern void AtSubCommit_Snapshot(int level);
extern void AtSubAbort_Snapshot(int level);
extern void AtEOXact_Snapshot(bool isCommit);
#endif /* SNAPMGR_H */ #endif /* SNAPMGR_H */
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, 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/utils/snapshot.h,v 1.2 2008/03/26 21:10:39 alvherre Exp $ * $PostgreSQL: pgsql/src/include/utils/snapshot.h,v 1.3 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -57,6 +57,9 @@ typedef struct SnapshotData ...@@ -57,6 +57,9 @@ typedef struct SnapshotData
* out any that are >= xmax * out any that are >= xmax
*/ */
CommandId curcid; /* in my xact, CID < curcid are visible */ CommandId curcid; /* in my xact, CID < curcid are visible */
uint32 active_count; /* refcount on ActiveSnapshot stack */
uint32 regd_count; /* refcount on RegisteredSnapshotList */
bool copied; /* false if it's a static snapshot */
} SnapshotData; } SnapshotData;
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.212 2008/05/12 00:00:54 alvherre Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.213 2008/05/12 20:02:02 alvherre Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -4129,7 +4129,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, ...@@ -4129,7 +4129,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
CachedPlan *cplan; CachedPlan *cplan;
ParamListInfo paramLI; ParamListInfo paramLI;
int i; int i;
Snapshot saveActiveSnapshot; MemoryContext oldcontext;
/* /*
* Forget it if expression wasn't simple before. * Forget it if expression wasn't simple before.
...@@ -4218,37 +4218,26 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate, ...@@ -4218,37 +4218,26 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
* updates made so far by our own function. * updates made so far by our own function.
*/ */
SPI_push(); SPI_push();
saveActiveSnapshot = ActiveSnapshot;
PG_TRY(); oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
if (!estate->readonly_func)
{ {
MemoryContext oldcontext; CommandCounterIncrement();
PushActiveSnapshot(GetTransactionSnapshot());
}
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); /*
if (!estate->readonly_func) * Finally we can call the executor to evaluate the expression
{ */
CommandCounterIncrement(); *result = ExecEvalExpr(expr->expr_simple_state,
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); econtext,
} isNull,
NULL);
MemoryContextSwitchTo(oldcontext);
/* if (!estate->readonly_func)
* Finally we can call the executor to evaluate the expression PopActiveSnapshot();
*/
*result = ExecEvalExpr(expr->expr_simple_state,
econtext,
isNull,
NULL);
MemoryContextSwitchTo(oldcontext);
}
PG_CATCH();
{
/* Restore global vars and propagate error */
ActiveSnapshot = saveActiveSnapshot;
PG_RE_THROW();
}
PG_END_TRY();
ActiveSnapshot = saveActiveSnapshot;
SPI_pop(); SPI_pop();
/* /*
......
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