diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml
index de60905..0df3977 100644
--- a/doc/src/sgml/recovery-config.sgml
+++ b/doc/src/sgml/recovery-config.sgml
@@ -73,6 +73,32 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
+
+ create_new_timeline (boolean)
+
+ create_new_timeline recovery parameter
+
+
+
+ If set, create a new timeline unconditionally. This parameter is
+ used in archive recovery scenarios where filesystem snapshots
+ are used.
+
+
+ If set to true, this overrides any recover_target that is
+ specified in the recovery.conf file. Instead, it will perform
+ a crash recovery, then switch to a new timeline.
+
+
+ When using create_new_timeline, the restore_command should be
+ the same as for a regular point-in-time recovery. In this
+ case it only gets used to retrieve the timeline history files
+ from the archive disk, so that postgres can correctly choose a
+ new timeline.
+
+
+
+
archive_cleanup_command (string)
diff --git a/src/backend/access/transam/recovery.conf.sample b/src/backend/access/transam/recovery.conf.sample
index 229c749..e962938 100644
--- a/src/backend/access/transam/recovery.conf.sample
+++ b/src/backend/access/transam/recovery.conf.sample
@@ -44,6 +44,14 @@
#restore_command = '' # e.g. 'cp /mnt/server/archivedir/%f %p'
#
#
+# create_new_timeline
+#
+# specifies whether we are starting a new timeline for recovery. This
+# is useful in scenarios using filesystem snapshots.
+#
+#create_new_timeline = false
+#
+#
# archive_cleanup_command
#
# specifies an optional shell command to execute at every restartpoint.
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 5c3ca47..ee43f44 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -201,6 +201,9 @@ static bool StandbyMode = false;
static char *PrimaryConnInfo = NULL;
static char *TriggerFile = NULL;
+/* option, possibly overridden by recovery.conf, for creating a new timeline for crash recovery */
+static bool createNewTimeLine = false;
+
/* if recoveryStopsHere returns true, it saves actual stop xid/time/name here */
static TransactionId recoveryStopXid;
static TimestampTz recoveryStopTime;
@@ -5385,6 +5388,15 @@ readRecoveryCommandFile(void)
(errmsg("trigger_file = '%s'",
TriggerFile)));
}
+ else if (strcmp(item->name, "create_new_timeline") == 0)
+ {
+ if (!parse_bool(item->value, &createNewTimeLine))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("parameter \"%s\" requires a Boolean value", item->name)));
+ ereport(DEBUG2,
+ (errmsg("create_new_timeline = '%s'", item->value)));
+ }
else
ereport(FATAL,
(errmsg("unrecognized recovery parameter \"%s\"",
@@ -5410,8 +5422,14 @@ readRecoveryCommandFile(void)
RECOVERY_COMMAND_FILE)));
}
- /* Enable fetching from archive recovery area */
- InArchiveRecovery = true;
+ /*
+ * Check whether we're creating a new timeline.
+ */
+ if (createNewTimeLine)
+ InRecovery = true;
+ else
+ /* Enable fetching from archive recovery area */
+ InArchiveRecovery = true;
/*
* If user specified recovery_target_timeline, validate it or compute the
@@ -5524,8 +5542,15 @@ exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg)
{
XLogFileCopy(endLogId, endLogSeg,
endTLI, endLogId, endLogSeg);
-
- if (XLogArchivingActive())
+ /*
+ * The PITR script should have set the '.done' flag for
+ * this file, so we don't want to archive it again, as the
+ * archive version is newer.
+ *
+ * If the '.done' flag was not set, the archiver will
+ * eventually handle it.
+ */
+ if (XLogArchivingActive() && !createNewTimeLine)
{
XLogFileName(xlogpath, endTLI, endLogId, endLogSeg);
XLogArchiveNotify(xlogpath);
@@ -6676,6 +6701,13 @@ StartupXLOG(void)
ereport(FATAL,
(errmsg("WAL ends before consistent recovery point")));
}
+
+ /*
+ * Check whether we're creating a new timeline, and if we are,
+ * put us into archive recovery mode.
+ */
+ if (createNewTimeLine)
+ InArchiveRecovery = true;
}
/*