You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-08-15 22:22:14 +03:00
The check command is implemented entirely in C.
Note that building the manifest on each host has been temporarily removed. This feature will likely be brought back as a non-default option (after the manifest code has been fully migrated to C) since it can be fairly expensive.
This commit is contained in:
committed by
David Steele
parent
ecae5e34e5
commit
a1c13a50dd
@@ -15,6 +15,14 @@
|
|||||||
<release date="XXXX-XX-XX" version="2.19dev" title="UNDER DEVELOPMENT">
|
<release date="XXXX-XX-XX" version="2.19dev" title="UNDER DEVELOPMENT">
|
||||||
<release-doc-list>
|
<release-doc-list>
|
||||||
<release-improvement-list>
|
<release-improvement-list>
|
||||||
|
<release-item>
|
||||||
|
<release-item-contributor-list>
|
||||||
|
<release-item-contributor id="cynthia.shang"/>
|
||||||
|
</release-item-contributor-list>
|
||||||
|
|
||||||
|
<p>The <cmd>check</cmd> command is implemented entirely in C.</p>
|
||||||
|
</release-item>
|
||||||
|
|
||||||
<release-item>
|
<release-item>
|
||||||
<release-item-contributor-list>
|
<release-item-contributor-list>
|
||||||
<release-item-contributor id="cynthia.shang"/>
|
<release-item-contributor id="cynthia.shang"/>
|
||||||
|
@@ -2786,7 +2786,7 @@
|
|||||||
|
|
||||||
<execute user="postgres" output="y">
|
<execute user="postgres" output="y">
|
||||||
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-log-level-console=info check</exe-cmd>
|
<exe-cmd>{[project-exe]} {[dash]}-stanza={[postgres-cluster-demo]} {[dash]}-log-level-console=info check</exe-cmd>
|
||||||
<exe-highlight>because no primary was found</exe-highlight>
|
<exe-highlight>because this is a standby</exe-highlight>
|
||||||
</execute>
|
</execute>
|
||||||
</execute-list>
|
</execute-list>
|
||||||
</section>
|
</section>
|
||||||
|
@@ -1,235 +0,0 @@
|
|||||||
####################################################################################################################################
|
|
||||||
# CHECK MODULE
|
|
||||||
####################################################################################################################################
|
|
||||||
package pgBackRest::Check::Check;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings FATAL => qw(all);
|
|
||||||
use Carp qw(confess);
|
|
||||||
use English '-no_match_vars';
|
|
||||||
|
|
||||||
use pgBackRest::Archive::Common;
|
|
||||||
use pgBackRest::Archive::Get::File;
|
|
||||||
use pgBackRest::Backup::Info;
|
|
||||||
use pgBackRest::Common::Exception;
|
|
||||||
use pgBackRest::Common::Log;
|
|
||||||
use pgBackRest::Common::Wait;
|
|
||||||
use pgBackRest::Config::Config;
|
|
||||||
use pgBackRest::Db;
|
|
||||||
use pgBackRest::Manifest;
|
|
||||||
use pgBackRest::Protocol::Helper;
|
|
||||||
use pgBackRest::Protocol::Storage::Helper;
|
|
||||||
|
|
||||||
####################################################################################################################################
|
|
||||||
# constructor
|
|
||||||
####################################################################################################################################
|
|
||||||
sub new
|
|
||||||
{
|
|
||||||
my $class = shift; # Class name
|
|
||||||
|
|
||||||
# Assign function parameters, defaults, and log debug info
|
|
||||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');
|
|
||||||
|
|
||||||
# Create the class hash
|
|
||||||
my $self = {};
|
|
||||||
bless $self, $class;
|
|
||||||
|
|
||||||
# Return from function and log return values if any
|
|
||||||
return logDebugReturn
|
|
||||||
(
|
|
||||||
$strOperation,
|
|
||||||
{name => 'self', value => $self}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
####################################################################################################################################
|
|
||||||
# process
|
|
||||||
#
|
|
||||||
# Validates the database configuration and checks that the archive logs can be read by backup. This will alert the user to any
|
|
||||||
# misconfiguration, particularly of archiving, that would result in the inability of a backup to complete (e.g waiting at the end
|
|
||||||
# until it times out because it could not find the WAL file).
|
|
||||||
####################################################################################################################################
|
|
||||||
sub process
|
|
||||||
{
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
# Assign function parameters, defaults, and log debug info
|
|
||||||
my $strOperation = logDebugParam(__PACKAGE__ . '->process');
|
|
||||||
|
|
||||||
# Initialize the local variables
|
|
||||||
my $iArchiveTimeout = cfgOption(CFGOPT_ARCHIVE_TIMEOUT);
|
|
||||||
|
|
||||||
my $iResult = 0;
|
|
||||||
my $strResultMessage = undef;
|
|
||||||
|
|
||||||
my $strArchiveId = undef;
|
|
||||||
my $strArchiveFile = undef;
|
|
||||||
my $strWalSegment = undef;
|
|
||||||
|
|
||||||
# Get the master database object to test to see if the manifest can be built
|
|
||||||
my ($oDb) = dbMasterGet();
|
|
||||||
|
|
||||||
# Get the database version to pass to the manifest constructor and the system-id in the event of a failure
|
|
||||||
my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info();
|
|
||||||
|
|
||||||
# Turn off console logging to control when to display the error
|
|
||||||
logLevelSet(undef, OFF);
|
|
||||||
|
|
||||||
# Loop through all defined databases and attempt to build a manifest
|
|
||||||
for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++)
|
|
||||||
{
|
|
||||||
# Make sure a db is defined for this index
|
|
||||||
if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) ||
|
|
||||||
cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)))
|
|
||||||
{
|
|
||||||
eval
|
|
||||||
{
|
|
||||||
# Passing file location dev/null so that the save will fail if it is ever attempted. Pass a miscellaneous value for
|
|
||||||
# encryption key since the file will not be saved.
|
|
||||||
my $oBackupManifest = new pgBackRest::Manifest("/dev/null/manifest.chk",
|
|
||||||
{bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion,
|
|
||||||
strCipherPass => 'x', strCipherPassSub => 'x'});
|
|
||||||
|
|
||||||
# Set required settings not set during manifest instantiation
|
|
||||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1);
|
|
||||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion);
|
|
||||||
$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);
|
|
||||||
|
|
||||||
$oBackupManifest->build(
|
|
||||||
storageDb({iRemoteIdx => $iRemoteIdx}), cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef,
|
|
||||||
cfgOptionValid(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE), false, $oDb->tablespaceMapGet());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
or do
|
|
||||||
{
|
|
||||||
# Capture error information
|
|
||||||
$strResultMessage = "Database: ${strDbVersion} ${ullDbSysId} " . exceptionMessage($EVAL_ERROR) .
|
|
||||||
(($iResult != 0) ? "\n[$iResult] : $strResultMessage" : "");
|
|
||||||
$iResult = exceptionCode($EVAL_ERROR);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reset the console logging
|
|
||||||
logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));
|
|
||||||
|
|
||||||
# If the manifest builds are ok, then proceed with the other checks
|
|
||||||
if ($iResult == 0)
|
|
||||||
{
|
|
||||||
# Reinitialize the database object in order to check the configured replicas. This will throw an error if at least one is not
|
|
||||||
# able to be connected to and warnings for any that cannot be properly connected to.
|
|
||||||
($oDb) = dbObjectGet();
|
|
||||||
|
|
||||||
# Validate the database configuration
|
|
||||||
$oDb->configValidate();
|
|
||||||
|
|
||||||
# Turn off console logging to control when to display the error
|
|
||||||
logLevelSet(undef, OFF);
|
|
||||||
|
|
||||||
# Check backup.info - if the archive check fails below (e.g --no-archive-check set) then at least know backup.info succeeded
|
|
||||||
eval
|
|
||||||
{
|
|
||||||
# Check that the backup info file is written and is valid for the current database of the stanza
|
|
||||||
$self->backupInfoCheck();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
# If there is an unhandled error then confess
|
|
||||||
or do
|
|
||||||
{
|
|
||||||
# Capture error information
|
|
||||||
$iResult = exceptionCode($EVAL_ERROR);
|
|
||||||
$strResultMessage = exceptionMessage($EVAL_ERROR);
|
|
||||||
};
|
|
||||||
|
|
||||||
# Check archive.info
|
|
||||||
if ($iResult == 0)
|
|
||||||
{
|
|
||||||
eval
|
|
||||||
{
|
|
||||||
# Check that the archive info file is written and is valid for the current database of the stanza
|
|
||||||
($strArchiveId) = archiveGetCheck();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
or do
|
|
||||||
{
|
|
||||||
# Capture error information
|
|
||||||
$iResult = exceptionCode($EVAL_ERROR);
|
|
||||||
$strResultMessage = exceptionMessage($EVAL_ERROR);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
# Reset the console logging
|
|
||||||
logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));
|
|
||||||
}
|
|
||||||
|
|
||||||
# Log the captured error
|
|
||||||
if ($iResult != 0)
|
|
||||||
{
|
|
||||||
&log(ERROR, $strResultMessage, $iResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return from function and log return values if any
|
|
||||||
return logDebugReturn
|
|
||||||
(
|
|
||||||
$strOperation,
|
|
||||||
{name => 'iResult', value => $iResult, trace => true}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
####################################################################################################################################
|
|
||||||
# backupInfoCheck
|
|
||||||
#
|
|
||||||
# Check the backup.info file, if it exists, to confirm the DB version, system-id, control and catalog numbers match the database.
|
|
||||||
####################################################################################################################################
|
|
||||||
sub backupInfoCheck
|
|
||||||
{
|
|
||||||
my $self = shift;
|
|
||||||
|
|
||||||
# Assign function parameters, defaults, and log debug info
|
|
||||||
my
|
|
||||||
(
|
|
||||||
$strOperation,
|
|
||||||
$strDbVersion,
|
|
||||||
$iControlVersion,
|
|
||||||
$iCatalogVersion,
|
|
||||||
$ullDbSysId,
|
|
||||||
) =
|
|
||||||
logDebugParam
|
|
||||||
(
|
|
||||||
__PACKAGE__ . '->backupInfoCheck', \@_,
|
|
||||||
{name => 'strDbVersion', required => false},
|
|
||||||
{name => 'iControlVersion', required => false},
|
|
||||||
{name => 'iCatalogVersion', required => false},
|
|
||||||
{name => 'ullDbSysId', required => false}
|
|
||||||
);
|
|
||||||
|
|
||||||
# If the db info are not passed, then we need to retrieve the database information
|
|
||||||
my $iDbHistoryId;
|
|
||||||
|
|
||||||
if (!defined($strDbVersion) || !defined($iControlVersion) || !defined($iCatalogVersion) || !defined($ullDbSysId))
|
|
||||||
{
|
|
||||||
# get DB info for comparison
|
|
||||||
($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isRepoLocal())
|
|
||||||
{
|
|
||||||
$iDbHistoryId = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(
|
|
||||||
OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$iDbHistoryId = (new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->check(
|
|
||||||
$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);
|
|
||||||
}
|
|
||||||
|
|
||||||
# Return from function and log return values if any
|
|
||||||
return logDebugReturn
|
|
||||||
(
|
|
||||||
$strOperation,
|
|
||||||
{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
@@ -106,17 +106,6 @@ sub main
|
|||||||
$oRemote->process(
|
$oRemote->process(
|
||||||
cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));
|
cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));
|
||||||
}
|
}
|
||||||
|
|
||||||
# Process check command
|
|
||||||
# --------------------------------------------------------------------------------------------------------------------------
|
|
||||||
elsif (cfgCommandTest(CFGCMD_CHECK))
|
|
||||||
{
|
|
||||||
# Load module dynamically
|
|
||||||
require pgBackRest::Check::Check;
|
|
||||||
pgBackRest::Check::Check->import();
|
|
||||||
|
|
||||||
$iResult = new pgBackRest::Check::Check()->process();
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
# Check that the repo path exists
|
# Check that the repo path exists
|
||||||
|
@@ -26,10 +26,6 @@ use constant OP_BACKUP_FILE => 'backupF
|
|||||||
use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';
|
use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';
|
||||||
push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);
|
push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);
|
||||||
|
|
||||||
# Check Module
|
|
||||||
use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck';
|
|
||||||
push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK);
|
|
||||||
|
|
||||||
# Db Module
|
# Db Module
|
||||||
use constant OP_DB_CONNECT => 'dbConnect';
|
use constant OP_DB_CONNECT => 'dbConnect';
|
||||||
push @EXPORT, qw(OP_DB_CONNECT);
|
push @EXPORT, qw(OP_DB_CONNECT);
|
||||||
|
@@ -15,7 +15,6 @@ use pgBackRest::Common::Log;
|
|||||||
use pgBackRest::Common::Io::Buffered;
|
use pgBackRest::Common::Io::Buffered;
|
||||||
use pgBackRest::Common::Wait;
|
use pgBackRest::Common::Wait;
|
||||||
use pgBackRest::Archive::Get::File;
|
use pgBackRest::Archive::Get::File;
|
||||||
use pgBackRest::Check::Check;
|
|
||||||
use pgBackRest::Config::Config;
|
use pgBackRest::Config::Config;
|
||||||
use pgBackRest::Db;
|
use pgBackRest::Db;
|
||||||
use pgBackRest::Protocol::Command::Minion;
|
use pgBackRest::Protocol::Command::Minion;
|
||||||
@@ -68,7 +67,6 @@ sub init
|
|||||||
# Create objects
|
# Create objects
|
||||||
my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();
|
my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();
|
||||||
|
|
||||||
my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;
|
|
||||||
my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;
|
my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;
|
||||||
|
|
||||||
# Create anonymous subs for each command
|
# Create anonymous subs for each command
|
||||||
@@ -77,9 +75,6 @@ sub init
|
|||||||
# ArchiveGet commands
|
# ArchiveGet commands
|
||||||
&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},
|
&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},
|
||||||
|
|
||||||
# Check commands
|
|
||||||
&OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck(@{shift()})},
|
|
||||||
|
|
||||||
# Db commands
|
# Db commands
|
||||||
&OP_DB_CONNECT => sub {$oDb->connect()},
|
&OP_DB_CONNECT => sub {$oDb->connect()},
|
||||||
&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},
|
&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},
|
||||||
|
@@ -246,10 +246,10 @@ command/backup/pageChecksum.o: command/backup/pageChecksum.c build.auto.h comman
|
|||||||
command/backup/protocol.o: command/backup/protocol.c build.auto.h command/backup/file.h command/backup/protocol.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/io.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h protocol/server.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/backup/protocol.o: command/backup/protocol.c build.auto.h command/backup/file.h command/backup/protocol.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/io/filter/filter.h common/io/filter/group.h common/io/io.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h protocol/server.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/backup/protocol.c -o command/backup/protocol.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/backup/protocol.c -o command/backup/protocol.o
|
||||||
|
|
||||||
command/check/check.o: command/check/check.c build.auto.h command/archive/common.h command/check/check.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoArchive.h info/infoPg.h postgres/client.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/check/check.o: command/check/check.c build.auto.h command/archive/common.h command/check/check.h command/check/common.h common/assert.h common/crypto/common.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoArchive.h info/infoPg.h postgres/client.h postgres/interface.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/check/check.c -o command/check/check.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/check/check.c -o command/check/check.o
|
||||||
|
|
||||||
command/check/common.o: command/check/common.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/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h postgres/client.h postgres/interface.h protocol/client.h protocol/command.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/check/common.o: command/check/common.c build.auto.h command/backup/common.h command/check/common.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.h postgres/interface.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h version.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/check/common.c -o command/check/common.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/check/common.c -o command/check/common.o
|
||||||
|
|
||||||
command/command.o: command/command.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/http/client.h common/io/http/header.h common/io/http/query.h common/io/read.h common/io/tls/client.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h version.h
|
command/command.o: command/command.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/http/client.h common/io/http/header.h common/io/http/query.h common/io/read.h common/io/tls/client.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h version.h
|
||||||
@@ -291,13 +291,13 @@ command/restore/restore.o: command/restore/restore.c build.auto.h command/backup
|
|||||||
command/stanza/common.o: command/stanza/common.c build.auto.h command/check/common.h common/assert.h common/crypto/common.h common/debug.h common/encode.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoPg.h postgres/client.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/stanza/common.o: command/stanza/common.c build.auto.h command/check/common.h common/assert.h common/crypto/common.h common/debug.h common/encode.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h db/helper.h info/info.h info/infoPg.h postgres/client.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/common.c -o command/stanza/common.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/common.c -o command/stanza/common.o
|
||||||
|
|
||||||
command/stanza/create.o: command/stanza/create.c build.auto.h command/backup/common.h command/control/common.h command/stanza/common.h command/stanza/create.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/stanza/create.o: command/stanza/create.c build.auto.h command/backup/common.h command/check/common.h command/control/common.h command/stanza/common.h command/stanza/create.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/create.c -o command/stanza/create.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/create.c -o command/stanza/create.o
|
||||||
|
|
||||||
command/stanza/delete.o: command/stanza/delete.c build.auto.h command/backup/common.h command/control/common.h command/stanza/delete.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/interface.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/stanza/delete.o: command/stanza/delete.c build.auto.h command/backup/common.h command/control/common.h command/stanza/delete.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/interface.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/delete.c -o command/stanza/delete.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/delete.c -o command/stanza/delete.o
|
||||||
|
|
||||||
command/stanza/upgrade.o: command/stanza/upgrade.c build.auto.h command/backup/common.h command/control/common.h command/stanza/common.h command/stanza/upgrade.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/stanza/upgrade.o: command/stanza/upgrade.c build.auto.h command/backup/common.h command/check/common.h command/control/common.h command/stanza/common.h command/stanza/upgrade.h common/assert.h common/crypto/common.h common/crypto/hash.h common/debug.h common/error.auto.h common/error.h common/ini.h common/io/filter/filter.h common/io/filter/group.h common/io/read.h common/io/write.h common/lock.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 config/config.auto.h config/config.h config/define.auto.h config/define.h db/db.h info/info.h info/infoArchive.h info/infoBackup.h info/infoPg.h info/manifest.h postgres/client.h postgres/interface.h postgres/version.h protocol/client.h protocol/command.h protocol/helper.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/upgrade.c -o command/stanza/upgrade.o
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(CMAKE) -c command/stanza/upgrade.c -o command/stanza/upgrade.o
|
||||||
|
|
||||||
command/storage/list.o: command/storage/list.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/handleWrite.h common/io/read.h common/io/write.h common/lock.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/json.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 config/config.auto.h config/config.h config/define.auto.h config/define.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
command/storage/list.o: command/storage/list.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/handleWrite.h common/io/read.h common/io/write.h common/lock.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/json.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 config/config.auto.h config/config.h config/define.auto.h config/define.h storage/helper.h storage/info.h storage/read.h storage/storage.h storage/write.h
|
||||||
|
@@ -5,14 +5,157 @@ Check Command
|
|||||||
|
|
||||||
#include "command/archive/common.h"
|
#include "command/archive/common.h"
|
||||||
#include "command/check/check.h"
|
#include "command/check/check.h"
|
||||||
|
#include "command/check/common.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/log.h"
|
#include "common/log.h"
|
||||||
#include "common/memContext.h"
|
#include "common/memContext.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "db/helper.h"
|
#include "db/helper.h"
|
||||||
#include "info/infoArchive.h"
|
#include "info/infoArchive.h"
|
||||||
|
#include "postgres/interface.h"
|
||||||
|
#include "protocol/helper.h"
|
||||||
#include "storage/helper.h"
|
#include "storage/helper.h"
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Helper functions (to assist with testing)
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
static unsigned int
|
||||||
|
checkManifest(void)
|
||||||
|
{
|
||||||
|
FUNCTION_LOG_VOID(logLevelTrace);
|
||||||
|
|
||||||
|
// Return the actual number of pg* defined
|
||||||
|
unsigned int result = 0;
|
||||||
|
|
||||||
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
// Loop through all defined databases and attempt to build a manifest
|
||||||
|
for (unsigned int pgIdx = 0; pgIdx < cfgOptionIndexTotal(cfgOptPgPath); pgIdx++)
|
||||||
|
{
|
||||||
|
if (cfgOptionTest(cfgOptPgHost + pgIdx) || cfgOptionTest(cfgOptPgPath + pgIdx))
|
||||||
|
{
|
||||||
|
result++;
|
||||||
|
// ??? Placeholder for manifest build
|
||||||
|
storageListNP(storagePgId(pgIdx + 1), varStr(cfgOption(cfgOptPgPath + pgIdx)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
FUNCTION_LOG_RETURN(UINT, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
checkStandby(const DbGetResult dbGroup, unsigned int pgPathDefinedTotal)
|
||||||
|
{
|
||||||
|
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||||
|
FUNCTION_LOG_PARAM(DB_GET_RESULT, dbGroup);
|
||||||
|
FUNCTION_LOG_PARAM(UINT, pgPathDefinedTotal);
|
||||||
|
FUNCTION_LOG_END();
|
||||||
|
|
||||||
|
// If a standby is defined, check the configuration
|
||||||
|
if (dbGroup.standby != NULL)
|
||||||
|
{
|
||||||
|
// If primary was not found
|
||||||
|
if (dbGroup.primary == NULL)
|
||||||
|
{
|
||||||
|
// If the repo is local or more than one pg-path is found then a master should have been found so error
|
||||||
|
if (repoIsLocal() || pgPathDefinedTotal > 1)
|
||||||
|
{
|
||||||
|
THROW(
|
||||||
|
ConfigError,
|
||||||
|
"primary database not found\n"
|
||||||
|
"HINT: check indexed pg-path/pg-host configurations");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the standby database config
|
||||||
|
PgControl pgControl = pgControlFromFile(storagePgId(dbGroup.standbyId));
|
||||||
|
|
||||||
|
// Check the user configured path and version against the database
|
||||||
|
checkDbConfig(pgControl.version, dbGroup.standbyId, dbGroup.standby, true);
|
||||||
|
|
||||||
|
// Get the repo storage in case it is remote and encryption settings need to be pulled down (performed here for testing)
|
||||||
|
storageRepo();
|
||||||
|
|
||||||
|
// Check that the backup and archive info files exist and are valid for the current database of the stanza
|
||||||
|
checkStanzaInfoPg(
|
||||||
|
storageRepo(), pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
|
|
||||||
|
LOG_INFO("switch wal not performed because this is a standby");
|
||||||
|
|
||||||
|
// Free the standby connection
|
||||||
|
dbFree(dbGroup.standby);
|
||||||
|
}
|
||||||
|
// If backup from standby is true then warn when a standby not found
|
||||||
|
else if (cfgOptionBool(cfgOptBackupStandby))
|
||||||
|
{
|
||||||
|
LOG_WARN("option '%s' is enabled but standby is not properly configured", cfgOptionName(cfgOptBackupStandby));
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION_LOG_RETURN_VOID();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
checkPrimary(const DbGetResult dbGroup)
|
||||||
|
{
|
||||||
|
FUNCTION_LOG_BEGIN(logLevelDebug);
|
||||||
|
FUNCTION_LOG_PARAM(DB_GET_RESULT, dbGroup);
|
||||||
|
FUNCTION_LOG_END();
|
||||||
|
|
||||||
|
// If a primary is defined, check the configuration and perform a WAL switch and make sure the WAL is archived
|
||||||
|
if (dbGroup.primary != NULL)
|
||||||
|
{
|
||||||
|
// Validate the primary database config
|
||||||
|
PgControl pgControl = pgControlFromFile(storagePgId(dbGroup.primaryId));
|
||||||
|
|
||||||
|
// Check the user configured path and version against the database
|
||||||
|
checkDbConfig(pgControl.version, dbGroup.primaryId, dbGroup.primary, false);
|
||||||
|
|
||||||
|
// Get the repo storage in case it is remote and encryption settings need to be pulled down (performed here for testing)
|
||||||
|
storageRepo();
|
||||||
|
|
||||||
|
// Check that the backup and archive info files exist and are valid for the current database of the stanza
|
||||||
|
checkStanzaInfoPg(
|
||||||
|
storageRepo(), pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
|
|
||||||
|
// Attempt to load the archive info file and retrieve the archiveId
|
||||||
|
InfoArchive *archiveInfo = infoArchiveLoadFile(
|
||||||
|
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
|
const String *archiveId = infoArchiveId(archiveInfo);
|
||||||
|
|
||||||
|
// Perform a WAL switch
|
||||||
|
const String *walSegment = dbWalSwitch(dbGroup.primary);
|
||||||
|
dbFree(dbGroup.primary);
|
||||||
|
|
||||||
|
// Wait for the WAL to appear in the repo
|
||||||
|
TimeMSec archiveTimeout = (TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC);
|
||||||
|
const String *walSegmentFile = walSegmentFind(storageRepo(), archiveId, walSegment, archiveTimeout);
|
||||||
|
|
||||||
|
if (walSegmentFile != NULL)
|
||||||
|
{
|
||||||
|
LOG_INFO(
|
||||||
|
"WAL segment %s successfully archived to '%s'", strPtr(walSegment),
|
||||||
|
strPtr(storagePath(storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId),
|
||||||
|
strPtr(walSegmentFile)))));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
THROW_FMT(
|
||||||
|
ArchiveTimeoutError,
|
||||||
|
"WAL segment %s was not archived before the %" PRIu64 "ms timeout\n"
|
||||||
|
"HINT: check the archive_command to ensure that all options are correct (especially --stanza).\n"
|
||||||
|
"HINT: check the PostgreSQL server log for errors.",
|
||||||
|
strPtr(walSegment), archiveTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION_LOG_RETURN_VOID();
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Perform standard checks
|
Perform standard checks
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
@@ -23,53 +166,15 @@ cmdCheck(void)
|
|||||||
|
|
||||||
MEM_CONTEXT_TEMP_BEGIN()
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
{
|
{
|
||||||
// Get the repo storage in case it is remote and encryption settings need to be pulled down
|
|
||||||
storageRepo();
|
|
||||||
|
|
||||||
// Attempt to load the archive info file
|
|
||||||
InfoArchive *archiveInfo = infoArchiveLoadFile(
|
|
||||||
storageRepo(), INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
|
||||||
cfgOptionStr(cfgOptRepoCipherPass));
|
|
||||||
const String *archiveId = infoArchiveId(archiveInfo);
|
|
||||||
|
|
||||||
// Get the primary/standby connections (standby is only required if backup from standby is enabled)
|
// Get the primary/standby connections (standby is only required if backup from standby is enabled)
|
||||||
DbGetResult dbGroup = dbGet(false, false);
|
DbGetResult dbGroup = dbGet(false, false);
|
||||||
|
|
||||||
// Free the standby connection immediately since we don't need it for anything
|
if (dbGroup.standby == NULL && dbGroup.primary == NULL)
|
||||||
dbFree(dbGroup.standby);
|
THROW(ConfigError, "no database found\nHINT: check indexed pg-path/pg-host configurations");
|
||||||
|
|
||||||
// Perform a WAL switch and make sure the WAL is archived if a primary was found
|
|
||||||
if (dbGroup.primary != NULL)
|
|
||||||
{
|
|
||||||
// Perform WAL switch
|
|
||||||
const String *walSegment = dbWalSwitch(dbGroup.primary);
|
|
||||||
dbFree(dbGroup.primary);
|
|
||||||
|
|
||||||
// Wait for the WAL to appear in the repo
|
|
||||||
TimeMSec archiveTimeout = (TimeMSec)(cfgOptionDbl(cfgOptArchiveTimeout) * MSEC_PER_SEC);
|
|
||||||
const String *walSegmentFile = walSegmentFind(storageRepo(), archiveId, walSegment, archiveTimeout);
|
|
||||||
|
|
||||||
if (walSegmentFile != NULL)
|
|
||||||
{
|
|
||||||
LOG_INFO(
|
|
||||||
"WAL segment %s successfully archived to '%s'", strPtr(walSegment),
|
|
||||||
strPtr(
|
|
||||||
storagePath(
|
|
||||||
storageRepo(), strNewFmt(STORAGE_REPO_ARCHIVE "/%s/%s", strPtr(archiveId), strPtr(walSegmentFile)))));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
THROW_FMT(
|
|
||||||
ArchiveTimeoutError,
|
|
||||||
"WAL segment %s was not archived before the %" PRIu64 "ms timeout\n"
|
|
||||||
"HINT: check the archive_command to ensure that all options are correct (especially --stanza).\n"
|
|
||||||
"HINT: check the PostgreSQL server log for errors.",
|
|
||||||
strPtr(walSegment), archiveTimeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
LOG_INFO("switch wal not performed because no primary was found");
|
|
||||||
|
|
||||||
|
unsigned int pgPathDefinedTotal = checkManifest();
|
||||||
|
checkStandby(dbGroup, pgPathDefinedTotal);
|
||||||
|
checkPrimary(dbGroup);
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_TEMP_END();
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
@@ -3,39 +3,167 @@ Check Common Handler
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#include "build.auto.h"
|
#include "build.auto.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "command/check/common.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "config/config.h"
|
#include "config/config.h"
|
||||||
#include "db/db.h"
|
|
||||||
#include "db/helper.h"
|
#include "db/helper.h"
|
||||||
|
#include "info/infoArchive.h"
|
||||||
|
#include "info/infoBackup.h"
|
||||||
#include "postgres/interface.h"
|
#include "postgres/interface.h"
|
||||||
|
#include "storage/helper.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Helper function
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
static bool
|
||||||
|
checkArchiveCommand(const String *archiveCommand)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM(STRING, archiveCommand);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
bool result = archiveCommand != NULL;
|
||||||
|
|
||||||
|
if (result && strstr(strPtr(archiveCommand), PROJECT_BIN) == NULL)
|
||||||
|
result = false;
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
THROW_FMT(
|
||||||
|
ArchiveCommandInvalidError, "archive_command '%s' must contain %s", (archiveCommand != NULL ? strPtr(archiveCommand)
|
||||||
|
: "[null]"), PROJECT_BIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Check the database path and version are configured correctly
|
Check the database path and version are configured correctly
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
void
|
void
|
||||||
checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const unsigned int dbVersion, const String *dbPath)
|
checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const Db *dbObject, bool isStandby)
|
||||||
{
|
{
|
||||||
FUNCTION_TEST_BEGIN();
|
FUNCTION_TEST_BEGIN();
|
||||||
FUNCTION_TEST_PARAM(UINT, pgVersion);
|
FUNCTION_TEST_PARAM(UINT, pgVersion);
|
||||||
FUNCTION_TEST_PARAM(UINT, dbIdx);
|
FUNCTION_TEST_PARAM(UINT, dbIdx);
|
||||||
FUNCTION_TEST_PARAM(UINT, dbVersion);
|
FUNCTION_TEST_PARAM(DB, dbObject);
|
||||||
FUNCTION_TEST_PARAM(STRING, dbPath);
|
FUNCTION_TEST_PARAM(BOOL, isStandby);
|
||||||
FUNCTION_TEST_END();
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
ASSERT(dbIdx > 0);
|
ASSERT(dbIdx > 0);
|
||||||
ASSERT(dbPath != NULL);
|
ASSERT(dbObject != NULL);
|
||||||
|
|
||||||
unsigned int pgPath = cfgOptPgPath + (dbIdx - 1);
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
unsigned int dbVersion = dbPgVersion(dbObject);
|
||||||
|
const String *dbPath = dbPgDataPath(dbObject);
|
||||||
|
unsigned int pgPath = cfgOptPgPath + (dbIdx - 1);
|
||||||
|
|
||||||
// Error if the version from the control file and the configured pg-path do not match the values obtained from the database
|
// Error if the version from the control file and the configured pg-path do not match the values obtained from the database
|
||||||
if (pgVersion != dbVersion || strCmp(cfgOptionStr(pgPath), dbPath) != 0)
|
if (pgVersion != dbVersion || strCmp(cfgOptionStr(pgPath), dbPath) != 0)
|
||||||
|
{
|
||||||
|
THROW_FMT(
|
||||||
|
DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/"
|
||||||
|
PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\nHINT: the %s and %s settings likely reference different clusters.",
|
||||||
|
strPtr(pgVersionToStr(dbVersion)), strPtr(dbPath), strPtr(pgVersionToStr(pgVersion)), strPtr(cfgOptionStr(pgPath)),
|
||||||
|
strPtr(cfgOptionStr(pgPath)), cfgOptionName(pgPath), cfgOptionName(cfgOptPgPort + (dbIdx - 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check archive configuration if option is valid for the command and set
|
||||||
|
if (!isStandby && cfgOptionValid(cfgOptArchiveCheck) && cfgOptionBool(cfgOptArchiveCheck))
|
||||||
|
{
|
||||||
|
// Error if archive_mode = off since pg_start_backup () will fail
|
||||||
|
if (strCmpZ(dbArchiveMode(dbObject), "off") == 0)
|
||||||
|
{
|
||||||
|
THROW(ArchiveDisabledError, "archive_mode must be enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error if archive_mode = always (support has not been added yet)
|
||||||
|
if (strCmpZ(dbArchiveMode(dbObject), "always") == 0)
|
||||||
|
{
|
||||||
|
THROW(FeatureNotSupportedError, "archive_mode=always not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if archive_command is set and is valid
|
||||||
|
checkArchiveCommand(dbArchiveCommand(dbObject));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Validate the archive and backup info files
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
void
|
||||||
|
checkStanzaInfo(const InfoPgData *archiveInfo, const InfoPgData *backupInfo)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, archiveInfo);
|
||||||
|
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, backupInfo);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
ASSERT(archiveInfo != NULL);
|
||||||
|
ASSERT(backupInfo != NULL);
|
||||||
|
|
||||||
|
// Error if there is a mismatch between the archive and backup info files
|
||||||
|
if (archiveInfo->id != backupInfo->id || archiveInfo->systemId != backupInfo->systemId ||
|
||||||
|
archiveInfo->version != backupInfo->version)
|
||||||
{
|
{
|
||||||
THROW_FMT(
|
THROW_FMT(
|
||||||
DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/"
|
FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\nHINT: the %s and %s settings likely reference different clusters.",
|
"archive: id = %u, version = %s, system-id = %" PRIu64 "\n"
|
||||||
strPtr(pgVersionToStr(dbVersion)), strPtr(dbPath), strPtr(pgVersionToStr(pgVersion)), strPtr(cfgOptionStr(pgPath)),
|
"backup : id = %u, version = %s, system-id = %" PRIu64 "\n"
|
||||||
strPtr(cfgOptionStr(pgPath)), cfgOptionName(pgPath), cfgOptionName(cfgOptPgPort + (dbIdx - 1)));
|
"HINT: this may be a symptom of repository corruption!",
|
||||||
|
archiveInfo->id, strPtr(pgVersionToStr(archiveInfo->version)), archiveInfo->systemId, backupInfo->id,
|
||||||
|
strPtr(pgVersionToStr(backupInfo->version)), backupInfo->systemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Load and validate the database data of the info files against each other and the current database
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
void
|
||||||
|
checkStanzaInfoPg(
|
||||||
|
const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, CipherType cipherType,
|
||||||
|
const String *cipherPass)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_LOG_PARAM(STORAGE, storage);
|
||||||
|
FUNCTION_LOG_PARAM(UINT, pgVersion);
|
||||||
|
FUNCTION_LOG_PARAM(UINT64, pgSystemId);
|
||||||
|
FUNCTION_LOG_PARAM(ENUM, cipherType);
|
||||||
|
FUNCTION_TEST_PARAM(STRING, cipherPass);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
ASSERT(storage != NULL);
|
||||||
|
|
||||||
|
MEM_CONTEXT_TEMP_BEGIN()
|
||||||
|
{
|
||||||
|
// Check that the backup and archive info files exist
|
||||||
|
InfoArchive *infoArchive = infoArchiveLoadFile(storage, INFO_ARCHIVE_PATH_FILE_STR, cipherType, cipherPass);
|
||||||
|
InfoPgData archiveInfoPg = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
||||||
|
InfoBackup *infoBackup = infoBackupLoadFile(storage, INFO_BACKUP_PATH_FILE_STR, cipherType, cipherPass);
|
||||||
|
InfoPgData backupInfoPg = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
||||||
|
|
||||||
|
// Check that the info files pg data match each other
|
||||||
|
checkStanzaInfo(&archiveInfoPg, &backupInfoPg);
|
||||||
|
|
||||||
|
// Check that the version and system id match the current database
|
||||||
|
if (pgVersion != archiveInfoPg.version || pgSystemId != archiveInfoPg.systemId)
|
||||||
|
{
|
||||||
|
THROW(FileInvalidError, "backup and archive info files exist but do not match the database\n"
|
||||||
|
"HINT: is this the correct stanza?\n"
|
||||||
|
"HINT: did an error occur during stanza-upgrade?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MEM_CONTEXT_TEMP_END();
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN_VOID();
|
||||||
|
}
|
||||||
|
@@ -5,10 +5,16 @@ Check Command Common
|
|||||||
#define COMMAND_CHECK_COMMON_H
|
#define COMMAND_CHECK_COMMON_H
|
||||||
|
|
||||||
#include "common/type/string.h"
|
#include "common/type/string.h"
|
||||||
|
#include "db/db.h"
|
||||||
|
#include "info/infoPg.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
void checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const unsigned int dbVersion, const String *dbPath);
|
void checkDbConfig(const unsigned int pgVersion, const unsigned int dbIdx, const Db *dbObject, bool isStandby);
|
||||||
|
void checkStanzaInfo(const InfoPgData *archiveInfo, const InfoPgData *backupInfo);
|
||||||
|
void checkStanzaInfoPg(
|
||||||
|
const Storage *storage, const unsigned int pgVersion, const uint64_t pgSystemId, CipherType cipherType,
|
||||||
|
const String *cipherPass);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -38,36 +38,6 @@ cipherPassGen(CipherType cipherType)
|
|||||||
FUNCTION_TEST_RETURN(result);
|
FUNCTION_TEST_RETURN(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
|
||||||
Validate the archive and backup info files
|
|
||||||
***********************************************************************************************************************************/
|
|
||||||
void
|
|
||||||
infoValidate(const InfoPgData *archiveInfo, const InfoPgData *backupInfo)
|
|
||||||
{
|
|
||||||
FUNCTION_TEST_BEGIN();
|
|
||||||
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, archiveInfo);
|
|
||||||
FUNCTION_TEST_PARAM_P(INFO_PG_DATA, backupInfo);
|
|
||||||
FUNCTION_TEST_END();
|
|
||||||
|
|
||||||
ASSERT(archiveInfo != NULL);
|
|
||||||
ASSERT(backupInfo != NULL);
|
|
||||||
|
|
||||||
// Error if there is a mismatch between the archive and backup info files
|
|
||||||
if (archiveInfo->id != backupInfo->id || archiveInfo->systemId != backupInfo->systemId ||
|
|
||||||
archiveInfo->version != backupInfo->version)
|
|
||||||
{
|
|
||||||
THROW_FMT(
|
|
||||||
FileInvalidError, "backup info file and archive info file do not match\n"
|
|
||||||
"archive: id = %u, version = %s, system-id = %" PRIu64 "\n"
|
|
||||||
"backup : id = %u, version = %s, system-id = %" PRIu64 "\n"
|
|
||||||
"HINT: this may be a symptom of repository corruption!",
|
|
||||||
archiveInfo->id, strPtr(pgVersionToStr(archiveInfo->version)), archiveInfo->systemId, backupInfo->id,
|
|
||||||
strPtr(pgVersionToStr(backupInfo->version)), backupInfo->systemId);
|
|
||||||
}
|
|
||||||
|
|
||||||
FUNCTION_TEST_RETURN_VOID();
|
|
||||||
}
|
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Validate and return database information
|
Validate and return database information
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
@@ -89,7 +59,7 @@ pgValidate(void)
|
|||||||
result = pgControlFromFile(storagePgId(dbObject.primaryId));
|
result = pgControlFromFile(storagePgId(dbObject.primaryId));
|
||||||
|
|
||||||
// Check the user configured path and version against the database
|
// Check the user configured path and version against the database
|
||||||
checkDbConfig(result.version, dbObject.primaryId, dbPgVersion(dbObject.primary), dbPgDataPath(dbObject.primary));
|
checkDbConfig(result.version, dbObject.primaryId, dbObject.primary, false);
|
||||||
}
|
}
|
||||||
// If the database is not online, assume that pg1 is the master
|
// If the database is not online, assume that pg1 is the master
|
||||||
else
|
else
|
||||||
|
@@ -11,7 +11,6 @@ Stanza Commands Handler
|
|||||||
Functions
|
Functions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
String *cipherPassGen(CipherType cipherType);
|
String *cipherPassGen(CipherType cipherType);
|
||||||
void infoValidate(const InfoPgData *archiveInfo, const InfoPgData *backupInfo);
|
|
||||||
PgControl pgValidate(void);
|
PgControl pgValidate(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -7,6 +7,7 @@ Stanza Create Command
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "command/check/common.h"
|
||||||
#include "command/control/common.h"
|
#include "command/control/common.h"
|
||||||
#include "command/stanza/common.h"
|
#include "command/stanza/common.h"
|
||||||
#include "command/stanza/create.h"
|
#include "command/stanza/create.h"
|
||||||
@@ -74,6 +75,7 @@ cmdStanzaCreate(void)
|
|||||||
|
|
||||||
// Create and save archive info
|
// Create and save archive info
|
||||||
infoArchive = infoArchiveNew(pgControl.version, pgControl.systemId, cipherPassSub);
|
infoArchive = infoArchiveNew(pgControl.version, pgControl.systemId, cipherPassSub);
|
||||||
|
|
||||||
infoArchiveSaveFile(
|
infoArchiveSaveFile(
|
||||||
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
infoArchive, storageRepoWriteStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
cfgOptionStr(cfgOptRepoCipherPass));
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
@@ -83,6 +85,7 @@ cmdStanzaCreate(void)
|
|||||||
|
|
||||||
// Create and save backup info
|
// Create and save backup info
|
||||||
infoBackup = infoBackupNew(pgControl.version, pgControl.systemId, cipherPassSub);
|
infoBackup = infoBackupNew(pgControl.version, pgControl.systemId, cipherPassSub);
|
||||||
|
|
||||||
infoBackupSaveFile(
|
infoBackupSaveFile(
|
||||||
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
infoBackup, storageRepoWriteStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
cfgOptionStr(cfgOptRepoCipherPass));
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
@@ -90,59 +93,41 @@ cmdStanzaCreate(void)
|
|||||||
// Else if at least one archive and one backup info file exists, then ensure both are valid
|
// Else if at least one archive and one backup info file exists, then ensure both are valid
|
||||||
else if ((archiveInfoFileExists || archiveInfoFileCopyExists) && (backupInfoFileExists || backupInfoFileCopyExists))
|
else if ((archiveInfoFileExists || archiveInfoFileCopyExists) && (backupInfoFileExists || backupInfoFileCopyExists))
|
||||||
{
|
{
|
||||||
infoArchive = infoArchiveLoadFile(
|
// Error if there is a mismatch between the archive and backup info files or the database version/system Id matches
|
||||||
storageRepoReadStanza, INFO_ARCHIVE_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
// current database
|
||||||
|
checkStanzaInfoPg(
|
||||||
|
storageRepoReadStanza, pgControl.version, pgControl.systemId, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
cfgOptionStr(cfgOptRepoCipherPass));
|
cfgOptionStr(cfgOptRepoCipherPass));
|
||||||
InfoPgData archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
|
||||||
|
|
||||||
infoBackup = infoBackupLoadFile(
|
// The files are valid - upgrade
|
||||||
storageRepoReadStanza, INFO_BACKUP_PATH_FILE_STR, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
const String *sourceFile = NULL;
|
||||||
cfgOptionStr(cfgOptRepoCipherPass));
|
const String *destinationFile = NULL;
|
||||||
InfoPgData backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
|
||||||
|
|
||||||
// Error if there is a mismatch between the archive and backup info files
|
// If the existing files are valid, then, if a file is missing, copy the existing one to the missing one to ensure
|
||||||
infoValidate(&archiveInfo, &backupInfo);
|
// there is both a .info and .info.copy
|
||||||
|
if (!archiveInfoFileExists || !archiveInfoFileCopyExists)
|
||||||
// The archive and backup info files match so check if the versions or system ids match the current database,
|
|
||||||
// if not, then an upgrade may be necessary
|
|
||||||
if (pgControl.version != archiveInfo.version || pgControl.systemId != archiveInfo.systemId)
|
|
||||||
{
|
{
|
||||||
THROW(FileInvalidError, "backup and archive info files already exist but do not match the database\n"
|
sourceFile = archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
|
||||||
"HINT: is this the correct stanza?\n"
|
destinationFile = !archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
|
||||||
"HINT: did an error occur during stanza-upgrade?");
|
|
||||||
|
storageCopyNP(
|
||||||
|
storageNewReadNP(storageRepoReadStanza, sourceFile),
|
||||||
|
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
|
||||||
}
|
}
|
||||||
// Else the files are valid
|
|
||||||
else
|
if (!backupInfoFileExists || !backupInfoFileCopyExists)
|
||||||
{
|
{
|
||||||
const String *sourceFile = NULL;
|
sourceFile = backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
|
||||||
const String *destinationFile = NULL;
|
destinationFile = !backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
|
||||||
|
|
||||||
// If the existing files are valid, then, if a file is missing, copy the existing one to the missing one to ensure
|
storageCopyNP(
|
||||||
// there is both a .info and .info.copy
|
storageNewReadNP(storageRepoReadStanza, sourceFile),
|
||||||
if (!archiveInfoFileExists || !archiveInfoFileCopyExists)
|
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
|
||||||
{
|
|
||||||
sourceFile = archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
|
|
||||||
destinationFile = !archiveInfoFileExists ? INFO_ARCHIVE_PATH_FILE_STR : INFO_ARCHIVE_PATH_FILE_COPY_STR;
|
|
||||||
|
|
||||||
storageCopyNP(
|
|
||||||
storageNewReadNP(storageRepoReadStanza, sourceFile),
|
|
||||||
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!backupInfoFileExists || !backupInfoFileCopyExists)
|
|
||||||
{
|
|
||||||
sourceFile = backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
|
|
||||||
destinationFile = !backupInfoFileExists ? INFO_BACKUP_PATH_FILE_STR : INFO_BACKUP_PATH_FILE_COPY_STR;
|
|
||||||
|
|
||||||
storageCopyNP(
|
|
||||||
storageNewReadNP(storageRepoReadStanza, sourceFile),
|
|
||||||
storageNewWriteNP(storageRepoWriteStanza, destinationFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no files copied, then the stanza was already valid
|
|
||||||
if (sourceFile == NULL)
|
|
||||||
LOG_INFO("stanza '%s' already exists and is valid", strPtr(cfgOptionStr(cfgOptStanza)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If no files copied, then the stanza was already valid
|
||||||
|
if (sourceFile == NULL)
|
||||||
|
LOG_INFO("stanza '%s' already exists and is valid", strPtr(cfgOptionStr(cfgOptStanza)));
|
||||||
}
|
}
|
||||||
// Else if both .info and corresponding .copy file are missing for one but not the other, then error
|
// Else if both .info and corresponding .copy file are missing for one but not the other, then error
|
||||||
else
|
else
|
||||||
|
@@ -7,6 +7,7 @@ Stanza Update Command
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include "command/check/common.h"
|
||||||
#include "command/control/common.h"
|
#include "command/control/common.h"
|
||||||
#include "command/stanza/common.h"
|
#include "command/stanza/common.h"
|
||||||
#include "command/stanza/upgrade.h"
|
#include "command/stanza/upgrade.h"
|
||||||
@@ -74,7 +75,7 @@ cmdStanzaUpgrade(void)
|
|||||||
// needed to be updated)
|
// needed to be updated)
|
||||||
backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
backupInfo = infoPgData(infoBackupPg(infoBackup), infoPgDataCurrentId(infoBackupPg(infoBackup)));
|
||||||
archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
archiveInfo = infoPgData(infoArchivePg(infoArchive), infoPgDataCurrentId(infoArchivePg(infoArchive)));
|
||||||
infoValidate(&archiveInfo, &backupInfo);
|
checkStanzaInfo(&archiveInfo, &backupInfo);
|
||||||
|
|
||||||
// Save archive info
|
// Save archive info
|
||||||
if (infoArchiveUpgrade)
|
if (infoArchiveUpgrade)
|
||||||
|
42
src/db/db.c
42
src/db/db.c
@@ -26,6 +26,8 @@ struct Db
|
|||||||
|
|
||||||
unsigned int pgVersion; // Version as reported by the database
|
unsigned int pgVersion; // Version as reported by the database
|
||||||
const String *pgDataPath; // Data directory reported by the database
|
const String *pgDataPath; // Data directory reported by the database
|
||||||
|
const String *archiveMode; // The archive_mode reported by the database
|
||||||
|
const String *archiveCommand; // The archive_command reported by the database
|
||||||
};
|
};
|
||||||
|
|
||||||
OBJECT_DEFINE_MOVE(DB);
|
OBJECT_DEFINE_MOVE(DB);
|
||||||
@@ -203,17 +205,21 @@ dbOpen(Db *this)
|
|||||||
this,
|
this,
|
||||||
STRDEF(
|
STRDEF(
|
||||||
"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4,"
|
"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4,"
|
||||||
" (select setting from pg_catalog.pg_settings where name = 'data_directory')::text"));
|
" (select setting from pg_catalog.pg_settings where name = 'data_directory')::text,"
|
||||||
|
" (select setting from pg_catalog.pg_settings where name = 'archive_mode')::text,"
|
||||||
|
" (select setting from pg_catalog.pg_settings where name = 'archive_command')::text"));
|
||||||
|
|
||||||
// Strip the minor version off since we don't need it. In the future it might be a good idea to warn users when they are
|
// Strip the minor version off since we don't need it. In the future it might be a good idea to warn users when they are
|
||||||
// running an old minor version.
|
// running an old minor version.
|
||||||
this->pgVersion = varUIntForce(varLstGet(row, 0)) / 100 * 100;
|
this->pgVersion = varUIntForce(varLstGet(row, 0)) / 100 * 100;
|
||||||
|
|
||||||
// Store the data directory that PostgreSQL is running in. This can be compared to the configured pgBackRest directory when
|
// Store the data directory that PostgreSQL is running in, the archive mode, and archive command. These can be compared to
|
||||||
// validating the configuration.
|
// the configured pgBackRest directory, and archive settings checked for validity, when validating the configuration.
|
||||||
MEM_CONTEXT_BEGIN(this->memContext)
|
MEM_CONTEXT_BEGIN(this->memContext)
|
||||||
{
|
{
|
||||||
this->pgDataPath = strDup(varStr(varLstGet(row, 1)));
|
this->pgDataPath = strDup(varStr(varLstGet(row, 1)));
|
||||||
|
this->archiveMode = strDup(varStr(varLstGet(row, 2)));
|
||||||
|
this->archiveCommand = strDup(varStr(varLstGet(row, 3)));
|
||||||
}
|
}
|
||||||
MEM_CONTEXT_END();
|
MEM_CONTEXT_END();
|
||||||
|
|
||||||
@@ -313,6 +319,36 @@ dbPgVersion(const Db *this)
|
|||||||
FUNCTION_TEST_RETURN(this->pgVersion);
|
FUNCTION_TEST_RETURN(this->pgVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Get pg version loaded from the server_version_num GUC
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
const String *
|
||||||
|
dbArchiveMode(const Db *this)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM(DB, this);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
ASSERT(this != NULL);
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(this->archiveMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***********************************************************************************************************************************
|
||||||
|
Get pg version loaded from the server_version_num GUC
|
||||||
|
***********************************************************************************************************************************/
|
||||||
|
const String *
|
||||||
|
dbArchiveCommand(const Db *this)
|
||||||
|
{
|
||||||
|
FUNCTION_TEST_BEGIN();
|
||||||
|
FUNCTION_TEST_PARAM(DB, this);
|
||||||
|
FUNCTION_TEST_END();
|
||||||
|
|
||||||
|
ASSERT(this != NULL);
|
||||||
|
|
||||||
|
FUNCTION_TEST_RETURN(this->archiveCommand);
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Render as string for logging
|
Render as string for logging
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
|
@@ -38,6 +38,8 @@ Getters
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
const String *dbPgDataPath(const Db *this);
|
const String *dbPgDataPath(const Db *this);
|
||||||
unsigned int dbPgVersion(const Db *this);
|
unsigned int dbPgVersion(const Db *this);
|
||||||
|
const String *dbArchiveMode(const Db *this);
|
||||||
|
const String *dbArchiveCommand(const Db *this);
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Destructor
|
Destructor
|
||||||
|
@@ -133,8 +133,6 @@ main(int argListSize, const char *argList[])
|
|||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
case cfgCmdCheck:
|
case cfgCmdCheck:
|
||||||
{
|
{
|
||||||
// Functionality is currently split between Perl and C
|
|
||||||
perlExec();
|
|
||||||
cmdCheck();
|
cmdCheck();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -3192,204 +3192,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"\n"
|
"\n"
|
||||||
"1;\n"
|
"1;\n"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.name = "pgBackRest/Check/Check.pm",
|
|
||||||
.data =
|
|
||||||
"\n\n\n"
|
|
||||||
"package pgBackRest::Check::Check;\n"
|
|
||||||
"\n"
|
|
||||||
"use strict;\n"
|
|
||||||
"use warnings FATAL => qw(all);\n"
|
|
||||||
"use Carp qw(confess);\n"
|
|
||||||
"use English '-no_match_vars';\n"
|
|
||||||
"\n"
|
|
||||||
"use pgBackRest::Archive::Common;\n"
|
|
||||||
"use pgBackRest::Archive::Get::File;\n"
|
|
||||||
"use pgBackRest::Backup::Info;\n"
|
|
||||||
"use pgBackRest::Common::Exception;\n"
|
|
||||||
"use pgBackRest::Common::Log;\n"
|
|
||||||
"use pgBackRest::Common::Wait;\n"
|
|
||||||
"use pgBackRest::Config::Config;\n"
|
|
||||||
"use pgBackRest::Db;\n"
|
|
||||||
"use pgBackRest::Manifest;\n"
|
|
||||||
"use pgBackRest::Protocol::Helper;\n"
|
|
||||||
"use pgBackRest::Protocol::Storage::Helper;\n"
|
|
||||||
"\n\n\n\n"
|
|
||||||
"sub new\n"
|
|
||||||
"{\n"
|
|
||||||
"my $class = shift;\n"
|
|
||||||
"\n\n"
|
|
||||||
"my ($strOperation) = logDebugParam(__PACKAGE__ . '->new');\n"
|
|
||||||
"\n\n"
|
|
||||||
"my $self = {};\n"
|
|
||||||
"bless $self, $class;\n"
|
|
||||||
"\n\n"
|
|
||||||
"return logDebugReturn\n"
|
|
||||||
"(\n"
|
|
||||||
"$strOperation,\n"
|
|
||||||
"{name => 'self', value => $self}\n"
|
|
||||||
");\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n\n\n\n\n\n\n"
|
|
||||||
"sub process\n"
|
|
||||||
"{\n"
|
|
||||||
"my $self = shift;\n"
|
|
||||||
"\n\n"
|
|
||||||
"my $strOperation = logDebugParam(__PACKAGE__ . '->process');\n"
|
|
||||||
"\n\n"
|
|
||||||
"my $iArchiveTimeout = cfgOption(CFGOPT_ARCHIVE_TIMEOUT);\n"
|
|
||||||
"\n"
|
|
||||||
"my $iResult = 0;\n"
|
|
||||||
"my $strResultMessage = undef;\n"
|
|
||||||
"\n"
|
|
||||||
"my $strArchiveId = undef;\n"
|
|
||||||
"my $strArchiveFile = undef;\n"
|
|
||||||
"my $strWalSegment = undef;\n"
|
|
||||||
"\n\n"
|
|
||||||
"my ($oDb) = dbMasterGet();\n"
|
|
||||||
"\n\n"
|
|
||||||
"my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info();\n"
|
|
||||||
"\n\n"
|
|
||||||
"logLevelSet(undef, OFF);\n"
|
|
||||||
"\n\n"
|
|
||||||
"for (my $iRemoteIdx = 1; $iRemoteIdx <= cfgOptionIndexTotal(CFGOPT_PG_HOST); $iRemoteIdx++)\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"if (cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)) ||\n"
|
|
||||||
"cfgOptionTest(cfgOptionIdFromIndex(CFGOPT_PG_HOST, $iRemoteIdx)))\n"
|
|
||||||
"{\n"
|
|
||||||
"eval\n"
|
|
||||||
"{\n"
|
|
||||||
"\n\n"
|
|
||||||
"my $oBackupManifest = new pgBackRest::Manifest(\"/dev/null/manifest.chk\",\n"
|
|
||||||
"{bLoad => false, strDbVersion => $strDbVersion, iDbCatalogVersion => $iCatalogVersion,\n"
|
|
||||||
"strCipherPass => 'x', strCipherPassSub => 'x'});\n"
|
|
||||||
"\n\n"
|
|
||||||
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID, undef, 1);\n"
|
|
||||||
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL, undef, $iControlVersion);\n"
|
|
||||||
"$oBackupManifest->numericSet(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID, undef, $ullDbSysId);\n"
|
|
||||||
"\n"
|
|
||||||
"$oBackupManifest->build(\n"
|
|
||||||
"storageDb({iRemoteIdx => $iRemoteIdx}), cfgOption(cfgOptionIdFromIndex(CFGOPT_PG_PATH, $iRemoteIdx)), undef,\n"
|
|
||||||
"cfgOptionValid(CFGOPT_ONLINE) && cfgOption(CFGOPT_ONLINE), false, $oDb->tablespaceMapGet());\n"
|
|
||||||
"\n"
|
|
||||||
"return true;\n"
|
|
||||||
"}\n"
|
|
||||||
"or do\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"$strResultMessage = \"Database: ${strDbVersion} ${ullDbSysId} \" . exceptionMessage($EVAL_ERROR) .\n"
|
|
||||||
"(($iResult != 0) ? \"\\n[$iResult] : $strResultMessage\" : \"\");\n"
|
|
||||||
"$iResult = exceptionCode($EVAL_ERROR);\n"
|
|
||||||
"};\n"
|
|
||||||
"}\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n"
|
|
||||||
"logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n"
|
|
||||||
"\n\n"
|
|
||||||
"if ($iResult == 0)\n"
|
|
||||||
"{\n"
|
|
||||||
"\n\n"
|
|
||||||
"($oDb) = dbObjectGet();\n"
|
|
||||||
"\n\n"
|
|
||||||
"$oDb->configValidate();\n"
|
|
||||||
"\n\n"
|
|
||||||
"logLevelSet(undef, OFF);\n"
|
|
||||||
"\n\n"
|
|
||||||
"eval\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"$self->backupInfoCheck();\n"
|
|
||||||
"return true;\n"
|
|
||||||
"}\n"
|
|
||||||
"\n"
|
|
||||||
"or do\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"$iResult = exceptionCode($EVAL_ERROR);\n"
|
|
||||||
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
|
|
||||||
"};\n"
|
|
||||||
"\n\n"
|
|
||||||
"if ($iResult == 0)\n"
|
|
||||||
"{\n"
|
|
||||||
"eval\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"($strArchiveId) = archiveGetCheck();\n"
|
|
||||||
"return true;\n"
|
|
||||||
"}\n"
|
|
||||||
"or do\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"$iResult = exceptionCode($EVAL_ERROR);\n"
|
|
||||||
"$strResultMessage = exceptionMessage($EVAL_ERROR);\n"
|
|
||||||
"};\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n"
|
|
||||||
"logLevelSet(undef, cfgOption(CFGOPT_LOG_LEVEL_CONSOLE));\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n"
|
|
||||||
"if ($iResult != 0)\n"
|
|
||||||
"{\n"
|
|
||||||
"&log(ERROR, $strResultMessage, $iResult);\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n"
|
|
||||||
"return logDebugReturn\n"
|
|
||||||
"(\n"
|
|
||||||
"$strOperation,\n"
|
|
||||||
"{name => 'iResult', value => $iResult, trace => true}\n"
|
|
||||||
");\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n\n\n\n\n"
|
|
||||||
"sub backupInfoCheck\n"
|
|
||||||
"{\n"
|
|
||||||
"my $self = shift;\n"
|
|
||||||
"\n\n"
|
|
||||||
"my\n"
|
|
||||||
"(\n"
|
|
||||||
"$strOperation,\n"
|
|
||||||
"$strDbVersion,\n"
|
|
||||||
"$iControlVersion,\n"
|
|
||||||
"$iCatalogVersion,\n"
|
|
||||||
"$ullDbSysId,\n"
|
|
||||||
") =\n"
|
|
||||||
"logDebugParam\n"
|
|
||||||
"(\n"
|
|
||||||
"__PACKAGE__ . '->backupInfoCheck', \\@_,\n"
|
|
||||||
"{name => 'strDbVersion', required => false},\n"
|
|
||||||
"{name => 'iControlVersion', required => false},\n"
|
|
||||||
"{name => 'iCatalogVersion', required => false},\n"
|
|
||||||
"{name => 'ullDbSysId', required => false}\n"
|
|
||||||
");\n"
|
|
||||||
"\n\n"
|
|
||||||
"my $iDbHistoryId;\n"
|
|
||||||
"\n"
|
|
||||||
"if (!defined($strDbVersion) || !defined($iControlVersion) || !defined($iCatalogVersion) || !defined($ullDbSysId))\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = dbMasterGet()->info();\n"
|
|
||||||
"}\n"
|
|
||||||
"\n"
|
|
||||||
"if (!isRepoLocal())\n"
|
|
||||||
"{\n"
|
|
||||||
"$iDbHistoryId = protocolGet(CFGOPTVAL_REMOTE_TYPE_BACKUP)->cmdExecute(\n"
|
|
||||||
"OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);\n"
|
|
||||||
"}\n"
|
|
||||||
"else\n"
|
|
||||||
"{\n"
|
|
||||||
"$iDbHistoryId = (new pgBackRest::Backup::Info(storageRepo()->pathGet(STORAGE_REPO_BACKUP)))->check(\n"
|
|
||||||
"$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);\n"
|
|
||||||
"}\n"
|
|
||||||
"\n\n"
|
|
||||||
"return logDebugReturn\n"
|
|
||||||
"(\n"
|
|
||||||
"$strOperation,\n"
|
|
||||||
"{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}\n"
|
|
||||||
");\n"
|
|
||||||
"}\n"
|
|
||||||
"\n"
|
|
||||||
"1;\n"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
.name = "pgBackRest/Common/Cipher.pm",
|
.name = "pgBackRest/Common/Cipher.pm",
|
||||||
.data =
|
.data =
|
||||||
@@ -8279,15 +8081,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"$oRemote->process(\n"
|
"$oRemote->process(\n"
|
||||||
"cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));\n"
|
"cfgOption(CFGOPT_LOCK_PATH), cfgOption(CFGOPT_COMMAND), cfgOption(CFGOPT_STANZA, false), cfgOption(CFGOPT_PROCESS));\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n\n\n"
|
|
||||||
"elsif (cfgCommandTest(CFGCMD_CHECK))\n"
|
|
||||||
"{\n"
|
|
||||||
"\n"
|
|
||||||
"require pgBackRest::Check::Check;\n"
|
|
||||||
"pgBackRest::Check::Check->import();\n"
|
|
||||||
"\n"
|
|
||||||
"$iResult = new pgBackRest::Check::Check()->process();\n"
|
|
||||||
"}\n"
|
|
||||||
"else\n"
|
"else\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -10342,9 +10135,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';\n"
|
"use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';\n"
|
||||||
"push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);\n"
|
"push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);\n"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck';\n"
|
|
||||||
"push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK);\n"
|
|
||||||
"\n\n"
|
|
||||||
"use constant OP_DB_CONNECT => 'dbConnect';\n"
|
"use constant OP_DB_CONNECT => 'dbConnect';\n"
|
||||||
"push @EXPORT, qw(OP_DB_CONNECT);\n"
|
"push @EXPORT, qw(OP_DB_CONNECT);\n"
|
||||||
"use constant OP_DB_EXECUTE_SQL => 'dbExecSql';\n"
|
"use constant OP_DB_EXECUTE_SQL => 'dbExecSql';\n"
|
||||||
@@ -11439,7 +11229,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"use pgBackRest::Common::Io::Buffered;\n"
|
"use pgBackRest::Common::Io::Buffered;\n"
|
||||||
"use pgBackRest::Common::Wait;\n"
|
"use pgBackRest::Common::Wait;\n"
|
||||||
"use pgBackRest::Archive::Get::File;\n"
|
"use pgBackRest::Archive::Get::File;\n"
|
||||||
"use pgBackRest::Check::Check;\n"
|
|
||||||
"use pgBackRest::Config::Config;\n"
|
"use pgBackRest::Config::Config;\n"
|
||||||
"use pgBackRest::Db;\n"
|
"use pgBackRest::Db;\n"
|
||||||
"use pgBackRest::Protocol::Command::Minion;\n"
|
"use pgBackRest::Protocol::Command::Minion;\n"
|
||||||
@@ -11481,7 +11270,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"\n\n"
|
"\n\n"
|
||||||
"my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n"
|
"my $oStorage = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? storageDb() : storageRepo();\n"
|
||||||
"\n"
|
"\n"
|
||||||
"my $oCheck = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_BACKUP) ? new pgBackRest::Check::Check() : undef;\n"
|
|
||||||
"my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n"
|
"my $oDb = cfgOptionTest(CFGOPT_TYPE, CFGOPTVAL_REMOTE_TYPE_DB) ? new pgBackRest::Db() : undef;\n"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"my $hCommandMap =\n"
|
"my $hCommandMap =\n"
|
||||||
@@ -11489,8 +11277,6 @@ static const EmbeddedModule embeddedModule[] =
|
|||||||
"\n"
|
"\n"
|
||||||
"&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},\n"
|
"&OP_ARCHIVE_GET_CHECK => sub {archiveGetCheck(@{shift()})},\n"
|
||||||
"\n\n"
|
"\n\n"
|
||||||
"&OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck(@{shift()})},\n"
|
|
||||||
"\n\n"
|
|
||||||
"&OP_DB_CONNECT => sub {$oDb->connect()},\n"
|
"&OP_DB_CONNECT => sub {$oDb->connect()},\n"
|
||||||
"&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},\n"
|
"&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},\n"
|
||||||
"&OP_DB_INFO => sub {$oDb->info(@{shift()})},\n"
|
"&OP_DB_INFO => sub {$oDb->info(@{shift()})},\n"
|
||||||
|
@@ -640,7 +640,8 @@ unit:
|
|||||||
|
|
||||||
# ----------------------------------------------------------------------------------------------------------------------------
|
# ----------------------------------------------------------------------------------------------------------------------------
|
||||||
- name: check
|
- name: check
|
||||||
total: 2
|
total: 4
|
||||||
|
containerReq: true
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
command/check/common: full
|
command/check/common: full
|
||||||
|
@@ -111,7 +111,7 @@ stanza-create db - fail on database mismatch and warn force option deprecated (d
|
|||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
|
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --config=[TEST_PATH]/db-master/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/db-master/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/db-master/log --log-subprocess --no-log-timestamp --no-online --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-path=[TEST_PATH]/db-master/repo --stanza=db
|
||||||
P00 WARN: option --force is no longer supported
|
P00 WARN: option --force is no longer supported
|
||||||
P00 ERROR: [028]: backup and archive info files already exist but do not match the database
|
P00 ERROR: [028]: backup and archive info files exist but do not match the database
|
||||||
HINT: is this the correct stanza?
|
HINT: is this the correct stanza?
|
||||||
HINT: did an error occur during stanza-upgrade?
|
HINT: did an error occur during stanza-upgrade?
|
||||||
P00 INFO: stanza-create command end: aborted with exception [028]
|
P00 INFO: stanza-create command end: aborted with exception [028]
|
||||||
|
@@ -129,7 +129,7 @@ stanza-create db - fail on database mismatch and warn force option deprecated (b
|
|||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
|
P00 INFO: stanza-create command begin [BACKREST-VERSION]: --compress-level=3 --compress-level-network=1 --config=[TEST_PATH]/backup/pgbackrest.conf --db-timeout=45 --force --lock-path=[TEST_PATH]/backup/lock --log-level-console=detail --log-level-file=trace --log-level-stderr=off --log-path=[TEST_PATH]/backup/log --log-subprocess --no-log-timestamp --no-online --pg1-host=db-master --pg1-host-cmd=[BACKREST-BIN] --pg1-host-config=[TEST_PATH]/db-master/pgbackrest.conf --pg1-host-user=[USER-1] --pg1-path=[TEST_PATH]/db-master/db/base --protocol-timeout=60 --repo1-cipher-pass=<redacted> --repo1-cipher-type=aes-256-cbc --repo1-path=/ --repo1-s3-bucket=pgbackrest-dev --repo1-s3-endpoint=s3.amazonaws.com --repo1-s3-key=<redacted> --repo1-s3-key-secret=<redacted> --repo1-s3-region=us-east-1 --no-repo1-s3-verify-tls --repo1-type=s3 --stanza=db
|
||||||
P00 WARN: option --force is no longer supported
|
P00 WARN: option --force is no longer supported
|
||||||
P00 ERROR: [028]: backup and archive info files already exist but do not match the database
|
P00 ERROR: [028]: backup and archive info files exist but do not match the database
|
||||||
HINT: is this the correct stanza?
|
HINT: is this the correct stanza?
|
||||||
HINT: did an error occur during stanza-upgrade?
|
HINT: did an error occur during stanza-upgrade?
|
||||||
P00 DETAIL: tls statistics:[TLS-STATISTICS]
|
P00 DETAIL: tls statistics:[TLS-STATISTICS]
|
||||||
|
@@ -45,10 +45,6 @@ check db - fail on backup info mismatch (db-master host)
|
|||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
check db - confirm master manifest->build executed (db-master host)
|
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
check db - verify success after backup (db-master host)
|
check db - verify success after backup (db-master host)
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -153,10 +153,6 @@ repo1-host-config=[TEST_PATH]/db-master/pgbackrest.conf
|
|||||||
repo1-host-user=[USER-1]
|
repo1-host-user=[USER-1]
|
||||||
spool-path=[TEST_PATH]/db-standby/spool
|
spool-path=[TEST_PATH]/db-standby/spool
|
||||||
|
|
||||||
check db - confirm standby manifest->build executed (db-standby host)
|
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
check db - verify check command on standby (db-standby host)
|
check db - verify check command on standby (db-standby host)
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check
|
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -157,10 +157,6 @@ spool-path=[TEST_PATH]/db-standby/spool
|
|||||||
archive-copy=y
|
archive-copy=y
|
||||||
start-fast=y
|
start-fast=y
|
||||||
|
|
||||||
check db - confirm standby manifest->build executed (db-standby host)
|
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
incr backup - update during backup (db-standby host)
|
incr backup - update during backup (db-standby host)
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stop-auto --buffer-size=32768 --delta --stanza=db backup --test --test-delay=1 --test-point=manifest-build=y
|
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stop-auto --buffer-size=32768 --delta --stanza=db backup --test --test-delay=1 --test-point=manifest-build=y
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -69,10 +69,6 @@ check db - fail on backup info mismatch (backup host)
|
|||||||
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
check db - confirm master manifest->build executed (db-master host)
|
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
check db - verify success after backup (db-master host)
|
check db - verify success after backup (db-master host)
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -215,10 +215,6 @@ repo1-path=[TEST_PATH]/backup/repo
|
|||||||
archive-copy=y
|
archive-copy=y
|
||||||
start-fast=y
|
start-fast=y
|
||||||
|
|
||||||
check db - confirm standby manifest->build executed (db-standby host)
|
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
check db - verify check command on standby (db-standby host)
|
check db - verify check command on standby (db-standby host)
|
||||||
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check
|
> [CONTAINER-EXEC] db-standby [BACKREST-BIN] --config=[TEST_PATH]/db-standby/pgbackrest.conf --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -69,10 +69,6 @@ check db - fail on backup info mismatch (backup host)
|
|||||||
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] backup [BACKREST-BIN] --config=[TEST_PATH]/backup/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
check db - confirm master manifest->build executed (db-master host)
|
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
check db - verify success after backup (db-master host)
|
check db - verify success after backup (db-master host)
|
||||||
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
> [CONTAINER-EXEC] db-master [BACKREST-BIN] --config=[TEST_PATH]/db-master/pgbackrest.conf --archive-timeout=5 --stanza=db check
|
||||||
------------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
@@ -228,14 +228,15 @@ sub run
|
|||||||
# load the archive info file and munge it for testing by breaking the database version
|
# load the archive info file and munge it for testing by breaking the database version
|
||||||
$oHostBackup->infoMunge(
|
$oHostBackup->infoMunge(
|
||||||
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
storageRepo()->pathGet(STORAGE_REPO_ARCHIVE . qw{/} . ARCHIVE_INFO_FILE),
|
||||||
{&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}});
|
{&INFO_ARCHIVE_SECTION_DB => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'},
|
||||||
|
&INFO_ARCHIVE_SECTION_DB_HISTORY => {1 => {&INFO_ARCHIVE_KEY_DB_VERSION => '8.0'}}});
|
||||||
|
|
||||||
$oHostDbMaster->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH});
|
$oHostDbMaster->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_FILE_INVALID});
|
||||||
|
|
||||||
# If running the remote tests then also need to run check locally
|
# If running the remote tests then also need to run check locally
|
||||||
if ($bHostBackup)
|
if ($bHostBackup)
|
||||||
{
|
{
|
||||||
$oHostBackup->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_ARCHIVE_MISMATCH});
|
$oHostBackup->check($strComment, {iTimeout => 0.1, iExpectedExitStatus => ERROR_FILE_INVALID});
|
||||||
}
|
}
|
||||||
|
|
||||||
# Restore the file to its original condition
|
# Restore the file to its original condition
|
||||||
@@ -264,29 +265,32 @@ sub run
|
|||||||
$oHostBackup->infoMunge(
|
$oHostBackup->infoMunge(
|
||||||
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO),
|
storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO),
|
||||||
{&INFO_BACKUP_SECTION_DB =>
|
{&INFO_BACKUP_SECTION_DB =>
|
||||||
{&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999}});
|
{&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999},
|
||||||
|
&INFO_BACKUP_SECTION_DB_HISTORY =>
|
||||||
|
{1 => {&INFO_BACKUP_KEY_DB_VERSION => '8.0', &INFO_BACKUP_KEY_SYSTEM_ID => 6999999999999999999}}});
|
||||||
|
|
||||||
# Run the test
|
# Run the test
|
||||||
$oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_BACKUP_MISMATCH});
|
$oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_INVALID});
|
||||||
|
|
||||||
# If running the remote tests then also need to run check locally
|
# If running the remote tests then also need to run check locally
|
||||||
if ($bHostBackup)
|
if ($bHostBackup)
|
||||||
{
|
{
|
||||||
$oHostBackup->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_BACKUP_MISMATCH});
|
$oHostBackup->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_INVALID});
|
||||||
}
|
}
|
||||||
|
|
||||||
# Restore the file to its original condition
|
# Restore the file to its original condition
|
||||||
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO));
|
$oHostBackup->infoRestore(storageRepo()->pathGet(STORAGE_REPO_BACKUP . qw{/} . FILE_BACKUP_INFO));
|
||||||
|
|
||||||
|
# ??? Removed temporarily until manifest build can be brought back into the check command
|
||||||
# Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check
|
# Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check
|
||||||
my $strDir = $oHostDbMaster->dbBasePath() . '/rootreaddir';
|
# my $strDir = $oHostDbMaster->dbBasePath() . '/rootreaddir';
|
||||||
executeTest('sudo mkdir ' . $strDir);
|
# executeTest('sudo mkdir ' . $strDir);
|
||||||
executeTest("sudo chown root:root ${strDir}");
|
# executeTest("sudo chown root:root ${strDir}");
|
||||||
executeTest("sudo chmod 400 ${strDir}");
|
# executeTest("sudo chmod 400 ${strDir}");
|
||||||
|
#
|
||||||
$strComment = 'confirm master manifest->build executed';
|
# $strComment = 'confirm master manifest->build executed';
|
||||||
$oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN});
|
# $oHostDbMaster->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN});
|
||||||
executeTest("sudo rmdir ${strDir}");
|
# executeTest("sudo rmdir ${strDir}");
|
||||||
|
|
||||||
# Providing a sufficient archive-timeout, verify that the check command runs successfully now with valid
|
# Providing a sufficient archive-timeout, verify that the check command runs successfully now with valid
|
||||||
# archive.info and backup.info files
|
# archive.info and backup.info files
|
||||||
@@ -491,27 +495,28 @@ sub run
|
|||||||
$strFullBackup = $strStandbyBackup;
|
$strFullBackup = $strStandbyBackup;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check
|
# ??? Removed temporarily until manifest build can be brought back into the check command
|
||||||
my $strDir = $oHostDbStandby->dbBasePath() . '/rootreaddir';
|
# # Create a directory in pg_data location that is only readable by root to ensure manifest->build is called by check
|
||||||
executeTest('sudo mkdir ' . $strDir);
|
# my $strDir = $oHostDbStandby->dbBasePath() . '/rootreaddir';
|
||||||
executeTest("sudo chown root:root ${strDir}");
|
# executeTest('sudo mkdir ' . $strDir);
|
||||||
executeTest("sudo chmod 400 ${strDir}");
|
# executeTest("sudo chown root:root ${strDir}");
|
||||||
|
# executeTest("sudo chmod 400 ${strDir}");
|
||||||
my $strComment = 'confirm standby manifest->build executed';
|
#
|
||||||
|
# my $strComment = 'confirm standby manifest->build executed';
|
||||||
# If there is an invalid host, the final error returned from check will be the inability to resolve the name which is
|
#
|
||||||
# an open error instead of a read error
|
# # If there is an invalid host, the final error returned from check will be the inability to resolve the name which is
|
||||||
if (!$oHostDbStandby->bogusHost())
|
# # an open error instead of a read error
|
||||||
{
|
# if (!$oHostDbStandby->bogusHost())
|
||||||
$oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN});
|
# {
|
||||||
}
|
# $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_PATH_OPEN});
|
||||||
else
|
# }
|
||||||
{
|
# else
|
||||||
$oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_READ});
|
# {
|
||||||
}
|
# $oHostDbStandby->check($strComment, {iTimeout => 5, iExpectedExitStatus => ERROR_FILE_READ});
|
||||||
|
# }
|
||||||
# Remove the directory in pg_data location that is only readable by root
|
#
|
||||||
executeTest("sudo rmdir ${strDir}");
|
# # Remove the directory in pg_data location that is only readable by root
|
||||||
|
# executeTest("sudo rmdir ${strDir}");
|
||||||
|
|
||||||
# Confirm the check command runs without error on a standby (when a bogus host is not configured)
|
# Confirm the check command runs without error on a standby (when a bogus host is not configured)
|
||||||
if (!$oHostDbStandby->bogusHost())
|
if (!$oHostDbStandby->bogusHost())
|
||||||
|
@@ -54,21 +54,29 @@ Macros for defining groups of functions that implement various queries and comma
|
|||||||
{.session = sessionParam, .function = HRNPQ_CLEAR}, \
|
{.session = sessionParam, .function = HRNPQ_CLEAR}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
|
{.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
|
||||||
|
|
||||||
#define HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, versionParam, pgPathParam) \
|
#define HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, versionParam, pgPathParam, archiveMode, archiveCommand) \
|
||||||
{.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = \
|
{.session = sessionParam, .function = HRNPQ_SENDQUERY, .param = \
|
||||||
"[\"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4," \
|
"[\"select (select setting from pg_catalog.pg_settings where name = 'server_version_num')::int4," \
|
||||||
" (select setting from pg_catalog.pg_settings where name = 'data_directory')::text\"]", \
|
" (select setting from pg_catalog.pg_settings where name = 'data_directory')::text," \
|
||||||
|
" (select setting from pg_catalog.pg_settings where name = 'archive_mode')::text," \
|
||||||
|
" (select setting from pg_catalog.pg_settings where name = 'archive_command')::text\"]", \
|
||||||
.resultInt = 1}, \
|
.resultInt = 1}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_CONSUMEINPUT}, \
|
{.session = sessionParam, .function = HRNPQ_CONSUMEINPUT}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_ISBUSY}, \
|
{.session = sessionParam, .function = HRNPQ_ISBUSY}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_GETRESULT}, \
|
{.session = sessionParam, .function = HRNPQ_GETRESULT}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK}, \
|
{.session = sessionParam, .function = HRNPQ_RESULTSTATUS, .resultInt = PGRES_TUPLES_OK}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1}, \
|
{.session = sessionParam, .function = HRNPQ_NTUPLES, .resultInt = 1}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 2}, \
|
{.session = sessionParam, .function = HRNPQ_NFIELDS, .resultInt = 4}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT}, \
|
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[0]", .resultInt = HRNPQ_TYPE_INT}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT}, \
|
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[1]", .resultInt = HRNPQ_TYPE_TEXT}, \
|
||||||
|
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[2]", .resultInt = HRNPQ_TYPE_TEXT}, \
|
||||||
|
{.session = sessionParam, .function = HRNPQ_FTYPE, .param = "[3]", .resultInt = HRNPQ_TYPE_TEXT}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(versionParam)}, \
|
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,0]", .resultZ = STRINGIFY(versionParam)}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = pgPathParam}, \
|
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,1]", .resultZ = pgPathParam}, \
|
||||||
|
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,2]", .resultZ = archiveMode == NULL ? "on" \
|
||||||
|
: archiveMode}, \
|
||||||
|
{.session = sessionParam, .function = HRNPQ_GETVALUE, .param = "[0,3]", .resultZ = archiveCommand == NULL ? PROJECT_BIN \
|
||||||
|
: archiveCommand}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_CLEAR}, \
|
{.session = sessionParam, .function = HRNPQ_CLEAR}, \
|
||||||
{.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
|
{.session = sessionParam, .function = HRNPQ_GETRESULT, .resultNull = true}
|
||||||
|
|
||||||
@@ -135,15 +143,15 @@ Macros for defining groups of functions that implement various queries and comma
|
|||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Macros to simplify dbOpen() for specific database versions
|
Macros to simplify dbOpen() for specific database versions
|
||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#define HRNPQ_MACRO_OPEN_84(sessionParam, connectParam, pgPathParam) \
|
#define HRNPQ_MACRO_OPEN_84(sessionParam, connectParam, pgPathParam, archiveMode, archiveCommand) \
|
||||||
HRNPQ_MACRO_OPEN(sessionParam, connectParam), \
|
HRNPQ_MACRO_OPEN(sessionParam, connectParam), \
|
||||||
HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \
|
HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \
|
||||||
HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_84, pgPathParam)
|
HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_84, pgPathParam, archiveMode, archiveCommand)
|
||||||
|
|
||||||
#define HRNPQ_MACRO_OPEN_92(sessionParam, connectParam, pgPathParam, standbyParam) \
|
#define HRNPQ_MACRO_OPEN_92(sessionParam, connectParam, pgPathParam, standbyParam, archiveMode, archiveCommand) \
|
||||||
HRNPQ_MACRO_OPEN(sessionParam, connectParam), \
|
HRNPQ_MACRO_OPEN(sessionParam, connectParam), \
|
||||||
HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \
|
HRNPQ_MACRO_SET_SEARCH_PATH(sessionParam), \
|
||||||
HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_92, pgPathParam), \
|
HRNPQ_MACRO_VALIDATE_QUERY(sessionParam, PG_VERSION_92, pgPathParam, archiveMode, archiveCommand), \
|
||||||
HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam), \
|
HRNPQ_MACRO_SET_APPLICATION_NAME(sessionParam), \
|
||||||
HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam)
|
HRNPQ_MACRO_IS_STANDBY_QUERY(sessionParam, standbyParam)
|
||||||
|
|
||||||
|
@@ -3,11 +3,15 @@ Test Check Command
|
|||||||
***********************************************************************************************************************************/
|
***********************************************************************************************************************************/
|
||||||
#include "postgres/version.h"
|
#include "postgres/version.h"
|
||||||
#include "storage/helper.h"
|
#include "storage/helper.h"
|
||||||
|
#include "storage/posix/storage.h"
|
||||||
#include "storage/storage.intern.h"
|
#include "storage/storage.intern.h"
|
||||||
|
|
||||||
|
#include "command/stanza/create.h"
|
||||||
#include "common/harnessConfig.h"
|
#include "common/harnessConfig.h"
|
||||||
#include "common/harnessInfo.h"
|
#include "common/harnessInfo.h"
|
||||||
#include "common/harnessPq.h"
|
#include "common/harnessPq.h"
|
||||||
|
#include "info/infoArchive.h"
|
||||||
|
#include "info/infoBackup.h"
|
||||||
|
|
||||||
/***********************************************************************************************************************************
|
/***********************************************************************************************************************************
|
||||||
Test Run
|
Test Run
|
||||||
@@ -17,19 +21,173 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
FUNCTION_HARNESS_VOID();
|
FUNCTION_HARNESS_VOID();
|
||||||
|
|
||||||
String *pg1Path = strNewFmt("%s/pg1", testPath());
|
Storage *storageTest = storagePosixNew(
|
||||||
|
strNew(testPath()), STORAGE_MODE_FILE_DEFAULT, STORAGE_MODE_PATH_DEFAULT, true, NULL);
|
||||||
|
|
||||||
|
String *pg1 = strNew("pg1");
|
||||||
|
String *pg1Path = strNewFmt("%s/%s", testPath(), strPtr(pg1));
|
||||||
String *pg1PathOpt = strNewFmt("--pg1-path=%s", strPtr(pg1Path));
|
String *pg1PathOpt = strNewFmt("--pg1-path=%s", strPtr(pg1Path));
|
||||||
|
String *pg8 = strNew("pg8");
|
||||||
|
String *pg8Path = strNewFmt("%s/%s", testPath(), strPtr(pg8));
|
||||||
|
String *pg8PathOpt = strNewFmt("--pg8-path=%s", strPtr(pg8Path));
|
||||||
|
String *stanza = strNew("test1");
|
||||||
|
String *stanzaOpt = strNewFmt("--stanza=%s", strPtr(stanza));
|
||||||
|
StringList *argList = strLstNew();
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("cmdCheck()"))
|
if (testBegin("cmdCheck()"))
|
||||||
{
|
{
|
||||||
StringList *argList = strLstNew();
|
// Load Parameters
|
||||||
strLstAddZ(argList, "--stanza=test1");
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
strLstAdd(argList, pg1PathOpt);
|
strLstAdd(argList, pg1PathOpt);
|
||||||
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
strLstAddZ(argList, "--archive-timeout=.5");
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
harnessCfgLoad(cfgCmdCheck, argList);
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
// Set up harness to expect a failure to connect to the database
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
{.function = HRNPQ_CONNECTDB, .param = "[\"dbname='postgres' port=5432\"]"},
|
||||||
|
{.function = HRNPQ_STATUS, .resultInt = CONNECTION_BAD},
|
||||||
|
{.function = HRNPQ_ERRORMESSAGE, .resultZ = "error"},
|
||||||
|
{.function = HRNPQ_FINISH},
|
||||||
|
{.function = NULL}
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(cmdCheck(), ConfigError, "no database found\nHINT: check indexed pg-path/pg-host configurations");
|
||||||
|
harnessLogResult(
|
||||||
|
"P00 WARN: unable to check pg-1: [DbConnectError] unable to connect to 'dbname='postgres' port=5432': error");
|
||||||
|
|
||||||
|
// Standby only, repo local
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ERROR(cmdCheck(), ConfigError, "primary database not found\nHINT: check indexed pg-path/pg-host configurations");
|
||||||
|
|
||||||
|
// Standby only, repo remote but more than one pg-path configured
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAddZ(argList, "--pg8-path=/path/to/standby2");
|
||||||
|
strLstAddZ(argList, "--pg8-port=5433");
|
||||||
|
strLstAddZ(argList, "--repo1-host=repo.domain.com");
|
||||||
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
// Two standbys found but no primary
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ERROR(cmdCheck(), ConfigError, "primary database not found\nHINT: check indexed pg-path/pg-host configurations");
|
||||||
|
|
||||||
|
// Standby only, repo remote but only one pg-path configured
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAddZ(argList, "--repo1-host=repo.domain.com");
|
||||||
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Only confirming we get passed the check for isRepoLocal || more than one pg-path configured
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
cmdCheck(), FileMissingError, "unable to open missing file '%s/global/pg_control' for read", strPtr(pg1Path));
|
||||||
|
|
||||||
|
// backup-standby set without standby
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
|
strLstAddZ(argList, "--backup-standby");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
// Primary database connection ok
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
cmdCheck(), FileMissingError, "unable to open missing file '%s' for read",
|
||||||
|
strPtr(strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg1Path))));
|
||||||
|
harnessLogResult(
|
||||||
|
strPtr(strNewFmt("P00 WARN: option '%s' is enabled but standby is not properly configured",
|
||||||
|
cfgOptionName(cfgOptBackupStandby))));
|
||||||
|
|
||||||
|
// Standby and primary database
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Create pg_control for standby
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg1))),
|
||||||
|
pgControlTestToBuffer((PgControl){.version = PG_VERSION_92, .systemId = 6569239123849665679}));
|
||||||
|
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
|
strLstAdd(argList, pg8PathOpt);
|
||||||
|
strLstAddZ(argList, "--pg8-port=5433");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
// Standby database path doesn't match pg_control
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, NULL, NULL),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
cmdCheck(), DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'"
|
||||||
|
" read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n"
|
||||||
|
"HINT: the pg1-path and pg1-port settings likely reference different clusters.",
|
||||||
|
strPtr(pgVersionToStr(PG_VERSION_92)), testPath(), strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path),
|
||||||
|
strPtr(pg1Path));
|
||||||
|
|
||||||
|
// Standby - Stanza has not yet been created
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, NULL, NULL),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
cmdCheck(), FileMissingError,
|
cmdCheck(), FileMissingError,
|
||||||
"unable to load info file '%s/repo/archive/test1/archive.info' or '%s/repo/archive/test1/archive.info.copy':\n"
|
"unable to load info file '%s/repo/archive/test1/archive.info' or '%s/repo/archive/test1/archive.info.copy':\n"
|
||||||
@@ -42,7 +200,14 @@ testRun(void)
|
|||||||
testPath(), testPath(), strPtr(strNewFmt("%s/repo/archive/test1/archive.info", testPath())),
|
testPath(), testPath(), strPtr(strNewFmt("%s/repo/archive/test1/archive.info", testPath())),
|
||||||
strPtr(strNewFmt("%s/repo/archive/test1/archive.info.copy", testPath())));
|
strPtr(strNewFmt("%s/repo/archive/test1/archive.info.copy", testPath())));
|
||||||
|
|
||||||
// Create archive.info file
|
// Standby - Stanza created
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// Create pg_control for primary
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(pg8))),
|
||||||
|
pgControlTestToBuffer((PgControl){.version = PG_VERSION_92, .systemId = 6569239123849665679}));
|
||||||
|
|
||||||
|
// Create info files
|
||||||
storagePutNP(
|
storagePutNP(
|
||||||
storageNewWriteNP(storageRepoWrite(), INFO_ARCHIVE_PATH_FILE_STR),
|
storageNewWriteNP(storageRepoWrite(), INFO_ARCHIVE_PATH_FILE_STR),
|
||||||
harnessInfoChecksum(
|
harnessInfoChecksum(
|
||||||
@@ -55,12 +220,49 @@ testRun(void)
|
|||||||
"[db:history]\n"
|
"[db:history]\n"
|
||||||
"1={\"db-id\":6569239123849665679,\"db-version\":\"9.2\"}\n")));
|
"1={\"db-id\":6569239123849665679,\"db-version\":\"9.2\"}\n")));
|
||||||
|
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(storageRepoWrite(), INFO_BACKUP_PATH_FILE_STR),
|
||||||
|
harnessInfoChecksum(
|
||||||
|
strNew(
|
||||||
|
"[db]\n"
|
||||||
|
"db-catalog-version=201608131\n"
|
||||||
|
"db-control-version=920\n"
|
||||||
|
"db-id=1\n"
|
||||||
|
"db-system-id=6569239123849665679\n"
|
||||||
|
"db-version=\"9.2\"\n"
|
||||||
|
"\n"
|
||||||
|
"[db:history]\n"
|
||||||
|
"1={\"db-catalog-version\":201608131,\"db-control-version\":920,\"db-system-id\":6569239123849665679,"
|
||||||
|
"\"db-version\":\"9.2\"}\n")));
|
||||||
|
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", strPtr(pg8Path), false, "off", NULL),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Error on primary but standby check ok
|
||||||
|
TEST_ERROR_FMT(cmdCheck(), ArchiveDisabledError, "archive_mode must be enabled");
|
||||||
|
harnessLogResult("P00 INFO: switch wal not performed because this is a standby");
|
||||||
|
|
||||||
// Single primary
|
// Single primary
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
strLstAddZ(argList, "--archive-timeout=.5");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
// Error when WAL segment not found
|
// Error when WAL segment not found
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"),
|
HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"),
|
||||||
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"),
|
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
@@ -81,7 +283,7 @@ testRun(void)
|
|||||||
// WAL segment is found
|
// WAL segment is found
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"),
|
HRNPQ_MACRO_CREATE_RESTORE_POINT(1, "1/1"),
|
||||||
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"),
|
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000010000000100000001"),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
@@ -94,7 +296,7 @@ testRun(void)
|
|||||||
strNew(STORAGE_REPO_ARCHIVE "/9.2-1/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
strNew(STORAGE_REPO_ARCHIVE "/9.2-1/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")),
|
||||||
buffer);
|
buffer);
|
||||||
|
|
||||||
TEST_RESULT_VOID(cmdCheck(), "check");
|
TEST_RESULT_VOID(cmdCheck(), "check primary, WAL archived");
|
||||||
harnessLogResult(
|
harnessLogResult(
|
||||||
strPtr(
|
strPtr(
|
||||||
strNewFmt(
|
strNewFmt(
|
||||||
@@ -102,55 +304,228 @@ testRun(void)
|
|||||||
"0000000100000001/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
|
"0000000100000001/000000010000000100000001-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'",
|
||||||
testPath())));
|
testPath())));
|
||||||
|
|
||||||
// Single standby
|
// Primary == NULL (for test coverage)
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
DbGetResult dbGroup = {0};
|
||||||
|
TEST_RESULT_VOID(checkPrimary(dbGroup), "primary == NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************************************************
|
||||||
|
if (testBegin("checkManifest()"))
|
||||||
|
{
|
||||||
argList = strLstNew();
|
argList = strLstNew();
|
||||||
strLstAddZ(argList, "--stanza=test1");
|
strLstAdd(argList, stanzaOpt);
|
||||||
strLstAdd(argList, pg1PathOpt);
|
strLstAdd(argList, pg1PathOpt);
|
||||||
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
strLstAddZ(argList, "--pg5-host=localhost");
|
||||||
strLstAddZ(argList, "--archive-timeout=.5");
|
strLstAddZ(argList, "--pg5-path=/path/to/pg5");
|
||||||
|
strLstAdd(argList, strNewFmt("--pg5-host-user=%s", testUser()));
|
||||||
harnessCfgLoad(cfgCmdCheck, argList);
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
// Set script
|
// Placeholder test for manifest
|
||||||
|
TEST_ERROR(
|
||||||
|
checkManifest(), UnknownError,
|
||||||
|
"remote-0 process on 'localhost' terminated unexpectedly [127]: bash: pgbackrest: command not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// *****************************************************************************************************************************
|
||||||
|
if (testBegin("checkDbConfig(), checkArchiveCommand()"))
|
||||||
|
{
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkArchiveCommand(NULL), ArchiveCommandInvalidError, "archive_command '[null]' must contain " PROJECT_BIN);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkArchiveCommand(strNew("")), ArchiveCommandInvalidError, "archive_command '' must contain " PROJECT_BIN);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkArchiveCommand(strNew("backrest")), ArchiveCommandInvalidError, "archive_command 'backrest' must contain "
|
||||||
|
PROJECT_BIN);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_RESULT_BOOL(checkArchiveCommand(strNew("pgbackrest --stanza=demo archive-push %p")), true, "archive_command valid");
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, pg8PathOpt);
|
||||||
|
strLstAddZ(argList, "--pg8-port=5433");
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
DbGetResult db = {0};
|
||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), true),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/badpath", true, NULL, NULL),
|
||||||
|
|
||||||
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
|
HRNPQ_MACRO_DONE()
|
||||||
|
});
|
||||||
|
|
||||||
|
TEST_ASSIGN(db, dbGet(false, false), "get primary and standby");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config");
|
||||||
|
|
||||||
|
// Version mismatch
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkDbConfig(PG_VERSION_94, db.primaryId, db.primary, false), DbMismatchError,
|
||||||
|
"version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/"
|
||||||
|
PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n"
|
||||||
|
"HINT: the pg1-path and pg1-port settings likely reference different clusters.",
|
||||||
|
strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path), strPtr(pgVersionToStr(PG_VERSION_94)), strPtr(pg1Path),
|
||||||
|
strPtr(pg1Path));
|
||||||
|
|
||||||
|
// Path mismatch
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkDbConfig(PG_VERSION_92, db.standbyId, db.standby, true), DbMismatchError,
|
||||||
|
"version '%s' and path '%s' queried from cluster do not match version '%s' and '%s' read from '%s/"
|
||||||
|
PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n"
|
||||||
|
"HINT: the pg8-path and pg8-port settings likely reference different clusters.",
|
||||||
|
strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(dbPgDataPath(db.standby)), strPtr(pgVersionToStr(PG_VERSION_92)),
|
||||||
|
strPtr(pg8Path), strPtr(pg8Path));
|
||||||
|
|
||||||
|
// archive-check=false
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
strLstAddZ(argList, "--no-archive-check");
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config --no-archive-check");
|
||||||
|
|
||||||
|
// archive-check not valid for command
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, pg8PathOpt);
|
||||||
|
strLstAddZ(argList, "--pg8-port=5433");
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
harnessCfgLoad(cfgCmdStanzaCreate, argList);
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(
|
||||||
|
checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), "valid db config, archive-check not valid for command");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(dbFree(db.primary), "free primary");
|
||||||
|
TEST_RESULT_VOID(dbFree(db.standby), "free standby");
|
||||||
|
|
||||||
|
// archive_mode=always not supported
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, pg1PathOpt);
|
||||||
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
harnessCfgLoad(cfgCmdCheck, argList);
|
||||||
|
|
||||||
|
harnessPqScriptSet((HarnessPq [])
|
||||||
|
{
|
||||||
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, "always", NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
|
|
||||||
TEST_RESULT_VOID(cmdCheck(), "check");
|
TEST_ASSIGN(db, dbGet(true, true), "get primary");
|
||||||
harnessLogResult("P00 INFO: switch wal not performed because no primary was found");
|
TEST_ERROR_FMT(
|
||||||
|
checkDbConfig(PG_VERSION_92, db.primaryId, db.primary, false), FeatureNotSupportedError,
|
||||||
|
"archive_mode=always not supported");
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(dbFree(db.primary), "free primary");
|
||||||
}
|
}
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("checkDbConfig()"))
|
if (testBegin("checkStanzaInfo(), checkStanzaInfoPg()"))
|
||||||
{
|
{
|
||||||
StringList *argList = strLstNew();
|
InfoArchive *archiveInfo = infoArchiveNew(PG_VERSION_96, 6569239123849665679, NULL);
|
||||||
strLstAddZ(argList, "--stanza=test1");
|
InfoPgData archivePg = infoPgData(infoArchivePg(archiveInfo), infoPgDataCurrentId(infoArchivePg(archiveInfo)));
|
||||||
strLstAdd(argList, pg1PathOpt);
|
|
||||||
|
InfoBackup *backupInfo = infoBackupNew(PG_VERSION_96, 6569239123849665679, NULL);
|
||||||
|
InfoPgData backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo)));
|
||||||
|
|
||||||
|
TEST_RESULT_VOID(checkStanzaInfo(&archivePg, &backupPg), "stanza info files match");
|
||||||
|
|
||||||
|
// Create a corrupted backup file - system id
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
backupInfo = infoBackupNew(PG_VERSION_96, 6569239123849665999, NULL);
|
||||||
|
backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo)));
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
|
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
|
"backup : id = 1, version = 9.6, system-id = 6569239123849665999\n"
|
||||||
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
|
// Create a corrupted backup file - system id and version
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
backupInfo = infoBackupNew(PG_VERSION_95, 6569239123849665999, NULL);
|
||||||
|
backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo)));
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
|
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
|
"backup : id = 1, version = 9.5, system-id = 6569239123849665999\n"
|
||||||
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
|
// Create a corrupted backup file - version
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
backupInfo = infoBackupNew(PG_VERSION_95, 6569239123849665679, NULL);
|
||||||
|
backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo)));
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
|
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
|
"backup : id = 1, version = 9.5, system-id = 6569239123849665679\n"
|
||||||
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
|
// Create a corrupted backup file - db id
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
infoBackupPgSet(backupInfo, PG_VERSION_96, 6569239123849665679);
|
||||||
|
backupPg = infoPgData(infoBackupPg(backupInfo), infoPgDataCurrentId(infoBackupPg(backupInfo)));
|
||||||
|
|
||||||
|
TEST_ERROR_FMT(
|
||||||
|
checkStanzaInfo(&archivePg, &backupPg), FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
|
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
|
"backup : id = 2, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
|
// checkStanzaInfoPg
|
||||||
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
|
argList = strLstNew();
|
||||||
|
strLstAddZ(argList, "--no-online");
|
||||||
|
strLstAdd(argList, stanzaOpt);
|
||||||
|
strLstAdd(argList, strNewFmt("--pg1-path=%s/%s", testPath(), strPtr(stanza)));
|
||||||
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
strLstAdd(argList, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
harnessCfgLoad(cfgCmdCheck, argList);
|
strLstAddZ(argList, "--repo1-cipher-type=aes-256-cbc");
|
||||||
|
setenv("PGBACKREST_REPO1_CIPHER_PASS", "12345678", true);
|
||||||
|
harnessCfgLoad(cfgCmdStanzaCreate, argList);
|
||||||
|
|
||||||
TEST_RESULT_VOID(checkDbConfig(PG_VERSION_92, 1, PG_VERSION_92, pg1Path), "valid db config");
|
// Create pg_control
|
||||||
|
storagePutNP(
|
||||||
|
storageNewWriteNP(storageTest, strNewFmt("%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL, strPtr(stanza))),
|
||||||
|
pgControlTestToBuffer((PgControl){.version = PG_VERSION_96, .systemId = 6569239123849665679}));
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// Create info files
|
||||||
|
TEST_RESULT_VOID(cmdStanzaCreate(), "stanza create - encryption");
|
||||||
|
|
||||||
|
// Version mismatch
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
checkDbConfig(PG_VERSION_92, 1, PG_VERSION_94, pg1Path),
|
checkStanzaInfoPg(storageRepo(), PG_VERSION_94, 6569239123849665679, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'"
|
cfgOptionStr(cfgOptRepoCipherPass)), FileInvalidError,
|
||||||
" read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n"
|
"backup and archive info files exist but do not match the database\n"
|
||||||
"HINT: the pg1-path and pg1-port settings likely reference different clusters.",
|
"HINT: is this the correct stanza?\n"
|
||||||
strPtr(pgVersionToStr(PG_VERSION_94)), strPtr(pg1Path), strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path),
|
"HINT: did an error occur during stanza-upgrade?");
|
||||||
strPtr(pg1Path));
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// SystemId mismatch
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
checkDbConfig(PG_VERSION_92, 1, PG_VERSION_92, strNew("bogus/path")),
|
checkStanzaInfoPg(storageRepo(), PG_VERSION_96, 6569239123849665699, cipherType(cfgOptionStr(cfgOptRepoCipherType)),
|
||||||
DbMismatchError, "version '%s' and path '%s' queried from cluster do not match version '%s' and '%s'"
|
cfgOptionStr(cfgOptRepoCipherPass)), FileInvalidError,
|
||||||
" read from '%s/" PG_PATH_GLOBAL "/" PG_FILE_PGCONTROL "'\n"
|
"backup and archive info files exist but do not match the database\n"
|
||||||
"HINT: the pg1-path and pg1-port settings likely reference different clusters.",
|
"HINT: is this the correct stanza?\n"
|
||||||
strPtr(pgVersionToStr(PG_VERSION_92)), "bogus/path", strPtr(pgVersionToStr(PG_VERSION_92)), strPtr(pg1Path),
|
"HINT: did an error occur during stanza-upgrade?");
|
||||||
strPtr(pg1Path));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FUNCTION_HARNESS_RESULT_VOID();
|
FUNCTION_HARNESS_RESULT_VOID();
|
||||||
|
@@ -34,7 +34,7 @@ testRun(void)
|
|||||||
strLstAdd(argListBase, strNewFmt("--repo1-path=%s/repo", testPath()));
|
strLstAdd(argListBase, strNewFmt("--repo1-path=%s/repo", testPath()));
|
||||||
|
|
||||||
// *****************************************************************************************************************************
|
// *****************************************************************************************************************************
|
||||||
if (testBegin("cmdStanzaCreate(), infoValidate()"))
|
if (testBegin("cmdStanzaCreate(), checkStanzaInfo()"))
|
||||||
{
|
{
|
||||||
// Load Parameters
|
// Load Parameters
|
||||||
StringList *argList = strLstDup(argListBase);
|
StringList *argList = strLstDup(argListBase);
|
||||||
@@ -231,7 +231,7 @@ testRun(void)
|
|||||||
cmdStanzaCreate(), FileMissingError, "archive.info exists but backup.info is missing\n"
|
cmdStanzaCreate(), FileMissingError, "archive.info exists but backup.info is missing\n"
|
||||||
"HINT: this may be a symptom of repository corruption!");
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
// infoValidate()
|
// checkStanzaInfo() - already checked in checkTest so just a sanity check here
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
// Create a corrupted backup file - db id
|
// Create a corrupted backup file - db id
|
||||||
contentBackup = strNew
|
contentBackup = strNew
|
||||||
@@ -250,7 +250,7 @@ testRun(void)
|
|||||||
TEST_RESULT_VOID(
|
TEST_RESULT_VOID(
|
||||||
storagePutNP(
|
storagePutNP(
|
||||||
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
||||||
"put back info to file - bad db-id");
|
"put backup info to file - bad db-id");
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n"
|
cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n"
|
||||||
@@ -258,57 +258,12 @@ testRun(void)
|
|||||||
"backup : id = 2, version = 9.6, system-id = 6569239123849665679\n"
|
"backup : id = 2, version = 9.6, system-id = 6569239123849665679\n"
|
||||||
"HINT: this may be a symptom of repository corruption!");
|
"HINT: this may be a symptom of repository corruption!");
|
||||||
|
|
||||||
// Create a corrupted backup file - system id
|
//--------------------------------------------------------------------------------------------------------------------------
|
||||||
contentBackup = strNew
|
// Copy files may or may not exist - remove
|
||||||
(
|
storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(archiveInfoFileName)));
|
||||||
"[db]\n"
|
storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(backupInfoFileName)));
|
||||||
"db-catalog-version=201608131\n"
|
|
||||||
"db-control-version=960\n"
|
|
||||||
"db-id=1\n"
|
|
||||||
"db-system-id=6569239123849665999\n"
|
|
||||||
"db-version=\"9.6\"\n"
|
|
||||||
"\n"
|
|
||||||
"[db:history]\n"
|
|
||||||
"1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665999,"
|
|
||||||
"\"db-version\":\"9.6\"}\n"
|
|
||||||
);
|
|
||||||
TEST_RESULT_VOID(
|
|
||||||
storagePutNP(
|
|
||||||
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
|
||||||
"put back info to file - bad system-id");
|
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
// Create an archive.info file and backup.info files that match but do not match the current database version
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n"
|
|
||||||
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
|
||||||
"backup : id = 1, version = 9.6, system-id = 6569239123849665999\n"
|
|
||||||
"HINT: this may be a symptom of repository corruption!");
|
|
||||||
|
|
||||||
// Create a corrupted backup file - system id and version
|
|
||||||
contentBackup = strNew
|
|
||||||
(
|
|
||||||
"[db]\n"
|
|
||||||
"db-catalog-version=201608131\n"
|
|
||||||
"db-control-version=960\n"
|
|
||||||
"db-id=1\n"
|
|
||||||
"db-system-id=6569239123849665999\n"
|
|
||||||
"db-version=\"9.5\"\n"
|
|
||||||
"\n"
|
|
||||||
"[db:history]\n"
|
|
||||||
"1={\"db-catalog-version\":201608131,\"db-control-version\":960,\"db-system-id\":6569239123849665999,"
|
|
||||||
"\"db-version\":\"9.5\"}\n"
|
|
||||||
);
|
|
||||||
TEST_RESULT_VOID(
|
|
||||||
storagePutNP(
|
|
||||||
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
|
||||||
"put back info to file - bad system-id and version");
|
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n"
|
|
||||||
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
|
||||||
"backup : id = 1, version = 9.5, system-id = 6569239123849665999\n"
|
|
||||||
"HINT: this may be a symptom of repository corruption!");
|
|
||||||
|
|
||||||
// Create a corrupted backup file - version
|
|
||||||
contentBackup = strNew
|
contentBackup = strNew
|
||||||
(
|
(
|
||||||
"[db]\n"
|
"[db]\n"
|
||||||
@@ -325,20 +280,8 @@ testRun(void)
|
|||||||
TEST_RESULT_VOID(
|
TEST_RESULT_VOID(
|
||||||
storagePutNP(
|
storagePutNP(
|
||||||
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
||||||
"put back info to file - bad version");
|
"put backup info to file");
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup info file and archive info file do not match\n"
|
|
||||||
"archive: id = 1, version = 9.6, system-id = 6569239123849665679\n"
|
|
||||||
"backup : id = 1, version = 9.5, system-id = 6569239123849665679\n"
|
|
||||||
"HINT: this may be a symptom of repository corruption!");
|
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Copy files may or may not exist - remove
|
|
||||||
storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(archiveInfoFileName)));
|
|
||||||
storageRemoveNP(storageTest, strNewFmt("%s" INFO_COPY_EXT, strPtr(backupInfoFileName)));
|
|
||||||
|
|
||||||
// Create an archive.info file that matches the backup.info file but does not match the current database version
|
|
||||||
contentArchive = strNew
|
contentArchive = strNew
|
||||||
(
|
(
|
||||||
"[db]\n"
|
"[db]\n"
|
||||||
@@ -355,7 +298,7 @@ testRun(void)
|
|||||||
"put archive info file");
|
"put archive info file");
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup and archive info files already exist but do not match the database\n"
|
cmdStanzaCreate(), FileInvalidError, "backup and archive info files exist but do not match the database\n"
|
||||||
"HINT: is this the correct stanza?\n"
|
"HINT: is this the correct stanza?\n"
|
||||||
"HINT: did an error occur during stanza-upgrade?");
|
"HINT: did an error occur during stanza-upgrade?");
|
||||||
|
|
||||||
@@ -391,10 +334,10 @@ testRun(void)
|
|||||||
TEST_RESULT_VOID(
|
TEST_RESULT_VOID(
|
||||||
storagePutNP(
|
storagePutNP(
|
||||||
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
storageNewWriteNP(storageTest, backupInfoFileName), harnessInfoChecksum(contentBackup)),
|
||||||
"put back info to file");
|
"put backup info to file");
|
||||||
|
|
||||||
TEST_ERROR_FMT(
|
TEST_ERROR_FMT(
|
||||||
cmdStanzaCreate(), FileInvalidError, "backup and archive info files already exist but do not match the database\n"
|
cmdStanzaCreate(), FileInvalidError, "backup and archive info files exist but do not match the database\n"
|
||||||
"HINT: is this the correct stanza?\n"
|
"HINT: is this the correct stanza?\n"
|
||||||
"HINT: did an error occur during stanza-upgrade?");
|
"HINT: did an error occur during stanza-upgrade?");
|
||||||
|
|
||||||
@@ -449,7 +392,7 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
@@ -460,7 +403,7 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
@@ -477,7 +420,7 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
@@ -498,7 +441,7 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(strNewFmt("%s/pg2", testPath())), false),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", strPtr(strNewFmt("%s/pg2", testPath())), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
@@ -532,8 +475,8 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", testPath(), true, NULL, NULL),
|
||||||
HRNPQ_MACRO_OPEN_92(2, "dbname='postgres' port=5434", strPtr(pg1Path), false),
|
HRNPQ_MACRO_OPEN_92(2, "dbname='postgres' port=5434", strPtr(pg1Path), false, NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(2),
|
HRNPQ_MACRO_CLOSE(2),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
|
@@ -43,12 +43,12 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
||||||
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
||||||
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata"),
|
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata", NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
|
||||||
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
||||||
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
||||||
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata"),
|
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_84, "/pgdata", NULL, NULL),
|
||||||
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000030000000200000003"),
|
HRNPQ_MACRO_WAL_SWITCH(1, "xlog", "000000030000000200000003"),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ testRun(void)
|
|||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
HRNPQ_MACRO_OPEN(1, "dbname='postgres' port=5432"),
|
||||||
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
HRNPQ_MACRO_SET_SEARCH_PATH(1),
|
||||||
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_94, "/pgdata"),
|
HRNPQ_MACRO_VALIDATE_QUERY(1, PG_VERSION_94, "/pgdata", NULL, NULL),
|
||||||
HRNPQ_MACRO_SET_APPLICATION_NAME(1),
|
HRNPQ_MACRO_SET_APPLICATION_NAME(1),
|
||||||
HRNPQ_MACRO_IS_STANDBY_QUERY(1, true),
|
HRNPQ_MACRO_IS_STANDBY_QUERY(1, true),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
@@ -141,7 +141,7 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata"),
|
HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata", NULL, NULL),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_DONE()
|
HRNPQ_MACRO_DONE()
|
||||||
});
|
});
|
||||||
@@ -169,8 +169,8 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata"),
|
HRNPQ_MACRO_OPEN_84(1, "dbname='postgres' port=5432", "/pgdata", NULL, NULL),
|
||||||
HRNPQ_MACRO_OPEN_84(8, "dbname='postgres' port=5433", "/pgdata"),
|
HRNPQ_MACRO_OPEN_84(8, "dbname='postgres' port=5433", "/pgdata", NULL, NULL),
|
||||||
|
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
HRNPQ_MACRO_CLOSE(8),
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
@@ -184,8 +184,8 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL),
|
||||||
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true),
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL),
|
||||||
|
|
||||||
HRNPQ_MACRO_CLOSE(8),
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
@@ -199,8 +199,8 @@ testRun(void)
|
|||||||
// -------------------------------------------------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------------------------------------------------
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL),
|
||||||
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true),
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5433", "/pgdata", true, NULL, NULL),
|
||||||
|
|
||||||
HRNPQ_MACRO_CLOSE(8),
|
HRNPQ_MACRO_CLOSE(8),
|
||||||
HRNPQ_MACRO_CLOSE(1),
|
HRNPQ_MACRO_CLOSE(1),
|
||||||
@@ -234,7 +234,7 @@ testRun(void)
|
|||||||
|
|
||||||
harnessPqScriptSet((HarnessPq [])
|
harnessPqScriptSet((HarnessPq [])
|
||||||
{
|
{
|
||||||
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true),
|
HRNPQ_MACRO_OPEN_92(1, "dbname='postgres' port=5432", "/pgdata", true, NULL, NULL),
|
||||||
|
|
||||||
// pg-4 error
|
// pg-4 error
|
||||||
{.session = 4, .function = HRNPQ_CONNECTDB, .param = "[\"dbname='postgres' port=5433\"]"},
|
{.session = 4, .function = HRNPQ_CONNECTDB, .param = "[\"dbname='postgres' port=5433\"]"},
|
||||||
@@ -242,7 +242,7 @@ testRun(void)
|
|||||||
{.session = 4, .function = HRNPQ_ERRORMESSAGE, .resultZ = "error"},
|
{.session = 4, .function = HRNPQ_ERRORMESSAGE, .resultZ = "error"},
|
||||||
{.session = 4, .function = HRNPQ_FINISH},
|
{.session = 4, .function = HRNPQ_FINISH},
|
||||||
|
|
||||||
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5434", "/pgdata", false),
|
HRNPQ_MACRO_OPEN_92(8, "dbname='postgres' port=5434", "/pgdata", false, NULL, NULL),
|
||||||
|
|
||||||
HRNPQ_MACRO_CREATE_RESTORE_POINT(8, "2/3"),
|
HRNPQ_MACRO_CREATE_RESTORE_POINT(8, "2/3"),
|
||||||
HRNPQ_MACRO_WAL_SWITCH(8, "xlog", "000000010000000200000003"),
|
HRNPQ_MACRO_WAL_SWITCH(8, "xlog", "000000010000000200000003"),
|
||||||
@@ -261,6 +261,8 @@ testRun(void)
|
|||||||
|
|
||||||
TEST_RESULT_INT(result.primaryId, 8, " check primary id");
|
TEST_RESULT_INT(result.primaryId, 8, " check primary id");
|
||||||
TEST_RESULT_BOOL(result.primary != NULL, true, " check primary");
|
TEST_RESULT_BOOL(result.primary != NULL, true, " check primary");
|
||||||
|
TEST_RESULT_STR(strPtr(dbArchiveMode(result.primary)), "on", " dbArchiveMode");
|
||||||
|
TEST_RESULT_STR(strPtr(dbArchiveCommand(result.primary)), PROJECT_BIN, " dbArchiveCommand");
|
||||||
TEST_RESULT_STR(strPtr(dbWalSwitch(result.primary)), "000000010000000200000003", " wal switch");
|
TEST_RESULT_STR(strPtr(dbWalSwitch(result.primary)), "000000010000000200000003", " wal switch");
|
||||||
TEST_RESULT_INT(result.standbyId, 1, " check standby id");
|
TEST_RESULT_INT(result.standbyId, 1, " check standby id");
|
||||||
TEST_RESULT_BOOL(result.standby != NULL, true, " check standby");
|
TEST_RESULT_BOOL(result.standby != NULL, true, " check standby");
|
||||||
|
Reference in New Issue
Block a user