1
0
mirror of https://github.com/postgres/postgres.git synced 2025-10-27 00:12:01 +03:00

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.
This commit is contained in:
Alvaro Herrera
2008-05-12 20:02:02 +00:00
parent aa82790fca
commit 5da9da71c4
27 changed files with 995 additions and 551 deletions

View File

@@ -11,7 +11,7 @@
*
*
* 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)
rvs = get_tables_to_cluster(cluster_context);
/* Commit to get out of starting transaction */
PopActiveSnapshot();
CommitTransactionCommand();
/* Ok, now that we've got them all, cluster them one by one */
@@ -222,8 +223,9 @@ cluster(ClusterStmt *stmt, bool isTopLevel)
/* Start a new transaction for each relation. */
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
PushActiveSnapshot(GetTransactionSnapshot());
cluster_rel(rvtc, true);
PopActiveSnapshot();
CommitTransactionCommand();
}

View File

@@ -8,7 +8,7 @@
*
*
* 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)
plan = planner(query, 0, NULL);
/*
* Update snapshot command ID to ensure this query sees results of any
* previously executed queries. (It's a bit cheesy to modify
* 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.)
* Use a snapshot with an updated command ID to ensure this query sees
* results of any previously executed queries.
*/
ActiveSnapshot->curcid = GetCurrentCommandId(false);
PushUpdatedSnapshot(GetActiveSnapshot());
/* Create dest receiver for COPY OUT */
dest = CreateDestReceiver(DestCopyOut, NULL);
((DR_copy *) dest)->cstate = cstate;
/* Create a QueryDesc requesting no output */
cstate->queryDesc = CreateQueryDesc(plan,
ActiveSnapshot, InvalidSnapshot,
cstate->queryDesc = CreateQueryDesc(plan, GetActiveSnapshot(),
InvalidSnapshot,
dest, NULL, false);
/*
@@ -1161,6 +1158,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString)
/* Close down the query and free resources. */
ExecutorEnd(cstate->queryDesc);
FreeQueryDesc(cstate->queryDesc);
PopActiveSnapshot();
}
/* Clean up storage (probably not really necessary) */
@@ -1390,7 +1388,7 @@ CopyTo(CopyState cstate)
values = (Datum *) palloc(num_phys_attrs * sizeof(Datum));
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)
{

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* 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,
int eflags;
/*
* Update snapshot command ID to ensure this query sees results of any
* previously executed queries. (It's a bit cheesy to modify
* 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.)
* Use a snapshot with an updated command ID to ensure this query sees
* results of any previously executed queries.
*/
ActiveSnapshot->curcid = GetCurrentCommandId(false);
PushUpdatedSnapshot(GetActiveSnapshot());
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(plannedstmt,
ActiveSnapshot, InvalidSnapshot,
GetActiveSnapshot(), InvalidSnapshot,
None_Receiver, params,
stmt->analyze);
@@ -324,6 +321,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, ParamListInfo params,
FreeQueryDesc(queryDesc);
PopActiveSnapshot();
/* We need a CCI just in case query expanded to multiple plans */
if (stmt->analyze)
CommandCounterIncrement();

View File

@@ -8,7 +8,7 @@
*
*
* 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,
*/
LockRelationIdForSession(&heaprelid, ShareUpdateExclusiveLock);
PopActiveSnapshot();
CommitTransactionCommand();
StartTransactionCommand();
@@ -542,7 +543,7 @@ DefineIndex(RangeVar *heapRelation,
indexRelation = index_open(indexRelationId, RowExclusiveLock);
/* 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 */
indexInfo = BuildIndexInfo(indexRelation);
@@ -581,6 +582,9 @@ DefineIndex(RangeVar *heapRelation,
heap_close(pg_index, RowExclusiveLock);
/* we can do away with our snapshot */
PopActiveSnapshot();
/*
* Commit this transaction to make the indisready update visible.
*/
@@ -616,8 +620,8 @@ DefineIndex(RangeVar *heapRelation,
* We also set ActiveSnapshot to this snap, since functions in indexes may
* need a snapshot.
*/
snapshot = CopySnapshot(GetTransactionSnapshot());
ActiveSnapshot = snapshot;
snapshot = RegisterSnapshot(GetTransactionSnapshot());
PushActiveSnapshot(snapshot);
/*
* Scan the index and the heap, insert any missing index entries.
@@ -645,7 +649,7 @@ DefineIndex(RangeVar *heapRelation,
* Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
* check for that.
*/
old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax, false,
old_snapshots = GetCurrentVirtualXIDs(snapshot->xmax, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM);
while (VirtualTransactionIdIsValid(*old_snapshots))
@@ -686,6 +690,12 @@ DefineIndex(RangeVar *heapRelation,
*/
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.
*/
@@ -1453,6 +1463,7 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
heap_close(relationRelation, AccessShareLock);
/* Now reindex each rel in a separate transaction */
PopActiveSnapshot();
CommitTransactionCommand();
foreach(l, relids)
{
@@ -1460,11 +1471,12 @@ ReindexDatabase(const char *databaseName, bool do_system, bool do_user)
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
PushActiveSnapshot(GetTransactionSnapshot());
if (reindex_relation(relid, true))
ereport(NOTICE,
(errmsg("table \"%s\" was reindexed",
get_rel_name(relid))));
PopActiveSnapshot();
CommitTransactionCommand();
}
StartTransactionCommand();

View File

@@ -14,7 +14,7 @@
*
*
* 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,
/*
* Start execution, inserting parameters if any.
*/
PortalStart(portal, params, ActiveSnapshot);
PortalStart(portal, params, GetActiveSnapshot());
Assert(portal->strategy == PORTAL_ONE_SELECT);
@@ -293,7 +293,6 @@ PersistHoldablePortal(Portal portal)
{
QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveActivePortal;
Snapshot saveActiveSnapshot;
ResourceOwner saveResourceOwner;
MemoryContext savePortalContext;
MemoryContext oldcxt;
@@ -334,18 +333,18 @@ PersistHoldablePortal(Portal portal)
* Set up global portal context pointers.
*/
saveActivePortal = ActivePortal;
saveActiveSnapshot = ActiveSnapshot;
saveResourceOwner = CurrentResourceOwner;
savePortalContext = PortalContext;
PG_TRY();
{
ActivePortal = portal;
ActiveSnapshot = queryDesc->snapshot;
CurrentResourceOwner = portal->resowner;
PortalContext = PortalGetHeapMemory(portal);
MemoryContextSwitchTo(PortalContext);
PushActiveSnapshot(queryDesc->snapshot);
/*
* Rewind the executor: we need to store the entire result set in the
* tuplestore, so that subsequent backward FETCHs can be processed.
@@ -411,7 +410,6 @@ PersistHoldablePortal(Portal portal)
/* Restore global vars and propagate error */
ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
@@ -425,10 +423,11 @@ PersistHoldablePortal(Portal portal)
portal->status = PORTAL_READY;
ActivePortal = saveActivePortal;
ActiveSnapshot = saveActiveSnapshot;
CurrentResourceOwner = saveResourceOwner;
PortalContext = savePortalContext;
PopActiveSnapshot();
/*
* 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,

View File

@@ -10,7 +10,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
*
* 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,
/*
* Run the portal to completion.
*/
PortalStart(portal, paramLI, ActiveSnapshot);
PortalStart(portal, paramLI, GetActiveSnapshot());
(void) PortalRun(portal, FETCH_ALL, false, dest, dest, completionTag);

View File

@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.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
AfterTriggerFireDeferred(void)
{
AfterTriggerEventList *events;
bool snap_pushed = false;
/* Must be inside a transaction */
Assert(afterTriggers != NULL);
@@ -2990,7 +2991,10 @@ AfterTriggerFireDeferred(void)
*/
events = &afterTriggers->events;
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
@@ -3003,6 +3007,9 @@ AfterTriggerFireDeferred(void)
afterTriggerInvokeEvents(events, firing_id, NULL, true);
}
if (snap_pushed)
PopActiveSnapshot();
Assert(events->head == NULL);
}

View File

@@ -13,7 +13,7 @@
*
*
* 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,
*/
if (use_own_xacts)
{
/* ActiveSnapshot is not set by autovacuum */
if (ActiveSnapshotSet())
PopActiveSnapshot();
/* matches the StartTransaction in PostgresMain() */
CommitTransactionCommand();
}
@@ -446,7 +450,7 @@ vacuum(VacuumStmt *vacstmt, List *relids,
{
StartTransactionCommand();
/* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
PushActiveSnapshot(GetTransactionSnapshot());
}
else
old_context = MemoryContextSwitchTo(anl_context);
@@ -454,7 +458,10 @@ vacuum(VacuumStmt *vacstmt, List *relids,
analyze_rel(relid, vacstmt, vac_strategy);
if (use_own_xacts)
{
PopActiveSnapshot();
CommitTransactionCommand();
}
else
{
MemoryContextSwitchTo(old_context);
@@ -981,7 +988,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (vacstmt->full)
{
/* functions in indexes may want a snapshot set */
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
PushActiveSnapshot(GetTransactionSnapshot());
}
else
{
@@ -1038,6 +1045,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (!onerel)
{
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand();
return;
}
@@ -1068,6 +1077,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
(errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
RelationGetRelationName(onerel))));
relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand();
return;
}
@@ -1082,6 +1093,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
RelationGetRelationName(onerel))));
relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand();
return;
}
@@ -1096,6 +1109,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
if (isOtherTempNamespace(RelationGetNamespace(onerel)))
{
relation_close(onerel, lmode);
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand();
return;
}
@@ -1143,6 +1158,8 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, char expected_relkind,
/*
* Complete the transaction and free all temporary memory used.
*/
if (vacstmt->full)
PopActiveSnapshot();
CommitTransactionCommand();
/*

View File

@@ -9,7 +9,7 @@
*
*
* 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)
const char *
assign_XactIsoLevel(const char *value, bool doit, GucSource source)
{
if (SerializableSnapshot != NULL)
if (FirstSnapshotSet)
{
ereport(GUC_complaint_elevel(source),
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),