1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-12 10:04:14 +02:00

Add standby restore type.

This restore type automatically adds standby_mode=on to recovery.conf.

This could be accomplished previously by setting --recovery-option=standby_mode=on but PostgreSQL 12 requires standby mode to be enabled by a special file named standby.signal.

The new restore type allows us to maintain a common interface between PostgreSQL versions.
This commit is contained in:
David Steele 2019-09-26 17:39:45 -04:00
parent 8979336819
commit c41fb575fb
14 changed files with 84 additions and 28 deletions

View File

@ -438,6 +438,8 @@ use constant CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediat
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_IMMEDIATE);
use constant CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default';
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_DEFAULT);
use constant CFGOPTVAL_RESTORE_TYPE_STANDBY => 'standby';
push @EXPORT, qw(CFGOPTVAL_RESTORE_TYPE_STANDBY);
# Restore target action
#-----------------------------------------------------------------------------------------------------------------------------------
@ -949,6 +951,7 @@ my %hConfigDefine =
[
&CFGOPTVAL_RESTORE_TYPE_DEFAULT,
&CFGOPTVAL_RESTORE_TYPE_NAME,
&CFGOPTVAL_RESTORE_TYPE_STANDBY,
&CFGOPTVAL_RESTORE_TYPE_TIME,
&CFGOPTVAL_RESTORE_TYPE_XID,
],
@ -1003,6 +1006,7 @@ my %hConfigDefine =
&CFGOPTVAL_RESTORE_TYPE_NONE,
&CFGOPTVAL_RESTORE_TYPE_IMMEDIATE,
&CFGOPTVAL_RESTORE_TYPE_DEFAULT,
&CFGOPTVAL_RESTORE_TYPE_STANDBY,
]
}
}
@ -2389,6 +2393,7 @@ my %hConfigDefine =
&CFGOPTVAL_RESTORE_TYPE_IMMEDIATE,
&CFGOPTVAL_RESTORE_TYPE_NAME,
&CFGOPTVAL_RESTORE_TYPE_TIME,
&CFGOPTVAL_RESTORE_TYPE_STANDBY,
&CFGOPTVAL_RESTORE_TYPE_XID,
],
},

View File

@ -1055,6 +1055,7 @@
<li><id>xid</id> - recover to the transaction id specified in <br-option>--target</br-option>.</li>
<li><id>time</id> - recover to the time specified in <br-option>--target</br-option>.</li>
<li><id>preserve</id> - preserve the existing <file>recovery.conf</file> file.</li>
<li><id>standby</id> - add <setting>standby_mode=on</setting> to <file>recovery.conf</file> file so cluster will start in standby mode.</li>
<li><id>none</id> - no <file>recovery.conf</file> file is written so <postgres/> will attempt to achieve consistency using WAL segments present in <path>pg_xlog</path>/<path>pg_wal</path>. Provide the required WAL segments or use the <setting>archive-copy</setting> setting to include them with the backup.</li>
</ul></text>
<example>xid</example>

View File

@ -14,6 +14,12 @@
<release-list>
<release date="XXXX-XX-XX" version="2.18dev" title="UNDER DEVELOPMENT">
<release-core-list>
<release-feature-list>
<release-item>
<p>Add <id>standby</id> restore type which automatically adds <pg-option>standby_mode</pg-option> to <file>recovery.conf</file>.</p>
</release-item>
</release-feature-list>
<release-improvement-list>
<release-item>
<release-item-contributor-list>

View File

@ -2611,7 +2611,7 @@
<p>A hot standby performs replication using the WAL archive and allows read-only queries.</p>
<p><backrest/> configuration is very similar to <host>{[host-pg1]}</host> except that the <pg-option>standby_mode</pg-option> setting will be enabled to keep the cluster in recovery mode when the end of the WAL stream has been reached.</p>
<p><backrest/> configuration is very similar to <host>{[host-pg1]}</host> except that the <id>standby</id> recovery type will be used to keep the cluster in recovery mode when the end of the WAL stream has been reached.</p>
<backrest-config host="{[host-pg2]}" file="{[backrest-config-demo]}">
<title>Configure <backrest/> on the standby</title>
@ -2620,8 +2620,6 @@
<backrest-config-option section="global" key="repo1-host">{[host-repo1]}</backrest-config-option>
<backrest-config-option section="demo" key="recovery-option">standby_mode=on</backrest-config-option>
<backrest-config-option section="global" key="log-level-file">detail</backrest-config-option>
<backrest-config-option section="global" key="log-level-stderr">off</backrest-config-option>
@ -2656,11 +2654,11 @@
<title>Restore the {[postgres-cluster-demo]} standby cluster</title>
<execute user="postgres" if="{[os-type-is-debian]}">
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta restore</exe-cmd>
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta --type=standby restore</exe-cmd>
</execute>
<execute user="postgres" if="{[os-type-is-centos]}">
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} restore</exe-cmd>
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} --type=standby restore</exe-cmd>
</execute>
<execute user="postgres" output="y" filter="n">
@ -2668,8 +2666,6 @@
</execute>
</execute-list>
<admonition type="note">The <pg-setting>standby_mode</pg-setting> setting has been written into the <file>recovery.conf</file> file. Configuring recovery settings in <backrest/> means that the <file>recovery.conf</file> file does not need to be stored elsewhere since it will be properly recreated with each restore. The <br-setting>--type=preserve</br-setting> option can be used with the <cmd>restore</cmd> to leave the existing <file>recovery.conf</file> file in place if that behavior is preferred.</admonition>
<p>The <pg-setting>hot_standby</pg-setting> setting must be enabled before starting <postgres/> to allow read-only connections on <host>{[host-pg2]}</host>. Otherwise, connection attempts will be refused. The rest of the configuration is in case the standby is promoted to a primary.</p>
<postgres-config host="{[host-pg2]}" file="{[postgres-config-demo]}">
@ -2851,7 +2847,7 @@
</execute>
<execute user="postgres">
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta restore</exe-cmd>
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta --type=standby restore</exe-cmd>
</execute>
<execute user="postgres" output="y" filter="n">
@ -2859,6 +2855,8 @@
</execute>
</execute-list>
<admonition type="note">The <pg-setting>primary_conninfo</pg-setting> setting has been written into the <file>recovery.conf</file> file. Configuring recovery settings in <backrest/> means that the <file>recovery.conf</file> file does not need to be stored elsewhere since it will be properly recreated with each restore. The <br-setting>{[dash]}-type=preserve</br-setting> option can be used with the <cmd>restore</cmd> to leave the existing <file>recovery.conf</file> file in place if that behavior is preferred.</admonition>
<p if="{[os-type-is-centos]}">By default {[user-guide-os]} stores the <file>postgresql.conf</file> file in the <postgres/> data directory. That means the change made to <file>postgresql.conf</file> was overwritten by the last restore and the <pg-option>hot_standby</pg-option> setting must be enabled again. Other solutions to this problem are to store the <file>postgresql.conf</file> file elsewhere or to enable the <pg-option>hot_standby</pg-option> setting on the <host>{[host-pg1]}</host> host where it will be ignored.</p>
<postgres-config host="{[host-pg2]}" if="{[os-type-is-centos]}" file="{[postgres-config-demo]}">
@ -3321,11 +3319,11 @@
<title>Restore the {[postgres-cluster-demo]} standby cluster</title>
<execute user="postgres" if="{[os-type-is-debian]}">
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta restore</exe-cmd>
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-delta --type=standby restore</exe-cmd>
</execute>
<execute user="postgres" if="{[os-type-is-centos]}">
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} restore</exe-cmd>
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} --type=standby restore</exe-cmd>
</execute>
</execute-list>

View File

@ -53,6 +53,7 @@ sub libcAutoConstant
CFGOPTVAL_RESTORE_TYPE_NONE => 'none',
CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate',
CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default',
CFGOPTVAL_RESTORE_TYPE_STANDBY => 'standby',
CFGDEF_TYPE_BOOLEAN => 0,
CFGDEF_TYPE_FLOAT => 1,
@ -114,6 +115,7 @@ sub libcAutoExportTag
'CFGOPTVAL_RESTORE_TYPE_NONE',
'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE',
'CFGOPTVAL_RESTORE_TYPE_DEFAULT',
'CFGOPTVAL_RESTORE_TYPE_STANDBY',
'CFGCMD_ARCHIVE_GET',
'CFGCMD_ARCHIVE_GET_ASYNC',
'CFGCMD_ARCHIVE_PUSH',

View File

@ -40,6 +40,7 @@ Recovery constants
#define RECOVERY_TARGET_INCLUSIVE "recovery_target_inclusive"
#define RECOVERY_TARGET_TIMELINE "recovery_target_timeline"
#define PAUSE_AT_RECOVERY_TARGET "pause_at_recovery_target"
#define STANDBY_MODE "standby_mode"
#define RECOVERY_TYPE_DEFAULT "default"
STRING_STATIC(RECOVERY_TYPE_DEFAULT_STR, RECOVERY_TYPE_DEFAULT);
@ -49,6 +50,8 @@ Recovery constants
STRING_STATIC(RECOVERY_TYPE_NONE_STR, RECOVERY_TYPE_NONE);
#define RECOVERY_TYPE_PRESERVE "preserve"
STRING_STATIC(RECOVERY_TYPE_PRESERVE_STR, RECOVERY_TYPE_PRESERVE);
#define RECOVERY_TYPE_STANDBY "standby"
STRING_STATIC(RECOVERY_TYPE_STANDBY_STR, RECOVERY_TYPE_STANDBY);
/***********************************************************************************************************************************
Validate restore path
@ -1179,6 +1182,12 @@ restoreRecoveryConf(unsigned int pgVersion)
{
strCat(result, RECOVERY_TARGET " = '" RECOVERY_TYPE_IMMEDIATE "'\n");
}
// Else recovery type is standby
else if (strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_STANDBY_STR))
{
// Write standby_mode
strCatFmt(result, STANDBY_MODE " = 'on'\n");
}
// Else recovery type is not default so write target options
else if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_DEFAULT_STR))
{

View File

@ -2645,6 +2645,7 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
"immediate",
"name",
"time",
"standby",
"xid"
)
)
@ -4610,6 +4611,7 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
cfgDefOptType,
"default",
"name",
"standby",
"time",
"xid"
)
@ -4788,7 +4790,8 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
"preserve",
"none",
"immediate",
"default"
"default",
"standby"
)
CFGDEFDATA_OPTION_OPTIONAL_DEFAULT("default")
@ -4805,6 +4808,7 @@ static ConfigDefineOptionData configDefineOptionData[] = CFGDEFDATA_OPTION_LIST
"* xid - recover to the transaction id specified in --target.\n"
"* time - recover to the time specified in --target.\n"
"* preserve - preserve the existing recovery.conf file.\n"
"* standby - add standby_mode=on to recovery.conf file so cluster will start in standby mode.\n"
"* none - no recovery.conf file is written so PostgreSQL will attempt to achieve consistency using WAL "
"segments present in pg_xlog/pg_wal. Provide the required WAL segments or use the archive-copy setting to "
"include them with the backup."

View File

@ -7861,6 +7861,7 @@ static const EmbeddedModule embeddedModule[] =
"CFGOPTVAL_RESTORE_TYPE_NONE => 'none',\n"
"CFGOPTVAL_RESTORE_TYPE_IMMEDIATE => 'immediate',\n"
"CFGOPTVAL_RESTORE_TYPE_DEFAULT => 'default',\n"
"CFGOPTVAL_RESTORE_TYPE_STANDBY => 'standby',\n"
"\n"
"CFGDEF_TYPE_BOOLEAN => 0,\n"
"CFGDEF_TYPE_FLOAT => 1,\n"
@ -7921,6 +7922,7 @@ static const EmbeddedModule embeddedModule[] =
"'CFGOPTVAL_RESTORE_TYPE_NONE',\n"
"'CFGOPTVAL_RESTORE_TYPE_IMMEDIATE',\n"
"'CFGOPTVAL_RESTORE_TYPE_DEFAULT',\n"
"'CFGOPTVAL_RESTORE_TYPE_STANDBY',\n"
"'CFGCMD_ARCHIVE_GET',\n"
"'CFGCMD_ARCHIVE_GET_ASYNC',\n"
"'CFGCMD_ARCHIVE_PUSH',\n"

View File

@ -227,14 +227,14 @@ restore delta, force, type 'name', target 'backrest' (db-master host)
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_name = 'backrest'
restore delta, backup '[BACKUP-INCR-1]', type 'default', timeline '4' (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --set=[BACKUP-INCR-1] --target-timeline="4" --link-all --stanza=db restore
restore delta, backup '[BACKUP-INCR-1]', type 'standby', timeline '4' (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --delta --set=[BACKUP-INCR-1] --type=standby --target-timeline="4" --link-all --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
standby_mode = 'on'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
recovery_target_timeline = '4'
incr backup - fail on --no-online (db-master host)
@ -251,7 +251,6 @@ incr backup - succeed on --no-online with --force (db-master host)
pg1-path=[TEST_PATH]/db-master/db/base
pg1-port=6543
pg1-socket-path=[TEST_PATH]/db-master/db
recovery-option=standby-mode=on
[global]
archive-async=y

View File

@ -70,15 +70,15 @@ repo1-host-config=[TEST_PATH]/db-master/pgbackrest.conf
repo1-host-user=[USER-1]
spool-path=[TEST_PATH]/db-standby/spool
restore, type 'default', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option=standby_mode=on --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
restore, type 'standby', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --type=standby --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
primary_conninfo = 'host=db-master port=6543 user=replicator'
standby_mode = 'on'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
full backup - backup from standby, failure to access at least one standby (db-master host)
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --pg8-host=bogus --backup-standby --type=full --stanza=db backup

View File

@ -72,15 +72,15 @@ spool-path=[TEST_PATH]/db-standby/spool
archive-copy=y
start-fast=y
restore, type 'default', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option=standby_mode=on --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
restore, type 'standby', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --type=standby --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
primary_conninfo = 'host=db-master port=6543 user=replicator'
standby_mode = 'on'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
full backup - backup from standby, failure to reach master (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --pg8-host=bogus --backup-standby --type=full --stanza=db backup

View File

@ -101,15 +101,15 @@ repo1-path=[TEST_PATH]/backup/repo
archive-copy=y
start-fast=y
restore, type 'default', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option=standby_mode=on --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
restore, type 'standby', remap - restore backup on replica (db-standby host)
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --recovery-option="primary_conninfo=host=db-master port=6543 user=replicator" --type=standby --link-map="pg_xlog=[TEST_PATH]/db-standby/db/pg_xlog" --link-all --stanza=db restore
------------------------------------------------------------------------------------------------------------------------------------
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
primary_conninfo = 'host=db-master port=6543 user=replicator'
standby_mode = 'on'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
full backup - backup from standby, failure to access at least one standby (backup host)
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --pg8-host=bogus --backup-standby --type=full --stanza=db backup

View File

@ -439,9 +439,9 @@ sub run
$oHostDbStandby->restore(
'restore backup on replica', cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
{rhRemapHash => \%oRemapHash,
{rhRemapHash => \%oRemapHash, strType => CFGOPTVAL_RESTORE_TYPE_STANDBY,
strOptionalParam =>
' --recovery-option=standby_mode=on --recovery-option="primary_conninfo=host=' . HOST_DB_MASTER .
' --recovery-option="primary_conninfo=host=' . HOST_DB_MASTER .
' port=' . $oHostDbMaster->pgPort() . ' user=replicator"'});
$oHostDbStandby->clusterStart({bHotStandby => true});
@ -960,8 +960,10 @@ sub run
$oHostDbMaster->restore(
undef, $strIncrBackup,
{bDelta => true, strType => CFGOPTVAL_RESTORE_TYPE_DEFAULT, strTargetTimeline => 4,
rhRecoveryHash => $oHostDbMaster->pgVersion() >= PG_VERSION_90 ? {'standby-mode' => 'on'} : undef});
{bDelta => true,
strType => $oHostDbMaster->pgVersion() >= PG_VERSION_90 ?
CFGOPTVAL_RESTORE_TYPE_STANDBY : CFGOPTVAL_RESTORE_TYPE_DEFAULT,
strTargetTimeline => 4});
$oHostDbMaster->clusterStart({bHotStandby => true});
$oHostDbMaster->sqlSelectOneTest('select message from test', $strTimelineMessage, {iTimeout => 120});

View File

@ -1323,6 +1323,34 @@ testRun(void)
TEST_ERROR(
restoreRecoveryConf(PG_VERSION_90), OptionInvalidError,
"target-action option is only available in PostgreSQL >= 9.1");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("recovery type = standby");
argList = strLstDup(argBaseList);
strLstAddZ(argList, "--type=standby");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
"restore_command = 'my_restore_command'\n"
"standby_mode = 'on'\n",
"check recovery options");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("recovery type = standby with timeline");
argList = strLstDup(argBaseList);
strLstAddZ(argList, "--type=standby");
strLstAddZ(argList, "--target-timeline=current");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
"restore_command = 'my_restore_command'\n"
"standby_mode = 'on'\n"
"recovery_target_timeline = 'current'\n",
"check recovery options");
}
// *****************************************************************************************************************************