diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 6d3528323bf016339031ed1ea0a0f2795963880e..eb9f8701ae1b901fb3debaafcdcea79107323fd0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.262 2008/08/11 11:05:10 heikki Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.263 2008/09/11 14:01:09 alvherre Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -219,6 +219,7 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
 	/*
 	 * Prune and repair fragmentation for the whole page, if possible.
 	 */
+	Assert(TransactionIdIsValid(RecentGlobalXmin));
 	heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
 
 	/*
@@ -1469,6 +1470,8 @@ heap_hot_search_buffer(ItemPointer tid, Buffer buffer, Snapshot snapshot,
 	if (all_dead)
 		*all_dead = true;
 
+	Assert(TransactionIdIsValid(RecentGlobalXmin));
+
 	Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer));
 	offnum = ItemPointerGetOffsetNumber(tid);
 	at_chain_start = true;
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 7d6028804a5db65033b0acb33decaf134ba39570..0c132d5fc09deaa0ae5bbf58f9e56abb6322a2f2 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.109 2008/06/19 00:46:03 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.110 2008/09/11 14:01:09 alvherre Exp $
  *
  * INTERFACE ROUTINES
  *		index_open		- open an index relation by relation OID
@@ -419,6 +419,8 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
 	SCAN_CHECKS;
 	GET_SCAN_PROCEDURE(amgettuple);
 
+	Assert(TransactionIdIsValid(RecentGlobalXmin));
+
 	/*
 	 * We always reset xs_hot_dead; if we are here then either we are just
 	 * starting the scan, or we previously returned a visible tuple, and in
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 7eb5777d3ab9b54586393ef1000dacd0199c6668..af7b6646d2887cb021ca4b9777290237243f9f91 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.376 2008/08/13 00:07:50 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.377 2008/09/11 14:01:09 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -790,14 +790,12 @@ vac_update_datfrozenxid(void)
 	bool		dirty = false;
 
 	/*
-	 * Initialize the "min" calculation with RecentGlobalXmin.	Any
-	 * not-yet-committed pg_class entries for new tables must have
-	 * relfrozenxid at least this high, because any other open xact must have
-	 * RecentXmin >= its PGPROC.xmin >= our RecentGlobalXmin; see
-	 * AddNewRelationTuple().  So we cannot produce a wrong minimum by
-	 * starting with this.
+	 * Initialize the "min" calculation with GetOldestXmin, which is a
+	 * reasonable approximation to the minimum relfrozenxid for not-yet-
+	 * committed pg_class entries for new tables; see AddNewRelationTuple().
+	 * Se we cannot produce a wrong minimum by starting with this.
 	 */
-	newFrozenXid = RecentGlobalXmin;
+	newFrozenXid = GetOldestXmin(true, true);
 
 	/*
 	 * We must seqscan pg_class to find the minimum Xid, because there is no
@@ -990,18 +988,16 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 	/* Begin a transaction for vacuuming this relation */
 	StartTransactionCommand();
 
-	if (vacstmt->full)
-	{
-		/* functions in indexes may want a snapshot set */
-		PushActiveSnapshot(GetTransactionSnapshot());
-	}
-	else
+	/*
+	 * Functions in indexes may want a snapshot set.  Also, setting
+	 * a snapshot ensures that RecentGlobalXmin is kept truly recent.
+	 */
+	PushActiveSnapshot(GetTransactionSnapshot());
+
+	if (!vacstmt->full)
 	{
 		/*
-		 * During a lazy VACUUM we do not run any user-supplied functions, and
-		 * so it should be safe to not create a transaction snapshot.
-		 *
-		 * We can furthermore set the PROC_IN_VACUUM flag, which lets other
+		 * In lazy vacuum, we can set the PROC_IN_VACUUM flag, which lets other
 		 * concurrent VACUUMs know that they can ignore this one while
 		 * determining their OldestXmin.  (The reason we don't set it during a
 		 * full VACUUM is exactly that we may have to run user- defined
@@ -1050,8 +1046,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 
 	if (!onerel)
 	{
-		if (vacstmt->full)
-			PopActiveSnapshot();
+		PopActiveSnapshot();
 		CommitTransactionCommand();
 		return;
 	}
@@ -1082,8 +1077,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 					(errmsg("skipping \"%s\" --- only table or database owner can vacuum it",
 							RelationGetRelationName(onerel))));
 		relation_close(onerel, lmode);
-		if (vacstmt->full)
-			PopActiveSnapshot();
+		PopActiveSnapshot();
 		CommitTransactionCommand();
 		return;
 	}
@@ -1099,8 +1093,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 				(errmsg("skipping \"%s\" --- cannot vacuum indexes, views, or special system tables",
 						RelationGetRelationName(onerel))));
 		relation_close(onerel, lmode);
-		if (vacstmt->full)
-			PopActiveSnapshot();
+		PopActiveSnapshot();
 		CommitTransactionCommand();
 		return;
 	}
@@ -1115,8 +1108,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 	if (isOtherTempNamespace(RelationGetNamespace(onerel)))
 	{
 		relation_close(onerel, lmode);
-		if (vacstmt->full)
-			PopActiveSnapshot();
+		PopActiveSnapshot();
 		CommitTransactionCommand();
 		return;
 	}
@@ -1168,8 +1160,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
 	/*
 	 * Complete the transaction and free all temporary memory used.
 	 */
-	if (vacstmt->full)
-		PopActiveSnapshot();
+	PopActiveSnapshot();
 	CommitTransactionCommand();
 
 	/*
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index e09ece65375b22e29aff0ba301dd090254acaa15..41b9da62eab905624b815f1fd38ed328d8e0d8c6 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -21,7 +21,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.29 2008/06/19 00:46:04 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.30 2008/09/11 14:01:09 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,6 +37,7 @@
 
 #include "access/heapam.h"
 #include "access/relscan.h"
+#include "access/transam.h"
 #include "executor/execdebug.h"
 #include "executor/nodeBitmapHeapscan.h"
 #include "pgstat.h"
@@ -262,6 +263,7 @@ bitgetpage(HeapScanDesc scan, TBMIterateResult *tbmres)
 	/*
 	 * Prune and repair fragmentation for the whole page, if possible.
 	 */
+	Assert(TransactionIdIsValid(RecentGlobalXmin));
 	heap_page_prune_opt(scan->rs_rd, buffer, RecentGlobalXmin);
 
 	/*
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index e0dbbf931116c4486c66bc063614836a2f26b6e2..6b66b2e3926440bf3215afb73f0d5908d70afa77 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.184 2008/05/12 00:00:52 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.185 2008/09/11 14:01:09 alvherre Exp $
  *
  *
  *-------------------------------------------------------------------------
@@ -47,6 +47,7 @@
 #include "utils/plancache.h"
 #include "utils/portal.h"
 #include "utils/relcache.h"
+#include "utils/snapmgr.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
@@ -461,10 +462,15 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
 	on_shmem_exit(ShutdownPostgres, 0);
 
 	/*
-	 * Start a new transaction here before first access to db
+	 * Start a new transaction here before first access to db, and get a
+	 * snapshot.  We don't have a use for the snapshot itself, but we're
+	 * interested in the secondary effect that it sets RecentGlobalXmin.
 	 */
 	if (!bootstrap)
+	{
 		StartTransactionCommand();
+		(void) GetTransactionSnapshot();
+	}
 
 	/*
 	 * Now that we have a transaction, we can take locks.  Take a writer's
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index 841a92567d1d7c0d64f254c0f21e5e47487eca17..0add5f489c4eee0d515bd8baf288e77c02c15a09 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.4 2008/07/11 02:10:14 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/time/snapmgr.c,v 1.5 2008/09/11 14:01:10 alvherre Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,10 +59,14 @@ static Snapshot	SecondarySnapshot = NULL;
  * These are updated by GetSnapshotData.  We initialize them this way
  * for the convenience of TransactionIdIsInProgress: even in bootstrap
  * mode, we don't want it to say that BootstrapTransactionId is in progress.
+ *
+ * RecentGlobalXmin is initialized to InvalidTransactionId, to ensure that no
+ * one tries to use a stale value.  Readers should ensure that it has been set
+ * to something else before using it.
  */
 TransactionId TransactionXmin = FirstNormalTransactionId;
 TransactionId RecentXmin = FirstNormalTransactionId;
-TransactionId RecentGlobalXmin = FirstNormalTransactionId;
+TransactionId RecentGlobalXmin = InvalidTransactionId;
 
 /*
  * Elements of the list of registered snapshots.