Folks,
The nice people at VMware, where I work, have come up with a small
patch to allow PITR to create a new timeline. This is useful in cases
where you're using filesystem snapshots of $PGDATA which may be old.
PFA a patch implementing and documenting same :)
Cheers,
David.
--
David Fetter <[email protected]> http://fetter.org/
Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter
Skype: davidfetter XMPP: [email protected]
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics
Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
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
</listitem>
</varlistentry>
+ <varlistentry id="create-new-timeline" xreflabel="create_new_timeline">
+ <term><varname>create_new_timeline</varname>
(<type>boolean</type>)</term>
+ <indexterm>
+ <primary><varname>create_new_timeline</varname> recovery
parameter</primary>
+ </indexterm>
+ <listitem>
+ <para>
+ If set, create a new timeline unconditionally. This parameter is
+ used in archive recovery scenarios where filesystem snapshots
+ are used.
+ </para>
+ <para>
+ 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.
+ </para>
+ <para>
+ 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.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="archive-cleanup-command"
xreflabel="archive_cleanup_command">
<term><varname>archive_cleanup_command</varname>
(<type>string</type>)</term>
<indexterm>
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;
}
/*
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers