You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-09-16 09:06:18 +02:00
Split the check command out of the Archive.pm module.
This commit is contained in:
@@ -139,7 +139,11 @@ local $EVAL_ERROR = undef; eval
|
||||
################################################################################################################################
|
||||
if (commandTest(CMD_CHECK))
|
||||
{
|
||||
exitSafe(new pgBackRest::Archive::Archive()->check());
|
||||
# Load module dynamically
|
||||
require pgBackRest::Check::Check;
|
||||
pgBackRest::Check::Check->import();
|
||||
|
||||
exitSafe(new pgBackRest::Check::Check()->process());
|
||||
}
|
||||
|
||||
################################################################################################################################
|
||||
|
@@ -211,6 +211,10 @@
|
||||
<release-item>
|
||||
<p>Moved the <code>Archive</code> modules to the <path>Archive</path> directory.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<p>Split the <cmd>check</cmd> command out of the <code>Archive.pm</code> module.</p>
|
||||
</release-item>
|
||||
</release-refactor-list>
|
||||
</release-core-list>
|
||||
|
||||
|
@@ -432,63 +432,6 @@ sub getCheck
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# getBackupInfoCheck
|
||||
#
|
||||
# Check the backup.info file, if it exists, to confirm the DB version, system-id, control and catalog numbers match the database.
|
||||
####################################################################################################################################
|
||||
sub getBackupInfoCheck
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oFile,
|
||||
$strDbVersion,
|
||||
$iControlVersion,
|
||||
$iCatalogVersion,
|
||||
$ullDbSysId
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->getBackupInfoCheck', \@_,
|
||||
{name => 'oFile'},
|
||||
{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 ($oFile->isRemote(PATH_BACKUP))
|
||||
{
|
||||
$iDbHistoryId = $oFile->{oProtocol}->cmdExecute(
|
||||
OP_ARCHIVE_GET_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iDbHistoryId = (new pgBackRest::BackupInfo($oFile->pathGet(PATH_BACKUP_CLUSTER)))->check(
|
||||
$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# getArchiveId
|
||||
#
|
||||
@@ -1058,151 +1001,4 @@ sub xfer
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# check
|
||||
#
|
||||
# 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 check
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my $strOperation = logDebugParam(__PACKAGE__ . '->check');
|
||||
|
||||
# Initialize default file object
|
||||
my $oFile = new pgBackRest::File
|
||||
(
|
||||
optionGet(OPTION_STANZA),
|
||||
optionGet(OPTION_REPO_PATH),
|
||||
protocolGet(isRepoLocal() ? DB : BACKUP)
|
||||
);
|
||||
|
||||
# Initialize the database object
|
||||
my $oDb = dbMasterGet();
|
||||
|
||||
# Validate the database configuration
|
||||
$oDb->configValidate();
|
||||
|
||||
# Get the timeout and error message to display - if it is 0 we are testing
|
||||
my $iArchiveTimeout = optionGet(OPTION_ARCHIVE_TIMEOUT);
|
||||
|
||||
# Initialize the result variables
|
||||
my $iResult = 0;
|
||||
my $strResultMessage = undef;
|
||||
|
||||
# Record the start time to wait for the archive.info file to be written
|
||||
my $oWait = waitInit($iArchiveTimeout);
|
||||
|
||||
my $strArchiveId = undef;
|
||||
my $strArchiveFile = undef;
|
||||
my $strWalSegment = undef;
|
||||
|
||||
# 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->getBackupInfoCheck($oFile);
|
||||
return true;
|
||||
}
|
||||
# If there is an unhandled error then confess
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
|
||||
# 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 = $self->getCheck($oFile);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
}
|
||||
|
||||
# If able to get the archive id then force archiving and check the arrival of the archived WAL file with the time specified
|
||||
if ($iResult == 0 && !$oDb->isStandby())
|
||||
{
|
||||
$strWalSegment = $oDb->xlogSwitch();
|
||||
|
||||
eval
|
||||
{
|
||||
$strArchiveFile = $self->walFileName($oFile, $strArchiveId, $strWalSegment, false, $iArchiveTimeout);
|
||||
return true;
|
||||
}
|
||||
# If this is a backrest error then capture the code and message else confess
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
# Reset the console logging
|
||||
logLevelSet(undef, optionGet(OPTION_LOG_LEVEL_CONSOLE));
|
||||
|
||||
# If the archiving was successful and backup.info check did not error in an unexpected way, then indicate success
|
||||
# Else, log the error.
|
||||
if ($iResult == 0)
|
||||
{
|
||||
if (!$oDb->isStandby())
|
||||
{
|
||||
&log(INFO,
|
||||
"WAL segment ${strWalSegment} successfully stored in the archive at '" .
|
||||
$oFile->pathGet(PATH_BACKUP_ARCHIVE, "$strArchiveId/${strArchiveFile}") . "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
&log(INFO, "switch xlog cannot be performed on the standby, all other checks passed successfully");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
&log(ERROR, $strResultMessage, $iResult);
|
||||
|
||||
# If a switch xlog was attempted, then alert the user to the WAL that did not reach the archive
|
||||
if (defined($strWalSegment))
|
||||
{
|
||||
&log(WARN,
|
||||
"WAL segment ${strWalSegment} did not reach the archive:" . (defined($strArchiveId) ? $strArchiveId : '') . "\n" .
|
||||
"HINT: Check the archive_command to ensure that all options are correct (especialy --stanza).\n" .
|
||||
"HINT: Check the PostreSQL server log for errors.");
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iResult', value => $iResult, trace => true}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
|
248
lib/pgBackRest/Check/Check.pm
Normal file
248
lib/pgBackRest/Check/Check.pm
Normal file
@@ -0,0 +1,248 @@
|
||||
####################################################################################################################################
|
||||
# CHECK MODULE
|
||||
####################################################################################################################################
|
||||
package pgBackRest::Check::Check;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Db;
|
||||
use pgBackRest::File;
|
||||
use pgBackRest::Protocol::Common;
|
||||
use pgBackRest::Protocol::Protocol;
|
||||
|
||||
####################################################################################################################################
|
||||
# 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 default file object
|
||||
my $oFile = new pgBackRest::File
|
||||
(
|
||||
optionGet(OPTION_STANZA),
|
||||
optionGet(OPTION_REPO_PATH),
|
||||
protocolGet(isRepoLocal() ? DB : BACKUP)
|
||||
);
|
||||
|
||||
# Initialize the archive object
|
||||
my $oArchive = new pgBackRest::Archive::Archive();
|
||||
|
||||
# Initialize the database object
|
||||
my $oDb = dbMasterGet();
|
||||
|
||||
# Validate the database configuration
|
||||
$oDb->configValidate();
|
||||
|
||||
# Get the timeout and error message to display - if it is 0 we are testing
|
||||
my $iArchiveTimeout = optionGet(OPTION_ARCHIVE_TIMEOUT);
|
||||
|
||||
# Initialize the result variables
|
||||
my $iResult = 0;
|
||||
my $strResultMessage = undef;
|
||||
|
||||
# Record the start time to wait for the archive.info file to be written
|
||||
my $oWait = waitInit($iArchiveTimeout);
|
||||
|
||||
my $strArchiveId = undef;
|
||||
my $strArchiveFile = undef;
|
||||
my $strWalSegment = undef;
|
||||
|
||||
# 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($oFile);
|
||||
return true;
|
||||
}
|
||||
# If there is an unhandled error then confess
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
|
||||
# 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 = $oArchive->getCheck($oFile);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
}
|
||||
|
||||
# If able to get the archive id then force archiving and check the arrival of the archived WAL file with the time specified
|
||||
if ($iResult == 0 && !$oDb->isStandby())
|
||||
{
|
||||
$strWalSegment = $oDb->xlogSwitch();
|
||||
|
||||
eval
|
||||
{
|
||||
$strArchiveFile = $oArchive->walFileName($oFile, $strArchiveId, $strWalSegment, false, $iArchiveTimeout);
|
||||
return true;
|
||||
}
|
||||
# If this is a backrest error then capture the code and message else confess
|
||||
or do
|
||||
{
|
||||
# Confess unhandled errors
|
||||
confess $EVAL_ERROR if (!isException($EVAL_ERROR));
|
||||
|
||||
# If this is a backrest error then capture the last code and message
|
||||
$iResult = $EVAL_ERROR->code();
|
||||
$strResultMessage = $EVAL_ERROR->message();
|
||||
};
|
||||
}
|
||||
|
||||
# Reset the console logging
|
||||
logLevelSet(undef, optionGet(OPTION_LOG_LEVEL_CONSOLE));
|
||||
|
||||
# If the archiving was successful and backup.info check did not error in an unexpected way, then indicate success
|
||||
# Else, log the error.
|
||||
if ($iResult == 0)
|
||||
{
|
||||
if (!$oDb->isStandby())
|
||||
{
|
||||
&log(INFO,
|
||||
"WAL segment ${strWalSegment} successfully stored in the archive at '" .
|
||||
$oFile->pathGet(PATH_BACKUP_ARCHIVE, "$strArchiveId/${strArchiveFile}") . "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
&log(INFO, "switch xlog cannot be performed on the standby, all other checks passed successfully");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
&log(ERROR, $strResultMessage, $iResult);
|
||||
|
||||
# If a switch xlog was attempted, then alert the user to the WAL that did not reach the archive
|
||||
if (defined($strWalSegment))
|
||||
{
|
||||
&log(WARN,
|
||||
"WAL segment ${strWalSegment} did not reach the archive:" . (defined($strArchiveId) ? $strArchiveId : '') . "\n" .
|
||||
"HINT: Check the archive_command to ensure that all options are correct (especialy --stanza).\n" .
|
||||
"HINT: Check the PostreSQL server log for errors.");
|
||||
}
|
||||
}
|
||||
|
||||
# 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,
|
||||
$oFile,
|
||||
$strDbVersion,
|
||||
$iControlVersion,
|
||||
$iCatalogVersion,
|
||||
$ullDbSysId
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->getBackupInfoCheck', \@_,
|
||||
{name => 'oFile'},
|
||||
{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 ($oFile->isRemote(PATH_BACKUP))
|
||||
{
|
||||
$iDbHistoryId = $oFile->{oProtocol}->cmdExecute(
|
||||
OP_CHECK_BACKUP_INFO_CHECK, [$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$iDbHistoryId = (new pgBackRest::BackupInfo($oFile->pathGet(PATH_BACKUP_CLUSTER)))->check(
|
||||
$strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iDbHistoryId', value => $iDbHistoryId, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
@@ -43,13 +43,15 @@ use constant OP_BACKUP_FILE => 'backupF
|
||||
# Archive Module
|
||||
use constant OP_ARCHIVE_GET_ARCHIVE_ID => 'archiveId';
|
||||
push @EXPORT, qw(OP_ARCHIVE_GET_ARCHIVE_ID);
|
||||
use constant OP_ARCHIVE_GET_BACKUP_INFO_CHECK => 'backupInfoCheck';
|
||||
push @EXPORT, qw(OP_ARCHIVE_GET_BACKUP_INFO_CHECK);
|
||||
use constant OP_ARCHIVE_GET_CHECK => 'archiveCheck';
|
||||
push @EXPORT, qw(OP_ARCHIVE_GET_CHECK);
|
||||
use constant OP_ARCHIVE_PUSH_CHECK => 'archivePushCheck';
|
||||
push @EXPORT, qw(OP_ARCHIVE_PUSH_CHECK);
|
||||
|
||||
# Check Module
|
||||
use constant OP_CHECK_BACKUP_INFO_CHECK => 'backupInfoCheck';
|
||||
push @EXPORT, qw(OP_CHECK_BACKUP_INFO_CHECK);
|
||||
|
||||
# Db Module
|
||||
use constant OP_DB_CONNECT => 'dbConnect';
|
||||
push @EXPORT, qw(OP_DB_CONNECT);
|
||||
|
@@ -13,6 +13,7 @@ use File::Basename qw(dirname);
|
||||
use pgBackRest::BackupFile;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Archive::Archive;
|
||||
use pgBackRest::Check::Check;
|
||||
use pgBackRest::Config::Config;
|
||||
use pgBackRest::Db;
|
||||
use pgBackRest::File;
|
||||
@@ -79,6 +80,7 @@ sub init
|
||||
);
|
||||
|
||||
my $oArchive = new pgBackRest::Archive::Archive();
|
||||
my $oCheck = new pgBackRest::Check::Check();
|
||||
my $oInfo = new pgBackRest::Info();
|
||||
my $oDb = new pgBackRest::Db();
|
||||
|
||||
@@ -87,10 +89,12 @@ sub init
|
||||
{
|
||||
# Archive commands
|
||||
&OP_ARCHIVE_GET_ARCHIVE_ID => sub {$oArchive->getArchiveId($oFile)},
|
||||
&OP_ARCHIVE_GET_BACKUP_INFO_CHECK => sub {$oArchive->getBackupInfoCheck($oFile, @{shift()})},
|
||||
&OP_ARCHIVE_GET_CHECK => sub {$oArchive->getCheck($oFile, @{shift()})},
|
||||
&OP_ARCHIVE_PUSH_CHECK => sub {$oArchive->pushCheck($oFile, @{shift()})},
|
||||
|
||||
# Check commands
|
||||
&OP_CHECK_BACKUP_INFO_CHECK => sub {$oCheck->backupInfoCheck($oFile, @{shift()})},
|
||||
|
||||
# Db commands
|
||||
&OP_DB_CONNECT => sub {$oDb->connect()},
|
||||
&OP_DB_EXECUTE_SQL => sub {$oDb->executeSql(@{shift()})},
|
||||
|
Reference in New Issue
Block a user