aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2008-05-12 20:02:02 +0000
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2008-05-12 20:02:02 +0000
commit5da9da71c44f27ba48fdad08ef263bf70e43e689 (patch)
treed8afb52acd9386a59c1862a265d4f8e6d2fdbaba /src/backend/tcop
parentaa82790fcab98b8d3d4eca2e2f6f7bfce57870bc (diff)
downloadpostgresql-5da9da71c44f27ba48fdad08ef263bf70e43e689.tar.gz
postgresql-5da9da71c44f27ba48fdad08ef263bf70e43e689.zip
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.
Diffstat (limited to 'src/backend/tcop')
-rw-r--r--src/backend/tcop/fastpath.c7
-rw-r--r--src/backend/tcop/postgres.c56
-rw-r--r--src/backend/tcop/pquery.c84
3 files changed, 68 insertions, 79 deletions
diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c
index 80cf04680a9..90848112580 100644
--- a/src/backend/tcop/fastpath.c
+++ b/src/backend/tcop/fastpath.c
@@ -8,7 +8,7 @@
*
*
* 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
* This cruft is the server side of PQfn.
@@ -309,7 +309,7 @@ HandleFunctionRequest(StringInfo msgBuf)
* 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.
*/
- ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
+ PushActiveSnapshot(GetTransactionSnapshot());
/*
* Begin parsing the buffer contents.
@@ -396,6 +396,9 @@ HandleFunctionRequest(StringInfo msgBuf)
SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
+ /* We no longer need the snapshot */
+ PopActiveSnapshot();
+
/*
* Emit duration logging if appropriate.
*/
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index d9599851c59..d212eb9449e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* 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
* this is the "main" module of the postgres backend and
@@ -732,49 +732,37 @@ List *
pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams,
bool needSnapshot)
{
- List * volatile stmt_list = NIL;
- Snapshot saveActiveSnapshot = ActiveSnapshot;
+ List *stmt_list = NIL;
+ ListCell *query_list;
+ bool snapshot_set = false;
- /* PG_TRY to ensure previous ActiveSnapshot is restored on error */
- PG_TRY();
+ foreach(query_list, querytrees)
{
- Snapshot mySnapshot = NULL;
- ListCell *query_list;
+ Query *query = (Query *) lfirst(query_list);
+ Node *stmt;
- foreach(query_list, querytrees)
+ if (query->commandType == CMD_UTILITY)
{
- Query *query = (Query *) lfirst(query_list);
- Node *stmt;
-
- if (query->commandType == CMD_UTILITY)
- {
- /* Utility commands have no plans. */
- stmt = query->utilityStmt;
- }
- else
+ /* Utility commands have no plans. */
+ stmt = query->utilityStmt;
+ }
+ else
+ {
+ if (needSnapshot && !snapshot_set)
{
- if (needSnapshot && mySnapshot == NULL)
- {
- mySnapshot = CopySnapshot(GetTransactionSnapshot());
- ActiveSnapshot = mySnapshot;
- }
- stmt = (Node *) pg_plan_query(query, cursorOptions,
- boundParams);
+ PushActiveSnapshot(GetTransactionSnapshot());
+ snapshot_set = true;
}
- stmt_list = lappend(stmt_list, stmt);
+ stmt = (Node *) pg_plan_query(query, cursorOptions,
+ boundParams);
}
- if (mySnapshot)
- FreeSnapshot(mySnapshot);
+ stmt_list = lappend(stmt_list, stmt);
}
- PG_CATCH();
- {
- ActiveSnapshot = saveActiveSnapshot;
- PG_RE_THROW();
- }
- PG_END_TRY();
- ActiveSnapshot = saveActiveSnapshot;
+
+ if (snapshot_set)
+ PopActiveSnapshot();
return stmt_list;
}
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index cf5f2784142..a4afab04025 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.122 2008/03/26 18:48:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.123 2008/05/12 20:02:02 alvherre Exp $
*
*-------------------------------------------------------------------------
*/
@@ -70,8 +70,9 @@ CreateQueryDesc(PlannedStmt *plannedstmt,
qd->operation = plannedstmt->commandType; /* operation */
qd->plannedstmt = plannedstmt; /* plan */
qd->utilitystmt = plannedstmt->utilityStmt; /* in case DECLARE CURSOR */
- qd->snapshot = snapshot; /* snapshot */
- qd->crosscheck_snapshot = crosscheck_snapshot; /* RI check snapshot */
+ qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */
+ /* RI check snapshot */
+ qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
qd->dest = dest; /* output dest */
qd->params = params; /* parameter values passed into query */
qd->doInstrument = doInstrument; /* instrumentation wanted? */
@@ -98,7 +99,7 @@ CreateUtilityQueryDesc(Node *utilitystmt,
qd->operation = CMD_UTILITY; /* operation */
qd->plannedstmt = NULL;
qd->utilitystmt = utilitystmt; /* utility command */
- qd->snapshot = snapshot; /* snapshot */
+ qd->snapshot = RegisterSnapshot(snapshot); /* snapshot */
qd->crosscheck_snapshot = InvalidSnapshot; /* RI check snapshot */
qd->dest = dest; /* output dest */
qd->params = params; /* parameter values passed into query */
@@ -120,6 +121,11 @@ FreeQueryDesc(QueryDesc *qdesc)
{
/* Can't be a live query */
Assert(qdesc->estate == NULL);
+
+ /* forget our snapshots */
+ UnregisterSnapshot(qdesc->snapshot);
+ UnregisterSnapshot(qdesc->crosscheck_snapshot);
+
/* Only the QueryDesc itself need be freed */
pfree(qdesc);
}
@@ -152,16 +158,15 @@ ProcessQuery(PlannedStmt *plan,
elog(DEBUG3, "ProcessQuery");
/*
- * Must always set snapshot for plannable queries. Note we assume that
- * caller will take care of restoring ActiveSnapshot on exit/error.
+ * Must always set a snapshot for plannable queries.
*/
- ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
+ PushActiveSnapshot(GetTransactionSnapshot());
/*
* Create the QueryDesc object
*/
queryDesc = CreateQueryDesc(plan,
- ActiveSnapshot, InvalidSnapshot,
+ GetActiveSnapshot(), InvalidSnapshot,
dest, params, false);
/*
@@ -216,15 +221,14 @@ ProcessQuery(PlannedStmt *plan,
/* Now take care of any queued AFTER triggers */
AfterTriggerEndQuery(queryDesc->estate);
+ PopActiveSnapshot();
+
/*
* Now, we close down all the scans and free allocated resources.
*/
ExecutorEnd(queryDesc);
FreeQueryDesc(queryDesc);
-
- FreeSnapshot(ActiveSnapshot);
- ActiveSnapshot = NULL;
}
/*
@@ -446,7 +450,6 @@ void
PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
{
Portal saveActivePortal;
- Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext oldContext;
@@ -460,13 +463,11 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
* Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
- saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
PG_TRY();
{
ActivePortal = portal;
- ActiveSnapshot = NULL; /* will be set later */
CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal);
@@ -487,21 +488,18 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
{
case PORTAL_ONE_SELECT:
- /*
- * Must set snapshot before starting executor. Be sure to
- * copy it into the portal's context.
- */
+ /* Must set snapshot before starting executor. */
if (snapshot)
- ActiveSnapshot = CopySnapshot(snapshot);
+ PushActiveSnapshot(snapshot);
else
- ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
+ PushActiveSnapshot(GetTransactionSnapshot());
/*
* Create QueryDesc in portal's context; for the moment, set
* the destination to DestNone.
*/
queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
- ActiveSnapshot,
+ GetActiveSnapshot(),
InvalidSnapshot,
None_Receiver,
params,
@@ -545,6 +543,8 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
portal->atEnd = false; /* allow fetches */
portal->portalPos = 0;
portal->posOverflow = false;
+
+ PopActiveSnapshot();
break;
case PORTAL_ONE_RETURNING:
@@ -608,7 +608,6 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
/* Restore global vars and propagate error */
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
@@ -619,7 +618,6 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
MemoryContextSwitchTo(oldContext);
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
@@ -707,7 +705,6 @@ PortalRun(Portal portal, long count, bool isTopLevel,
ResourceOwner saveTopTransactionResourceOwner;
MemoryContext saveTopTransactionContext;
Portal saveActivePortal;
- Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext saveMemoryContext;
@@ -751,14 +748,12 @@ PortalRun(Portal portal, long count, bool isTopLevel,
saveTopTransactionResourceOwner = TopTransactionResourceOwner;
saveTopTransactionContext = TopTransactionContext;
saveActivePortal = ActivePortal;
- saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
saveMemoryContext = CurrentMemoryContext;
PG_TRY();
{
ActivePortal = portal;
- ActiveSnapshot = NULL; /* will be set later */
CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal);
@@ -839,7 +834,6 @@ PortalRun(Portal portal, long count, bool isTopLevel,
else
MemoryContextSwitchTo(saveMemoryContext);
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
if (saveResourceOwner == saveTopTransactionResourceOwner)
CurrentResourceOwner = TopTransactionResourceOwner;
else
@@ -855,7 +849,6 @@ PortalRun(Portal portal, long count, bool isTopLevel,
else
MemoryContextSwitchTo(saveMemoryContext);
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
if (saveResourceOwner == saveTopTransactionResourceOwner)
CurrentResourceOwner = TopTransactionResourceOwner;
else
@@ -940,9 +933,10 @@ PortalRunSelect(Portal portal,
nprocessed = RunFromStore(portal, direction, count, dest);
else
{
- ActiveSnapshot = queryDesc->snapshot;
+ PushActiveSnapshot(queryDesc->snapshot);
ExecutorRun(queryDesc, direction, count);
nprocessed = queryDesc->estate->es_processed;
+ PopActiveSnapshot();
}
if (!ScanDirectionIsNoMovement(direction))
@@ -982,9 +976,10 @@ PortalRunSelect(Portal portal,
nprocessed = RunFromStore(portal, direction, count, dest);
else
{
- ActiveSnapshot = queryDesc->snapshot;
+ PushActiveSnapshot(queryDesc->snapshot);
ExecutorRun(queryDesc, direction, count);
nprocessed = queryDesc->estate->es_processed;
+ PopActiveSnapshot();
}
if (!ScanDirectionIsNoMovement(direction))
@@ -1140,6 +1135,8 @@ static void
PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
DestReceiver *dest, char *completionTag)
{
+ bool active_snapshot_set;
+
elog(DEBUG3, "ProcessUtility");
/*
@@ -1152,9 +1149,6 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
* hacks. Beware of listing anything that can modify the database --- if,
* say, it has to update an index with expressions that invoke
* user-defined functions, then it had better have a snapshot.
- *
- * Note we assume that caller will take care of restoring ActiveSnapshot
- * on exit/error.
*/
if (!(IsA(utilityStmt, TransactionStmt) ||
IsA(utilityStmt, LockStmt) ||
@@ -1167,9 +1161,12 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
IsA(utilityStmt, NotifyStmt) ||
IsA(utilityStmt, UnlistenStmt) ||
IsA(utilityStmt, CheckPointStmt)))
- ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
+ {
+ PushActiveSnapshot(GetTransactionSnapshot());
+ active_snapshot_set = true;
+ }
else
- ActiveSnapshot = NULL;
+ active_snapshot_set = false;
ProcessUtility(utilityStmt,
portal->sourceText,
@@ -1181,9 +1178,15 @@ PortalRunUtility(Portal portal, Node *utilityStmt, bool isTopLevel,
/* Some utility statements may change context on us */
MemoryContextSwitchTo(PortalGetHeapMemory(portal));
- if (ActiveSnapshot)
- FreeSnapshot(ActiveSnapshot);
- ActiveSnapshot = NULL;
+ /*
+ * Some utility commands may pop the ActiveSnapshot stack from under us,
+ * so we only pop the stack if we actually see a snapshot set. Note that
+ * the set of utility commands that do this must be the same set
+ * disallowed to run inside a transaction; otherwise, we could be popping
+ * a snapshot that belongs to some other operation.
+ */
+ if (active_snapshot_set && ActiveSnapshotSet())
+ PopActiveSnapshot();
}
/*
@@ -1321,7 +1324,6 @@ PortalRunFetch(Portal portal,
{
long result;
Portal saveActivePortal;
- Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext oldContext;
@@ -1341,13 +1343,11 @@ PortalRunFetch(Portal portal,
* Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
- saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
PG_TRY();
{
ActivePortal = portal;
- ActiveSnapshot = NULL; /* will be set later */
CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal);
@@ -1388,7 +1388,6 @@ PortalRunFetch(Portal portal,
/* Restore global vars and propagate error */
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
@@ -1402,7 +1401,6 @@ PortalRunFetch(Portal portal,
portal->status = PORTAL_READY;
ActivePortal = saveActivePortal;
- ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;