diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index a24b2b7c1ea4aef10ca6e07a97ee6f849a33d3a8..9aef06fca789db85f9113644962d1326522b3a15 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.64 2010/04/19 18:03:38 sriggs Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.65 2010/04/21 19:08:14 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1638,58 +1638,23 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
  * limitXmin is supplied as either latestRemovedXid, or InvalidTransactionId
  * in cases where we cannot accurately determine a value for latestRemovedXid.
  *
- * If limitXmin is InvalidTransactionId then we are forced to assume that
- * latest xid that might have caused a cleanup record will be
- * latestCompletedXid, so we set limitXmin to be latestCompletedXid instead.
- * We then skip any backends with xmin > limitXmin. This means that
- * cleanup records don't conflict with some recent snapshots.
- *
- * The reason for using latestCompletedxid is that we aren't certain which
- * of the xids in KnownAssignedXids are actually FATAL errors that did
- * not write abort records. In almost every case they won't be, but we
- * don't know that for certain. So we need to conflict with all current
- * snapshots whose xmin is less than latestCompletedXid to be safe. This
- * causes false positives in our assessment of which vxids conflict.
- *
- * By using exclusive lock we prevent new snapshots from being taken while
- * we work out which snapshots to conflict with. This protects those new
- * snapshots from also being included in our conflict list.
- *
- * After the lock is released, we allow snapshots again. It is possible
- * that we arrive at a snapshot that is identical to one that we just
- * decided we should conflict with. This a case of false positives, not an
- * actual problem.
- *
- * There are two cases: (1) if we were correct in using latestCompletedXid
- * then that means that all xids in the snapshot lower than that are FATAL
- * errors, so not xids that ever commit. We can make no visibility errors
- * if we allow such xids into the snapshot. (2) if we erred on the side of
- * caution and in fact the latestRemovedXid should have been earlier than
- * latestCompletedXid then we conflicted with a snapshot needlessly. Taking
- * another identical snapshot is OK, because the earlier conflicted
- * snapshot was a false positive.
- *
- * In either case, a snapshot taken after conflict assessment will still be
- * valid and non-conflicting even if an identical snapshot that existed
- * before conflict assessment was assessed as conflicting.
- *
- * If we allowed concurrent snapshots while we were deciding who to
- * conflict with we would need to include all concurrent snapshotters in
- * the conflict list as well. We'd have difficulty in working out exactly
- * who that was, so it is happier for all concerned if we take an exclusive
- * lock. Notice that we only hold that lock for as long as it takes to
- * make the conflict list, not for the whole duration of the conflict
- * resolution.
- *
- * It also means that users waiting for a snapshot is a good thing, since
- * it is more likely that they will live longer after having waited. So it
- * is a benefit, not an oversight that we use exclusive lock here.
- *
- * We replace InvalidTransactionId with latestCompletedXid here because
- * this is the most convenient place to do that, while we hold ProcArrayLock.
- * The originator of the cleanup record wanted to avoid checking the value of
- * latestCompletedXid since doing so would be a performance issue during
- * normal running, so we check it essentially for free on the standby.
+ * If limitXmin is InvalidTransactionId then we want to kill everybody,
+ * so we're not worried if they have a snapshot or not, nor does it really
+ * matter what type of lock we hold.
+ *
+ * All callers that are checking xmins always now supply a valid and useful
+ * value for limitXmin. The limitXmin is always lower than the lowest
+ * numbered KnownAssignedXid that is not already a FATAL error. This is
+ * because we only care about cleanup records that are cleaning up tuple
+ * versions from committed transactions. In that case they will only occur
+ * at the point where the record is less than the lowest running xid. That
+ * allows us to say that if any backend takes a snapshot concurrently with
+ * us then the conflict assessment made here would never include the snapshot
+ * that is being derived. So we take LW_SHARED on the ProcArray and allow
+ * concurrent snapshots when limitXmin is valid. We might think about adding
+ *   Assert(limitXmin < lowest(KnownAssignedXids))
+ * but that would not be true in the case of FATAL errors lagging in array,
+ * but we already know those are bogus anyway, so we skip that test.
  *
  * If dbOid is valid we skip backends attached to other databases.
  *
@@ -1719,14 +1684,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
 					 errmsg("out of memory")));
 	}
 
-	LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
-
-	/*
-	 * If we don't know the TransactionId that created the conflict, set it to
-	 * latestCompletedXid which is the latest possible value.
-	 */
-	if (!TransactionIdIsValid(limitXmin))
-		limitXmin = ShmemVariableCache->latestCompletedXid;
+	LWLockAcquire(ProcArrayLock, LW_SHARED);
 
 	for (index = 0; index < arrayP->numProcs; index++)
 	{
@@ -1747,7 +1705,8 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
 			 * no snapshot and cannot get another one while we hold exclusive
 			 * lock.
 			 */
-			if (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin))
+			if (!TransactionIdIsValid(limitXmin) ||
+				(TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
 			{
 				VirtualTransactionId vxid;
 
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 38fb912d5dc6ba8baeb05064d7b6a2e12e3bb5de..4d3cecb455b5e32f5b658cd5817e5a5af8e61ac0 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.16 2010/04/06 10:50:57 sriggs Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.17 2010/04/21 19:08:14 sriggs Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -246,6 +246,24 @@ ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid, RelFileNode
 {
 	VirtualTransactionId *backends;
 
+	/*
+	 * If we get passed InvalidTransactionId then we are a little surprised,
+	 * but it is theoretically possible, so spit out a LOG message, but not
+	 * one that needs translating.
+	 *
+	 * We grab latestCompletedXid instead because this is the very latest
+	 * value it could ever be.
+	 */
+	if (!TransactionIdIsValid(latestRemovedXid))
+	{
+		elog(LOG, "Invalid latestRemovedXid reported, using latestCompletedXid instead");
+
+		LWLockAcquire(ProcArrayLock, LW_SHARED);
+		latestRemovedXid = ShmemVariableCache->latestCompletedXid;
+		LWLockRelease(ProcArrayLock);
+	}
+	Assert(TransactionIdIsValid(latestRemovedXid));
+
 	backends = GetConflictingVirtualXIDs(latestRemovedXid,
 										 node.dbNode);