New recovery target recovery_target_lsn
Michael Paquier
This commit is contained in:
parent
0c40ab3a88
commit
35250b6ad7
@ -157,9 +157,10 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
|
|||||||
By default, recovery will recover to the end of the WAL log. The
|
By default, recovery will recover to the end of the WAL log. The
|
||||||
following parameters can be used to specify an earlier stopping point.
|
following parameters can be used to specify an earlier stopping point.
|
||||||
At most one of <varname>recovery_target</>,
|
At most one of <varname>recovery_target</>,
|
||||||
<varname>recovery_target_name</>, <varname>recovery_target_time</>, or
|
<varname>recovery_target_lsn</>, <varname>recovery_target_name</>,
|
||||||
<varname>recovery_target_xid</> can be used; if more than one of these
|
<varname>recovery_target_time</>, or <varname>recovery_target_xid</>
|
||||||
is specified in the configuration file, the last entry will be used.
|
can be used; if more than one of these is specified in the configuration
|
||||||
|
file, the last entry will be used.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<variablelist>
|
<variablelist>
|
||||||
@ -232,6 +233,23 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry id="recovery-target-lsn" xreflabel="recovery_target_lsn">
|
||||||
|
<term><varname>recovery_target_lsn</varname> (<type>pg_lsn</type>)
|
||||||
|
<indexterm>
|
||||||
|
<primary><varname>recovery_target_lsn</> recovery parameter</primary>
|
||||||
|
</indexterm>
|
||||||
|
</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
This parameter specifies the LSN of the transaction log location up
|
||||||
|
to which recovery will proceed. The precise stopping point is also
|
||||||
|
influenced by <xref linkend="recovery-target-inclusive">. This
|
||||||
|
parameter is parsed using the system data type
|
||||||
|
<link linkend="datatype-pg-lsn"><type>pg_lsn</></link>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
# must set a recovery target.
|
# must set a recovery target.
|
||||||
#
|
#
|
||||||
# You may set a recovery target either by transactionId, by name,
|
# You may set a recovery target either by transactionId, by name,
|
||||||
# or by timestamp. Recovery may either include or exclude the
|
# by timestamp or by WAL position (LSN). Recovery may either include or
|
||||||
# transaction(s) with the recovery target value (ie, stop either
|
# exclude the transaction(s) with the recovery target value (ie, stop either
|
||||||
# just after or just before the given target, respectively).
|
# just after or just before the given target, respectively).
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
@ -78,6 +78,8 @@
|
|||||||
#
|
#
|
||||||
#recovery_target_xid = ''
|
#recovery_target_xid = ''
|
||||||
#
|
#
|
||||||
|
#recovery_target_lsn = '' # e.g. '0/70006B8'
|
||||||
|
#
|
||||||
#recovery_target_inclusive = true
|
#recovery_target_inclusive = true
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/guc.h"
|
#include "utils/guc.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
#include "utils/pg_lsn.h"
|
||||||
#include "utils/ps_status.h"
|
#include "utils/ps_status.h"
|
||||||
#include "utils/relmapper.h"
|
#include "utils/relmapper.h"
|
||||||
#include "utils/snapmgr.h"
|
#include "utils/snapmgr.h"
|
||||||
@ -254,6 +255,7 @@ static RecoveryTargetAction recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE;
|
|||||||
static TransactionId recoveryTargetXid;
|
static TransactionId recoveryTargetXid;
|
||||||
static TimestampTz recoveryTargetTime;
|
static TimestampTz recoveryTargetTime;
|
||||||
static char *recoveryTargetName;
|
static char *recoveryTargetName;
|
||||||
|
static XLogRecPtr recoveryTargetLSN;
|
||||||
static int recovery_min_apply_delay = 0;
|
static int recovery_min_apply_delay = 0;
|
||||||
static TimestampTz recoveryDelayUntilTime;
|
static TimestampTz recoveryDelayUntilTime;
|
||||||
|
|
||||||
@ -275,6 +277,7 @@ static bool fast_promote = false;
|
|||||||
*/
|
*/
|
||||||
static TransactionId recoveryStopXid;
|
static TransactionId recoveryStopXid;
|
||||||
static TimestampTz recoveryStopTime;
|
static TimestampTz recoveryStopTime;
|
||||||
|
static XLogRecPtr recoveryStopLSN;
|
||||||
static char recoveryStopName[MAXFNAMELEN];
|
static char recoveryStopName[MAXFNAMELEN];
|
||||||
static bool recoveryStopAfter;
|
static bool recoveryStopAfter;
|
||||||
|
|
||||||
@ -5078,6 +5081,23 @@ readRecoveryCommandFile(void)
|
|||||||
(errmsg_internal("recovery_target_name = '%s'",
|
(errmsg_internal("recovery_target_name = '%s'",
|
||||||
recoveryTargetName)));
|
recoveryTargetName)));
|
||||||
}
|
}
|
||||||
|
else if (strcmp(item->name, "recovery_target_lsn") == 0)
|
||||||
|
{
|
||||||
|
recoveryTarget = RECOVERY_TARGET_LSN;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert the LSN string given by the user to XLogRecPtr form.
|
||||||
|
*/
|
||||||
|
recoveryTargetLSN =
|
||||||
|
DatumGetLSN(DirectFunctionCall3(pg_lsn_in,
|
||||||
|
CStringGetDatum(item->value),
|
||||||
|
ObjectIdGetDatum(InvalidOid),
|
||||||
|
Int32GetDatum(-1)));
|
||||||
|
ereport(DEBUG2,
|
||||||
|
(errmsg_internal("recovery_target_lsn = '%X/%X'",
|
||||||
|
(uint32) (recoveryTargetLSN >> 32),
|
||||||
|
(uint32) recoveryTargetLSN)));
|
||||||
|
}
|
||||||
else if (strcmp(item->name, "recovery_target") == 0)
|
else if (strcmp(item->name, "recovery_target") == 0)
|
||||||
{
|
{
|
||||||
if (strcmp(item->value, "immediate") == 0)
|
if (strcmp(item->value, "immediate") == 0)
|
||||||
@ -5400,11 +5420,29 @@ recoveryStopsBefore(XLogReaderState *record)
|
|||||||
|
|
||||||
recoveryStopAfter = false;
|
recoveryStopAfter = false;
|
||||||
recoveryStopXid = InvalidTransactionId;
|
recoveryStopXid = InvalidTransactionId;
|
||||||
|
recoveryStopLSN = InvalidXLogRecPtr;
|
||||||
recoveryStopTime = 0;
|
recoveryStopTime = 0;
|
||||||
recoveryStopName[0] = '\0';
|
recoveryStopName[0] = '\0';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if target LSN has been reached */
|
||||||
|
if (recoveryTarget == RECOVERY_TARGET_LSN &&
|
||||||
|
!recoveryTargetInclusive &&
|
||||||
|
record->ReadRecPtr >= recoveryTargetLSN)
|
||||||
|
{
|
||||||
|
recoveryStopAfter = false;
|
||||||
|
recoveryStopXid = InvalidTransactionId;
|
||||||
|
recoveryStopLSN = record->ReadRecPtr;
|
||||||
|
recoveryStopTime = 0;
|
||||||
|
recoveryStopName[0] = '\0';
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("recovery stopping before WAL position (LSN) \"%X/%X\"",
|
||||||
|
(uint32) (recoveryStopLSN >> 32),
|
||||||
|
(uint32) recoveryStopLSN)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Otherwise we only consider stopping before COMMIT or ABORT records. */
|
/* Otherwise we only consider stopping before COMMIT or ABORT records. */
|
||||||
if (XLogRecGetRmid(record) != RM_XACT_ID)
|
if (XLogRecGetRmid(record) != RM_XACT_ID)
|
||||||
return false;
|
return false;
|
||||||
@ -5479,6 +5517,7 @@ recoveryStopsBefore(XLogReaderState *record)
|
|||||||
recoveryStopAfter = false;
|
recoveryStopAfter = false;
|
||||||
recoveryStopXid = recordXid;
|
recoveryStopXid = recordXid;
|
||||||
recoveryStopTime = recordXtime;
|
recoveryStopTime = recordXtime;
|
||||||
|
recoveryStopLSN = InvalidXLogRecPtr;
|
||||||
recoveryStopName[0] = '\0';
|
recoveryStopName[0] = '\0';
|
||||||
|
|
||||||
if (isCommit)
|
if (isCommit)
|
||||||
@ -5532,6 +5571,7 @@ recoveryStopsAfter(XLogReaderState *record)
|
|||||||
{
|
{
|
||||||
recoveryStopAfter = true;
|
recoveryStopAfter = true;
|
||||||
recoveryStopXid = InvalidTransactionId;
|
recoveryStopXid = InvalidTransactionId;
|
||||||
|
recoveryStopLSN = InvalidXLogRecPtr;
|
||||||
(void) getRecordTimestamp(record, &recoveryStopTime);
|
(void) getRecordTimestamp(record, &recoveryStopTime);
|
||||||
strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
|
strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
|
||||||
|
|
||||||
@ -5543,6 +5583,23 @@ recoveryStopsAfter(XLogReaderState *record)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if the target LSN has been reached */
|
||||||
|
if (recoveryTarget == RECOVERY_TARGET_LSN &&
|
||||||
|
recoveryTargetInclusive &&
|
||||||
|
record->ReadRecPtr >= recoveryTargetLSN)
|
||||||
|
{
|
||||||
|
recoveryStopAfter = true;
|
||||||
|
recoveryStopXid = InvalidTransactionId;
|
||||||
|
recoveryStopLSN = record->ReadRecPtr;
|
||||||
|
recoveryStopTime = 0;
|
||||||
|
recoveryStopName[0] = '\0';
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("recovery stopping after WAL position (LSN) \"%X/%X\"",
|
||||||
|
(uint32) (recoveryStopLSN >> 32),
|
||||||
|
(uint32) recoveryStopLSN)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (rmid != RM_XACT_ID)
|
if (rmid != RM_XACT_ID)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -5598,6 +5655,7 @@ recoveryStopsAfter(XLogReaderState *record)
|
|||||||
recoveryStopAfter = true;
|
recoveryStopAfter = true;
|
||||||
recoveryStopXid = recordXid;
|
recoveryStopXid = recordXid;
|
||||||
recoveryStopTime = recordXtime;
|
recoveryStopTime = recordXtime;
|
||||||
|
recoveryStopLSN = InvalidXLogRecPtr;
|
||||||
recoveryStopName[0] = '\0';
|
recoveryStopName[0] = '\0';
|
||||||
|
|
||||||
if (xact_info == XLOG_XACT_COMMIT ||
|
if (xact_info == XLOG_XACT_COMMIT ||
|
||||||
@ -5629,6 +5687,7 @@ recoveryStopsAfter(XLogReaderState *record)
|
|||||||
recoveryStopAfter = true;
|
recoveryStopAfter = true;
|
||||||
recoveryStopXid = InvalidTransactionId;
|
recoveryStopXid = InvalidTransactionId;
|
||||||
recoveryStopTime = 0;
|
recoveryStopTime = 0;
|
||||||
|
recoveryStopLSN = InvalidXLogRecPtr;
|
||||||
recoveryStopName[0] = '\0';
|
recoveryStopName[0] = '\0';
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -6055,6 +6114,11 @@ StartupXLOG(void)
|
|||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("starting point-in-time recovery to \"%s\"",
|
(errmsg("starting point-in-time recovery to \"%s\"",
|
||||||
recoveryTargetName)));
|
recoveryTargetName)));
|
||||||
|
else if (recoveryTarget == RECOVERY_TARGET_LSN)
|
||||||
|
ereport(LOG,
|
||||||
|
(errmsg("starting point-in-time recovery to WAL position (LSN) \"%X/%X\"",
|
||||||
|
(uint32) (recoveryTargetLSN >> 32),
|
||||||
|
(uint32) recoveryTargetLSN)));
|
||||||
else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
|
else if (recoveryTarget == RECOVERY_TARGET_IMMEDIATE)
|
||||||
ereport(LOG,
|
ereport(LOG,
|
||||||
(errmsg("starting point-in-time recovery to earliest consistent point")));
|
(errmsg("starting point-in-time recovery to earliest consistent point")));
|
||||||
@ -7124,6 +7188,12 @@ StartupXLOG(void)
|
|||||||
"%s %s\n",
|
"%s %s\n",
|
||||||
recoveryStopAfter ? "after" : "before",
|
recoveryStopAfter ? "after" : "before",
|
||||||
timestamptz_to_str(recoveryStopTime));
|
timestamptz_to_str(recoveryStopTime));
|
||||||
|
else if (recoveryTarget == RECOVERY_TARGET_LSN)
|
||||||
|
snprintf(reason, sizeof(reason),
|
||||||
|
"%s LSN %X/%X\n",
|
||||||
|
recoveryStopAfter ? "after" : "before",
|
||||||
|
(uint32 ) (recoveryStopLSN >> 32),
|
||||||
|
(uint32) recoveryStopLSN);
|
||||||
else if (recoveryTarget == RECOVERY_TARGET_NAME)
|
else if (recoveryTarget == RECOVERY_TARGET_NAME)
|
||||||
snprintf(reason, sizeof(reason),
|
snprintf(reason, sizeof(reason),
|
||||||
"at restore point \"%s\"",
|
"at restore point \"%s\"",
|
||||||
|
@ -83,6 +83,7 @@ typedef enum
|
|||||||
RECOVERY_TARGET_XID,
|
RECOVERY_TARGET_XID,
|
||||||
RECOVERY_TARGET_TIME,
|
RECOVERY_TARGET_TIME,
|
||||||
RECOVERY_TARGET_NAME,
|
RECOVERY_TARGET_NAME,
|
||||||
|
RECOVERY_TARGET_LSN,
|
||||||
RECOVERY_TARGET_IMMEDIATE
|
RECOVERY_TARGET_IMMEDIATE
|
||||||
} RecoveryTargetType;
|
} RecoveryTargetType;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
use PostgresNode;
|
use PostgresNode;
|
||||||
use TestLib;
|
use TestLib;
|
||||||
use Test::More tests => 7;
|
use Test::More tests => 9;
|
||||||
|
|
||||||
# Create and test a standby from given backup, with a certain
|
# Create and test a standby from given backup, with a certain
|
||||||
# recovery target.
|
# recovery target.
|
||||||
@ -86,6 +86,16 @@ my $lsn4 =
|
|||||||
$node_master->safe_psql('postgres',
|
$node_master->safe_psql('postgres',
|
||||||
"SELECT pg_create_restore_point('$recovery_name');");
|
"SELECT pg_create_restore_point('$recovery_name');");
|
||||||
|
|
||||||
|
# And now for a recovery target LSN
|
||||||
|
$node_master->safe_psql('postgres',
|
||||||
|
"INSERT INTO tab_int VALUES (generate_series(4001,5000))");
|
||||||
|
my $recovery_lsn = $node_master->safe_psql('postgres', "SELECT pg_current_xlog_location()");
|
||||||
|
my $lsn5 =
|
||||||
|
$node_master->safe_psql('postgres', "SELECT pg_current_xlog_location();");
|
||||||
|
|
||||||
|
$node_master->safe_psql('postgres',
|
||||||
|
"INSERT INTO tab_int VALUES (generate_series(5001,6000))");
|
||||||
|
|
||||||
# Force archiving of WAL file
|
# Force archiving of WAL file
|
||||||
$node_master->safe_psql('postgres', "SELECT pg_switch_xlog()");
|
$node_master->safe_psql('postgres', "SELECT pg_switch_xlog()");
|
||||||
|
|
||||||
@ -102,6 +112,9 @@ test_recovery_standby('time', 'standby_3', $node_master, \@recovery_params,
|
|||||||
@recovery_params = ("recovery_target_name = '$recovery_name'");
|
@recovery_params = ("recovery_target_name = '$recovery_name'");
|
||||||
test_recovery_standby('name', 'standby_4', $node_master, \@recovery_params,
|
test_recovery_standby('name', 'standby_4', $node_master, \@recovery_params,
|
||||||
"4000", $lsn4);
|
"4000", $lsn4);
|
||||||
|
@recovery_params = ("recovery_target_lsn = '$recovery_lsn'");
|
||||||
|
test_recovery_standby('LSN', 'standby_5', $node_master, \@recovery_params,
|
||||||
|
"5000", $lsn5);
|
||||||
|
|
||||||
# Multiple targets
|
# Multiple targets
|
||||||
# Last entry has priority (note that an array respects the order of items
|
# Last entry has priority (note that an array respects the order of items
|
||||||
@ -111,16 +124,23 @@ test_recovery_standby('name', 'standby_4', $node_master, \@recovery_params,
|
|||||||
"recovery_target_xid = '$recovery_txid'",
|
"recovery_target_xid = '$recovery_txid'",
|
||||||
"recovery_target_time = '$recovery_time'");
|
"recovery_target_time = '$recovery_time'");
|
||||||
test_recovery_standby('name + XID + time',
|
test_recovery_standby('name + XID + time',
|
||||||
'standby_5', $node_master, \@recovery_params, "3000", $lsn3);
|
'standby_6', $node_master, \@recovery_params, "3000", $lsn3);
|
||||||
@recovery_params = (
|
@recovery_params = (
|
||||||
"recovery_target_time = '$recovery_time'",
|
"recovery_target_time = '$recovery_time'",
|
||||||
"recovery_target_name = '$recovery_name'",
|
"recovery_target_name = '$recovery_name'",
|
||||||
"recovery_target_xid = '$recovery_txid'");
|
"recovery_target_xid = '$recovery_txid'");
|
||||||
test_recovery_standby('time + name + XID',
|
test_recovery_standby('time + name + XID',
|
||||||
'standby_6', $node_master, \@recovery_params, "2000", $lsn2);
|
'standby_7', $node_master, \@recovery_params, "2000", $lsn2);
|
||||||
@recovery_params = (
|
@recovery_params = (
|
||||||
"recovery_target_xid = '$recovery_txid'",
|
"recovery_target_xid = '$recovery_txid'",
|
||||||
"recovery_target_time = '$recovery_time'",
|
"recovery_target_time = '$recovery_time'",
|
||||||
"recovery_target_name = '$recovery_name'");
|
"recovery_target_name = '$recovery_name'");
|
||||||
test_recovery_standby('XID + time + name',
|
test_recovery_standby('XID + time + name',
|
||||||
'standby_7', $node_master, \@recovery_params, "4000", $lsn4);
|
'standby_8', $node_master, \@recovery_params, "4000", $lsn4);
|
||||||
|
@recovery_params = (
|
||||||
|
"recovery_target_xid = '$recovery_txid'",
|
||||||
|
"recovery_target_time = '$recovery_time'",
|
||||||
|
"recovery_target_name = '$recovery_name'",
|
||||||
|
"recovery_target_lsn = '$recovery_lsn'",);
|
||||||
|
test_recovery_standby('XID + time + name + LSN',
|
||||||
|
'standby_9', $node_master, \@recovery_params, "5000", $lsn5);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user