*/
 static int LocalXLogInsertAllowed = -1;
 
-/* Are we recovering using offline XLOG archives? */
+/*
+ * When ArchiveRecoveryRequested is set, archive recovery was requested,
+ * ie. recovery.conf file was present. When InArchiveRecovery is set, we are
+ * currently recovering using offline XLOG archives. These variables are only
+ * valid in the startup process.
+ *
+ * When ArchiveRecoveryRequested is true, but InArchiveRecovery is false, we're
+ * currently performing crash recovery using only XLOG files in pg_xlog, but
+ * will switch to using offline XLOG archives as soon as we reach the end of
+ * WAL in pg_xlog.
+*/
+static bool ArchiveRecoveryRequested = false;
 static bool InArchiveRecovery = false;
 
 /* Was the last xlog file restored from archive, or local? */
 static char *recoveryTargetName;
 
 /* options taken from recovery.conf for XLOG streaming */
-static bool StandbyMode = false;
+static bool StandbyModeRequested = false;
 static char *PrimaryConnInfo = NULL;
 static char *TriggerFile = NULL;
 
+/* are we currently in standby mode? */
+bool StandbyMode = false;
+
 /* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
 static TransactionId recoveryStopXid;
 static TimestampTz recoveryStopTime;
        readFile = -1;
    }
 
+   /*
+    * If archive recovery was requested, but we were still doing crash
+    * recovery, switch to archive recovery and retry using the offline
+    * archive. We have now replayed all the valid WAL in pg_xlog, so
+    * we are presumably now consistent.
+    *
+    * We require that there's at least some valid WAL present in
+    * pg_xlog, however (!fetch_ckpt). We could recover using the WAL
+    * from the archive, even if pg_xlog is completely empty, but we'd
+    * have no idea how far we'd have to replay to reach consistency.
+    * So err on the safe side and give up.
+    */
+   if (!InArchiveRecovery && ArchiveRecoveryRequested && !fetching_ckpt)
+   {
+       ereport(DEBUG1,
+               (errmsg_internal("reached end of WAL in pg_xlog, entering archive recovery")));
+       InArchiveRecovery = true;
+       if (StandbyModeRequested)
+           StandbyMode = true;
+
+       /* initialize minRecoveryPoint to this record */
+       LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
+       ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
+       if (XLByteLT(ControlFile->minRecoveryPoint, EndRecPtr))
+           ControlFile->minRecoveryPoint = EndRecPtr;
+
+       /* update local copy */
+       minRecoveryPoint = ControlFile->minRecoveryPoint;
+
+       UpdateControlFile();
+       LWLockRelease(ControlFileLock);
+
+       CheckRecoveryConsistency();
+
+       goto retry;
+   }
+
    /* In standby-mode, keep trying */
    if (StandbyMode)
        goto retry;
        }
        else if (strcmp(item->name, "standby_mode") == 0)
        {
-           if (!parse_bool(item->value, &StandbyMode))
+           if (!parse_bool(item->value, &StandbyModeRequested))
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                         errmsg("parameter \"%s\" requires a Boolean value",
    /*
     * Check for compulsory parameters
     */
-   if (StandbyMode)
+   if (StandbyModeRequested)
    {
        if (PrimaryConnInfo == NULL && recoveryRestoreCommand == NULL)
            ereport(WARNING,
    }
 
    /* Enable fetching from archive recovery area */
-   InArchiveRecovery = true;
+   ArchiveRecoveryRequested = true;
 
    /*
     * If user specified recovery_target_timeline, validate it or compute the
     */
    if (rtliGiven)
    {
+       /*
+        * Temporarily set InArchiveRecovery, so that existsTimeLineHistory
+        * or findNewestTimeLine below will check the archive.
+        */
+       InArchiveRecovery = true;
        if (rtli)
        {
            /* Timeline 1 does not have a history file, all else should */
            recoveryTargetTLI = findNewestTimeLine(recoveryTargetTLI);
            recoveryTargetIsLatest = true;
        }
+       InArchiveRecovery = false;
    }
 
    FreeConfigVariables(head);
            archiveCleanupCommand ? archiveCleanupCommand : "",
            sizeof(XLogCtl->archiveCleanupCommand));
 
-   if (InArchiveRecovery)
+   if (ArchiveRecoveryRequested)
    {
-       if (StandbyMode)
+       if (StandbyModeRequested)
            ereport(LOG,
                    (errmsg("entering standby mode")));
        else if (recoveryTarget == RECOVERY_TARGET_XID)
     * Take ownership of the wakeup latch if we're going to sleep during
     * recovery.
     */
-   if (StandbyMode)
+   if (StandbyModeRequested)
        OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
    if (read_backup_label(&checkPointLoc, &backupEndRequired,
                          &backupFromStandby))
    {
+       /*
+        * Archive recovery was requested, and thanks to the backup label file,
+        * we know how far we need to replay to reach consistency. Enter
+        * archive recovery directly.
+        */
+       InArchiveRecovery = true;
+       if (StandbyModeRequested)
+           StandbyMode = true;
+
        /*
         * When a backup_label file is present, we want to roll forward from
         * the checkpoint it identifies, rather than using pg_control.
    }
    else
    {
+       /*
+        * It's possible that archive recovery was requested, but we don't
+        * know how far we need to replay the WAL before we reach consistency.
+        * This can happen for example if a base backup is taken from a running
+        * server using an atomic filesystem snapshot, without calling
+        * pg_start/stop_backup. Or if you just kill a running master server
+        * and put it into archive recovery by creating a recovery.conf file.
+        *
+        * Our strategy in that case is to perform crash recovery first,
+        * replaying all the WAL present in pg_xlog, and only enter archive
+        * recovery after that.
+        *
+        * But usually we already know how far we need to replay the WAL (up to
+        * minRecoveryPoint, up to backupEndPoint, or until we see an
+        * end-of-backup record), and we can enter archive recovery directly.
+        */
+       if (ArchiveRecoveryRequested &&
+           (!XLByteEQ(ControlFile->minRecoveryPoint, InvalidXLogRecPtr) ||
+            ControlFile->backupEndRequired ||
+            !XLByteEQ(ControlFile->backupEndPoint, InvalidXLogRecPtr) ||
+            ControlFile->state == DB_SHUTDOWNED))
+       {
+           InArchiveRecovery = true;
+           if (StandbyModeRequested)
+               StandbyMode = true;
+       }
+
        /*
         * Get the last valid checkpoint record.  If the latest one according
         * to pg_control is broken, try the next-to-last one.
    }
    else if (ControlFile->state != DB_SHUTDOWNED)
        InRecovery = true;
-   else if (InArchiveRecovery)
+   else if (ArchiveRecoveryRequested)
    {
        /* force recovery due to presence of recovery.conf */
        InRecovery = true;
        ControlFile->prevCheckPoint = ControlFile->checkPoint;
        ControlFile->checkPoint = checkPointLoc;
        ControlFile->checkPointCopy = checkPoint;
-       if (InArchiveRecovery)
-       {
-           /* initialize minRecoveryPoint if not set yet */
-           if (XLByteLT(ControlFile->minRecoveryPoint, checkPoint.redo))
-               ControlFile->minRecoveryPoint = checkPoint.redo;
-       }
 
        /*
         * Set backupStartPoint if we're starting recovery from a base backup.
         * control file and we've established a recovery snapshot from a
         * running-xacts WAL record.
         */
-       if (InArchiveRecovery && EnableHotStandby)
+       if (ArchiveRecoveryRequested && EnableHotStandby)
        {
            TransactionId *xids;
            int         nxids;
         * process in addition to postmaster!  Also, fsync requests are
         * subsequently to be handled by the checkpointer, not locally.
         */
-       if (InArchiveRecovery && IsUnderPostmaster)
+       if (ArchiveRecoveryRequested && IsUnderPostmaster)
        {
            PublishStartupProcessInformation();
            SetForwardFsyncRequests();
     * We don't need the latch anymore. It's not strictly necessary to disown
     * it, but let's do it for the sake of tidiness.
     */
-   if (StandbyMode)
+   if (StandbyModeRequested)
        DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
    /*
         * crashes while an online backup is in progress. We must not treat
         * that as an error, or the database will refuse to start up.
         */
-       if (InArchiveRecovery || ControlFile->backupEndRequired)
+       if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
        {
            if (ControlFile->backupEndRequired)
                ereport(FATAL,
     *
     * In a normal crash recovery, we can just extend the timeline we were in.
     */
-   if (InArchiveRecovery)
+   if (ArchiveRecoveryRequested)
    {
+       Assert(InArchiveRecovery);
+
        ThisTimeLineID = findNewestTimeLine(recoveryTargetTLI) + 1;
        ereport(LOG,
                (errmsg("selected new timeline ID: %u", ThisTimeLineID)));
     * that we also have a copy of the last block of the old WAL in readBuf;
     * we will use that below.)
     */
-   if (InArchiveRecovery)
+   if (ArchiveRecoveryRequested)
        exitArchiveRecovery(curFileTLI, endLogId, endLogSeg);
 
    /*
         * record, the backup was canceled and the end-of-backup record will
         * never arrive.
         */
-       if (InArchiveRecovery &&
+       if (ArchiveRecoveryRequested &&
            !XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
            XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
            ereport(PANIC,
         * Request a restartpoint if we've replayed too much xlog since the
         * last one.
         */
-       if (StandbyMode && bgwriterLaunched)
+       if (StandbyModeRequested && bgwriterLaunched)
        {
            if (XLogCheckpointNeeded(readId, readSeg))
            {