* ProcArrayInitRecovery -- initialize recovery xid mgmt environment
  *
  * Remember up to where the startup process initialized the CLOG and subtrans
- * so we can ensure its initialized gaplessly up to the point where necessary
+ * so we can ensure it's initialized gaplessly up to the point where necessary
  * while in recovery.
  */
 void
    Assert(TransactionIdIsNormal(initializedUptoXID));
 
    /*
-    * we set latestObservedXid to the xid SUBTRANS has been initialized upto
-    * so we can extend it from that point onwards when we reach a consistent
-    * state in ProcArrayApplyRecoveryInfo().
+    * we set latestObservedXid to the xid SUBTRANS has been initialized upto,
+    * so we can extend it from that point onwards in
+    * RecordKnownAssignedTransactionIds, and when we get consistent in
+    * ProcArrayApplyRecoveryInfo().
     */
    latestObservedXid = initializedUptoXID;
    TransactionIdRetreat(latestObservedXid);
    pfree(xids);
 
    /*
-    * latestObservedXid is set to the the point where SUBTRANS was started up
-    * to, initialize subtrans from thereon, up to nextXid - 1.
+    * latestObservedXid is at least set to the the point where SUBTRANS was
+    * started up to (c.f. ProcArrayInitRecovery()) or to the biggest xid
+    * RecordKnownAssignedTransactionIds() was called for.  Initialize
+    * subtrans from thereon, up to nextXid - 1.
+    *
+    * We need to duplicate parts of RecordKnownAssignedTransactionId() here,
+    * because we've just added xids to the known assigned xids machinery that
+    * haven't gone through RecordKnownAssignedTransactionId().
     */
    Assert(TransactionIdIsNormal(latestObservedXid));
+   TransactionIdAdvance(latestObservedXid);
    while (TransactionIdPrecedes(latestObservedXid, running->nextXid))
    {
-       ExtendCLOG(latestObservedXid);
        ExtendSUBTRANS(latestObservedXid);
-
        TransactionIdAdvance(latestObservedXid);
    }
+   TransactionIdRetreat(latestObservedXid);  /* = running->nextXid - 1 */
 
    /* ----------
     * Now we've got the running xids we need to set the global values that
 
    Assert(standbyState >= STANDBY_INITIALIZED);
 
-   /* can't do anything useful unless we have more state setup */
-   if (standbyState == STANDBY_INITIALIZED)
-       return;
-
    max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
 
    /*
    for (i = 0; i < nsubxids; i++)
        SubTransSetParent(subxids[i], topxid, false);
 
+   /* KnownAssignedXids isn't maintained yet, so we're done for now */
+   if (standbyState == STANDBY_INITIALIZED)
+       return;
+
    /*
     * Uses same locking as transaction commit
     */
 {
    Assert(standbyState >= STANDBY_INITIALIZED);
    Assert(TransactionIdIsValid(xid));
+   Assert(TransactionIdIsValid(latestObservedXid));
 
    elog(trace_recovery(DEBUG4), "record known xact %u latestObservedXid %u",
         xid, latestObservedXid);
 
-   /*
-    * If the KnownAssignedXids machinery isn't up yet, do nothing.
-    */
-   if (standbyState <= STANDBY_INITIALIZED)
-       return;
-
-   Assert(TransactionIdIsValid(latestObservedXid));
-
    /*
     * When a newly observed xid arrives, it is frequently the case that it is
     * *not* the next xid in sequence. When this occurs, we must treat the
        TransactionId next_expected_xid;
 
        /*
-        * Extend clog and subtrans like we do in GetNewTransactionId() during
-        * normal operation using individual extend steps. Typical case
-        * requires almost no activity.
+        * Extend subtrans like we do in GetNewTransactionId() during normal
+        * operation using individual extend steps. Note that we do not need
+        * to extend clog since its extensions are WAL logged.
+        *
+        * This part has to be done regardless of standbyState since we
+        * immediately start assigning subtransactions to their toplevel
+        * transactions.
         */
        next_expected_xid = latestObservedXid;
-       TransactionIdAdvance(next_expected_xid);
-       while (TransactionIdPrecedesOrEquals(next_expected_xid, xid))
+       while (TransactionIdPrecedes(next_expected_xid, xid))
        {
-           ExtendCLOG(next_expected_xid);
+           TransactionIdAdvance(next_expected_xid);
            ExtendSUBTRANS(next_expected_xid);
+       }
+       Assert(next_expected_xid == xid);
 
-           TransactionIdAdvance(next_expected_xid);
+       /*
+        * If the KnownAssignedXids machinery isn't up yet, there's nothing
+        * more to do since we don't track assigned xids yet.
+        */
+       if (standbyState <= STANDBY_INITIALIZED)
+       {
+           latestObservedXid = xid;
+           return;
        }
 
        /*
-        * Add the new xids onto the KnownAssignedXids array.
+        * Add (latestObservedXid, xid] onto the KnownAssignedXids array.
         */
        next_expected_xid = latestObservedXid;
        TransactionIdAdvance(next_expected_xid);