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 <da...@fetter.org> http://fetter.org/ Phone: +1 415 235 3778 AIM: dfetter666 Yahoo!: dfetter Skype: davidfetter XMPP: david.fet...@gmail.com 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers