diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index de061279a14d1f2f81d5280511cf1fc562da7d73..5cd4f005c6544a8a74208839d58c5cb779cf4a0d 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.281 2010/01/10 04:26:36 rhaas Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.282 2010/01/14 11:08:00 sriggs Exp $
  *
  *
  * INTERFACE ROUTINES
@@ -4139,16 +4139,7 @@ heap_xlog_cleanup_info(XLogRecPtr lsn, XLogRecord *record)
 	xl_heap_cleanup_info *xlrec = (xl_heap_cleanup_info *) XLogRecGetData(record);
 
 	if (InHotStandby)
-	{
-		VirtualTransactionId *backends;
-
-		backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
-											 InvalidOid,
-											 true);
-		ResolveRecoveryConflictWithVirtualXIDs(backends,
-											   "VACUUM index cleanup",
-											   CONFLICT_MODE_ERROR);
-	}
+		ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
 
 	/*
 	 * Actual operation is a no-op. Record type exists to provide a means
@@ -4180,16 +4171,7 @@ heap_xlog_clean(XLogRecPtr lsn, XLogRecord *record, bool clean_move)
 	 * no queries running for which the removed tuples are still visible.
 	 */
 	if (InHotStandby)
-	{
-		VirtualTransactionId *backends;
-
-		backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
-											 InvalidOid,
-											 true);
-		ResolveRecoveryConflictWithVirtualXIDs(backends,
-											   "VACUUM heap cleanup",
-											   CONFLICT_MODE_ERROR);
-	}
+		ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
 
 	RestoreBkpBlocks(lsn, record, true);
 
@@ -4259,25 +4241,7 @@ heap_xlog_freeze(XLogRecPtr lsn, XLogRecord *record)
 	 * consider the frozen xids as running.
 	 */
 	if (InHotStandby)
-	{
-		VirtualTransactionId *backends;
-
-		/*
-		 * XXX: Using cutoff_xid is overly conservative. Even if cutoff_xid
-		 * is recent enough to conflict with a backend, the actual values
-		 * being frozen might not be. With a typical vacuum_freeze_min_age
-		 * setting in the ballpark of millions of transactions, it won't make
-		 * a difference, but it might if you run a manual VACUUM FREEZE.
-		 * Typically the cutoff is much earlier than any recently deceased
-		 * tuple versions removed by this vacuum, so don't worry too much.
-		 */
-		backends = GetConflictingVirtualXIDs(cutoff_xid,
-											 InvalidOid,
-											 true);
-		ResolveRecoveryConflictWithVirtualXIDs(backends,
-											   "VACUUM heap freeze",
-											   CONFLICT_MODE_ERROR);
-	}
+		ResolveRecoveryConflictWithSnapshot(cutoff_xid);
 
 	RestoreBkpBlocks(lsn, record, false);
 
diff --git a/src/backend/access/nbtree/nbtxlog.c b/src/backend/access/nbtree/nbtxlog.c
index 55f05bdc2c9f1f0a280033d3a9fa61f7899f2db5..9e2ebd9a9f5fd70e3da06ebb515d9c2328c39cc9 100644
--- a/src/backend/access/nbtree/nbtxlog.c
+++ b/src/backend/access/nbtree/nbtxlog.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.57 2010/01/02 16:57:35 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.58 2010/01/14 11:08:00 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -822,28 +822,18 @@ btree_redo(XLogRecPtr lsn, XLogRecord *record)
 	 * just once when that arrives. After that any we know that no conflicts
 	 * exist from individual btree vacuum records on that index.
 	 */
-	if (InHotStandby)
+	if (InHotStandby && info == XLOG_BTREE_DELETE)
 	{
-		if (info == XLOG_BTREE_DELETE)
-		{
-			xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
-			VirtualTransactionId *backends;
-
-			/*
-			 * XXX Currently we put everybody on death row, because
-			 * currently _bt_delitems() supplies InvalidTransactionId.
-			 * This can be fairly painful, so providing a better value
-			 * here is worth some thought and possibly some effort to
-			 * improve.
-			 */
-			backends = GetConflictingVirtualXIDs(xlrec->latestRemovedXid,
-												 InvalidOid,
-												 true);
+		xl_btree_delete *xlrec = (xl_btree_delete *) XLogRecGetData(record);
 
-			ResolveRecoveryConflictWithVirtualXIDs(backends,
-												   "b-tree delete",
-												   CONFLICT_MODE_ERROR);
-		}
+		/*
+		 * XXX Currently we put everybody on death row, because
+		 * currently _bt_delitems() supplies InvalidTransactionId.
+		 * This can be fairly painful, so providing a better value
+		 * here is worth some thought and possibly some effort to
+		 * improve.
+		 */
+		ResolveRecoveryConflictWithSnapshot(xlrec->latestRemovedXid);
 	}
 
 	/*
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 846f59244b4b0b70d143f41798d4b1a7cadf76f3..a45b351dd54ecd2d505073900ca7bb6c47266118 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -13,7 +13,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.231 2010/01/10 15:44:28 sriggs Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.232 2010/01/14 11:08:00 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1944,29 +1944,7 @@ dbase_redo(XLogRecPtr lsn, XLogRecord *record)
 		dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id);
 
 		if (InHotStandby)
-		{
-			/*
-			 * We don't do ResolveRecoveryConflictWithVirutalXIDs() here since
-			 * that only waits for transactions and completely idle sessions
-			 * would block us. This is rare enough that we do this as simply
-			 * as possible: no wait, just force them off immediately. 
-			 *
-			 * No locking is required here because we already acquired
-			 * AccessExclusiveLock. Anybody trying to connect while we do this
-			 * will block during InitPostgres() and then disconnect when they
-			 * see the database has been removed.
-			 */
-			while (CountDBBackends(xlrec->db_id) > 0)
-			{
-				CancelDBBackends(xlrec->db_id);
-
-				/*
-				 * Wait awhile for them to die so that we avoid flooding an
-				 * unresponsive backend when system is heavily loaded.
-				 */
-				pg_usleep(10000);
-			}
-		}
+			ResolveRecoveryConflictWithDatabase(xlrec->db_id);
 
 		/* Drop pages for this database that are in the shared buffer cache */
 		DropDatabaseBuffers(xlrec->db_id);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 1eaa0abeea2e6d2689a71982546a6ffda4519d52..2ff3835ab0f370d3e94efd2044ff8b4fdb13969d 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -40,7 +40,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.71 2010/01/12 02:42:51 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.72 2010/01/14 11:08:01 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1377,33 +1377,7 @@ tblspc_redo(XLogRecPtr lsn, XLogRecord *record)
 		 */
 		if (!destroy_tablespace_directories(xlrec->ts_id, true))
 		{
-			VirtualTransactionId *temp_file_users;
-
-			/*
-			 * Standby users may be currently using this tablespace for
-			 * for their temporary files. We only care about current
-			 * users because temp_tablespace parameter will just ignore
-			 * tablespaces that no longer exist.
-			 *
-			 * Ask everybody to cancel their queries immediately so
-			 * we can ensure no temp files remain and we can remove the
-			 * tablespace. Nuke the entire site from orbit, it's the only
-			 * way to be sure.
-			 *
-			 * XXX: We could work out the pids of active backends
-			 * using this tablespace by examining the temp filenames in the
-			 * directory. We would then convert the pids into VirtualXIDs
-			 * before attempting to cancel them.
-			 *
-			 * We don't wait for commit because drop tablespace is
-			 * non-transactional.
-			 */
-			temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
-														InvalidOid,
-														false);
-			ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
-												   "drop tablespace",
-												   CONFLICT_MODE_ERROR);
+			ResolveRecoveryConflictWithTablespace(xlrec->ts_id);
 
 			/*
 			 * If we did recovery processing then hopefully the
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 98a6ad6dd0bb4274bb8d3f433d3489c65fc0b293..bc9302c4bca5a0a53286a18f25873d517b569d2b 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.3 2010/01/02 16:57:51 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.4 2010/01/14 11:08:02 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,6 +37,9 @@ int		vacuum_defer_cleanup_age;
 
 static List *RecoveryLockList;
 
+static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
+									   char *reason, int cancel_mode);
+static void ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid);
 static void LogCurrentRunningXacts(RunningTransactions CurrRunningXacts);
 static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks);
 
@@ -162,7 +165,7 @@ WaitExceedsMaxStandbyDelay(void)
  *
  * We may ask for a specific cancel_mode, typically ERROR or FATAL.
  */
-void
+static void
 ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
 									   char *reason, int cancel_mode)
 {
@@ -272,6 +275,119 @@ ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
     }
 }
 
+void
+ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid)
+{
+	VirtualTransactionId *backends;
+
+	backends = GetConflictingVirtualXIDs(latestRemovedXid,
+										 InvalidOid,
+										 true);
+
+	ResolveRecoveryConflictWithVirtualXIDs(backends,
+										   "snapshot conflict",
+										   CONFLICT_MODE_ERROR);
+}
+
+void
+ResolveRecoveryConflictWithTablespace(Oid tsid)
+{
+	VirtualTransactionId *temp_file_users;
+
+	/*
+	 * Standby users may be currently using this tablespace for
+	 * for their temporary files. We only care about current
+	 * users because temp_tablespace parameter will just ignore
+	 * tablespaces that no longer exist.
+	 *
+	 * Ask everybody to cancel their queries immediately so
+	 * we can ensure no temp files remain and we can remove the
+	 * tablespace. Nuke the entire site from orbit, it's the only
+	 * way to be sure.
+	 *
+	 * XXX: We could work out the pids of active backends
+	 * using this tablespace by examining the temp filenames in the
+	 * directory. We would then convert the pids into VirtualXIDs
+	 * before attempting to cancel them.
+	 *
+	 * We don't wait for commit because drop tablespace is
+	 * non-transactional.
+	 */
+	temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId,
+												InvalidOid,
+												false);
+	ResolveRecoveryConflictWithVirtualXIDs(temp_file_users,
+										   "drop tablespace",
+										   CONFLICT_MODE_ERROR);
+}
+
+void
+ResolveRecoveryConflictWithDatabase(Oid dbid)
+{
+	/*
+	 * We don't do ResolveRecoveryConflictWithVirutalXIDs() here since
+	 * that only waits for transactions and completely idle sessions
+	 * would block us. This is rare enough that we do this as simply
+	 * as possible: no wait, just force them off immediately.
+	 *
+	 * No locking is required here because we already acquired
+	 * AccessExclusiveLock. Anybody trying to connect while we do this
+	 * will block during InitPostgres() and then disconnect when they
+	 * see the database has been removed.
+	 */
+	while (CountDBBackends(dbid) > 0)
+	{
+		CancelDBBackends(dbid);
+
+		/*
+		 * Wait awhile for them to die so that we avoid flooding an
+		 * unresponsive backend when system is heavily loaded.
+		 */
+		pg_usleep(10000);
+	}
+}
+
+static void
+ResolveRecoveryConflictWithLock(Oid dbOid, Oid relOid)
+{
+	VirtualTransactionId *backends;
+	bool			report_memory_error = false;
+	bool			lock_acquired = false;
+	int				num_attempts = 0;
+	LOCKTAG			locktag;
+
+	SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
+
+	/*
+	 * If blowing away everybody with conflicting locks doesn't work,
+	 * after the first two attempts then we just start blowing everybody
+	 * away until it does work. We do this because its likely that we
+	 * either have too many locks and we just can't get one at all,
+	 * or that there are many people crowding for the same table.
+	 * Recovery must win; the end justifies the means.
+	 */
+	while (!lock_acquired)
+	{
+		if (++num_attempts < 3)
+			backends = GetLockConflicts(&locktag, AccessExclusiveLock);
+		else
+		{
+			backends = GetConflictingVirtualXIDs(InvalidTransactionId,
+												 InvalidOid,
+												 true);
+			report_memory_error = true;
+		}
+
+		ResolveRecoveryConflictWithVirtualXIDs(backends,
+											   "exclusive lock",
+											   CONFLICT_MODE_ERROR);
+
+		if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false)
+											!= LOCKACQUIRE_NOT_AVAIL)
+			lock_acquired = true;
+	}
+}
+
 /*
  * -----------------------------------------------------
  * Locking in Recovery Mode
@@ -303,8 +419,6 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
 {
 	xl_standby_lock	*newlock;
 	LOCKTAG			locktag;
-	bool			report_memory_error = false;
-	int				num_attempts = 0;
 
 	/* Already processed? */
 	if (TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid))
@@ -323,41 +437,13 @@ StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
 	RecoveryLockList = lappend(RecoveryLockList, newlock);
 
 	/*
-	 * Attempt to acquire the lock as requested.
+	 * Attempt to acquire the lock as requested, if not resolve conflict
 	 */
 	SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
 
-	/*
-	 * Wait for lock to clear or kill anyone in our way.
-	 */
-	while (LockAcquireExtended(&locktag, AccessExclusiveLock,
-								true, true, report_memory_error)
+	if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false)
 											== LOCKACQUIRE_NOT_AVAIL)
-	{
-		VirtualTransactionId *backends;
-
-		/*
-		 * If blowing away everybody with conflicting locks doesn't work,
-		 * after the first two attempts then we just start blowing everybody
-		 * away until it does work. We do this because its likely that we
-		 * either have too many locks and we just can't get one at all,
-		 * or that there are many people crowding for the same table.
-		 * Recovery must win; the end justifies the means.
-		 */
-		if (++num_attempts < 3)
-			backends = GetLockConflicts(&locktag, AccessExclusiveLock);
-		else
-		{
-			backends = GetConflictingVirtualXIDs(InvalidTransactionId,
-												 InvalidOid,
-												 true);
-			report_memory_error = true;
-		}
-
-		ResolveRecoveryConflictWithVirtualXIDs(backends,
-											   "exclusive lock",
-											   CONFLICT_MODE_ERROR);
-	}
+		ResolveRecoveryConflictWithLock(newlock->dbOid, newlock->relOid);
 }
 
 static void
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index a58d666f0de48d94cfaa76be1e784bab5855e064..3f2e2c2d85587fdd2701428d5aadcfb42a2aa977 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.2 2010/01/02 16:58:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.3 2010/01/14 11:08:02 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,8 +24,9 @@ extern int	vacuum_defer_cleanup_age;
 #define CONFLICT_MODE_ERROR			1	/* Conflict can be resolved by canceling query */
 #define CONFLICT_MODE_FATAL			2	/* Conflict can only be resolved by disconnecting session */
 
-extern void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist,
-									   char *reason, int cancel_mode);
+extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid);
+extern void ResolveRecoveryConflictWithTablespace(Oid tsid);
+extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
 
 extern void InitRecoveryTransactionEnvironment(void);
 extern void ShutdownRecoveryTransactionEnvironment(void);