aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/pquery.c
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/pquery.c
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/pquery.c')
-rw-r--r--src/backend/tcop/pquery.c84
1 files changed, 41 insertions, 43 deletions
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;