2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# BACKUP INFO MODULE
|
|
|
|
####################################################################################################################################
|
2017-05-15 22:01:00 +02:00
|
|
|
package pgBackRest::Backup::Info;
|
2016-04-14 15:30:54 +02:00
|
|
|
use parent 'pgBackRest::Common::Ini';
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
2017-04-03 16:42:55 +02:00
|
|
|
use English '-no_match_vars';
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
use Exporter qw(import);
|
2015-08-29 20:20:46 +02:00
|
|
|
our @EXPORT = qw();
|
2015-06-14 00:25:49 +02:00
|
|
|
use File::Basename qw(dirname basename);
|
|
|
|
use File::stat;
|
|
|
|
|
2017-06-21 14:02:21 +02:00
|
|
|
use pgBackRest::Archive::Info;
|
2017-05-15 22:01:00 +02:00
|
|
|
use pgBackRest::Backup::Common;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Exception;
|
|
|
|
use pgBackRest::Common::Ini;
|
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Config::Config;
|
2017-04-03 16:42:55 +02:00
|
|
|
use pgBackRest::InfoCommon;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Manifest;
|
2017-05-15 17:12:14 +02:00
|
|
|
use pgBackRest::Protocol::Helper;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Protocol::Storage::Helper;
|
|
|
|
use pgBackRest::Storage::Helper;
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# File/path constants
|
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant FILE_BACKUP_INFO => 'backup.info';
|
|
|
|
push @EXPORT, qw(FILE_BACKUP_INFO);
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
# Backup info constants
|
2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_SECTION_BACKUP => MANIFEST_SECTION_BACKUP;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_SECTION_BACKUP_CURRENT => INFO_BACKUP_SECTION_BACKUP . ':current';
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP_CURRENT);
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_ARCHIVE_CHECK => MANIFEST_KEY_ARCHIVE_CHECK;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_CHECK);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_ARCHIVE_COPY => MANIFEST_KEY_ARCHIVE_COPY;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_COPY);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_ARCHIVE_START => MANIFEST_KEY_ARCHIVE_START;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_START);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_ARCHIVE_STOP => MANIFEST_KEY_ARCHIVE_STOP;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_STOP);
|
2016-08-25 17:25:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_BACKUP_STANDBY => MANIFEST_KEY_BACKUP_STANDBY;
|
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_STANDBY);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE => 'backup-info-repo-size';
|
2016-12-03 17:28:08 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA => 'backup-info-repo-size-delta';
|
2016-12-03 17:28:08 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_BACKUP_SIZE => 'backup-info-size';
|
2016-12-03 17:28:08 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_BACKUP_SIZE_DELTA => 'backup-info-size-delta';
|
2016-12-03 17:28:08 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE_DELTA);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_CATALOG => MANIFEST_KEY_CATALOG;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_CATALOG);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_CONTROL => MANIFEST_KEY_CONTROL;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_CONTROL);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_COMPRESS => MANIFEST_KEY_COMPRESS;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_COMPRESS);
|
2016-12-13 01:54:07 +02:00
|
|
|
use constant INFO_BACKUP_KEY_CHECKSUM_PAGE => MANIFEST_KEY_CHECKSUM_PAGE;
|
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_CHECKSUM_PAGE);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_DB_VERSION => MANIFEST_KEY_DB_VERSION;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_DB_VERSION);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_FORMAT => INI_KEY_FORMAT;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_FORMAT);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_HARDLINK => MANIFEST_KEY_HARDLINK;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_HARDLINK);
|
2016-04-15 04:50:02 +02:00
|
|
|
use constant INFO_BACKUP_KEY_HISTORY_ID => MANIFEST_KEY_DB_ID;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_HISTORY_ID);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_LABEL => MANIFEST_KEY_LABEL;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_LABEL);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_PRIOR => MANIFEST_KEY_PRIOR;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_PRIOR);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_REFERENCE => 'backup-reference';
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_REFERENCE);
|
2016-02-20 02:32:02 +02:00
|
|
|
use constant INFO_BACKUP_KEY_ONLINE => MANIFEST_KEY_ONLINE;
|
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_ONLINE);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_SYSTEM_ID => MANIFEST_KEY_SYSTEM_ID;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_SYSTEM_ID);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_TIMESTAMP_START => MANIFEST_KEY_TIMESTAMP_START;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_START);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_TIMESTAMP_STOP => MANIFEST_KEY_TIMESTAMP_STOP;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_STOP);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_TYPE => MANIFEST_KEY_TYPE;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_TYPE);
|
2015-08-29 20:20:46 +02:00
|
|
|
use constant INFO_BACKUP_KEY_VERSION => INI_KEY_VERSION;
|
2015-06-14 00:25:49 +02:00
|
|
|
push @EXPORT, qw(INFO_BACKUP_KEY_VERSION);
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Global variables
|
|
|
|
####################################################################################################################################
|
|
|
|
my $strBackupInfoMissingMsg =
|
|
|
|
FILE_BACKUP_INFO . " does not exist and is required to perform a backup.\n" .
|
|
|
|
"HINT: has a stanza-create been performed?";
|
|
|
|
|
2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# CONSTRUCTOR
|
|
|
|
####################################################################################################################################
|
|
|
|
sub new
|
|
|
|
{
|
2015-08-29 20:20:46 +02:00
|
|
|
my $class = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-04-15 04:50:02 +02:00
|
|
|
$strBackupClusterPath,
|
2016-12-20 23:52:20 +02:00
|
|
|
$bValidate,
|
|
|
|
$bRequired,
|
2017-06-09 23:51:41 +02:00
|
|
|
$oStorage,
|
|
|
|
$bLoad, # Should the file attemp to be loaded?
|
|
|
|
$bIgnoreMissing, # Don't error on missing files
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->new', \@_,
|
2016-04-15 04:50:02 +02:00
|
|
|
{name => 'strBackupClusterPath'},
|
2016-12-20 23:52:20 +02:00
|
|
|
{name => 'bValidate', default => true},
|
|
|
|
{name => 'bRequired', default => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
{name => 'oStorage', optional => true, default => storageRepo()},
|
|
|
|
{name => 'bLoad', optional => true, default => true},
|
|
|
|
{name => 'bIgnoreMissing', optional => true, default => false},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
# Build the backup info path/file name
|
|
|
|
my $strBackupInfoFile = "${strBackupClusterPath}/" . FILE_BACKUP_INFO;
|
2017-06-09 23:51:41 +02:00
|
|
|
my $self = {};
|
|
|
|
my $iResult = 0;
|
|
|
|
my $strResultMessage;
|
2015-06-14 00:25:49 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Init object and store variables
|
|
|
|
eval
|
2016-12-20 23:52:20 +02:00
|
|
|
{
|
2017-06-09 23:51:41 +02:00
|
|
|
$self = $class->SUPER::new($strBackupInfoFile, {bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing,
|
|
|
|
oStorage => $oStorage});
|
|
|
|
return true;
|
2016-12-20 23:52:20 +02:00
|
|
|
}
|
2017-06-09 23:51:41 +02:00
|
|
|
or do
|
|
|
|
{
|
|
|
|
# Capture error information
|
|
|
|
$iResult = exceptionCode($EVAL_ERROR);
|
|
|
|
$strResultMessage = exceptionMessage($EVAL_ERROR->message());
|
|
|
|
};
|
2016-12-20 23:52:20 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
if ($iResult != 0)
|
|
|
|
{
|
|
|
|
# If the backup info file does not exist and is required, then throw an error
|
|
|
|
# The backup info is only allowed not to exist when running a stanza-create on a new install
|
|
|
|
if ($iResult == ERROR_FILE_MISSING)
|
|
|
|
{
|
|
|
|
if ($bRequired)
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "${strBackupClusterPath}/$strBackupInfoMissingMsg", ERROR_FILE_MISSING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
confess &log(ERROR, $strResultMessage, $iResult);
|
|
|
|
}
|
|
|
|
}
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
$self->{strBackupClusterPath} = $strBackupClusterPath;
|
2017-06-09 23:51:41 +02:00
|
|
|
$self->{oStorage} = $oStorage;
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
# Validate the backup info
|
2016-04-15 04:50:02 +02:00
|
|
|
if ($bValidate)
|
|
|
|
{
|
|
|
|
$self->validate();
|
|
|
|
}
|
2015-06-14 00:25:49 +02:00
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'self', value => $self}
|
|
|
|
);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# validate
|
|
|
|
#
|
2016-12-20 23:52:20 +02:00
|
|
|
# Comfirm the file exists and reconstruct as necessary.
|
2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub validate
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
2016-08-11 23:32:28 +02:00
|
|
|
my ($strOperation) = logDebugParam(__PACKAGE__ . '->validate');
|
2015-08-29 20:20:46 +02:00
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
# Confirm the info file exists with the DB section
|
|
|
|
$self->confirmExists();
|
|
|
|
|
|
|
|
$self->reconstruct();
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# reconstruct
|
|
|
|
#
|
|
|
|
# Compare the backup info against the actual backups in the repository. Reconstruct the file based on manifests missing or no
|
|
|
|
# longer valid.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub reconstruct
|
|
|
|
{
|
|
|
|
my $self = shift;
|
2016-04-15 04:50:02 +02:00
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$bSave,
|
2017-04-03 16:42:55 +02:00
|
|
|
$bRequired, # If false then must be creating or reconstructing so the DB info must be supplied
|
|
|
|
$strDbVersion,
|
|
|
|
$ullDbSysId,
|
|
|
|
$iControlVersion,
|
|
|
|
$iCatalogVersion,
|
2016-12-20 23:52:20 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->reconstruct', \@_,
|
|
|
|
{name => 'bSave', default => true},
|
|
|
|
{name => 'bRequired', default => true},
|
2017-04-03 16:42:55 +02:00
|
|
|
{name => 'strDbVersion', required => false},
|
|
|
|
{name => 'ullDbSysId', required => false},
|
|
|
|
{name => 'iControlVersion', required => false},
|
|
|
|
{name => 'iCatalogVersion', required => false},
|
2016-12-20 23:52:20 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# Check for backups that are not in FILE_BACKUP_INFO
|
2017-06-09 23:51:41 +02:00
|
|
|
foreach my $strBackup ($self->{oStorage}->list(
|
|
|
|
$self->{strBackupClusterPath}, {strExpression => backupRegExpGet(true, true, true)}))
|
2016-04-15 04:50:02 +02:00
|
|
|
{
|
|
|
|
my $strManifestFile = "$self->{strBackupClusterPath}/${strBackup}/" . FILE_MANIFEST;
|
|
|
|
|
|
|
|
# ??? Check for and move history files that were not moved before and maybe don't consider it to be an error when they
|
2016-10-14 13:21:47 +02:00
|
|
|
# can't be moved. This would also be true for the first move attempt in Backup->process();
|
2016-04-15 04:50:02 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
if (!$self->current($strBackup) && $self->{oStorage}->exists($strManifestFile))
|
2016-04-15 04:50:02 +02:00
|
|
|
{
|
|
|
|
my $oManifest = pgBackRest::Manifest->new($strManifestFile);
|
2016-12-20 23:52:20 +02:00
|
|
|
|
2017-04-03 16:42:55 +02:00
|
|
|
# If we are reconstructing, then we need to be sure this db-id and version is in the history section. Also if it
|
|
|
|
# has a db-id greater than anything in the history section, then add it to the db section.
|
|
|
|
if (!$bRequired)
|
|
|
|
{
|
|
|
|
my $hDbList = $self->dbHistoryList();
|
|
|
|
my $iDbId = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID);
|
|
|
|
my $iDbIdMax = 0;
|
|
|
|
my $ullDbSysId = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_SYSTEM_ID);
|
|
|
|
my $strDbVersion = $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_VERSION);
|
|
|
|
|
|
|
|
# If this is the max history id then set the db section
|
|
|
|
foreach my $iDbHistoryId (keys %{$hDbList})
|
|
|
|
{
|
|
|
|
# If the current history ID is greater than the running max, then set it to the current id
|
|
|
|
if ($iDbHistoryId > $iDbIdMax)
|
|
|
|
{
|
|
|
|
$iDbIdMax = $iDbHistoryId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($iDbId >= $iDbIdMax)
|
|
|
|
{
|
|
|
|
$self->dbSectionSet($strDbVersion, $oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CONTROL),
|
|
|
|
$oManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_CATALOG), $ullDbSysId, $iDbId);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&log(WARN, "backup ${strBackup} found in repository added to " . FILE_BACKUP_INFO);
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
$self->add($oManifest, $bSave, $bRequired);
|
2016-04-15 04:50:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-03 16:42:55 +02:00
|
|
|
# If reconstructing, make sure the DB section is correct
|
|
|
|
if (!$bRequired)
|
|
|
|
{
|
|
|
|
# If any database info is missing, then assert
|
|
|
|
if (!defined($strDbVersion) || !defined($ullDbSysId) || !defined($iControlVersion) || !defined($iCatalogVersion))
|
|
|
|
{
|
|
|
|
confess &log(ASSERT, "backup info cannot be reconstructed without database information");
|
|
|
|
}
|
|
|
|
# If the DB section does not exist then create the db and history section
|
|
|
|
elsif (!$self->test(INFO_BACKUP_SECTION_DB))
|
|
|
|
{
|
|
|
|
$self->create($strDbVersion, $ullDbSysId, $iControlVersion, $iCatalogVersion, $bSave);
|
|
|
|
}
|
|
|
|
# Else update the DB section if it does not match the current database
|
|
|
|
else
|
|
|
|
{
|
|
|
|
# Turn off console logging to control when to display the error
|
|
|
|
logDisable();
|
|
|
|
|
|
|
|
eval
|
|
|
|
{
|
|
|
|
$self->check($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $bRequired);
|
|
|
|
logEnable();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
or do
|
|
|
|
{
|
|
|
|
# Reset the console logging
|
|
|
|
logEnable();
|
|
|
|
|
|
|
|
# Confess unhandled errors
|
|
|
|
confess $EVAL_ERROR if (exceptionCode($EVAL_ERROR) != ERROR_BACKUP_MISMATCH);
|
|
|
|
|
|
|
|
# Update the DB section if it does not match the current database
|
|
|
|
$self->dbSectionSet($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $self->dbHistoryIdGet(false)+1);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-29 20:02:11 +02:00
|
|
|
# Remove backups from FILE_BACKUP_INFO that are no longer in the repository
|
2015-06-14 00:25:49 +02:00
|
|
|
foreach my $strBackup ($self->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))
|
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
my $strManifestFile = "$self->{strBackupClusterPath}/${strBackup}/" . FILE_MANIFEST;
|
|
|
|
my $strBackupPath = "$self->{strBackupClusterPath}/${strBackup}";
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
if (!$self->{oStorage}->pathExists($strBackupPath))
|
2016-04-15 04:50:02 +02:00
|
|
|
{
|
|
|
|
&log(WARN, "backup ${strBackup} missing in repository removed from " . FILE_BACKUP_INFO);
|
|
|
|
$self->delete($strBackup);
|
|
|
|
}
|
2017-06-09 23:51:41 +02:00
|
|
|
elsif (!$self->{oStorage}->exists($strManifestFile))
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
&log(WARN, "backup ${strBackup} missing manifest removed from " . FILE_BACKUP_INFO);
|
2015-08-29 20:20:46 +02:00
|
|
|
$self->delete($strBackup);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
}
|
2015-08-29 20:20:46 +02:00
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
# ??? Add a section to remove backups that are missing references (unless they are hardlinked?)
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
2016-01-19 14:39:29 +02:00
|
|
|
return logDebugReturn($strOperation);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# check
|
|
|
|
#
|
2016-12-20 23:52:20 +02:00
|
|
|
# Check db info and make sure it matches what is already in the repository. Return the db-id if everything matches.
|
2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub check
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2015-09-02 01:05:10 +02:00
|
|
|
$strDbVersion,
|
|
|
|
$iControlVersion,
|
|
|
|
$iCatalogVersion,
|
|
|
|
$ullDbSysId,
|
2016-12-20 23:52:20 +02:00
|
|
|
$bRequired,
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->check', \@_,
|
2015-09-02 01:05:10 +02:00
|
|
|
{name => 'strDbVersion', trace => true},
|
|
|
|
{name => 'iControlVersion', trace => true},
|
|
|
|
{name => 'iCatalogVersion', trace => true},
|
2016-12-20 23:52:20 +02:00
|
|
|
{name => 'ullDbSysId', trace => true},
|
|
|
|
{name => 'bRequired', default => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
# Confirm the info file exists with the DB section
|
|
|
|
if ($bRequired)
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
2016-12-20 23:52:20 +02:00
|
|
|
$self->confirmExists();
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
if (!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID, undef, $ullDbSysId) ||
|
|
|
|
!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef, $strDbVersion))
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "database version = ${strDbVersion}, system-id ${ullDbSysId} does not match backup version = " .
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION) . ", system-id = " .
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID) . "\n" .
|
|
|
|
"HINT: is this the correct stanza?", ERROR_BACKUP_MISMATCH);
|
|
|
|
}
|
2016-04-15 04:50:02 +02:00
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
if (!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG, undef, $iCatalogVersion) ||
|
|
|
|
!$self->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL, undef, $iControlVersion))
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "database control-version = ${iControlVersion}, catalog-version ${iCatalogVersion}" .
|
|
|
|
" does not match backup control-version = " .
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL) . ", catalog-version = " .
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG) . "\n" .
|
|
|
|
"HINT: this may be a symptom of database or repository corruption!", ERROR_BACKUP_MISMATCH);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
2015-08-29 20:20:46 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
2016-04-15 04:50:02 +02:00
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-12-20 23:52:20 +02:00
|
|
|
{name => 'iDbHistoryId', value => $self->numericGet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID)}
|
2016-04-15 04:50:02 +02:00
|
|
|
);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
# add
|
2015-06-14 00:25:49 +02:00
|
|
|
#
|
|
|
|
# Add a backup to the info file.
|
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
sub add
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-12-20 23:52:20 +02:00
|
|
|
$oBackupManifest,
|
|
|
|
$bSave,
|
|
|
|
$bRequired,
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->add', \@_,
|
2016-12-20 23:52:20 +02:00
|
|
|
{name => 'oBackupManifest', trace => true},
|
|
|
|
{name => 'bSave', default => true, trace => true},
|
|
|
|
{name => 'bRequired', default => true, trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
# Confirm the info file exists with the DB section
|
|
|
|
if ($bRequired)
|
2016-04-15 04:50:02 +02:00
|
|
|
{
|
2016-12-20 23:52:20 +02:00
|
|
|
$self->confirmExists();
|
2016-04-15 04:50:02 +02:00
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
# Get the backup label
|
|
|
|
my $strBackupLabel = $oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);
|
|
|
|
|
2015-06-14 00:25:49 +02:00
|
|
|
# Calculate backup sizes and references
|
|
|
|
my $lBackupSize = 0;
|
|
|
|
my $lBackupSizeDelta = 0;
|
|
|
|
my $lBackupRepoSize = 0;
|
|
|
|
my $lBackupRepoSizeDelta = 0;
|
|
|
|
my $oReferenceHash = undef;
|
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
foreach my $strFileKey ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_FILE))
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
my $lFileSize =
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_SIZE);
|
|
|
|
my $lRepoSize =
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REPO_SIZE, false, $lFileSize);
|
|
|
|
my $strFileReference =
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_TARGET_FILE, $strFileKey, MANIFEST_SUBKEY_REFERENCE, false);
|
|
|
|
|
|
|
|
# Temporary until compressed size is back in
|
|
|
|
$lBackupSize += $lFileSize;
|
|
|
|
$lBackupRepoSize += $lRepoSize;
|
|
|
|
|
|
|
|
if (defined($strFileReference))
|
2016-03-22 15:57:39 +02:00
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
$$oReferenceHash{$strFileReference} = true;
|
2016-03-22 15:57:39 +02:00
|
|
|
}
|
2016-04-15 04:50:02 +02:00
|
|
|
else
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
2016-04-15 04:50:02 +02:00
|
|
|
$lBackupSizeDelta += $lFileSize;
|
|
|
|
$lBackupRepoSizeDelta += $lRepoSize;
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Set backup size info
|
2015-08-29 20:20:46 +02:00
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_SIZE, $lBackupSize);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_SIZE_DELTA, $lBackupSizeDelta);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_REPO_SIZE, $lBackupRepoSize);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA,
|
2015-06-14 00:25:49 +02:00
|
|
|
$lBackupRepoSizeDelta);
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_CHECK,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_CHECK));
|
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_COPY,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ARCHIVE_COPY));
|
2015-06-14 00:25:49 +02:00
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_START,
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_START, undef, false));
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ARCHIVE_STOP,
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_ARCHIVE_STOP, undef, false));
|
2016-08-25 17:25:46 +02:00
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_STANDBY,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BACKUP_STANDBY));
|
2016-12-13 01:54:07 +02:00
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_CHECKSUM_PAGE,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE));
|
2015-08-29 20:20:46 +02:00
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_COMPRESS,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_COMPRESS));
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_FORMAT,
|
|
|
|
$oBackupManifest->numericGet(INI_SECTION_BACKREST, INI_KEY_FORMAT));
|
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HARDLINK,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_HARDLINK));
|
2016-02-20 02:32:02 +02:00
|
|
|
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ONLINE,
|
|
|
|
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE));
|
2015-08-29 20:20:46 +02:00
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TIMESTAMP_START,
|
|
|
|
$oBackupManifest->numericGet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_START));
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TIMESTAMP_STOP,
|
|
|
|
$oBackupManifest->numericGet(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TIMESTAMP_STOP));
|
2015-06-14 00:25:49 +02:00
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_TYPE,
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE));
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_VERSION,
|
|
|
|
$oBackupManifest->get(INI_SECTION_BACKREST, INI_KEY_VERSION));
|
2017-04-03 16:42:55 +02:00
|
|
|
|
|
|
|
if ($bRequired)
|
|
|
|
{
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HISTORY_ID,
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID));
|
|
|
|
}
|
|
|
|
# If we are reconstructing, then the history id must be taken from the manifest
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_HISTORY_ID,
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_BACKUP_DB, MANIFEST_KEY_DB_ID));
|
|
|
|
}
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
if (!$oBackupManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef, BACKUP_TYPE_FULL))
|
|
|
|
{
|
2015-06-21 18:06:13 +02:00
|
|
|
my @stryReference = sort(keys(%$oReferenceHash));
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_PRIOR,
|
|
|
|
$oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_PRIOR));
|
|
|
|
$self->set(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_REFERENCE,
|
|
|
|
\@stryReference);
|
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
if ($bSave)
|
|
|
|
{
|
|
|
|
$self->save();
|
|
|
|
}
|
2015-08-29 20:20:46 +02:00
|
|
|
|
2016-01-19 14:39:29 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# current
|
|
|
|
#
|
|
|
|
# Test if a backup is current.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub current
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strBackup
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->current', \@_,
|
2016-01-19 14:39:29 +02:00
|
|
|
{name => 'strBackup'}
|
|
|
|
);
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
2016-01-19 14:39:29 +02:00
|
|
|
$strOperation,
|
|
|
|
{name => 'bTest', value => $self->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup)}
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
2016-01-19 14:39:29 +02:00
|
|
|
# list
|
|
|
|
#
|
|
|
|
# Get backup keys.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub list
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
2016-01-21 00:24:44 +02:00
|
|
|
$strFilter,
|
|
|
|
$strOrder
|
2016-01-19 14:39:29 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->list', \@_,
|
2016-01-21 00:24:44 +02:00
|
|
|
{name => 'strFilter', required => false},
|
|
|
|
{name => 'strOrder', default => 'forward'}
|
2016-01-19 14:39:29 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
# List of backups
|
|
|
|
my @stryBackup;
|
|
|
|
|
|
|
|
# Iterate through the backups and filter
|
|
|
|
for my $strBackup ($self->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))
|
|
|
|
{
|
2016-01-21 00:24:44 +02:00
|
|
|
if (!defined($strFilter) || $strBackup =~ $strFilter)
|
2016-01-19 14:39:29 +02:00
|
|
|
{
|
2016-01-21 00:24:44 +02:00
|
|
|
if ($strOrder eq 'reverse')
|
|
|
|
{
|
|
|
|
unshift(@stryBackup, $strBackup)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
push(@stryBackup, $strBackup)
|
|
|
|
}
|
2016-01-19 14:39:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'stryBackup', value => \@stryBackup}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-04-03 16:42:55 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# backupArchiveDbHistoryId
|
|
|
|
#
|
|
|
|
# Gets the backup.info db-id for the archiveId passed.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub backupArchiveDbHistoryId
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strArchiveId,
|
|
|
|
$strPathBackupArchive,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->backupArchiveDbHistoryId', \@_,
|
|
|
|
{name => 'strArchiveId'},
|
|
|
|
{name => 'strPathBackupArchive'},
|
|
|
|
);
|
|
|
|
|
|
|
|
# List of backups associated with the db-id provided
|
|
|
|
my @stryArchiveBackup;
|
|
|
|
|
|
|
|
# Build the db list from the history in the backup info and archive info file
|
2017-06-21 14:02:21 +02:00
|
|
|
my $oArchiveInfo = new pgBackRest::Archive::Info($strPathBackupArchive, true);
|
2017-04-03 16:42:55 +02:00
|
|
|
my $hDbListArchive = $oArchiveInfo->dbHistoryList();
|
|
|
|
my $hDbListBackup = $self->dbHistoryList();
|
|
|
|
my $iDbHistoryId = undef;
|
|
|
|
|
|
|
|
# Get the db-version and db-id (history id) from the archiveId
|
|
|
|
my ($strDbVersionArchive, $iDbIdArchive) = split("-", $strArchiveId);
|
|
|
|
|
2017-08-04 22:03:55 +02:00
|
|
|
# Get the DB system ID to map back to the backup info if it exists in the archive info file
|
|
|
|
if (exists($hDbListArchive->{$iDbIdArchive}))
|
2017-04-03 16:42:55 +02:00
|
|
|
{
|
2017-08-04 22:03:55 +02:00
|
|
|
my $ullDbSysIdArchive = $$hDbListArchive{$iDbIdArchive}{&INFO_SYSTEM_ID};
|
|
|
|
|
|
|
|
# Get the db-id from backup info history that corresponds to the archive db-version and db-system-id
|
|
|
|
foreach my $iDbIdBackup (keys %{$hDbListBackup})
|
2017-04-03 16:42:55 +02:00
|
|
|
{
|
2017-08-04 22:03:55 +02:00
|
|
|
if ($$hDbListBackup{$iDbIdBackup}{&INFO_SYSTEM_ID} == $ullDbSysIdArchive &&
|
|
|
|
$$hDbListBackup{$iDbIdBackup}{&INFO_DB_VERSION} eq $strDbVersionArchive)
|
|
|
|
{
|
|
|
|
$iDbHistoryId = $iDbIdBackup;
|
|
|
|
last;
|
|
|
|
}
|
2017-04-03 16:42:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# If the database is not found in the backup.info history list
|
|
|
|
if (!defined($iDbHistoryId))
|
|
|
|
{
|
|
|
|
# Check to see that the current DB sections match for the archive and backup info files
|
|
|
|
if (!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
|
|
|
($self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION)))) ||
|
|
|
|
!($oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef,
|
|
|
|
($self->get(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID)))))
|
|
|
|
{
|
|
|
|
# This should never happen unless the backup.info file is corrupt
|
|
|
|
confess &log(ASSERT, "the archive and backup database sections do not match", ERROR_FILE_INVALID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'iDbHistoryId', value => $iDbHistoryId}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# listByArchiveId
|
|
|
|
#
|
|
|
|
# Filters a list of backups by the archiveId passed.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub listByArchiveId
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strArchiveId,
|
|
|
|
$strPathBackupArchive,
|
|
|
|
$stryBackup,
|
|
|
|
$strOrder,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->listByArchiveId', \@_,
|
|
|
|
{name => 'strArchiveId'},
|
|
|
|
{name => 'strPathBackupArchive'},
|
|
|
|
{name => 'stryBackup'},
|
|
|
|
{name => 'strOrder', default => 'forward'}
|
|
|
|
);
|
|
|
|
|
|
|
|
# List of backups associated with the db-id provided
|
|
|
|
my @stryArchiveBackup;
|
|
|
|
|
|
|
|
my $iDbHistoryId = $self->backupArchiveDbHistoryId($strArchiveId, $strPathBackupArchive);
|
|
|
|
|
|
|
|
# If history found, then build list of backups associated with the archive id passed, else return empty array
|
|
|
|
if (defined($iDbHistoryId))
|
|
|
|
{
|
|
|
|
# Iterate through the backups and filter
|
|
|
|
foreach my $strBackup (@$stryBackup)
|
|
|
|
{
|
|
|
|
# From the backup.info current backup section, get the db-id for the backup and if it is the same, add to the list
|
|
|
|
if ($self->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID, $iDbHistoryId))
|
|
|
|
{
|
|
|
|
if ($strOrder eq 'reverse')
|
|
|
|
{
|
|
|
|
unshift(@stryArchiveBackup, $strBackup)
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
push(@stryArchiveBackup, $strBackup)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'stryArchiveBackup', value => \@stryArchiveBackup}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-04-15 04:50:02 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# last
|
|
|
|
#
|
|
|
|
# Find the last backup depending on the type.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub last
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strType
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->last', \@_,
|
2016-04-15 04:50:02 +02:00
|
|
|
{name => 'strType'}
|
|
|
|
);
|
|
|
|
|
|
|
|
my $strFilter = backupRegExpGet(true, $strType ne BACKUP_TYPE_FULL, $strType eq BACKUP_TYPE_INCR);
|
|
|
|
my $strBackup = ($self->list($strFilter, 'reverse'))[0];
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'strBackup', value => $strBackup}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-01-19 14:39:29 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# delete
|
2015-06-14 00:25:49 +02:00
|
|
|
#
|
2015-08-29 20:20:46 +02:00
|
|
|
# Delete a backup from the info file.
|
2015-06-14 00:25:49 +02:00
|
|
|
####################################################################################################################################
|
2015-08-29 20:20:46 +02:00
|
|
|
sub delete
|
2015-06-14 00:25:49 +02:00
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strBackupLabel
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->delete', \@_,
|
2015-08-29 20:20:46 +02:00
|
|
|
{name => 'strBackupLabel'}
|
|
|
|
);
|
2015-06-14 00:25:49 +02:00
|
|
|
|
|
|
|
$self->remove(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel);
|
2015-08-29 20:20:46 +02:00
|
|
|
|
|
|
|
# Return from function and log return values if any
|
2016-01-19 14:39:29 +02:00
|
|
|
return logDebugReturn($strOperation);
|
2015-06-14 00:25:49 +02:00
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# create
|
|
|
|
#
|
2017-04-07 01:36:37 +02:00
|
|
|
# Create the info file. WARNING - this file should only be called from stanza-create or test modules.
|
2016-12-20 23:52:20 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
sub create
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strDbVersion,
|
|
|
|
$ullDbSysId,
|
|
|
|
$iControlVersion,
|
|
|
|
$iCatalogVersion,
|
|
|
|
$bSave,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->create', \@_,
|
|
|
|
{name => 'strDbVersion'},
|
|
|
|
{name => 'ullDbSysId'},
|
|
|
|
{name => 'iControlVersion'},
|
|
|
|
{name => 'iCatalogVersion'},
|
|
|
|
{name => 'bSave', default => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Fill db section and db history section
|
|
|
|
$self->dbSectionSet($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId, $self->dbHistoryIdGet(false));
|
|
|
|
|
|
|
|
if ($bSave)
|
|
|
|
{
|
|
|
|
$self->save();
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# dbHistoryIdGet
|
|
|
|
#
|
|
|
|
# Get the db history ID
|
|
|
|
####################################################################################################################################
|
|
|
|
sub dbHistoryIdGet
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$bFileRequired,
|
|
|
|
) = logDebugParam
|
|
|
|
(
|
2017-08-04 22:03:55 +02:00
|
|
|
__PACKAGE__ . '->dbHistoryIdGet', \@_,
|
2016-12-20 23:52:20 +02:00
|
|
|
{name => 'bFileRequired', default => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Confirm the info file exists if it is required
|
|
|
|
if ($bFileRequired)
|
|
|
|
{
|
|
|
|
$self->confirmExists();
|
|
|
|
}
|
|
|
|
|
|
|
|
# If the DB section does not exist, initialize the history to one, else return the latest ID
|
|
|
|
my $iDbHistoryId = (!$self->test(INFO_BACKUP_SECTION_DB))
|
|
|
|
? 1 : $self->numericGet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID);
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'iDbHistoryId', value => $iDbHistoryId}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2017-04-03 16:42:55 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# dbHistoryList
|
|
|
|
#
|
|
|
|
# Get the data from the db history section.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub dbHistoryList
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
) = logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->dbHistoryList',
|
|
|
|
);
|
|
|
|
|
|
|
|
my %hDbHash;
|
|
|
|
|
|
|
|
foreach my $iHistoryId ($self->keys(INFO_BACKUP_SECTION_DB_HISTORY))
|
|
|
|
{
|
|
|
|
$hDbHash{$iHistoryId}{&INFO_DB_VERSION} =
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_DB_VERSION);
|
|
|
|
$hDbHash{$iHistoryId}{&INFO_SYSTEM_ID} =
|
|
|
|
$self->get(INFO_BACKUP_SECTION_DB_HISTORY, $iHistoryId, INFO_BACKUP_KEY_SYSTEM_ID);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'hDbHash', value => \%hDbHash}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# dbSectionSet
|
|
|
|
#
|
|
|
|
# Set the db and db:history sections.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub dbSectionSet
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strDbVersion,
|
|
|
|
$iControlVersion,
|
|
|
|
$iCatalogVersion,
|
|
|
|
$ullDbSysId,
|
|
|
|
$iDbHistoryId,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->dbSectionSet', \@_,
|
|
|
|
{name => 'strDbVersion', trace => true},
|
|
|
|
{name => 'iControlVersion', trace => true},
|
|
|
|
{name => 'iCatalogVersion', trace => true},
|
|
|
|
{name => 'ullDbSysId', trace => true},
|
|
|
|
{name => 'iDbHistoryId', trace => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
# Fill db section
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CATALOG, undef, $iCatalogVersion);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_CONTROL, undef, $iControlVersion);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_SYSTEM_ID, undef, $ullDbSysId);
|
|
|
|
$self->set(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef, $strDbVersion);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID, undef, $iDbHistoryId);
|
|
|
|
|
|
|
|
# Fill db history
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_CATALOG, $iCatalogVersion);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_CONTROL, $iControlVersion);
|
|
|
|
$self->numericSet(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_SYSTEM_ID, $ullDbSysId);
|
|
|
|
$self->set(INFO_BACKUP_SECTION_DB_HISTORY, $iDbHistoryId, INFO_BACKUP_KEY_DB_VERSION, $strDbVersion);
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn($strOperation);
|
|
|
|
}
|
|
|
|
|
2017-04-07 01:36:37 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# confirmDb
|
|
|
|
#
|
|
|
|
# Ensure that the backup is associated with the database passed.
|
|
|
|
# NOTE: The backup must exist in the backup:current section.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub confirmDb
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
my
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
$strBackup,
|
|
|
|
$strDbVersion,
|
|
|
|
$ullDbSysId,
|
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
|
|
|
__PACKAGE__ . '->confirmDb', \@_,
|
|
|
|
{name => 'strBackup', trace => true},
|
|
|
|
{name => 'strDbVersion', trace => true},
|
|
|
|
{name => 'ullDbSysId', trace => true},
|
|
|
|
);
|
|
|
|
|
|
|
|
my $bConfirmDb = undef;
|
|
|
|
|
|
|
|
# Get the db-id associated with the backup
|
|
|
|
my $iDbHistoryId = $self->get(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup, INFO_BACKUP_KEY_HISTORY_ID);
|
|
|
|
|
|
|
|
# Get the version and system-id for all known databases
|
|
|
|
my $hDbList = $self->dbHistoryList();
|
|
|
|
|
|
|
|
# If the db-id for the backup exists in the list
|
|
|
|
if (exists $hDbList->{$iDbHistoryId})
|
|
|
|
{
|
|
|
|
# If the version and system-id match then datbase is confirmed for the backup
|
|
|
|
if (($hDbList->{$iDbHistoryId}{&INFO_DB_VERSION} eq $strDbVersion) &&
|
|
|
|
($hDbList->{$iDbHistoryId}{&INFO_SYSTEM_ID} eq $ullDbSysId))
|
|
|
|
{
|
|
|
|
$bConfirmDb = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$bConfirmDb = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# If not, the backup.info file must be corrupt
|
|
|
|
else
|
|
|
|
{
|
|
|
|
confess &log(ERROR, "backup info file is missing database history information for an existing backup", ERROR_FILE_INVALID);
|
|
|
|
}
|
|
|
|
|
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
|
|
|
{name => 'bConfirmDb', value => $bConfirmDb}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2016-12-20 23:52:20 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# confirmExists
|
|
|
|
#
|
|
|
|
# Ensure that the backup.info file and the db section exist.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub confirmExists
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
# Confirm the file exists and the DB section is filled out
|
|
|
|
if (!$self->test(INFO_BACKUP_SECTION_DB) || !$self->{bExists})
|
|
|
|
{
|
|
|
|
confess &log(ERROR, $self->{strBackupClusterPath} . "/" . $strBackupInfoMissingMsg, ERROR_FILE_MISSING);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-14 00:25:49 +02:00
|
|
|
1;
|