diff options
author | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2008-05-12 20:02:02 +0000 |
---|---|---|
committer | Alvaro Herrera <alvherre@alvh.no-ip.org> | 2008-05-12 20:02:02 +0000 |
commit | 5da9da71c44f27ba48fdad08ef263bf70e43e689 (patch) | |
tree | d8afb52acd9386a59c1862a265d4f8e6d2fdbaba /src/backend/commands | |
parent | aa82790fcab98b8d3d4eca2e2f6f7bfce57870bc (diff) | |
download | postgresql-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/commands')
-rw-r--r-- | src/backend/commands/cluster.c | 6 | ||||
-rw-r--r-- | src/backend/commands/copy.c | 18 | ||||
-rw-r--r-- | src/backend/commands/explain.c | 15 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 24 | ||||
-rw-r--r-- | src/backend/commands/portalcmds.c | 13 | ||||
-rw-r--r-- | src/backend/commands/prepare.c | 4 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 11 | ||||
-rw-r--r-- | src/backend/commands/vacuum.c | 23 | ||||
-rw-r--r-- | src/backend/commands/variable.c | 4 |
9 files changed, 76 insertions, 42 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 374af6be893..18ad7ad812a 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -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(); } diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 2504bde78ef..69a059631bc 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -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) { diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index cbcc2a67e1c..6fbdabd1d2b 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -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(); diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 37c5c416f52..05eb55e8699 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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(); diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index 83998233b49..3e5e573c605 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -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, diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index d42f77d1f6c..8361fc67554 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -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); diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 1ec24812d71..7685906aeb0 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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); } diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 679c0126242..c5793231f22 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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(); /* diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c index 83d7c2e57f6..7d4cd8e598f 100644 --- a/src/backend/commands/variable.c +++ b/src/backend/commands/variable.c @@ -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), |