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

PostgreSQL 12 support.

Recovery settings are now written into postgresql.auto.conf instead of recovery.conf.  Existing recovery_target* settings will be commented out to help avoid conflicts.

A comment is added before recovery settings to identify them as written by pgBackRest since it is unclear how, in general, old settings will be removed.

recovery.signal and standby.signal are automatically created based on the recovery settings.
This commit is contained in:
David Steele 2019-10-01 13:20:43 -04:00
parent 6be7e6fde5
commit 29e132f5e9
29 changed files with 869 additions and 55 deletions

View File

@ -15,6 +15,10 @@
<release date="XXXX-XX-XX" version="2.18dev" title="UNDER DEVELOPMENT">
<release-core-list>
<release-feature-list>
<release-item>
<p><postgres/> 12 support.</p>
</release-item>
<release-item>
<release-item-contributor-list>
<release-item-contributor id="cynthia.shang"/>

View File

@ -130,7 +130,8 @@
<variable key="postgres-log-pgstartup-demo" if="{[os-type-is-centos]}">/var/lib/pgsql/{[pg-version]}/pgstartup.log</variable>
<variable key="postgres-recovery-demo">{[pg-path]}/recovery.conf</variable>
<variable key="postgres-recovery-demo" if="{[pg-version]} &lt; 12">{[pg-path]}/recovery.conf</variable>
<variable key="postgres-recovery-demo" if="{[pg-version]} &gt;= 12">{[pg-path]}/postgresql.auto.conf</variable>
<!-- Select correct WAL switch function based on the version of PostgreSQL -->
<variable key="pg-switch-wal" if="{[pg-version]} &lt; 10">pg_switch_xlog</variable>
@ -273,7 +274,7 @@
# Install PostgreSQL
RUN RELEASE_CODENAME=`lsb_release -c | awk '{print $2}'` &amp;&amp; \
echo 'deb http://apt.postgresql.org/pub/repos/apt/ '${RELEASE_CODENAME?}'-pgdg main' | \
echo 'deb http://apt.postgresql.org/pub/repos/apt/ '${RELEASE_CODENAME?}'-pgdg main 12' | \
tee -a /etc/apt/sources.list.d/pgdg.list &amp;&amp; \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - &amp;&amp; \
apt-get update &amp;&amp; \

View File

@ -74,6 +74,10 @@ my $oPgControlVersionHash =
{
201809051 => PG_VERSION_11,
},
1201 =>
{
201909212 => PG_VERSION_12,
},
};
####################################################################################################################################

View File

@ -64,7 +64,7 @@ sub versionSupport
my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionSupport');
my @strySupportVersion = (PG_VERSION_83, PG_VERSION_84, PG_VERSION_90, PG_VERSION_91, PG_VERSION_92, PG_VERSION_93,
PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11);
PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11, PG_VERSION_12);
# Return from function and log return values if any
return logDebugReturn

View File

@ -220,8 +220,12 @@ use constant DB_FILE_POSTMASTERPID => 'postmast
push @EXPORT, qw(DB_FILE_POSTMASTERPID);
use constant DB_FILE_RECOVERYCONF => 'recovery.conf';
push @EXPORT, qw(DB_FILE_RECOVERYCONF);
use constant DB_FILE_RECOVERYSIGNAL => 'recovery.signal';
push @EXPORT, qw(DB_FILE_RECOVERYSIGNAL);
use constant DB_FILE_RECOVERYDONE => 'recovery.done';
push @EXPORT, qw(DB_FILE_RECOVERYDONE);
use constant DB_FILE_STANDBYSIGNAL => 'standby.signal';
push @EXPORT, qw(DB_FILE_STANDBYSIGNAL);
use constant DB_FILE_TABLESPACEMAP => 'tablespace_map';
push @EXPORT, qw(DB_FILE_TABLESPACEMAP);
@ -268,8 +272,12 @@ use constant MANIFEST_FILE_POSTMASTERPID => MANIFEST_
push @EXPORT, qw(MANIFEST_FILE_POSTMASTERPID);
use constant MANIFEST_FILE_RECOVERYCONF => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYCONF;
push @EXPORT, qw(MANIFEST_FILE_RECOVERYCONF);
use constant MANIFEST_FILE_RECOVERYSIGNAL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYSIGNAL;
push @EXPORT, qw(MANIFEST_FILE_RECOVERYSIGNAL);
use constant MANIFEST_FILE_RECOVERYDONE => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYDONE;
push @EXPORT, qw(MANIFEST_FILE_RECOVERYDONE);
use constant MANIFEST_FILE_STANDBYSIGNAL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_STANDBYSIGNAL;
push @EXPORT, qw(MANIFEST_FILE_STANDBYSIGNAL);
use constant MANIFEST_FILE_TABLESPACEMAP => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_TABLESPACEMAP;
push @EXPORT, qw(MANIFEST_FILE_TABLESPACEMAP);
@ -884,13 +892,21 @@ sub build
# Skip pg_internal.init since it is recreated on startup
next if $strFile =~ (DB_FILE_PGINTERNALINIT . '$');
# Skip recovery files
if ($self->dbVersion() >= PG_VERSION_12)
{
next if ($strFile eq MANIFEST_FILE_RECOVERYSIGNAL || $strFile eq MANIFEST_FILE_STANDBYSIGNAL);
}
else
{
next if ($strFile eq MANIFEST_FILE_RECOVERYDONE || $strFile eq MANIFEST_FILE_RECOVERYCONF);
}
# Skip ignored files
if ($strFile eq MANIFEST_FILE_POSTGRESQLAUTOCONFTMP || # postgresql.auto.conf.tmp - temp file for safe writes
$strFile eq MANIFEST_FILE_BACKUPLABELOLD || # backup_label.old - old backup labels are not useful
$strFile eq MANIFEST_FILE_POSTMASTEROPTS || # postmaster.opts - not useful for backup
$strFile eq MANIFEST_FILE_POSTMASTERPID || # postmaster.pid - to avoid confusing postgres after restore
$strFile eq MANIFEST_FILE_RECOVERYCONF || # recovery.conf - doesn't make sense to backup this file
$strFile eq MANIFEST_FILE_RECOVERYDONE) # recovery.done - doesn't make sense to backup this file
$strFile eq MANIFEST_FILE_POSTMASTERPID) # postmaster.pid - to avoid confusing postgres after restore
{
next;
}

View File

@ -154,6 +154,7 @@ SRCS = \
postgres/interface/v096.c \
postgres/interface/v100.c \
postgres/interface/v110.c \
postgres/interface/v120.c \
postgres/pageChecksum.c \
protocol/client.c \
protocol/command.c \
@ -545,6 +546,9 @@ postgres/interface/v100.o: postgres/interface/v100.c build.auto.h common/assert.
postgres/interface/v110.o: postgres/interface/v110.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h postgres/interface.h postgres/interface/version.auto.h postgres/interface/version.h postgres/interface/version.intern.h postgres/version.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c postgres/interface/v110.c -o postgres/interface/v110.o
postgres/interface/v120.o: postgres/interface/v120.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h postgres/interface.h postgres/interface/version.auto.h postgres/interface/version.h postgres/interface/version.intern.h postgres/version.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c postgres/interface/v120.c -o postgres/interface/v120.o
postgres/pageChecksum.o: postgres/pageChecksum.c build.auto.h common/assert.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/log.h common/logLevel.h common/memContext.h common/stackTrace.h common/time.h common/type/buffer.h common/type/convert.h common/type/keyValue.h common/type/list.h common/type/string.h common/type/stringList.h common/type/variant.h common/type/variantList.h postgres/interface.h postgres/pageChecksum.h storage/info.h storage/read.h storage/storage.h storage/write.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) @COPTIMIZE_PAGE_CHECKSUM@ -c postgres/pageChecksum.c -o postgres/pageChecksum.o

View File

@ -5,6 +5,7 @@ Restore Command
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "command/restore/protocol.h"
@ -24,6 +25,7 @@ Restore Command
#include "protocol/parallel.h"
#include "storage/helper.h"
#include "storage/write.intern.h"
#include "version.h"
/***********************************************************************************************************************************
Recovery constants
@ -32,6 +34,10 @@ Recovery constants
STRING_STATIC(RESTORE_COMMAND_STR, RESTORE_COMMAND);
#define RECOVERY_TARGET "recovery_target"
#define RECOVERY_TARGET_LSN "recovery_target_lsn"
#define RECOVERY_TARGET_NAME "recovery_target_name"
#define RECOVERY_TARGET_TIME "recovery_target_time"
#define RECOVERY_TARGET_XID "recovery_target_xid"
#define RECOVERY_TARGET_ACTION "recovery_target_action"
#define RECOVERY_TARGET_ACTION_SHUTDOWN "shutdown"
@ -41,6 +47,7 @@ Recovery constants
#define RECOVERY_TARGET_TIMELINE "recovery_target_timeline"
#define PAUSE_AT_RECOVERY_TARGET "pause_at_recovery_target"
#define STANDBY_MODE "standby_mode"
STRING_STATIC(STANDBY_MODE_STR, STANDBY_MODE);
#define RECOVERY_TYPE_DEFAULT "default"
STRING_STATIC(RECOVERY_TYPE_DEFAULT_STR, RECOVERY_TYPE_DEFAULT);
@ -781,9 +788,20 @@ restoreCleanBuild(Manifest *manifest)
cleanData->fileIgnore = strLstNew();
strLstAdd(cleanData->fileIgnore, BACKUP_MANIFEST_FILE_STR);
// Alse ignore recovery.conf when recovery type = preserve
// Also ignore recovery files when recovery type = preserve
if (strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_PRESERVE_STR))
{
// If recovery GUCs then three files must be preserved
if (manifestData(manifest)->pgVersion >= PG_VERSION_RECOVERY_GUC)
{
strLstAdd(cleanData->fileIgnore, PG_FILE_POSTGRESQLAUTOCONF_STR);
strLstAdd(cleanData->fileIgnore, PG_FILE_RECOVERYSIGNAL_STR);
strLstAdd(cleanData->fileIgnore, PG_FILE_STANDBYSIGNAL_STR);
}
// Else just recovery.conf
else
strLstAdd(cleanData->fileIgnore, PG_FILE_RECOVERYCONF_STR);
}
// If this is a tablespace append the tablespace identifier
if (cleanData->target->type == manifestTargetTypeLink && cleanData->target->tablespaceId != 0)
@ -865,6 +883,15 @@ restoreCleanBuild(Manifest *manifest)
manifestFileRemove(manifest, STRDEF(MANIFEST_TARGET_PGDATA "/" PG_FILE_TABLESPACEMAP));
}
// Skip postgresql.auto.conf if preserve is set and the PostgreSQL version supports recovery GUCs
if (manifestData(manifest)->pgVersion >= PG_VERSION_RECOVERY_GUC &&
strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_PRESERVE_STR) &&
manifestFileFindDefault(manifest, STRDEF(MANIFEST_TARGET_PGDATA "/" PG_FILE_POSTGRESQLAUTOCONF), NULL) != NULL)
{
LOG_DETAIL("skip '" PG_FILE_POSTGRESQLAUTOCONF "' -- recovery type is preserve");
manifestFileRemove(manifest, STRDEF(MANIFEST_TARGET_PGDATA "/" PG_FILE_POSTGRESQLAUTOCONF));
}
// Step 2: Clean target directories
// -------------------------------------------------------------------------------------------------------------------------
// Delete the pg_control file (if it exists) so the cluster cannot be started if restore does not complete. Sync the path
@ -1200,8 +1227,9 @@ restoreRecoveryOption(unsigned int pgVersion)
// Else recovery type is standby
else if (strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_STANDBY_STR))
{
// Write standby_mode
kvPut(result, VARSTRZ(STANDBY_MODE), VARSTRDEF("on"));
// Write standby_mode for PostgreSQL versions that support it
if (pgVersion < PG_VERSION_RECOVERY_GUC)
kvPut(result, VARSTR(STANDBY_MODE_STR), VARSTRDEF("on"));
}
// Else recovery type is not default so write target options
else if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_DEFAULT_STR))
@ -1264,19 +1292,20 @@ restoreRecoveryOption(unsigned int pgVersion)
FUNCTION_LOG_RETURN(KEY_VALUE, result);
}
// Helper to write recovery options into recovery.conf
// Helper to convert recovery options to text format
static String *
restoreRecoveryConf(unsigned int pgVersion)
restoreRecoveryConf(unsigned int pgVersion, const String *restoreLabel)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(UINT, pgVersion);
FUNCTION_LOG_PARAM(STRING, restoreLabel);
FUNCTION_LOG_END();
String *result = NULL;
MEM_CONTEXT_TEMP_BEGIN()
{
result = strNew("");
result = strNewFmt("# Recovery settings generated by " PROJECT_NAME " restore on %s\n", strPtr(restoreLabel));
// Output all recovery options
KeyValue *optionKv = restoreRecoveryOption(pgVersion);
@ -1298,28 +1327,180 @@ restoreRecoveryConf(unsigned int pgVersion)
FUNCTION_LOG_RETURN(STRING, result);
}
// Helper to write recovery options into recovery.conf
static void
restoreRecoveryWriteConf(const Manifest *manifest, unsigned int pgVersion, const String *restoreLabel)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(MANIFEST, manifest);
FUNCTION_LOG_PARAM(UINT, pgVersion);
FUNCTION_LOG_PARAM(STRING, restoreLabel);
FUNCTION_LOG_END();
// Only write recovery.conf if recovery type != none
if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_NONE_STR))
{
LOG_INFO("write %s", strPtr(storagePathNP(storagePg(), PG_FILE_RECOVERYCONF_STR)));
// Use the data directory to set permissions and ownership for recovery file
const ManifestPath *dataPath = manifestPathFind(manifest, MANIFEST_TARGET_PGDATA_STR);
mode_t recoveryFileMode = dataPath->mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
// Write recovery.conf
storagePutNP(
storageNewWriteP(
storagePgWrite(), PG_FILE_RECOVERYCONF_STR, .noCreatePath = true, .modeFile = recoveryFileMode, .noAtomic = true,
.noSyncPath = true, .user = dataPath->user, .group = dataPath->group),
BUFSTR(restoreRecoveryConf(pgVersion, restoreLabel)));
}
FUNCTION_LOG_RETURN_VOID();
}
// Helper to write recovery options into postgresql.auto.conf
static void
restoreRecoveryWriteAutoConf(unsigned int pgVersion, const String *restoreLabel)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_LOG_PARAM(UINT, pgVersion);
FUNCTION_LOG_PARAM(STRING, restoreLabel);
FUNCTION_LOG_END();
MEM_CONTEXT_TEMP_BEGIN()
{
String *content = strNew("");
// Load postgresql.auto.conf so we can preserve the existing contents
Buffer *autoConf = storageGetNP(storageNewReadP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR, .ignoreMissing = true));
// It is unusual for the file not to exist, but we'll continue processing by creating a blank file
if (autoConf == NULL)
{
LOG_WARN(PG_FILE_POSTGRESQLAUTOCONF " does not exist -- creating to contain recovery settings");
}
// Else the file does exist so cleanup old recovery options that could interfere with the current recovery
else
{
// Generate a regexp that will match on all current recovery_target settings
RegExp *recoveryExp =
regExpNew(
STRDEF(
"^\\s*(" RECOVERY_TARGET "|" RECOVERY_TARGET_ACTION "|" RECOVERY_TARGET_INCLUSIVE "|" RECOVERY_TARGET_LSN
"|" RECOVERY_TARGET_NAME "|" RECOVERY_TARGET_TIME "|" RECOVERY_TARGET_TIMELINE "|" RECOVERY_TARGET_XID
")\\s*="));
// Check each line for recovery settings
const StringList *contentList = strLstNewSplit(strNewBuf(autoConf), LF_STR);
for (unsigned int contentIdx = 0; contentIdx < strLstSize(contentList); contentIdx++)
{
if (contentIdx != 0)
strCat(content, "\n");
const String *line = strLstGet(contentList, contentIdx);
if (regExpMatch(recoveryExp, line))
strCatFmt(content, "# Removed by " PROJECT_NAME " restore on %s # ", strPtr(restoreLabel));
strCat(content, strPtr(line));
}
// If settings will be appended then format the file so a blank line will be between old and new settings
if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_NONE_STR))
{
strTrim(content);
strCat(content, "\n\n");
}
}
// If recovery was requested then write the recovery options
if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_NONE_STR))
{
// If the user specified standby_mode as a recovery option then error. It's tempting to just set type=standby in this
// case but since config parsing has already happened the target options could be in an invalid state.
if (cfgOptionTest(cfgOptRecoveryOption))
{
const KeyValue *recoveryOption = cfgOptionKv(cfgOptRecoveryOption);
StringList *recoveryOptionKey = strLstNewVarLst(kvKeyList(recoveryOption));
for (unsigned int keyIdx = 0; keyIdx < strLstSize(recoveryOptionKey); keyIdx++)
{
// Get the key and value
String *key = strLstGet(recoveryOptionKey, keyIdx);
// Replace - in key with _. Since we use - users naturally will as well.
strReplaceChr(key, '-', '_');
if (strEq(key, STANDBY_MODE_STR))
{
THROW_FMT(
OptionInvalidError,
"'" STANDBY_MODE "' setting is not valid for " PG_NAME " >= %s\n"
"HINT: use --" CFGOPT_TYPE "=" RECOVERY_TYPE_STANDBY " instead of --" CFGOPT_RECOVERY_OPTION "="
STANDBY_MODE "=on.",
strPtr(pgVersionToStr(PG_VERSION_RECOVERY_GUC)));
}
}
}
strCatFmt(content, "%s", strPtr(restoreRecoveryConf(pgVersion, restoreLabel)));
}
LOG_INFO(
"write %s%s", autoConf == NULL ? "" : "updated ", strPtr(storagePathNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR)));
// Use the data directory to set permissions and ownership for recovery file
const StorageInfo dataPath = storageInfoNP(storagePg(), NULL);
mode_t recoveryFileMode = dataPath.mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
// Write postgresql.auto.conf
storagePutNP(
storageNewWriteP(
storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR, .noCreatePath = true, .modeFile = recoveryFileMode,
.noAtomic = true, .noSyncPath = true, .user = dataPath.user, .group = dataPath.group),
BUFSTR(content));
// The recovery.signal file is required for targeted recovery
storagePutNP(
storageNewWriteP(
storagePgWrite(), PG_FILE_RECOVERYSIGNAL_STR, .noCreatePath = true, .modeFile = recoveryFileMode,
.noAtomic = true, .noSyncPath = true, .user = dataPath.user, .group = dataPath.group),
NULL);
// The standby.signal file is required for standby mode
if (strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_STANDBY_STR))
{
storagePutNP(
storageNewWriteP(
storagePgWrite(), PG_FILE_STANDBYSIGNAL_STR, .noCreatePath = true, .modeFile = recoveryFileMode,
.noAtomic = true, .noSyncPath = true, .user = dataPath.user, .group = dataPath.group),
NULL);
}
}
MEM_CONTEXT_TEMP_END();
FUNCTION_LOG_RETURN_VOID();
}
static void
restoreRecoveryWrite(const Manifest *manifest)
{
FUNCTION_LOG_BEGIN(logLevelDebug);
FUNCTION_TEST_PARAM(MANIFEST, manifest);
FUNCTION_LOG_PARAM(MANIFEST, manifest);
FUNCTION_LOG_END();
// Get PostgreSQL version to write recovery for
unsigned int pgVersion = manifestData(manifest)->pgVersion;
// Determine which file recovery setttings will be written to
const String *recoveryFile = PG_FILE_RECOVERYCONF_STR;
// Use the data directory to set permissions and ownership for recovery file
const ManifestPath *dataPath = manifestPathFind(manifest, MANIFEST_TARGET_PGDATA_STR);
mode_t recoveryFileMode = dataPath->mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MEM_CONTEXT_TEMP_BEGIN()
{
// If recovery type is preserve then leave recovery file as it is
if (strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_PRESERVE_STR))
{
// Determine which file recovery setttings will be written to
const String *recoveryFile = pgVersion >= PG_VERSION_RECOVERY_GUC ?
PG_FILE_POSTGRESQLAUTOCONF_STR : PG_FILE_RECOVERYCONF_STR;
if (!storageExistsNP(storagePg(), recoveryFile))
{
LOG_WARN(
@ -1327,20 +1508,20 @@ restoreRecoveryWrite(const Manifest *manifest)
strPtr(storagePathNP(storagePg(), recoveryFile)));
}
}
// Else write recovery file if requested
// Else write recovery file
else
{
// Only generate recovery file if recovery type is not none
if (!strEq(cfgOptionStr(cfgOptType), RECOVERY_TYPE_NONE_STR))
{
LOG_INFO("write %s", strPtr(storagePathNP(storagePg(), recoveryFile)));
// Generate a label used to identify this restore in the recovery file
char restoreTimestamp[20];
time_t timestamp = time(NULL);
strftime(restoreTimestamp, sizeof(restoreTimestamp), "%Y-%m-%d %H:%M:%S", localtime(&timestamp));
const String *restoreLabel = STR(restoreTimestamp);
storagePutNP(
storageNewWriteP(
storagePgWrite(), recoveryFile, .noCreatePath = true, .modeFile = recoveryFileMode, .noAtomic = true,
.noSyncPath = true, .user = dataPath->user, .group = dataPath->group),
BUFSTR(restoreRecoveryConf(pgVersion)));
}
// Write recovery file based on PostgreSQL version
if (pgVersion >= PG_VERSION_RECOVERY_GUC)
restoreRecoveryWriteAutoConf(pgVersion, restoreLabel);
else
restoreRecoveryWriteConf(manifest, pgVersion, restoreLabel);
}
}
MEM_CONTEXT_TEMP_END();

View File

@ -6817,6 +6817,10 @@ static const EmbeddedModule embeddedModule[] =
"{\n"
"201809051 => PG_VERSION_11,\n"
"},\n"
"1201 =>\n"
"{\n"
"201909212 => PG_VERSION_12,\n"
"},\n"
"};\n"
"\n\n\n\n"
"sub new\n"
@ -7707,7 +7711,7 @@ static const EmbeddedModule embeddedModule[] =
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionSupport');\n"
"\n"
"my @strySupportVersion = (PG_VERSION_83, PG_VERSION_84, PG_VERSION_90, PG_VERSION_91, PG_VERSION_92, PG_VERSION_93,\n"
"PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11);\n"
"PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11, PG_VERSION_12);\n"
"\n\n"
"return logDebugReturn\n"
"(\n"
@ -8596,8 +8600,12 @@ static const EmbeddedModule embeddedModule[] =
"push @EXPORT, qw(DB_FILE_POSTMASTERPID);\n"
"use constant DB_FILE_RECOVERYCONF => 'recovery.conf';\n"
"push @EXPORT, qw(DB_FILE_RECOVERYCONF);\n"
"use constant DB_FILE_RECOVERYSIGNAL => 'recovery.signal';\n"
"push @EXPORT, qw(DB_FILE_RECOVERYSIGNAL);\n"
"use constant DB_FILE_RECOVERYDONE => 'recovery.done';\n"
"push @EXPORT, qw(DB_FILE_RECOVERYDONE);\n"
"use constant DB_FILE_STANDBYSIGNAL => 'standby.signal';\n"
"push @EXPORT, qw(DB_FILE_STANDBYSIGNAL);\n"
"use constant DB_FILE_TABLESPACEMAP => 'tablespace_map';\n"
"push @EXPORT, qw(DB_FILE_TABLESPACEMAP);\n"
"\n"
@ -8641,8 +8649,12 @@ static const EmbeddedModule embeddedModule[] =
"push @EXPORT, qw(MANIFEST_FILE_POSTMASTERPID);\n"
"use constant MANIFEST_FILE_RECOVERYCONF => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYCONF;\n"
"push @EXPORT, qw(MANIFEST_FILE_RECOVERYCONF);\n"
"use constant MANIFEST_FILE_RECOVERYSIGNAL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYSIGNAL;\n"
"push @EXPORT, qw(MANIFEST_FILE_RECOVERYSIGNAL);\n"
"use constant MANIFEST_FILE_RECOVERYDONE => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_RECOVERYDONE;\n"
"push @EXPORT, qw(MANIFEST_FILE_RECOVERYDONE);\n"
"use constant MANIFEST_FILE_STANDBYSIGNAL => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_STANDBYSIGNAL;\n"
"push @EXPORT, qw(MANIFEST_FILE_STANDBYSIGNAL);\n"
"use constant MANIFEST_FILE_TABLESPACEMAP => MANIFEST_TARGET_PGDATA . '/' . DB_FILE_TABLESPACEMAP;\n"
"push @EXPORT, qw(MANIFEST_FILE_TABLESPACEMAP);\n"
"\n\n\n\n"
@ -9142,12 +9154,19 @@ static const EmbeddedModule embeddedModule[] =
"\n\n"
"next if $strFile =~ (DB_FILE_PGINTERNALINIT . '$');\n"
"\n\n"
"if ($self->dbVersion() >= PG_VERSION_12)\n"
"{\n"
"next if ($strFile eq MANIFEST_FILE_RECOVERYSIGNAL || $strFile eq MANIFEST_FILE_STANDBYSIGNAL);\n"
"}\n"
"else\n"
"{\n"
"next if ($strFile eq MANIFEST_FILE_RECOVERYDONE || $strFile eq MANIFEST_FILE_RECOVERYCONF);\n"
"}\n"
"\n\n"
"if ($strFile eq MANIFEST_FILE_POSTGRESQLAUTOCONFTMP ||\n"
"$strFile eq MANIFEST_FILE_BACKUPLABELOLD ||\n"
"$strFile eq MANIFEST_FILE_POSTMASTEROPTS ||\n"
"$strFile eq MANIFEST_FILE_POSTMASTERPID ||\n"
"$strFile eq MANIFEST_FILE_RECOVERYCONF || # recovery.conf - doesn't make sense to backup this file\n"
"$strFile eq MANIFEST_FILE_RECOVERYDONE) # recovery.done - doesn't make sense to backup this file\n"
"$strFile eq MANIFEST_FILE_POSTMASTERPID)\n"
"{\n"
"next;\n"
"}\n"

View File

@ -18,8 +18,11 @@ PostgreSQL Interface
Defines for various Postgres paths and files
***********************************************************************************************************************************/
STRING_EXTERN(PG_FILE_PGVERSION_STR, PG_FILE_PGVERSION);
STRING_EXTERN(PG_FILE_POSTGRESQLAUTOCONF_STR, PG_FILE_POSTGRESQLAUTOCONF);
STRING_EXTERN(PG_FILE_POSTMASTERPID_STR, PG_FILE_POSTMASTERPID);
STRING_EXTERN(PG_FILE_RECOVERYCONF_STR, PG_FILE_RECOVERYCONF);
STRING_EXTERN(PG_FILE_RECOVERYSIGNAL_STR, PG_FILE_RECOVERYSIGNAL);
STRING_EXTERN(PG_FILE_STANDBYSIGNAL_STR, PG_FILE_STANDBYSIGNAL);
STRING_EXTERN(PG_PATH_GLOBAL_STR, PG_PATH_GLOBAL);
@ -94,6 +97,23 @@ typedef struct PgInterface
static const PgInterface pgInterface[] =
{
{
.version = PG_VERSION_12,
.catalogVersion = pgInterfaceCatalogVersion120,
.controlIs = pgInterfaceControlIs120,
.control = pgInterfaceControl120,
.controlVersion = pgInterfaceControlVersion120,
.walIs = pgInterfaceWalIs120,
.wal = pgInterfaceWal120,
#ifdef DEBUG
.controlTest = pgInterfaceControlTest120,
.walTest = pgInterfaceWalTest120,
#endif
},
{
.version = PG_VERSION_11,

View File

@ -16,10 +16,16 @@ Defines for various Postgres paths and files
#define PG_FILE_PGCONTROL "pg_control"
#define PG_FILE_PGVERSION "PG_VERSION"
STRING_DECLARE(PG_FILE_PGVERSION_STR);
#define PG_FILE_POSTGRESQLAUTOCONF "postgresql.auto.conf"
STRING_DECLARE(PG_FILE_POSTGRESQLAUTOCONF_STR);
#define PG_FILE_POSTMASTERPID "postmaster.pid"
STRING_DECLARE(PG_FILE_POSTMASTERPID_STR);
#define PG_FILE_RECOVERYCONF "recovery.conf"
STRING_DECLARE(PG_FILE_RECOVERYCONF_STR);
#define PG_FILE_RECOVERYSIGNAL "recovery.signal"
STRING_DECLARE(PG_FILE_RECOVERYSIGNAL_STR);
#define PG_FILE_STANDBYSIGNAL "standby.signal"
STRING_DECLARE(PG_FILE_STANDBYSIGNAL_STR);
#define PG_FILE_TABLESPACEMAP "tablespace_map"
#define PG_PATH_ARCHIVE_STATUS "archive_status"

View File

@ -0,0 +1,12 @@
/***********************************************************************************************************************************
PostgreSQL 12 Interface
See postgres/interface/version.intern.h for documentation.
***********************************************************************************************************************************/
#include "build.auto.h"
#define PG_VERSION PG_VERSION_12
#include "postgres/interface/version.intern.h"
PG_INTERFACE(120);

View File

@ -219,6 +219,18 @@ Types from src/include/catalog/catversion.h
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
/*
* We could use anything we wanted for version numbers, but I recommend
* following the "YYYYMMDDN" style often used for DNS zone serial numbers.
* YYYYMMDD are the date of the change, and N is the number of the change
* on that day. (Hopefully we'll never commit ten independent sets of
* catalog changes on the same day...)
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 201909212
#elif PG_VERSION >= PG_VERSION_11
/*
@ -364,6 +376,28 @@ Types from src/include/catalog/catversion.h
#endif
/***********************************************************************************************************************************
Types from src/include/access/transam.h
***********************************************************************************************************************************/
// FullTransactionId type
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
/*
* A 64 bit value that contains an epoch and a TransactionId. This is
* wrapped in a struct to prevent implicit conversion to/from TransactionId.
* Not all values represent valid normal XIDs.
*/
typedef struct FullTransactionId
{
uint64 value;
} FullTransactionId;
#endif
/***********************************************************************************************************************************
Types from src/include/catalog/pg_control.h
***********************************************************************************************************************************/
@ -372,6 +406,11 @@ Types from src/include/catalog/pg_control.h
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 1201
#elif PG_VERSION >= PG_VERSION_11
/* Version identifier for this pg_control format */
@ -434,6 +473,44 @@ Types from src/include/catalog/pg_control.h
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
* a copy of the latest one in pg_control for possible disaster recovery.
* Changing this struct requires a PG_CONTROL_VERSION bump.
*/
typedef struct CheckPoint
{
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
FullTransactionId nextFullXid; /* next free full transaction ID */
Oid nextOid; /* next free OID */
MultiXactId nextMulti; /* next free MultiXactId */
MultiXactOffset nextMultiOffset; /* next free MultiXact offset */
TransactionId oldestXid; /* cluster-wide minimum datfrozenxid */
Oid oldestXidDB; /* database with minimum datfrozenxid */
MultiXactId oldestMulti; /* cluster-wide minimum datminmxid */
Oid oldestMultiDB; /* database with minimum datminmxid */
pg_time_t time; /* time stamp of checkpoint */
TransactionId oldestCommitTsXid; /* oldest Xid with valid commit
* timestamp */
TransactionId newestCommitTsXid; /* newest Xid with valid commit
* timestamp */
/*
* Oldest XID still running. This is only needed to initialize hot standby
* mode from an online checkpoint, so we only bother calculating this for
* online checkpoints and only when wal_level is replica. Otherwise it's
* set to InvalidTransactionId.
*/
TransactionId oldestActiveXid;
} CheckPoint;
#elif PG_VERSION >= PG_VERSION_96
/*
@ -700,6 +777,146 @@ typedef enum DBState
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
/*
* Contents of pg_control.
*/
typedef struct ControlFileData
{
/*
* Unique system identifier --- to ensure we match up xlog files with the
* installation that produced them.
*/
uint64 system_identifier;
/*
* Version identifier information. Keep these fields at the same offset,
* especially pg_control_version; they won't be real useful if they move
* around. (For historical reasons they must be 8 bytes into the file
* rather than immediately at the front.)
*
* pg_control_version identifies the format of pg_control itself.
* catalog_version_no identifies the format of the system catalogs.
*
* There are additional version identifiers in individual files; for
* example, WAL logs contain per-page magic numbers that can serve as
* version cues for the WAL log.
*/
uint32 pg_control_version; /* PG_CONTROL_VERSION */
uint32 catalog_version_no; /* see catversion.h */
/*
* System status data
*/
DBState state; /* see enum above */
pg_time_t time; /* time stamp of last pg_control update */
XLogRecPtr checkPoint; /* last check point record ptr */
CheckPoint checkPointCopy; /* copy of last check point record */
XLogRecPtr unloggedLSN; /* current fake LSN value, for unlogged rels */
/*
* These two values determine the minimum point we must recover up to
* before starting up:
*
* minRecoveryPoint is updated to the latest replayed LSN whenever we
* flush a data change during archive recovery. That guards against
* starting archive recovery, aborting it, and restarting with an earlier
* stop location. If we've already flushed data changes from WAL record X
* to disk, we mustn't start up until we reach X again. Zero when not
* doing archive recovery.
*
* backupStartPoint is the redo pointer of the backup start checkpoint, if
* we are recovering from an online backup and haven't reached the end of
* backup yet. It is reset to zero when the end of backup is reached, and
* we mustn't start up before that. A boolean would suffice otherwise, but
* we use the redo pointer as a cross-check when we see an end-of-backup
* record, to make sure the end-of-backup record corresponds the base
* backup we're recovering from.
*
* backupEndPoint is the backup end location, if we are recovering from an
* online backup which was taken from the standby and haven't reached the
* end of backup yet. It is initialized to the minimum recovery point in
* pg_control which was backed up last. It is reset to zero when the end
* of backup is reached, and we mustn't start up before that.
*
* If backupEndRequired is true, we know for sure that we're restoring
* from a backup, and must see a backup-end record before we can safely
* start up. If it's false, but backupStartPoint is set, a backup_label
* file was found at startup but it may have been a leftover from a stray
* pg_start_backup() call, not accompanied by pg_stop_backup().
*/
XLogRecPtr minRecoveryPoint;
TimeLineID minRecoveryPointTLI;
XLogRecPtr backupStartPoint;
XLogRecPtr backupEndPoint;
bool backupEndRequired;
/*
* Parameter settings that determine if the WAL can be used for archival
* or hot standby.
*/
int wal_level;
bool wal_log_hints;
int MaxConnections;
int max_worker_processes;
int max_wal_senders;
int max_prepared_xacts;
int max_locks_per_xact;
bool track_commit_timestamp;
/*
* This data is used to check for hardware-architecture compatibility of
* the database and the backend executable. We need not check endianness
* explicitly, since the pg_control version will surely look wrong to a
* machine of different endianness, but we do need to worry about MAXALIGN
* and floating-point format. (Note: storage layout nominally also
* depends on SHORTALIGN and INTALIGN, but in practice these are the same
* on all architectures of interest.)
*
* Testing just one double value is not a very bulletproof test for
* floating-point compatibility, but it will catch most cases.
*/
uint32 maxAlign; /* alignment requirement for tuples */
double floatFormat; /* constant 1234567.0 */
#define FLOATFORMAT_VALUE 1234567.0
/*
* This data is used to make sure that configuration of this database is
* compatible with the backend executable.
*/
uint32 blcksz; /* data block size for this DB */
uint32 relseg_size; /* blocks per segment of large relation */
uint32 xlog_blcksz; /* block size within WAL files */
uint32 xlog_seg_size; /* size of each WAL segment */
uint32 nameDataLen; /* catalog name field width */
uint32 indexMaxKeys; /* max number of columns in an index */
uint32 toast_max_chunk_size; /* chunk size in TOAST tables */
uint32 loblksize; /* chunk size in pg_largeobject */
/* flags indicating pass-by-value status of various types */
bool float4ByVal; /* float4 pass-by-value? */
bool float8ByVal; /* float8, int8, etc pass-by-value? */
/* Are data pages protected by checksums? Zero if no checksum version */
uint32 data_checksum_version;
/*
* Random nonce, used in authentication requests that need to proceed
* based on values that are cluster-unique, like a SASL exchange that
* failed at an early stage.
*/
char mock_authentication_nonce[MOCK_AUTH_NONCE_LEN];
/* CRC of all above ... MUST BE LAST! */
pg_crc32c crc;
} ControlFileData;
#elif PG_VERSION >= PG_VERSION_11
/*
@ -1827,6 +2044,10 @@ Types from src/include/access/xlog_internal.h
// ---------------------------------------------------------------------------------------------------------------------------------
#if PG_VERSION > PG_VERSION_MAX
#elif PG_VERSION >= PG_VERSION_12
#define XLOG_PAGE_MAGIC 0xD101 /* can be used as WAL version indicator */
#elif PG_VERSION >= PG_VERSION_11
#define XLOG_PAGE_MAGIC 0xD098 /* can be used as WAL version indicator */

View File

@ -86,6 +86,13 @@ uint32_t pgInterfaceControlVersion110(void);
bool pgInterfaceWalIs110(const unsigned char *walFile);
PgWal pgInterfaceWal110(const unsigned char *controlFile);
uint32_t pgInterfaceCatalogVersion120(void);
bool pgInterfaceControlIs120(const unsigned char *controlFile);
PgControl pgInterfaceControl120(const unsigned char *controlFile);
uint32_t pgInterfaceControlVersion120(void);
bool pgInterfaceWalIs120(const unsigned char *walFile);
PgWal pgInterfaceWal120(const unsigned char *controlFile);
/***********************************************************************************************************************************
Test Functions
***********************************************************************************************************************************/
@ -122,6 +129,9 @@ Test Functions
void pgInterfaceControlTest110(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest110(PgWal pgWal, unsigned char *buffer);
void pgInterfaceControlTest120(PgControl pgControl, unsigned char *buffer);
void pgInterfaceWalTest120(PgWal pgWal, unsigned char *buffer);
#endif
#endif

View File

@ -23,8 +23,9 @@ PostgreSQL version constants
#define PG_VERSION_96 90600
#define PG_VERSION_10 100000
#define PG_VERSION_11 110000
#define PG_VERSION_12 120000
#define PG_VERSION_MAX PG_VERSION_11
#define PG_VERSION_MAX PG_VERSION_12
/***********************************************************************************************************************************
Version where various PostgreSQL capabilities were introduced
@ -50,6 +51,9 @@ Version where various PostgreSQL capabilities were introduced
// xlog was renamed to wal
#define PG_VERSION_WAL_RENAME PG_VERSION_10
// recovery settings are implemented as GUCs (recovery.conf is no longer valid)
#define PG_VERSION_RECOVERY_GUC PG_VERSION_12
/***********************************************************************************************************************************
PostgreSQL version string constants for use in error messages
***********************************************************************************************************************************/
@ -64,5 +68,6 @@ PostgreSQL version string constants for use in error messages
#define PG_VERSION_96_STR "9.6"
#define PG_VERSION_10_STR "10"
#define PG_VERSION_11_STR "11"
#define PG_VERSION_12_STR "12"
#endif

View File

@ -693,7 +693,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: restore
total: 10
total: 11
perlReq: true
coverage:

View File

@ -638,6 +638,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-2]' - fix permissions (db-master host)
@ -698,6 +699,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-2]' - fix broken symlink (db-master host)
@ -758,6 +760,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-2]' - restore all links by mapping (db-master host)
@ -819,6 +822,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-2]', expect exit 70 - restore all links by mapping (db-master host)
@ -923,6 +927,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, force, backup '[BACKUP-FULL-2]', expect exit 40 - fail on missing PG_VERSION (db-master host)
@ -1002,6 +1007,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
incr backup - invalid database version (db-master host)
@ -2024,6 +2030,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-DIFF-2]', remap - ensure file in tblspc root remains after --delta (db-master host)
@ -2092,6 +2099,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
incr backup - add files and remove tablespace 2 (db-master host)
@ -3924,6 +3932,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, remap - selective restore 32768 (db-master host)
@ -3987,6 +3996,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, remap, expect exit 80 - error on invalid id (db-master host)
@ -4075,6 +4085,7 @@ P00 INFO: restore command end: completed successfully
+ supplemental file: [TEST_PATH]/db-master/db/base-2/base/recovery.conf
-----------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
info all stanzas - normal output (db-master host)

View File

@ -473,6 +473,7 @@ restore delta, backup '[BACKUP-FULL-2]' - add and delete files (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --cmd-ssh=/usr/bin/ssh --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-2]' - fix broken symlink (db-master host)
@ -481,6 +482,7 @@ restore delta, backup '[BACKUP-FULL-2]' - fix broken symlink (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --compress-level-network=0 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, force, backup '[BACKUP-FULL-2]', expect exit 40 - fail on missing PG_VERSION (db-master host)
@ -504,6 +506,7 @@ P00 WARN: unknown group 'bogus' in backup manifest mapped to current group
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
incr backup - invalid database version (backup host)
@ -1415,6 +1418,7 @@ restore, backup '[BACKUP-DIFF-2]', remap - remap all paths (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-DIFF-2]', remap - ensure file in tblspc root remains after --delta (db-master host)
@ -1423,6 +1427,7 @@ restore delta, backup '[BACKUP-DIFF-2]', remap - ensure file in tblspc root rema
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
incr backup - add files and remove tablespace 2 (backup host)
@ -3253,6 +3258,7 @@ restore delta, remap - selective restore 16384 (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, remap - selective restore 32768 (db-master host)
@ -3261,6 +3267,7 @@ restore delta, remap - selective restore 32768 (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base-2/recovery.conf
------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, remap, expect exit 80 - error on invalid id (db-master host)
@ -3279,6 +3286,7 @@ restore, remap - no tablespace remap (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base-2/base/recovery.conf
-----------------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
info all stanzas - normal output (backup host)

View File

@ -168,6 +168,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promote (db-master host)
@ -176,6 +177,7 @@ restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promot
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target = 'immediate'
recovery_target_action = 'promote'
@ -186,6 +188,7 @@ restore, force, backup '[BACKUP-INCR-1]', type 'xid', target '[XID-TARGET-1]', t
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_xid = '[XID-TARGET-1]'
recovery_target_action = 'promote'
@ -196,6 +199,7 @@ restore, type 'preserve' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_xid = '[XID-TARGET-1]'
recovery_target_action = 'promote'
@ -206,6 +210,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'
@ -216,6 +221,7 @@ restore delta, backup '[BACKUP-INCR-1]', type 'xid', target '[XID-TARGET-1]', ex
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_xid = '[XID-TARGET-1]'
recovery_target_inclusive = 'false'
@ -227,6 +233,7 @@ restore delta, force, type 'name', target 'backrest', target-action=promote (db-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_name = 'backrest'
recovery_target_action = 'promote'
@ -237,6 +244,7 @@ restore delta, backup '[BACKUP-INCR-1]', type 'standby', timeline '4' (db-master
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
recovery_target_timeline = '4'

View File

@ -76,6 +76,7 @@ restore, type 'standby', remap - restore backup on replica (db-standby host)
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
primary_conninfo = 'host=db-master port=6543 user=replicator'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
@ -234,6 +235,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promote (db-master host)
@ -242,6 +244,7 @@ restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promot
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target = 'immediate'
recovery_target_action = 'promote'
@ -252,6 +255,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'

View File

@ -78,6 +78,7 @@ restore, type 'standby', remap - restore backup on replica (db-standby host)
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
primary_conninfo = 'host=db-master port=6543 user=replicator'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
@ -236,6 +237,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promote (db-master host)
@ -244,6 +246,7 @@ restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promot
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target = 'immediate'
recovery_target_action = 'promote'
@ -254,6 +257,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'

View File

@ -238,6 +238,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-1]', target-action=promote (db-master host)
@ -246,6 +247,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'

View File

@ -107,6 +107,7 @@ restore, type 'standby', remap - restore backup on replica (db-standby host)
+ supplemental file: [TEST_PATH]/db-standby/db/base/recovery.conf
-----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
primary_conninfo = 'host=db-master port=6543 user=replicator'
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db archive-get %f "%p"'
standby_mode = 'on'
@ -327,6 +328,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promote (db-master host)
@ -335,6 +337,7 @@ restore, force, backup '[BACKUP-FULL-1]', type 'immediate', target-action=promot
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target = 'immediate'
recovery_target_action = 'promote'
@ -345,6 +348,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'

View File

@ -240,6 +240,7 @@ restore, type 'default' (db-master host)
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --buffer-size=16384 --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-1]', target-action=promote (db-master host)
@ -248,6 +249,7 @@ restore delta, backup '[BACKUP-FULL-1]', type 'time', target '[TIMESTAMP-TARGET-
+ supplemental file: [TEST_PATH]/db-master/db/base/recovery.conf
----------------------------------------------------------------
# Recovery settings generated by pgBackRest restore on [TIMESTAMP]
restore_command = '[BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --stanza=db archive-get %f "%p"'
recovery_target_time = '[TIMESTAMP-TARGET-1]'
recovery_target_action = 'promote'

View File

@ -429,6 +429,9 @@ sub regExpReplaceAll
$strLine = $self->regExpReplace($strLine, 'TIMESTAMP', "start\" : [0-9]{10}", '[0-9]{10}$', false);
$strLine = $self->regExpReplace($strLine, 'TIMESTAMP', "stop\" : [0-9]{10}", '[0-9]{10}$', false);
$strLine = $self->regExpReplace($strLine, 'TIMESTAMP', TEST_GROUP . '\, [0-9]{10}', '[0-9]{10}$', false);
$strLine = $self->regExpReplace(
$strLine, 'TIMESTAMP', 'generated by pgBackRest restore on .*$',
'[0-9]{4}\-[0-9]{2}\-[0-9]{2} [0-9]{2}\:[0-9]{2}\:[0-9]{2}$', false);
$strLine = $self->regExpReplace($strLine, 'SIZE', "size\"[ ]{0,1}:[ ]{0,1}[0-9]+", '[0-9]+$', false);
$strLine = $self->regExpReplace($strLine, 'DELTA', "delta\"[ ]{0,1}:[ ]{0,1}[0-9]+", '[0-9]+$', false);
$strLine = $self->regExpReplace(

View File

@ -147,6 +147,7 @@ my $oyVm =
PG_VERSION_92,
PG_VERSION_94,
PG_VERSION_95,
PG_VERSION_10,
],
},
@ -356,8 +357,8 @@ my $oyVm =
&VM_DB_TEST =>
[
PG_VERSION_10,
PG_VERSION_11,
PG_VERSION_12,
],
},
};

View File

@ -1937,6 +1937,13 @@ sub restoreCompare
}
}
# If PostgreSQL >= 12 don't compare postgresql.auto.conf since it will have recovery settings written into it
if (${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION} >= PG_VERSION_12)
{
delete($oExpectedManifestRef->{&MANIFEST_SECTION_TARGET_FILE}{'pg_data/postgresql.auto.conf'});
$oActualManifest->remove(MANIFEST_SECTION_TARGET_FILE, 'pg_data/postgresql.auto.conf');
}
# If the link section is empty then delete it and the default section
if (keys(%{${$oExpectedManifestRef}{&MANIFEST_SECTION_TARGET_LINK}}) == 0)
{

View File

@ -246,6 +246,7 @@ sub dbCatalogVersion
&PG_VERSION_96 => 201608131,
&PG_VERSION_10 => 201707211,
&PG_VERSION_11 => 201806231,
&PG_VERSION_12 => 201909212,
};
if (!defined($hCatalogVersion->{$strPgVersion}))
@ -288,6 +289,7 @@ sub dbControlVersion
&PG_VERSION_96 => 960,
&PG_VERSION_10 => 1002,
&PG_VERSION_11 => 1100,
&PG_VERSION_12 => 1201,
};
if (!defined($hControlVersion->{$strPgVersion}))
@ -337,6 +339,7 @@ sub controlGenerateContent
'9.6' => 200 - length($tControlContent),
'10' => 200 - length($tControlContent),
'11' => 192 - length($tControlContent),
'12' => 196 - length($tControlContent),
},
64 =>
@ -352,6 +355,7 @@ sub controlGenerateContent
'9.6' => 216 - length($tControlContent),
'10' => 216 - length($tControlContent),
'11' => 208 - length($tControlContent),
'12' => 212 - length($tControlContent),
},
};
@ -443,6 +447,7 @@ sub walGenerateContent
&PG_VERSION_96 => hex('0xD093'),
&PG_VERSION_10 => hex('0xD097'),
&PG_VERSION_11 => hex('0xD098'),
&PG_VERSION_12 => hex('0xD101'),
};
my $tWalContent = pack('S', $hWalMagic->{$strPgVersion});

View File

@ -872,10 +872,11 @@ sub run
undef, $strIncrBackup,
{bForce => true, strType => CFGOPTVAL_RESTORE_TYPE_XID, strTarget => $strXidTarget,
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef,
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef,
strOptionalParam => '--tablespace-map-all=../../tablespace', bTablespace => false});
# Save recovery file to test so we can use it in the next test
$strRecoveryFile = DB_FILE_RECOVERYCONF;
$strRecoveryFile = $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'postgresql.auto.conf' : DB_FILE_RECOVERYCONF;
storageDb()->copy(
$oHostDbMaster->dbBasePath() . qw{/} . $strRecoveryFile, $self->testPath() . qw{/} . $strRecoveryFile);
@ -920,7 +921,8 @@ sub run
$oHostDbMaster->restore(
undef, $strFullBackup,
{bDelta => true, strType => CFGOPTVAL_RESTORE_TYPE_TIME, strTarget => $strTimeTarget,
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef});
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef,
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef});
$oHostDbMaster->clusterStart();
$oHostDbMaster->sqlSelectOneTest('select message from test', $strTimeMessage);
@ -936,7 +938,8 @@ sub run
$oHostDbMaster->restore(
undef, $strIncrBackup,
{bDelta => true, strType => CFGOPTVAL_RESTORE_TYPE_XID, strTarget => $strXidTarget, bTargetExclusive => true,
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef});
strTargetAction => $oHostDbMaster->pgVersion() >= PG_VERSION_91 ? 'promote' : undef,
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef});
$oHostDbMaster->clusterStart();
$oHostDbMaster->sqlSelectOneTest('select message from test', $strIncrMessage);
@ -953,7 +956,8 @@ sub run
$oHostDbMaster->restore(
undef, cfgDefOptionDefault(CFGCMD_RESTORE, CFGOPT_SET),
{bDelta => true, bForce => true, strType => CFGOPTVAL_RESTORE_TYPE_NAME, strTarget => $strNameTarget,
strTargetAction => 'promote'});
strTargetAction => 'promote',
strTargetTimeline => $oHostDbMaster->pgVersion() >= PG_VERSION_12 ? 'current' : undef});
$oHostDbMaster->clusterStart();
$oHostDbMaster->sqlSelectOneTest('select message from test', $strNameMessage);

View File

@ -1019,6 +1019,59 @@ testRun(void)
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_RECOVERYCONF_STR), NULL);
TEST_RESULT_VOID(restoreCleanBuild(manifest), "normal restore ignore recovery.conf");
TEST_RESULT_LOG(
"P00 DETAIL: check '{[path]}/pg' exists\n"
"P00 DETAIL: check '{[path]}/conf' exists\n"
"P00 DETAIL: create symlink '{[path]}/pg/pg_hba.conf' to '../conf/pg_hba.conf'");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("succeed when all directories empty and PG12 and preserve but no recovery files");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
manifest->data.pgVersion = PG_VERSION_12;
TEST_RESULT_VOID(restoreCleanBuild(manifest), "restore");
TEST_RESULT_LOG(
"P00 DETAIL: check '{[path]}/pg' exists\n"
"P00 DETAIL: check '{[path]}/conf' exists\n"
"P00 DETAIL: create symlink '{[path]}/pg/pg_hba.conf' to '../conf/pg_hba.conf'");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("succeed when all directories empty and ignore PG12 recovery files");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
manifestFileAdd(manifest, &(ManifestFile){.name = STRDEF(MANIFEST_TARGET_PGDATA "/" PG_FILE_POSTGRESQLAUTOCONF)});
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR), NULL);
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_RECOVERYSIGNAL_STR), NULL);
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_STANDBYSIGNAL_STR), NULL);
TEST_RESULT_VOID(restoreCleanBuild(manifest), "restore");
TEST_RESULT_LOG(
"P00 DETAIL: check '{[path]}/pg' exists\n"
"P00 DETAIL: check '{[path]}/conf' exists\n"
"P00 DETAIL: skip 'postgresql.auto.conf' -- recovery type is preserve\n"
"P00 DETAIL: create symlink '{[path]}/pg/pg_hba.conf' to '../conf/pg_hba.conf'");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("succeed when all directories empty and PG12");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAdd(argList, strNewFmt("--repo1-path=%s", strPtr(repoPath)));
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_VOID(restoreCleanBuild(manifest), "restore");
TEST_RESULT_LOG(
"P00 DETAIL: check '{[path]}/pg' exists\n"
"P00 DETAIL: check '{[path]}/conf' exists\n"
@ -1182,7 +1235,7 @@ testRun(void)
}
// *****************************************************************************************************************************
if (testBegin("restoreRecoveryConf()"))
if (testBegin("restoreRecoveryOption() and restoreRecoveryConf()"))
{
StringList *argBaseList = strLstNew();
strLstAddZ(argBaseList, "pgbackrest");
@ -1191,6 +1244,9 @@ testRun(void)
strLstAddZ(argBaseList, "--pg1-path=/pg");
strLstAddZ(argBaseList, "restore");
const String *restoreLabel = STRDEF("LABEL");
#define RECOVERY_SETTING_HEADER "# Recovery settings generated by pgBackRest restore on LABEL\n"
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("user-specified options");
@ -1200,7 +1256,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"a_setting = 'a'\n"
"b_setting = 'b'\n"
"restore_command = 'pgbackrest --pg1-path=/pg --repo1-path=/repo --stanza=test1 archive-get %f \"%p\"'\n",
@ -1214,7 +1271,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n",
"check recovery options");
@ -1226,7 +1284,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target = 'immediate'\n",
"check recovery options");
@ -1241,7 +1300,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target_time = 'TIME'\n"
"recovery_target_timeline = '3'\n",
@ -1257,7 +1317,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target_time = 'TIME'\n"
"recovery_target_inclusive = 'false'\n",
@ -1272,7 +1333,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target_name = 'NAME'\n",
"check recovery options");
@ -1286,14 +1348,15 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_95),
restoreRecoveryConf(PG_VERSION_95, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target = 'immediate'\n"
"recovery_target_action = 'shutdown'\n",
"check recovery options");
TEST_ERROR(
restoreRecoveryConf(PG_VERSION_94), OptionInvalidError,
restoreRecoveryConf(PG_VERSION_94, restoreLabel), OptionInvalidError,
"target-action=shutdown is only available in PostgreSQL >= 9.5");
// -------------------------------------------------------------------------------------------------------------------------
@ -1305,14 +1368,15 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"recovery_target = 'immediate'\n"
"pause_at_recovery_target = 'false'\n",
"check recovery options");
TEST_ERROR(
restoreRecoveryConf(PG_VERSION_90), OptionInvalidError,
restoreRecoveryConf(PG_VERSION_90, restoreLabel), OptionInvalidError,
"target-action option is only available in PostgreSQL >= 9.1");
// -------------------------------------------------------------------------------------------------------------------------
@ -1323,7 +1387,8 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"standby_mode = 'on'\n",
"check recovery options");
@ -1337,11 +1402,194 @@ testRun(void)
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_94),
restoreRecoveryConf(PG_VERSION_94, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n"
"standby_mode = 'on'\n"
"recovery_target_timeline = 'current'\n",
"check recovery options");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("recovery type = standby with recovery GUCs");
argList = strLstDup(argBaseList);
strLstAddZ(argList, "--type=standby");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_RESULT_STR_Z(
restoreRecoveryConf(PG_VERSION_12, restoreLabel),
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n",
"check recovery options");
}
// *****************************************************************************************************************************
if (testBegin("restoreRecoveryWrite*()"))
{
const String *pgPath = strNewFmt("%s/pg", testPath());
storagePathCreateP(storageTest, pgPath, .mode = 0700);
const String *restoreLabel = STRDEF("LABEL");
#define RECOVERY_SETTING_PREFIX "# Removed by pgBackRest restore on LABEL # "
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("error when standby_mode setting is present");
StringList *argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAddZ(argList, "--repo1-path=/repo");
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "--type=default");
strLstAddZ(argList, "--recovery-option=standby-mode=on");
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
TEST_ERROR(
restoreRecoveryWriteAutoConf(PG_VERSION_12, restoreLabel), OptionInvalidError,
"'standby_mode' setting is not valid for PostgreSQL >= 12\n"
"HINT: use --type=standby instead of --recovery-option=standby_mode=on.");
TEST_RESULT_LOG("P00 WARN: postgresql.auto.conf does not exist -- creating to contain recovery settings");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("PG12 restore missing postgresql.auto.conf");
argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAddZ(argList, "--repo1-path=/repo");
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "--type=none");
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
restoreRecoveryWriteAutoConf(PG_VERSION_12, restoreLabel);
TEST_RESULT_STR_Z(
strNewBuf(storageGetNP(storageNewReadNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR))),
"", "check postgresql.auto.conf");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_RECOVERYSIGNAL_STR), true, "recovery.signal exists");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_STANDBYSIGNAL_STR), false, "standby.signal missing");
TEST_RESULT_LOG(
"P00 WARN: postgresql.auto.conf does not exist -- creating to contain recovery settings\n"
"P00 INFO: write {[path]}/pg/postgresql.auto.conf");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("PG12 restore type none");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
storagePutNP(
storageNewWriteNP(storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR),
BUFSTRDEF(
"# DO NOT MODIFY\n"
"\t recovery_target_action='promote'\n\n"));
restoreRecoveryWriteAutoConf(PG_VERSION_12, restoreLabel);
TEST_RESULT_STR_Z(
strNewBuf(storageGetNP(storageNewReadNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR))),
"# DO NOT MODIFY\n"
RECOVERY_SETTING_PREFIX "\t recovery_target_action='promote'\n\n",
"check postgresql.auto.conf");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_RECOVERYSIGNAL_STR), true, "recovery.signal exists");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_STANDBYSIGNAL_STR), false, "standby.signal missing");
TEST_RESULT_LOG("P00 INFO: write updated {[path]}/pg/postgresql.auto.conf");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("PG12 restore type standby and remove existing recovery settings");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
storagePutNP(
storageNewWriteNP(storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR),
BUFSTRDEF(
"# DO NOT MODIFY\n"
"recovery_target_name\t='name'\n"
"recovery_target_inclusive = false\n"));
argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAddZ(argList, "--repo1-path=/repo");
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "--recovery-option=restore-command=my_restore_command");
strLstAddZ(argList, "--type=standby");
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
restoreRecoveryWriteAutoConf(PG_VERSION_12, restoreLabel);
TEST_RESULT_STR_Z(
strNewBuf(storageGetNP(storageNewReadNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR))),
"# DO NOT MODIFY\n"
RECOVERY_SETTING_PREFIX "recovery_target_name\t='name'\n"
RECOVERY_SETTING_PREFIX "recovery_target_inclusive = false\n"
"\n"
RECOVERY_SETTING_HEADER
"restore_command = 'my_restore_command'\n",
"check postgresql.auto.conf");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_RECOVERYSIGNAL_STR), true, "recovery.signal exists");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_STANDBYSIGNAL_STR), true, "standby.signal missing");
TEST_RESULT_LOG("P00 INFO: write updated {[path]}/pg/postgresql.auto.conf");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("PG12 restore type preserve");
Manifest *manifest = testManifestMinimal(STRDEF("20161219-212741F"), PG_VERSION_12, STRDEF("/pg"));
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR), BUFSTRDEF("# DO NOT MODIFY\n"));
storagePutNP(storageNewWriteNP(storagePgWrite(), PG_FILE_STANDBYSIGNAL_STR), NULL);
argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAddZ(argList, "--repo1-path=/repo");
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "--type=preserve");
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
restoreRecoveryWrite(manifest);
TEST_RESULT_STR_Z(
strNewBuf(storageGetNP(storageNewReadNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR))), "# DO NOT MODIFY\n",
"check postgresql.auto.conf");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_RECOVERYSIGNAL_STR), false, "recovery.signal missing");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_STANDBYSIGNAL_STR), true, "standby.signal exists");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("PG12 restore type default");
TEST_SYSTEM_FMT("rm -rf %s/*", strPtr(pgPath));
storagePutNP(
storageNewWriteNP(storagePgWrite(), PG_FILE_POSTGRESQLAUTOCONF_STR),
BUFSTRDEF("# DO NOT MODIFY\n"));
argList = strLstNew();
strLstAddZ(argList, "pgbackrest");
strLstAddZ(argList, "--stanza=test1");
strLstAddZ(argList, "--repo1-path=/repo");
strLstAdd(argList, strNewFmt("--pg1-path=%s", strPtr(pgPath)));
strLstAddZ(argList, "restore");
harnessCfgLoad(strLstSize(argList), strLstPtr(argList));
restoreRecoveryWrite(manifest);
TEST_RESULT_BOOL(
bufEq(storageGetNP(storageNewReadNP(storagePg(), PG_FILE_POSTGRESQLAUTOCONF_STR)), BUFSTRDEF("# DO NOT MODIFY\n")),
false, "check postgresql.auto.conf has changed");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_RECOVERYSIGNAL_STR), true, "recovery.signal exists");
TEST_RESULT_BOOL(storageExistsNP(storagePg(), PG_FILE_STANDBYSIGNAL_STR), false, "standby.signal missing");
TEST_RESULT_LOG("P00 INFO: write updated {[path]}/pg/postgresql.auto.conf");
}
// *****************************************************************************************************************************