From 155c8081632d1081da8b7e94ebd3a7d422f0f280 Mon Sep 17 00:00:00 2001 From: David Steele Date: Tue, 10 Jan 2017 19:54:51 -0500 Subject: [PATCH] Split the check command out of the Archive.pm module. --- bin/pgbackrest | 6 +- doc/xml/release.xml | 4 + lib/pgBackRest/Archive/Archive.pm | 204 ------------------- lib/pgBackRest/Check/Check.pm | 248 ++++++++++++++++++++++++ lib/pgBackRest/Protocol/Common.pm | 6 +- lib/pgBackRest/Protocol/RemoteMinion.pm | 6 +- 6 files changed, 266 insertions(+), 208 deletions(-) create mode 100644 lib/pgBackRest/Check/Check.pm diff --git a/bin/pgbackrest b/bin/pgbackrest index 5170838b1..69d418ba2 100755 --- a/bin/pgbackrest +++ b/bin/pgbackrest @@ -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()); } ################################################################################################################################ diff --git a/doc/xml/release.xml b/doc/xml/release.xml index 5f602aadb..2637a76c9 100644 --- a/doc/xml/release.xml +++ b/doc/xml/release.xml @@ -211,6 +211,10 @@

Moved the Archive modules to the Archive directory.

+ + +

Split the check command out of the Archive.pm module.

+
diff --git a/lib/pgBackRest/Archive/Archive.pm b/lib/pgBackRest/Archive/Archive.pm index 9b513acec..3ddb6db2d 100644 --- a/lib/pgBackRest/Archive/Archive.pm +++ b/lib/pgBackRest/Archive/Archive.pm @@ -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; diff --git a/lib/pgBackRest/Check/Check.pm b/lib/pgBackRest/Check/Check.pm new file mode 100644 index 000000000..70e18e591 --- /dev/null +++ b/lib/pgBackRest/Check/Check.pm @@ -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; diff --git a/lib/pgBackRest/Protocol/Common.pm b/lib/pgBackRest/Protocol/Common.pm index b18908d78..9e09d8d0b 100644 --- a/lib/pgBackRest/Protocol/Common.pm +++ b/lib/pgBackRest/Protocol/Common.pm @@ -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); diff --git a/lib/pgBackRest/Protocol/RemoteMinion.pm b/lib/pgBackRest/Protocol/RemoteMinion.pm index a83ea1923..4a0ab6f3d 100644 --- a/lib/pgBackRest/Protocol/RemoteMinion.pm +++ b/lib/pgBackRest/Protocol/RemoteMinion.pm @@ -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()})},