MemSet(&checkPoint, 0, sizeof(checkPoint));
    checkPoint.time = (pg_time_t) time(NULL);
 
+   /*
+    * For Hot Standby, derive the oldestActiveXid before we fix the redo pointer.
+    * This allows us to begin accumulating changes to assemble our starting
+    * snapshot of locks and transactions.
+    */
+   if (!shutdown && XLogStandbyInfoActive())
+       checkPoint.oldestActiveXid = GetOldestActiveTransactionId();
+   else
+       checkPoint.oldestActiveXid = InvalidTransactionId;
+
    /*
     * We must hold WALInsertLock while examining insert state to determine
     * the checkpoint REDO pointer.
     * Update checkPoint.nextXid since we have a later value
     */
    if (!shutdown && XLogStandbyInfoActive())
-       LogStandbySnapshot(&checkPoint.oldestActiveXid, &checkPoint.nextXid);
-   else
-       checkPoint.oldestActiveXid = InvalidTransactionId;
+       LogStandbySnapshot(&checkPoint.nextXid);
 
    START_CRIT_SECTION();
 
 
    return CurrentRunningXacts;
 }
 
+/*
+ * GetOldestActiveTransactionId()
+ *
+ * Similar to GetSnapshotData but returns just oldestActiveXid. We include
+ * all PGPROCs with an assigned TransactionId, even VACUUM processes.
+ * We look at all databases, though there is no need to include WALSender
+ * since this has no effect on hot standby conflicts.
+ *
+ * This is never executed during recovery so there is no need to look at
+ * KnownAssignedXids.
+ *
+ * We don't worry about updating other counters, we want to keep this as
+ * simple as possible and leave GetSnapshotData() as the primary code for
+ * that bookkeeping.
+ */
+TransactionId
+GetOldestActiveTransactionId(void)
+{
+   ProcArrayStruct *arrayP = procArray;
+   TransactionId oldestRunningXid;
+   int         index;
+
+   Assert(!RecoveryInProgress());
+
+   LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+   oldestRunningXid = ShmemVariableCache->nextXid;
+
+   /*
+    * Spin over procArray collecting all xids and subxids.
+    */
+   for (index = 0; index < arrayP->numProcs; index++)
+   {
+       volatile PGPROC *proc = arrayP->procs[index];
+       TransactionId xid;
+
+       /* Fetch xid just once - see GetNewTransactionId */
+       xid = proc->xid;
+
+       if (!TransactionIdIsNormal(xid))
+           continue;
+
+       if (TransactionIdPrecedes(xid, oldestRunningXid))
+           oldestRunningXid = xid;
+
+       /*
+        * Top-level XID of a transaction is always less than any of its
+        * subxids, so we don't need to check if any of the subxids are
+        * smaller than oldestRunningXid
+        */
+   }
+
+   LWLockRelease(ProcArrayLock);
+
+   return oldestRunningXid;
+}
+
 /*
  * GetTransactionsInCommit -- Get the XIDs of transactions that are committing
  *
 
  * making WAL entries.
  */
 void
-LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid)
+LogStandbySnapshot(TransactionId *nextXid)
 {
    RunningTransactions running;
    xl_standby_lock *locks;
    /* GetRunningTransactionData() acquired XidGenLock, we must release it */
    LWLockRelease(XidGenLock);
 
-   *oldestActiveXid = running->oldestRunningXid;
    *nextXid = running->nextXid;
 }
 
 
 extern bool TransactionIdIsInProgress(TransactionId xid);
 extern bool TransactionIdIsActive(TransactionId xid);
 extern TransactionId GetOldestXmin(bool allDbs, bool ignoreVacuum);
+extern TransactionId GetOldestActiveTransactionId(void);
 
 extern int GetTransactionsInCommit(TransactionId **xids_p);
 extern bool HaveTransactionsInCommit(TransactionId *xids, int nxids);
 
 extern void LogAccessExclusiveLock(Oid dbOid, Oid relOid);
 extern void LogAccessExclusiveLockPrepare(void);
 
-extern void LogStandbySnapshot(TransactionId *oldestActiveXid, TransactionId *nextXid);
+extern void LogStandbySnapshot(TransactionId *nextXid);
 
 #endif   /* STANDBY_H */