mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-12 10:04:14 +02:00
e951c4f9c2
Contributed by Cynthia Shang.
250 lines
8.7 KiB
Perl
250 lines
8.7 KiB
Perl
####################################################################################################################################
|
|
# STANZA MODULE
|
|
#
|
|
# Contains functions for adding, upgrading and removing a stanza.
|
|
####################################################################################################################################
|
|
package pgBackRest::Stanza;
|
|
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
use English '-no_match_vars';
|
|
|
|
use Exporter qw(import);
|
|
our @EXPORT = qw();
|
|
|
|
use pgBackRest::Common::Exception;
|
|
use pgBackRest::Common::Log;
|
|
use pgBackRest::Config::Config;
|
|
use pgBackRest::Archive;
|
|
use pgBackRest::ArchiveInfo;
|
|
use pgBackRest::BackupInfo;
|
|
use pgBackRest::Db;
|
|
use pgBackRest::DbVersion;
|
|
use pgBackRest::File;
|
|
use pgBackRest::FileCommon;
|
|
use pgBackRest::Protocol::Common;
|
|
use pgBackRest::Protocol::Protocol;
|
|
use IO::Uncompress::Gunzip qw($GunzipError);
|
|
|
|
####################################################################################################################################
|
|
# CONSTRUCTOR
|
|
####################################################################################################################################
|
|
sub new
|
|
{
|
|
my $class = shift; # Class name
|
|
|
|
# Create the class hash
|
|
my $self = {};
|
|
bless $self, $class;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my $strOperation = logDebugParam(__PACKAGE__ . '->new');
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'self', value => $self}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# Process Stanza Commands
|
|
####################################################################################################################################
|
|
sub process
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my ($strOperation) = logDebugParam(__PACKAGE__ . '->process');
|
|
|
|
my $iResult;
|
|
|
|
# Process stanza create
|
|
if (commandTest(CMD_STANZA_CREATE))
|
|
{
|
|
$iResult = $self->stanzaCreate();
|
|
}
|
|
# Else error if any other command is found
|
|
else
|
|
{
|
|
confess &log(ASSERT, "Stanza->process() called with invalid command: " . commandGet());
|
|
}
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'iResult', value => $iResult, trace => true}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# stanzaCreate
|
|
#
|
|
# Creates the required data for the stanza.
|
|
####################################################################################################################################
|
|
sub stanzaCreate
|
|
{
|
|
my $self = shift;
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my ($strOperation) = logDebugParam(__PACKAGE__ . '->stanzaCreate');
|
|
|
|
# Initialize default file object with protocol set to NONE meaning strictly local
|
|
my $oFile = new pgBackRest::File
|
|
(
|
|
optionGet(OPTION_STANZA),
|
|
optionGet(OPTION_REPO_PATH),
|
|
protocolGet(NONE)
|
|
);
|
|
|
|
# Initialize the database object
|
|
my $oDb = dbMasterGet();
|
|
|
|
# Validate the database configuration - if the db-path in pgbackrest.conf does not match the pg_control
|
|
# then this will error alerting the user to fix the pgbackrest.conf
|
|
$oDb->configValidate();
|
|
|
|
my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) = $oDb->info();
|
|
|
|
# Initialize the result variables
|
|
my $iResult = 0;
|
|
my $strResultMessage = undef;
|
|
|
|
# Since restore points are only supported in PG>= 9.1 the check command may fail for older versions if there has been no write
|
|
# activity since the last log rotation. Therefore, manually create the files to be sure the backup and archive.info files
|
|
# get created. If the command is twice, just check the files if the DB version is older than 9.1.
|
|
|
|
# If the backup path does not exist, create it
|
|
if (!fileExists($oFile->pathGet(PATH_BACKUP_CLUSTER)))
|
|
{
|
|
# Create the cluster backup path
|
|
$oFile->pathCreate(PATH_BACKUP_CLUSTER, undef, undef, true, true);
|
|
}
|
|
|
|
# If the cluster backup path is empty then create the backup info file
|
|
my @stryBackupList = fileList($oFile->pathGet(PATH_BACKUP_CLUSTER), undef, 'forward', true);
|
|
my $strBackupInfo = &FILE_BACKUP_INFO;
|
|
my $oBackupInfo = new pgBackRest::BackupInfo($oFile->pathGet(PATH_BACKUP_CLUSTER));
|
|
|
|
if (!@stryBackupList)
|
|
{
|
|
# Create the backup.info file
|
|
$oBackupInfo->check($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);
|
|
$oBackupInfo->save();
|
|
}
|
|
elsif (!grep(/^$strBackupInfo$/i, @stryBackupList))
|
|
{
|
|
$iResult = &ERROR_BACKUP_DIR_INVALID;
|
|
$strResultMessage = "the backup directory is not empty but the backup.info file is missing\n" .
|
|
"HINT: Has the directory been copied from another location and the copy has not completed?"
|
|
}
|
|
elsif ($strDbVersion < PG_VERSION_91)
|
|
{
|
|
# Turn off console logging to control when to display the error
|
|
logLevelSet(undef, OFF);
|
|
|
|
eval
|
|
{
|
|
# Check that the backup info file is valid for the current database of the stanza
|
|
$oBackupInfo->check($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId);
|
|
return true;
|
|
}
|
|
or do
|
|
{
|
|
# Confess unhandled errors
|
|
if (!isException($EVAL_ERROR))
|
|
{
|
|
confess $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 ($iResult == 0)
|
|
{
|
|
# If the archive path does not exist, create it
|
|
if (!fileExists($oFile->pathGet(PATH_BACKUP_ARCHIVE)))
|
|
{
|
|
# Create the cluster archive path
|
|
$oFile->pathCreate(PATH_BACKUP_ARCHIVE, undef, undef, true, true);
|
|
}
|
|
|
|
my @stryArchiveList = fileList($oFile->pathGet(PATH_BACKUP_ARCHIVE), undef, 'forward', true);
|
|
my $strArchiveInfo = &ARCHIVE_INFO_FILE;
|
|
my $oArchiveInfo = new pgBackRest::ArchiveInfo($oFile->pathGet(PATH_BACKUP_ARCHIVE), false);
|
|
|
|
if (!@stryArchiveList)
|
|
{
|
|
$oArchiveInfo->check($strDbVersion, $ullDbSysId);
|
|
}
|
|
elsif (!grep(/^$strArchiveInfo/i, @stryArchiveList ))
|
|
{
|
|
$iResult = &ERROR_ARCHIVE_DIR_INVALID;
|
|
$strResultMessage = "the archive directory is not empty but the archive.info file is missing\n" .
|
|
"HINT: Has the directory been copied from another location and the copy has not completed?"
|
|
}
|
|
elsif ($strDbVersion < PG_VERSION_91)
|
|
{
|
|
# Turn off console logging to control when to display the error
|
|
logLevelSet(undef, OFF);
|
|
|
|
eval
|
|
{
|
|
# check that the archive info file is valid for the current database of the stanza
|
|
$oArchiveInfo->check($strDbVersion, $ullDbSysId);
|
|
return true;
|
|
}
|
|
or do
|
|
{
|
|
# Confess unhandled errors
|
|
if (!isException($EVAL_ERROR))
|
|
{
|
|
confess $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));
|
|
}
|
|
}
|
|
|
|
# The DB function xlogSwitch checks for the version >= 9.1 and only performs the restore point if met so check would fail here
|
|
# on initial stanza-create for those systems, so only run the full check on systems > 9.1.
|
|
if (($iResult == 0) && ($strDbVersion >= PG_VERSION_91))
|
|
{
|
|
$iResult = new pgBackRest::Archive()->check();
|
|
}
|
|
|
|
if ($iResult == 0)
|
|
{
|
|
&log(INFO, "successfully created stanza " . optionGet(OPTION_STANZA));
|
|
}
|
|
else
|
|
{
|
|
&log(ERROR, $strResultMessage, $iResult);
|
|
&log(WARN, "the stanza " . optionGet(OPTION_STANZA) . " could not be created");
|
|
}
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'iResult', value => $iResult, trace => true}
|
|
);
|
|
}
|
|
|
|
1;
|