You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2026-05-22 10:15:16 +02:00
Move Perl modules out of lib directory.
This directory was once the home of the production Perl code but since f0ef73db this is no longer true.
Move the modules to test in most cases, except where the module is expected to be useful for the doc engine beyond the expected lifetime of the Perl test code (about a year if all goes well).
The exception is pgBackRest::Version which requires more work to migrate since it is used to track pgBackRest versions.
This commit is contained in:
@@ -15,8 +15,8 @@ use English '-no_match_vars';
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
####################################################################################################################################
|
||||
# VM hash keywords
|
||||
|
||||
@@ -14,7 +14,7 @@ use English '-no_match_vars';
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
|
||||
|
||||
@@ -18,10 +18,11 @@ use Exporter qw(import);
|
||||
use File::Basename qw(dirname);
|
||||
use Getopt::Long qw(GetOptions);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
use BackRestDoc::Html::DocHtmlBuilder;
|
||||
use BackRestDoc::Html::DocHtmlElement;
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
####################################################################################################################################
|
||||
# DB VERSION MODULE
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::DbVersion;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# PostgreSQL version numbers
|
||||
####################################################################################################################################
|
||||
use constant PG_VERSION_83 => '8.3';
|
||||
push @EXPORT, qw(PG_VERSION_83);
|
||||
use constant PG_VERSION_84 => '8.4';
|
||||
push @EXPORT, qw(PG_VERSION_84);
|
||||
use constant PG_VERSION_90 => '9.0';
|
||||
push @EXPORT, qw(PG_VERSION_90);
|
||||
use constant PG_VERSION_91 => '9.1';
|
||||
push @EXPORT, qw(PG_VERSION_91);
|
||||
use constant PG_VERSION_92 => '9.2';
|
||||
push @EXPORT, qw(PG_VERSION_92);
|
||||
use constant PG_VERSION_93 => '9.3';
|
||||
push @EXPORT, qw(PG_VERSION_93);
|
||||
use constant PG_VERSION_94 => '9.4';
|
||||
push @EXPORT, qw(PG_VERSION_94);
|
||||
use constant PG_VERSION_95 => '9.5';
|
||||
push @EXPORT, qw(PG_VERSION_95);
|
||||
use constant PG_VERSION_96 => '9.6';
|
||||
push @EXPORT, qw(PG_VERSION_96);
|
||||
use constant PG_VERSION_10 => '10';
|
||||
push @EXPORT, qw(PG_VERSION_10);
|
||||
use constant PG_VERSION_11 => '11';
|
||||
push @EXPORT, qw(PG_VERSION_11);
|
||||
use constant PG_VERSION_12 => '12';
|
||||
push @EXPORT, qw(PG_VERSION_12);
|
||||
|
||||
use constant PG_VERSION_APPLICATION_NAME => PG_VERSION_90;
|
||||
push @EXPORT, qw(PG_VERSION_APPLICATION_NAME);
|
||||
use constant PG_VERSION_HOT_STANDBY => PG_VERSION_91;
|
||||
push @EXPORT, qw(PG_VERSION_HOT_STANDBY);
|
||||
use constant PG_VERSION_BACKUP_STANDBY => PG_VERSION_92;
|
||||
push @EXPORT, qw(PG_VERSION_BACKUP_STANDBY);
|
||||
|
||||
####################################################################################################################################
|
||||
# versionSupport
|
||||
#
|
||||
# Returns an array of the supported Postgres versions.
|
||||
####################################################################################################################################
|
||||
sub versionSupport
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->versionSupport');
|
||||
|
||||
my @strySupportVersion = (PG_VERSION_83, PG_VERSION_84, PG_VERSION_90, PG_VERSION_91, PG_VERSION_92, PG_VERSION_93,
|
||||
PG_VERSION_94, PG_VERSION_95, PG_VERSION_96, PG_VERSION_10, PG_VERSION_11, PG_VERSION_12);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strySupportVersion', value => \@strySupportVersion}
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(versionSupport);
|
||||
|
||||
1;
|
||||
@@ -13,8 +13,8 @@ use Carp qw(confess);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
|
||||
|
||||
@@ -17,10 +17,11 @@ use IPC::Open3;
|
||||
use POSIX ':sys_wait_h';
|
||||
use Symbol 'gensym';
|
||||
|
||||
use pgBackRest::Common::Io::Handle;
|
||||
use pgBackRest::Common::Io::Buffered;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::Io::Handle;
|
||||
use pgBackRestTest::Common::Io::Buffered;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
@@ -101,11 +102,11 @@ sub begin
|
||||
$self->{pId} = open3(undef, $self->{hOut}, $self->{hError}, $self->{strCommand});
|
||||
|
||||
# Create buffered read object
|
||||
$self->{oIo} = new pgBackRest::Common::Io::Buffered(new pgBackRest::Common::Io::Handle('exec test', $self->{hOut}), 0, 65536);
|
||||
$self->{oIo} = new pgBackRestTest::Common::Io::Buffered(new pgBackRestTest::Common::Io::Handle('exec test', $self->{hOut}), 0, 65536);
|
||||
|
||||
# Create buffered error object
|
||||
$self->{oIoError} = new pgBackRest::Common::Io::Buffered(
|
||||
new pgBackRest::Common::Io::Handle('exec test', $self->{hError}), 0, 65536);
|
||||
$self->{oIoError} = new pgBackRestTest::Common::Io::Buffered(
|
||||
new pgBackRestTest::Common::Io::Handle('exec test', $self->{hError}), 0, 65536);
|
||||
|
||||
# Record start time and set process timeout
|
||||
$self->{iProcessTimeout} = 300;
|
||||
|
||||
@@ -21,23 +21,23 @@ use IPC::Open3;
|
||||
use POSIX ':sys_wait_h';
|
||||
use Symbol 'gensym';
|
||||
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Base;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::LogTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostDbCommonTest;
|
||||
use pgBackRestTest::Env::Host::HostDbTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# testLinkCreate
|
||||
|
||||
@@ -14,8 +14,8 @@ use Cwd qw(abs_path);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ use Cwd qw(abs_path);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
####################################################################################################################################
|
||||
# Base IO Module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Io::Base;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use Scalar::Util qw(blessed);
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# Package name constant
|
||||
####################################################################################################################################
|
||||
use constant COMMON_IO_BASE => __PACKAGE__;
|
||||
push @EXPORT, qw(COMMON_IO_BASE);
|
||||
|
||||
####################################################################################################################################
|
||||
# Default buffer max
|
||||
####################################################################################################################################
|
||||
use constant COMMON_IO_BUFFER_MAX => 4194304;
|
||||
push @EXPORT, qw(COMMON_IO_BUFFER_MAX);
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strId},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strId', trace => true},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# error - throw errors
|
||||
####################################################################################################################################
|
||||
sub error
|
||||
{
|
||||
my $self = shift;
|
||||
my $iCode = shift;
|
||||
my $strMessage = shift;
|
||||
my $strDetail = shift;
|
||||
|
||||
logErrorResult($iCode, $strMessage, $strDetail);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# result - retrieve a result from io or a filter
|
||||
####################################################################################################################################
|
||||
sub result
|
||||
{
|
||||
my $self = shift;
|
||||
my $strModule = shift;
|
||||
|
||||
if (!defined($strModule))
|
||||
{
|
||||
return $self->{rhResult};
|
||||
}
|
||||
|
||||
return $self->{rhResult}{$strModule};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# resultAll - get all results
|
||||
####################################################################################################################################
|
||||
sub resultAll
|
||||
{
|
||||
shift->{rhResult};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# resultSet - set a result from io or a filter
|
||||
####################################################################################################################################
|
||||
sub resultSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $strModule = shift;
|
||||
my $xResult = shift;
|
||||
|
||||
$self->{rhResult}{$strModule} = $xResult;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
sub className {blessed(shift)}
|
||||
sub id {shift->{strId}}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,281 @@
|
||||
####################################################################################################################################
|
||||
# Buffered Handle IO
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Io::Buffered;
|
||||
use parent 'pgBackRestTest::Common::Io::Filter';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use IO::Select;
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::Io::Base;
|
||||
use pgBackRestTest::Common::Io::Handle;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# Package name constant
|
||||
####################################################################################################################################
|
||||
use constant COMMON_IO_BUFFERED => __PACKAGE__;
|
||||
push @EXPORT, qw(COMMON_IO_BUFFERED);
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oParent,
|
||||
$iTimeout,
|
||||
$lBufferMax,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oParent', trace => true},
|
||||
{name => 'iTimeout', default => 0, trace => true},
|
||||
{name => 'lBufferMax', default => COMMON_IO_BUFFER_MAX, trace => true},
|
||||
);
|
||||
|
||||
# Bless with new class
|
||||
my $self = $class->SUPER::new($oParent);
|
||||
bless $self, $class;
|
||||
|
||||
# Set read handle so select object is created
|
||||
$self->handleReadSet($self->handleRead());
|
||||
|
||||
# Set variables
|
||||
$self->{iTimeout} = $iTimeout;
|
||||
$self->{lBufferMax} = $lBufferMax;
|
||||
|
||||
# Initialize buffer
|
||||
$self->{tBuffer} = '';
|
||||
$self->{lBufferSize} = 0;
|
||||
$self->{lBufferPos} = 0;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# read - buffered read from a handle with optional blocking
|
||||
####################################################################################################################################
|
||||
sub read
|
||||
{
|
||||
my $self = shift;
|
||||
my $tBufferRef = shift;
|
||||
my $iRequestSize = shift;
|
||||
my $bBlock = shift;
|
||||
|
||||
# Set working variables
|
||||
my $iRemainingSize = $iRequestSize;
|
||||
|
||||
# If there is data left over in the buffer from lineRead then use it
|
||||
my $lBufferRemaining = $self->{lBufferSize} - $self->{lBufferPos};
|
||||
|
||||
if ($lBufferRemaining > 0)
|
||||
{
|
||||
my $iReadSize = $iRequestSize < $lBufferRemaining ? $iRequestSize : $lBufferRemaining;
|
||||
|
||||
$$tBufferRef .= substr($self->{tBuffer}, $self->{lBufferPos}, $iReadSize);
|
||||
$self->{lBufferPos} += $iReadSize;
|
||||
|
||||
$iRemainingSize -= $iReadSize;
|
||||
}
|
||||
|
||||
# If this is a blocking read then loop until all bytes have been read, else error. If not blocking read until the request size
|
||||
# has been met or EOF.
|
||||
my $fTimeStart = gettimeofday();
|
||||
my $fRemaining = $self->timeout();
|
||||
|
||||
while ($iRemainingSize > 0 && $fRemaining > 0)
|
||||
{
|
||||
# Check if the sysread call will block
|
||||
if ($self->pending() || $self->{oReadSelect}->can_read($fRemaining))
|
||||
{
|
||||
# Read data into the buffer
|
||||
my $iReadSize = $self->parent()->read($tBufferRef, $iRemainingSize);
|
||||
|
||||
# Check for EOF
|
||||
if ($iReadSize == 0)
|
||||
{
|
||||
if ($bBlock)
|
||||
{
|
||||
$self->error(ERROR_FILE_READ, "unable to read ${iRequestSize} byte(s) due to EOF from " . $self->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
return $iRequestSize - $iRemainingSize;
|
||||
}
|
||||
}
|
||||
|
||||
# Update remaining size and return when it reaches 0
|
||||
$iRemainingSize -= $iReadSize;
|
||||
}
|
||||
|
||||
# Calculate time remaining before timeout
|
||||
$fRemaining = $self->timeout() - (gettimeofday() - $fTimeStart);
|
||||
};
|
||||
|
||||
# Throw an error if timeout happened before required bytes were read
|
||||
if ($iRemainingSize != 0 && $bBlock)
|
||||
{
|
||||
$self->error(
|
||||
ERROR_FILE_READ, "unable to read ${iRequestSize} byte(s) after " . $self->timeout() . ' second(s) from ' . $self->id());
|
||||
}
|
||||
|
||||
return $iRequestSize - $iRemainingSize;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# readLine - read the next lf-terminated line.
|
||||
####################################################################################################################################
|
||||
sub readLine
|
||||
{
|
||||
my $self = shift;
|
||||
my $bIgnoreEOF = shift;
|
||||
my $bError = shift;
|
||||
|
||||
# Try to find the next linefeed
|
||||
my $iLineFeedPos = index($self->{tBuffer}, "\n", $self->{lBufferPos});
|
||||
|
||||
# If no linefeed was found then load more data
|
||||
if ($iLineFeedPos == -1)
|
||||
{
|
||||
my $fRemaining = $self->timeout();
|
||||
my $fTimeStart = gettimeofday();
|
||||
|
||||
# Load data
|
||||
do
|
||||
{
|
||||
# If the buffer already has data and the buffer position is not 0 then trim it so there's room for more data
|
||||
if ($self->{lBufferPos} != 0)
|
||||
{
|
||||
$self->{tBuffer} = substr($self->{tBuffer}, $self->{lBufferPos});
|
||||
$self->{lBufferSize} = $self->{lBufferSize} - $self->{lBufferPos};
|
||||
$self->{lBufferPos} = 0;
|
||||
}
|
||||
|
||||
# Load data into the buffer
|
||||
my $iBufferRead = 0;
|
||||
|
||||
if ($self->pending() || $self->{oReadSelect}->can_read($fRemaining))
|
||||
{
|
||||
$iBufferRead = $self->parent()->read(
|
||||
\$self->{tBuffer},
|
||||
$self->{lBufferSize} >= $self->bufferMax() ? $self->bufferMax() : $self->bufferMax() - $self->{lBufferSize});
|
||||
|
||||
# Check for EOF
|
||||
if ($iBufferRead == 0)
|
||||
{
|
||||
# Return undef if EOF is ignored
|
||||
if (defined($bIgnoreEOF) && $bIgnoreEOF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
# Else throw an error
|
||||
$self->error(ERROR_FILE_READ, 'unexpected EOF reading line from ' . $self->id());
|
||||
}
|
||||
}
|
||||
|
||||
# If data was read then check for a linefeed
|
||||
if ($iBufferRead > 0)
|
||||
{
|
||||
$self->{lBufferSize} += $iBufferRead;
|
||||
|
||||
$iLineFeedPos = index($self->{tBuffer}, "\n");
|
||||
}
|
||||
|
||||
# Calculate time remaining before timeout
|
||||
if ($iLineFeedPos == -1)
|
||||
{
|
||||
$fRemaining = $self->timeout() - (gettimeofday() - $fTimeStart);
|
||||
}
|
||||
}
|
||||
while ($iLineFeedPos == -1 && $fRemaining > 0);
|
||||
|
||||
# If not linefeed was found within the timeout throw error
|
||||
if ($iLineFeedPos == -1)
|
||||
{
|
||||
if (!defined($bError) || $bError)
|
||||
{
|
||||
$self->error(
|
||||
ERROR_FILE_READ, 'unable to read line after ' . $self->timeout() . ' second(s) from ' . $self->id());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# Return the line that was found and adjust the buffer position
|
||||
my $strLine = substr($self->{tBuffer}, $self->{lBufferPos}, $iLineFeedPos - $self->{lBufferPos});
|
||||
$self->{lBufferPos} = $iLineFeedPos + 1;
|
||||
|
||||
return $strLine;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# writeLine - write a string and \n terminate it
|
||||
####################################################################################################################################
|
||||
sub writeLine
|
||||
{
|
||||
my $self = shift;
|
||||
my $strBuffer = shift;
|
||||
|
||||
$strBuffer .= "\n";
|
||||
return $self->parent()->write(\$strBuffer);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters/Setters
|
||||
####################################################################################################################################
|
||||
sub timeout {shift->{iTimeout}};
|
||||
sub bufferMax {shift->{lBufferMax}};
|
||||
|
||||
####################################################################################################################################
|
||||
# handleReadSet - create a select object when read handle is set
|
||||
####################################################################################################################################
|
||||
sub handleReadSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $fhRead = shift;
|
||||
|
||||
$self->parent()->handleReadSet($fhRead);
|
||||
|
||||
# Create select object to make IO waits more efficient
|
||||
$self->{oReadSelect} = IO::Select->new();
|
||||
$self->{oReadSelect}->add($self->handleRead());
|
||||
|
||||
# Check if the read handle has a pending method. This should be checked before can_read for SSL sockets.
|
||||
$self->{bPending} = defined($fhRead) && $fhRead->can('pending') ? true : false;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Are bytes pending that won't show up in select?
|
||||
####################################################################################################################################
|
||||
sub pending
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return ($self->{bPending} && $self->handleRead()->pending() ? true : false);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,74 @@
|
||||
####################################################################################################################################
|
||||
# Base Filter Module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Io::Filter;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use Scalar::Util qw(blessed);
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{oParent},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oParent', trace => true},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Pass through for unimplemented methods
|
||||
####################################################################################################################################
|
||||
sub bufferMax {shift->{oParent}->bufferMax()};
|
||||
sub className {shift->{oParent}->className()};
|
||||
sub close {shift->{oParent}->close()};
|
||||
sub eof {shift->{oParent}->eof()};
|
||||
sub eofSet {shift->{oParent}->eofSet(@_)};
|
||||
sub error {shift->{oParent}->error(@_)};
|
||||
sub id {shift->{oParent}->id()};
|
||||
sub handleRead {shift->{oParent}->handleRead()};
|
||||
sub handleReadSet {shift->{oParent}->handleReadSet(@_)};
|
||||
sub handleWrite {shift->{oParent}->handleWrite()};
|
||||
sub handleWriteSet {shift->{oParent}->handleWriteSet(@_)};
|
||||
sub name {shift->{oParent}->name()};
|
||||
sub read {shift->{oParent}->read(@_)};
|
||||
sub readLine {shift->{oParent}->readLine(@_)};
|
||||
sub size {shift->{oParent}->size()};
|
||||
sub timeout {shift->{oParent}->timeout()};
|
||||
sub write {shift->{oParent}->write(@_)};
|
||||
sub writeLine {shift->{oParent}->writeLine(@_)};
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
sub parent {shift->{oParent}}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,185 @@
|
||||
####################################################################################################################################
|
||||
# Basic Handle IO
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Io::Handle;
|
||||
use parent 'pgBackRestTest::Common::Io::Base';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# Package name constant
|
||||
####################################################################################################################################
|
||||
use constant COMMON_IO_HANDLE => __PACKAGE__;
|
||||
push @EXPORT, qw(COMMON_IO_HANDLE);
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strId,
|
||||
$fhRead,
|
||||
$fhWrite,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strId', trace => true},
|
||||
{name => 'fhRead', required => false, trace => true},
|
||||
{name => 'fhWrite', required => false, trace => true},
|
||||
);
|
||||
|
||||
# Create class
|
||||
my $self = $class->SUPER::new($strId);
|
||||
bless $self, $class;
|
||||
|
||||
# Set handles
|
||||
$self->handleReadSet($fhRead) if defined($fhRead);
|
||||
$self->handleWriteSet($fhWrite) if defined($fhWrite);
|
||||
|
||||
# Size tracks number of bytes read and written
|
||||
$self->{lSize} = 0;
|
||||
|
||||
# Initialize EOF to false
|
||||
$self->eofSet(false);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# eof - have reads reached eof?
|
||||
#
|
||||
# Note that there may be more bytes to be read but this is set to true whenever there is a zero read and back to false on a
|
||||
# non-zero read.
|
||||
####################################################################################################################################
|
||||
sub eof
|
||||
{
|
||||
return shift->{bEOF};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# eofSet - set eof
|
||||
####################################################################################################################################
|
||||
sub eofSet
|
||||
{
|
||||
my $self = shift;
|
||||
my $bEOF = shift;
|
||||
|
||||
$self->{bEOF} = $bEOF;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# read - read data from handle
|
||||
####################################################################################################################################
|
||||
sub read
|
||||
{
|
||||
my $self = shift;
|
||||
my $rtBuffer = shift;
|
||||
my $iSize = shift;
|
||||
|
||||
# Read the block
|
||||
my $iActualSize;
|
||||
|
||||
eval
|
||||
{
|
||||
$iActualSize = sysread($self->handleRead(), $$rtBuffer, $iSize, defined($$rtBuffer) ? length($$rtBuffer) : 0);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
$self->error(ERROR_FILE_READ, 'unable to read from ' . $self->id(), $EVAL_ERROR);
|
||||
};
|
||||
|
||||
# Report any errors
|
||||
# uncoverable branch true - all errors seem to be caught by the handler above but check for error here just in case
|
||||
defined($iActualSize)
|
||||
or $self->error(ERROR_FILE_READ, 'unable to read from ' . $self->id(), $OS_ERROR);
|
||||
|
||||
# Update size
|
||||
$self->{lSize} += $iActualSize;
|
||||
|
||||
# Update EOF
|
||||
$self->eofSet($iActualSize == 0 ? true : false);
|
||||
|
||||
return $iActualSize;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# write - write data to handle
|
||||
####################################################################################################################################
|
||||
sub write
|
||||
{
|
||||
my $self = shift;
|
||||
my $rtBuffer = shift;
|
||||
|
||||
# Write the block
|
||||
my $iActualSize;
|
||||
|
||||
eval
|
||||
{
|
||||
$iActualSize = syswrite($self->handleWrite(), $$rtBuffer);
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
$self->error(ERROR_FILE_WRITE, 'unable to write to ' . $self->id(), $EVAL_ERROR);
|
||||
};
|
||||
|
||||
# Report any errors
|
||||
# uncoverable branch true - all errors seem to be caught by the handler above but check for error here just in case
|
||||
defined($iActualSize)
|
||||
or $self->error(ERROR_FILE_WRITE, 'unable to write to ' . $self->id(), $OS_ERROR);
|
||||
|
||||
# Update size
|
||||
$self->{lSize} += $iActualSize;
|
||||
|
||||
return $iActualSize;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# close - record read/write size
|
||||
####################################################################################################################################
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Set bytes read and written
|
||||
if (defined($self->{lSize}))
|
||||
{
|
||||
$self->resultSet(COMMON_IO_HANDLE, $self->{lSize});
|
||||
undef($self->{lSize});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters/Setters
|
||||
####################################################################################################################################
|
||||
sub handleRead {return shift->{fhHandleRead}}
|
||||
sub handleReadSet {my $self = shift; $self->{fhHandleRead} = shift}
|
||||
sub handleWrite {return shift->{fhHandleWrite}}
|
||||
sub handleWriteSet {my $self = shift; $self->{fhHandleWrite} = shift}
|
||||
sub size {shift->{lSize}}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,193 @@
|
||||
####################################################################################################################################
|
||||
# Process Execution, Management, and IO
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Io::Process;
|
||||
use parent 'pgBackRestTest::Common::Io::Filter';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use IPC::Open3 qw(open3);
|
||||
use POSIX qw(:sys_wait_h);
|
||||
use Symbol 'gensym';
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::Io::Buffered;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# Amount of time to attempt to retrieve errors when a process terminates unexpectedly
|
||||
####################################################################################################################################
|
||||
use constant IO_ERROR_TIMEOUT => 5;
|
||||
|
||||
####################################################################################################################################
|
||||
# new - use open3 to run the command and get the io handles
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oParent,
|
||||
$strCommand,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'oParent', trace => true},
|
||||
{name => 'strCommand', trace => true},
|
||||
);
|
||||
|
||||
# Bless with new class
|
||||
my $self = $class->SUPER::new($oParent);
|
||||
bless $self, $class;
|
||||
|
||||
# Use open3 to run the command
|
||||
my ($iProcessId, $fhRead, $fhWrite, $fhReadError);
|
||||
$fhReadError = gensym;
|
||||
|
||||
$iProcessId = IPC::Open3::open3($fhWrite, $fhRead, $fhReadError, $strCommand);
|
||||
|
||||
# Set handles
|
||||
$self->handleReadSet($fhRead);
|
||||
$self->handleWriteSet($fhWrite);
|
||||
|
||||
# Set variables
|
||||
$self->{iProcessId} = $iProcessId;
|
||||
$self->{fhReadError} = $fhReadError;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# error - handle errors
|
||||
####################################################################################################################################
|
||||
sub error
|
||||
{
|
||||
my $self = shift;
|
||||
my $iCode = shift;
|
||||
my $strMessage = shift;
|
||||
my $strDetail = shift;
|
||||
my $bClose = shift;
|
||||
|
||||
if (defined($self->{iProcessId}))
|
||||
{
|
||||
my $oWait = waitInit(defined($iCode) ? IO_ERROR_TIMEOUT : 0);
|
||||
|
||||
do
|
||||
{
|
||||
# Check the result
|
||||
my $iResult = waitpid($self->{iProcessId}, $bClose ? 0 : WNOHANG);
|
||||
|
||||
# Error if the process exited unexpectedly
|
||||
if ($iResult != 0)
|
||||
{
|
||||
# Get the exit status
|
||||
$self->{iExitStatus} = $iResult == -1 ? 255 : ${^CHILD_ERROR_NATIVE} >> 8;
|
||||
|
||||
# Drain the stderr stream
|
||||
my $strError;
|
||||
my $oIoError = new pgBackRestTest::Common::Io::Buffered(
|
||||
new pgBackRestTest::Common::Io::Handle($self->id(), $self->{fhReadError}), 5, $self->bufferMax());
|
||||
|
||||
while (defined(my $strLine = $oIoError->readLine(true, false)))
|
||||
{
|
||||
$strError .= (defined($strError) ? "\n" : '') . $strLine;
|
||||
}
|
||||
|
||||
delete($self->{iProcessId});
|
||||
|
||||
if ((!$bClose && $self->{iExitStatus} != 0) || defined($strError))
|
||||
{
|
||||
my $iErrorCode =
|
||||
$self->{iExitStatus} >= ERROR_MINIMUM && $self->{iExitStatus} <= ERROR_MAXIMUM ?
|
||||
$self->{iExitStatus} : ERROR_FILE_READ;
|
||||
|
||||
logErrorResult(
|
||||
$iErrorCode, $self->id() . ' terminated unexpectedly' .
|
||||
($self->{iExitStatus} != 255 ? sprintf(' [%03d]', $self->{iExitStatus}) : ''),
|
||||
$strError);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (waitMore($oWait));
|
||||
|
||||
if (defined($iCode))
|
||||
{
|
||||
$self->parent()->error($iCode, $strMessage, $strDetail);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
confess &log(ASSERT, 'cannot call error() after process has been closed');
|
||||
}
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get process id
|
||||
####################################################################################################################################
|
||||
sub processId
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{iProcessId};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get exit status (after close() is called)
|
||||
####################################################################################################################################
|
||||
sub exitStatus
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
return $self->{iExitStatus};
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# writeLine - check for error before writing line
|
||||
####################################################################################################################################
|
||||
sub writeLine
|
||||
{
|
||||
my $self = shift;
|
||||
my $strBuffer = shift;
|
||||
|
||||
# Check if the process has exited abnormally (doesn't seem like we should need this, but the next syswrite does a hard
|
||||
# abort if the remote process has already closed)
|
||||
$self->error();
|
||||
|
||||
return $self->parent()->writeLine($strBuffer);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# close - check if the process terminated on error
|
||||
####################################################################################################################################
|
||||
sub close
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
if (defined($self->{iProcessId}))
|
||||
{
|
||||
$self->error(undef, undef, undef, true);
|
||||
|
||||
# Class parent close
|
||||
$self->parent()->close();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -18,15 +18,16 @@ use File::Basename qw(dirname basename);
|
||||
use POSIX qw(ceil);
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::BuildTest;
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::CoverageTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::DefineTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::ListTest;
|
||||
|
||||
@@ -13,8 +13,8 @@ use Carp qw(confess);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::DefineTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
|
||||
@@ -15,9 +15,10 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::BuildTest;
|
||||
use pgBackRestTest::Common::DefineTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
@@ -28,6 +28,7 @@ use pgBackRestTest::Common::LogTest;
|
||||
use pgBackRestTest::Common::Storage;
|
||||
use pgBackRestTest::Common::StoragePosix;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# Constant to use when bogus data is required
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Implements storage functionality using drivers.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Storage;
|
||||
use parent 'pgBackRest::Storage::Base';
|
||||
use parent 'pgBackRestTest::Common::StorageBase';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
@@ -11,10 +11,11 @@ use English '-no_match_vars';
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Storage::Base;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
####################################################################################################################################
|
||||
# Base Storage Module
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::StorageBase;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Digest::SHA qw(sha1_hex);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::Io::Base;
|
||||
|
||||
####################################################################################################################################
|
||||
# Storage constants
|
||||
####################################################################################################################################
|
||||
use constant STORAGE_LOCAL => '<LOCAL>';
|
||||
push @EXPORT, qw(STORAGE_LOCAL);
|
||||
|
||||
use constant STORAGE_OBJECT => 'object';
|
||||
push @EXPORT, qw(STORAGE_OBJECT);
|
||||
use constant STORAGE_POSIX => 'posix';
|
||||
push @EXPORT, qw(STORAGE_POSIX);
|
||||
|
||||
####################################################################################################################################
|
||||
# Filter constants
|
||||
####################################################################################################################################
|
||||
use constant STORAGE_FILTER_CIPHER_BLOCK => 'pgBackRest::Storage::Filter::CipherBlock';
|
||||
push @EXPORT, qw(STORAGE_FILTER_CIPHER_BLOCK);
|
||||
|
||||
####################################################################################################################################
|
||||
# Capability constants
|
||||
####################################################################################################################################
|
||||
# Does the storage support symlinks and hardlinks?
|
||||
use constant STORAGE_CAPABILITY_LINK => 'link';
|
||||
push @EXPORT, qw(STORAGE_CAPABILITY_LINK);
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{lBufferMax},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'lBufferMax', optional => true, default => COMMON_IO_BUFFER_MAX, trace => true},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Calculate sha1 hash and size of file. If special encryption settings are required, then the file objects from openRead/openWrite
|
||||
# must be passed instead of file names.
|
||||
####################################################################################################################################
|
||||
sub hashSize
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFileExp,
|
||||
$bIgnoreMissing,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->hashSize', \@_,
|
||||
{name => 'xFileExp'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Set operation variables
|
||||
my $strHash;
|
||||
my $lSize;
|
||||
|
||||
# Is this an IO object or a file expression?
|
||||
my $rtContent = $self->get($xFileExp, {bIgnoreMissing => $bIgnoreMissing});
|
||||
|
||||
if (defined($rtContent))
|
||||
{
|
||||
if (defined($$rtContent))
|
||||
{
|
||||
$strHash = sha1_hex($$rtContent);
|
||||
$lSize = length($$rtContent);
|
||||
}
|
||||
else
|
||||
{
|
||||
$strHash = sha1_hex('');
|
||||
$lSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strHash', value => $strHash},
|
||||
{name => 'lSize', value => $lSize}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# pathAbsolute - generate an absolute path from an absolute base path and a relative path
|
||||
####################################################################################################################################
|
||||
sub pathAbsolute
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strBasePath,
|
||||
$strPath
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::pathAbsolute', \@_,
|
||||
{name => 'strBasePath', trace => true},
|
||||
{name => 'strPath', trace => true}
|
||||
);
|
||||
|
||||
# Working variables
|
||||
my $strAbsolutePath;
|
||||
|
||||
# If the path is already absolute
|
||||
if (index($strPath, '/') == 0)
|
||||
{
|
||||
$strAbsolutePath = $strPath;
|
||||
}
|
||||
# Else make it absolute using the base path
|
||||
else
|
||||
{
|
||||
# Make sure the absolute path is really absolute
|
||||
if (index($strBasePath, '/') != 0 || index($strBasePath, '/..') != -1)
|
||||
{
|
||||
confess &log(ERROR, "${strBasePath} is not an absolute path", ERROR_PATH_TYPE);
|
||||
}
|
||||
|
||||
while (index($strPath, '..') == 0)
|
||||
{
|
||||
$strBasePath = dirname($strBasePath);
|
||||
$strPath = substr($strPath, 2);
|
||||
|
||||
if (index($strPath, '/') == 0)
|
||||
{
|
||||
$strPath = substr($strPath, 1);
|
||||
}
|
||||
}
|
||||
|
||||
$strAbsolutePath = "${strBasePath}/${strPath}";
|
||||
}
|
||||
|
||||
# Make sure the result is really an absolute path
|
||||
if (index($strAbsolutePath, '/') != 0 || index($strAbsolutePath, '/..') != -1)
|
||||
{
|
||||
confess &log(ERROR, "result ${strAbsolutePath} was not an absolute path", ERROR_PATH_TYPE);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strAbsolutePath', value => $strAbsolutePath, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -16,9 +16,10 @@ use File::Basename qw(basename dirname);
|
||||
use Fcntl qw(:mode);
|
||||
use File::stat qw{lstat};
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Base;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::StoragePosixRead;
|
||||
use pgBackRestTest::Common::StoragePosixWrite;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Posix File Read
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::StoragePosixRead;
|
||||
use parent 'pgBackRest::Common::Io::Handle';
|
||||
use parent 'pgBackRestTest::Common::Io::Handle';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
@@ -11,8 +11,8 @@ use English '-no_match_vars';
|
||||
|
||||
use Fcntl qw(O_RDONLY);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# Posix File Write
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::StoragePosixWrite;
|
||||
use parent 'pgBackRest::Common::Io::Handle';
|
||||
use parent 'pgBackRestTest::Common::Io::Handle';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
@@ -12,11 +12,11 @@ use English '-no_match_vars';
|
||||
use Fcntl qw(O_RDONLY O_WRONLY O_CREAT O_TRUNC);
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRest::Common::Io::Handle;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRestTest::Common::Io::Handle;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
|
||||
@@ -0,0 +1,618 @@
|
||||
####################################################################################################################################
|
||||
# C Storage Interface
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::StorageRepo;
|
||||
use parent 'pgBackRestTest::Common::StorageBase';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Digest::SHA qw(sha1_hex);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use Fcntl qw(:mode);
|
||||
use File::stat qw{lstat};
|
||||
use JSON::PP;
|
||||
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::Io::Handle;
|
||||
use pgBackRestTest::Common::Io::Process;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
|
||||
####################################################################################################################################
|
||||
# Temp file extension
|
||||
####################################################################################################################################
|
||||
use constant STORAGE_TEMP_EXT => PROJECT_EXE . '.tmp';
|
||||
push @EXPORT, qw(STORAGE_TEMP_EXT);
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Create the class hash
|
||||
my $self = {};
|
||||
bless $self, $class;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
(
|
||||
my $strOperation,
|
||||
$self->{strCommand},
|
||||
$self->{strType},
|
||||
$self->{lBufferMax},
|
||||
$self->{iTimeoutIo},
|
||||
$self->{strDefaultPathMode},
|
||||
$self->{strDefaultFileMode},
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strCommand'},
|
||||
{name => 'strType'},
|
||||
{name => 'lBufferMax'},
|
||||
{name => 'iTimeoutIo'},
|
||||
{name => 'strDefaultPathMode', optional => true, default => '0750'},
|
||||
{name => 'strDefaultFileMode', optional => true, default => '0640'},
|
||||
);
|
||||
|
||||
# Create JSON object
|
||||
$self->{oJSON} = JSON::PP->new()->allow_nonref();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Escape characteres that have special meaning on the command line
|
||||
####################################################################################################################################
|
||||
sub escape
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strValue,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->escape', \@_,
|
||||
{name => 'strValue', trace => true},
|
||||
);
|
||||
|
||||
$strValue =~ s/\\/\\\\/g;
|
||||
$strValue =~ s/\</\\\</g;
|
||||
$strValue =~ s/\>/\\\>/g;
|
||||
$strValue =~ s/\!/\\\!/g;
|
||||
$strValue =~ s/\*/\\\*/g;
|
||||
$strValue =~ s/\(/\\\(/g;
|
||||
$strValue =~ s/\)/\\\)/g;
|
||||
$strValue =~ s/\&/\\\&/g;
|
||||
$strValue =~ s/\'/\\\'/g;
|
||||
$strValue =~ s/\;/\\\;/g;
|
||||
$strValue =~ s/\?/\\\?/g;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strValue', value => $strValue},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Execute command and return the output
|
||||
####################################################################################################################################
|
||||
sub exec
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->exec', \@_,
|
||||
{name => 'strCommand'},
|
||||
);
|
||||
|
||||
$strCommand = "$self->{strCommand} ${strCommand}";
|
||||
my $oBuffer = new pgBackRestTest::Common::Io::Buffered(
|
||||
new pgBackRestTest::Common::Io::Handle($strCommand), $self->{iTimeoutIo}, $self->{lBufferMax});
|
||||
my $oProcess = new pgBackRestTest::Common::Io::Process($oBuffer, $strCommand);
|
||||
|
||||
my $tResult;
|
||||
|
||||
while (!$oBuffer->eof())
|
||||
{
|
||||
$oBuffer->read(\$tResult, $self->{lBufferMax}, false);
|
||||
}
|
||||
|
||||
$oProcess->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'tResult', value => $tResult},
|
||||
{name => 'iExitStatus', value => $oProcess->exitStatus()},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Create storage
|
||||
####################################################################################################################################
|
||||
sub create
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my ($strOperation) = logDebugParam(__PACKAGE__ . '->create');
|
||||
|
||||
$self->exec("repo-create");
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Check if file exists (not a path)
|
||||
####################################################################################################################################
|
||||
sub exists
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strFileExp,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->exists', \@_,
|
||||
{name => 'strFileExp'},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bExists', value => $self->info($strFileExp, {bIgnoreMissing => true})->{type} eq 'f'}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Read a buffer from storage all at once
|
||||
####################################################################################################################################
|
||||
sub get
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$xFile,
|
||||
$strCipherPass,
|
||||
$bRaw,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->get', \@_,
|
||||
{name => 'xFile', required => false},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
{name => 'bRaw', optional => true, default => false},
|
||||
);
|
||||
|
||||
# If openRead() was called first set values from that call
|
||||
my $strFile = $xFile;
|
||||
my $bIgnoreMissing = false;
|
||||
|
||||
if (ref($xFile))
|
||||
{
|
||||
$strFile = $xFile->{strFile};
|
||||
$bIgnoreMissing = $xFile->{bIgnoreMissing};
|
||||
$strCipherPass = $xFile->{strCipherPass};
|
||||
}
|
||||
|
||||
# Check invalid params
|
||||
if ($bRaw && defined($strCipherPass))
|
||||
{
|
||||
confess &log(ERROR, 'bRaw and strCipherPass cannot both be set');
|
||||
}
|
||||
|
||||
# Get file
|
||||
my ($tResult, $iExitStatus) = $self->exec(
|
||||
(defined($strCipherPass) ? ' --cipher-pass=' . $self->escape($strCipherPass) : '') . ($bRaw ? ' --raw' : '') .
|
||||
($bIgnoreMissing ? ' --ignore-missing' : '') . ' repo-get ' . $self->escape($strFile));
|
||||
|
||||
# Error if missing an not ignored
|
||||
if ($iExitStatus == 1 && !$bIgnoreMissing)
|
||||
{
|
||||
confess &log(ERROR, "unable to open '${strFile}'", ERROR_FILE_OPEN);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rtContent', value => $iExitStatus == 0 ? \$tResult : undef, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Get information for path/file
|
||||
####################################################################################################################################
|
||||
sub info
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathFileExp,
|
||||
$bIgnoreMissing,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->info', \@_,
|
||||
{name => 'strPathFileExp'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rhInfo', value => $self->manifest($strPathFileExp, {bRecurse => false})->{'.'}, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# List all files/paths in path
|
||||
####################################################################################################################################
|
||||
sub list
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
$strExpression,
|
||||
$strSortOrder,
|
||||
$bIgnoreMissing,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->list', \@_,
|
||||
{name => 'strPathExp', required => false},
|
||||
{name => 'strExpression', optional => true},
|
||||
{name => 'strSortOrder', optional => true, default => 'forward'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Get file list
|
||||
my $rstryFileList = [];
|
||||
my $rhManifest = $self->manifest($strPathExp, {bRecurse => false});
|
||||
|
||||
foreach my $strKey ($strSortOrder eq 'reverse' ? sort {$b cmp $a} keys(%{$rhManifest}) : sort keys(%{$rhManifest}))
|
||||
{
|
||||
next if $strKey eq '.';
|
||||
next if defined($strExpression) && $strKey !~ $strExpression;
|
||||
|
||||
push(@{$rstryFileList}, $strKey);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'stryFileList', value => $rstryFileList}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Build path/file/link manifest starting with base path and including all subpaths
|
||||
####################################################################################################################################
|
||||
sub manifest
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPathExp,
|
||||
$bRecurse,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->manifest', \@_,
|
||||
{name => 'strPathExp'},
|
||||
{name => 'bRecurse', optional => true, default => true},
|
||||
);
|
||||
|
||||
my $rhManifest = $self->{oJSON}->decode(
|
||||
$self->exec("--output=json " . ($bRecurse ? ' --recurse' : '') . " repo-ls " . $self->escape($strPathExp)));
|
||||
|
||||
# Transform the manifest to the old format
|
||||
foreach my $strKey (keys(%{$rhManifest}))
|
||||
{
|
||||
if ($rhManifest->{$strKey}{type} eq 'file')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'f';
|
||||
|
||||
if (defined($rhManifest->{$strKey}{time}))
|
||||
{
|
||||
$rhManifest->{$strKey}{modified_time} = $rhManifest->{$strKey}{time};
|
||||
delete($rhManifest->{$strKey}{time});
|
||||
}
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'path')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'd';
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'link')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 'l';
|
||||
}
|
||||
elsif ($rhManifest->{$strKey}{type} eq 'special')
|
||||
{
|
||||
$rhManifest->{$strKey}{type} = 's';
|
||||
}
|
||||
else
|
||||
{
|
||||
confess "invalid file type '$rhManifest->{type}'";
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rhManifest', value => $rhManifest, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Open file for reading
|
||||
####################################################################################################################################
|
||||
sub openRead
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strFile,
|
||||
$bIgnoreMissing,
|
||||
$strCipherPass,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->openRead', \@_,
|
||||
{name => 'strFile'},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'rhFileIo', value => {strFile => $strFile, bIgnoreMissing => $bIgnoreMissing, strCipherPass => $strCipherPass},
|
||||
trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Remove path and all files below it
|
||||
####################################################################################################################################
|
||||
sub pathRemove
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strPath,
|
||||
$bRecurse,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->pathRemove', \@_,
|
||||
{name => 'strPath'},
|
||||
{name => 'bRecurse', optional => true, default => false},
|
||||
);
|
||||
|
||||
$self->exec("repo-rm " . ($bRecurse ? '--recurse ' : '') . $self->escape($strPath));
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# put - writes a buffer out to storage all at once
|
||||
####################################################################################################################################
|
||||
sub put
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strFile,
|
||||
$tContent,
|
||||
$strCipherPass,
|
||||
$bRaw,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->put', \@_,
|
||||
{name => 'strFile'},
|
||||
{name => 'tContent', required => false},
|
||||
{name => 'strCipherPass', optional => true, redact => true},
|
||||
{name => 'bRaw', optional => true, default => false},
|
||||
);
|
||||
|
||||
# Check invalid params
|
||||
if ($bRaw && defined($strCipherPass))
|
||||
{
|
||||
confess &log(ERROR, 'bRaw and strCipherPass cannot both be set');
|
||||
}
|
||||
|
||||
# Put file
|
||||
my $strCommand =
|
||||
"$self->{strCommand}" . (defined($strCipherPass) ? ' --cipher-pass=' . $self->escape($strCipherPass) : '') .
|
||||
($bRaw ? ' --raw' : '') . ' repo-put ' . $self->escape($strFile);
|
||||
|
||||
my $oBuffer = new pgBackRestTest::Common::Io::Buffered(
|
||||
new pgBackRestTest::Common::Io::Handle($strCommand), $self->{iTimeoutIo}, $self->{lBufferMax});
|
||||
my $oProcess = new pgBackRestTest::Common::Io::Process($oBuffer, $strCommand);
|
||||
|
||||
if (defined($tContent))
|
||||
{
|
||||
$oBuffer->write(\$tContent);
|
||||
}
|
||||
|
||||
close($oBuffer->handleWrite());
|
||||
|
||||
my $tResult;
|
||||
|
||||
while (!$oBuffer->eof())
|
||||
{
|
||||
$oBuffer->read(\$tResult, $self->{lBufferMax}, false);
|
||||
}
|
||||
|
||||
close($oBuffer->handleRead());
|
||||
$oProcess->close();
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Remove file
|
||||
####################################################################################################################################
|
||||
sub remove
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strFile,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->remove', \@_,
|
||||
{name => 'xFileExp'},
|
||||
);
|
||||
|
||||
$self->exec("repo-rm " . $self->escape($strFile));
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Cache storage so it can be retrieved quickly
|
||||
####################################################################################################################################
|
||||
my $oRepoStorage;
|
||||
|
||||
####################################################################################################################################
|
||||
# storageRepoCommandSet
|
||||
####################################################################################################################################
|
||||
my $strStorageRepoCommand;
|
||||
my $strStorageRepoType;
|
||||
|
||||
sub storageRepoCommandSet
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strCommand,
|
||||
$strStorageType,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::storageRepoCommandSet', \@_,
|
||||
{name => 'strCommand'},
|
||||
{name => 'strStorageType'},
|
||||
);
|
||||
|
||||
$strStorageRepoCommand = $strCommand;
|
||||
$strStorageRepoType = $strStorageType;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepoCommandSet);
|
||||
|
||||
####################################################################################################################################
|
||||
# storageRepo - get repository storage
|
||||
####################################################################################################################################
|
||||
sub storageRepo
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strStanza,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::storageRepo', \@_,
|
||||
{name => 'strStanza', optional => true, trace => true},
|
||||
);
|
||||
|
||||
# Create storage if not defined
|
||||
if (!defined($oRepoStorage))
|
||||
{
|
||||
$oRepoStorage = new pgBackRestTest::Common::StorageRepo($strStorageRepoCommand, $strStorageRepoType, 64 * 1024, 60);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'oStorageRepo', value => $oRepoStorage, trace => true},
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(storageRepo);
|
||||
|
||||
####################################################################################################################################
|
||||
# Getters
|
||||
####################################################################################################################################
|
||||
sub capability {shift->type() eq STORAGE_POSIX}
|
||||
sub type {shift->{strType}}
|
||||
|
||||
1;
|
||||
@@ -13,9 +13,10 @@ use Carp qw(confess);
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::DbVersion;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
|
||||
####################################################################################################################################
|
||||
# VM hash keywords
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
####################################################################################################################################
|
||||
# COMMON WAIT MODULE
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Common::Wait;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
use POSIX qw(ceil);
|
||||
use Time::HiRes qw(gettimeofday usleep);
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
####################################################################################################################################
|
||||
# Wait constants
|
||||
####################################################################################################################################
|
||||
use constant WAIT_TIME_MINIMUM => .1;
|
||||
push @EXPORT, qw(WAIT_TIME_MINIMUM);
|
||||
|
||||
####################################################################################################################################
|
||||
# waitRemainder
|
||||
####################################################################################################################################
|
||||
sub waitRemainder
|
||||
{
|
||||
my $bWait = shift;
|
||||
|
||||
my $lTimeBegin = gettimeofday();
|
||||
|
||||
if (!defined($bWait) || $bWait)
|
||||
{
|
||||
my $lSleepMs = ceil(((int($lTimeBegin) + 1.05) - $lTimeBegin) * 1000);
|
||||
|
||||
usleep($lSleepMs * 1000);
|
||||
|
||||
&log(TRACE, "WAIT_REMAINDER: slept ${lSleepMs}ms: begin ${lTimeBegin}, end " . gettimeofday());
|
||||
}
|
||||
|
||||
return int($lTimeBegin);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(waitRemainder);
|
||||
|
||||
####################################################################################################################################
|
||||
# waitHiRes
|
||||
####################################################################################################################################
|
||||
sub waitHiRes
|
||||
{
|
||||
my $fSecond = shift;
|
||||
|
||||
return usleep($fSecond * 1000000);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(waitHiRes);
|
||||
|
||||
####################################################################################################################################
|
||||
# waitInit
|
||||
####################################################################################################################################
|
||||
sub waitInit
|
||||
{
|
||||
my $fWaitTime = shift;
|
||||
my $fSleep = shift;
|
||||
|
||||
# Declare oWait hash
|
||||
my $oWait = {};
|
||||
|
||||
# If wait seconds is not defined or 0 then return undef
|
||||
if (!defined($fWaitTime) || $fWaitTime == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
# Wait seconds can be a minimum of .1
|
||||
if ($fWaitTime < .1)
|
||||
{
|
||||
confess &log(ASSERT, 'fWaitTime cannot be < .1');
|
||||
}
|
||||
|
||||
# If fSleep is not defined set it
|
||||
if (!defined($fSleep))
|
||||
{
|
||||
if ($fWaitTime >= 1)
|
||||
{
|
||||
$$oWait{sleep} = .1;
|
||||
}
|
||||
else
|
||||
{
|
||||
$$oWait{sleep} = $fWaitTime / 10;
|
||||
}
|
||||
}
|
||||
# Else make sure it's not greater than fWaitTime
|
||||
else
|
||||
{
|
||||
# Make sure fsleep is less than fWaitTime
|
||||
if ($fSleep >= $fWaitTime)
|
||||
{
|
||||
confess &log(ASSERT, 'fSleep > fWaitTime - this is useless');
|
||||
}
|
||||
}
|
||||
|
||||
# Set variables
|
||||
$$oWait{wait_time} = $fWaitTime;
|
||||
$$oWait{time_begin} = gettimeofday();
|
||||
$$oWait{time_end} = $$oWait{time_begin};
|
||||
|
||||
return $oWait;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(waitInit);
|
||||
|
||||
####################################################################################################################################
|
||||
# waitMore
|
||||
####################################################################################################################################
|
||||
sub waitMore
|
||||
{
|
||||
my $oWait = shift;
|
||||
|
||||
# Return if oWait is not defined
|
||||
if (!defined($oWait))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
# Sleep for fSleep time
|
||||
waitHiRes($$oWait{sleep});
|
||||
|
||||
# Capture the end time
|
||||
$$oWait{time_end} = gettimeofday();
|
||||
|
||||
# Exit if wait time has expired
|
||||
if ((gettimeofday() - $$oWait{time_begin}) < $$oWait{wait_time})
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
# Else calculate the new sleep time
|
||||
my $fSleepNext = $$oWait{sleep} + (defined($$oWait{sleep_prev}) ? $$oWait{sleep_prev} : 0);
|
||||
|
||||
if ($fSleepNext > $$oWait{wait_time} - ($$oWait{time_end} - $$oWait{time_begin}))
|
||||
{
|
||||
$fSleepNext = ($$oWait{wait_time} - ($$oWait{time_end} - $$oWait{time_begin})) + .001
|
||||
}
|
||||
|
||||
$$oWait{sleep_prev} = $$oWait{sleep};
|
||||
$$oWait{sleep} = $fSleepNext;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(waitMore);
|
||||
|
||||
####################################################################################################################################
|
||||
# waitInterval
|
||||
####################################################################################################################################
|
||||
sub waitInterval
|
||||
{
|
||||
my $oWait = shift;
|
||||
|
||||
# Error if oWait is not defined
|
||||
if (!defined($oWait))
|
||||
{
|
||||
confess &log(ERROR, "oWait is not defined");
|
||||
}
|
||||
|
||||
return int(($$oWait{time_end} - $$oWait{time_begin}) * 1000) / 1000;
|
||||
}
|
||||
|
||||
push @EXPORT, qw(waitInterval);
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,478 @@
|
||||
####################################################################################################################################
|
||||
# ARCHIVE INFO MODULE
|
||||
#
|
||||
# The archive.info file is created when archiving begins. It is located under the stanza directory. The file contains information
|
||||
# regarding the stanza database version, database WAL segment system id and other information to ensure that archiving is being
|
||||
# performed on the proper database.
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Env::ArchiveInfo;
|
||||
use parent 'BackRestDoc::Common::Ini';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname basename);
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Env::InfoCommon;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# File/path constants
|
||||
####################################################################################################################################
|
||||
use constant ARCHIVE_INFO_FILE => 'archive.info';
|
||||
push @EXPORT, qw(ARCHIVE_INFO_FILE);
|
||||
|
||||
####################################################################################################################################
|
||||
# RegEx constants
|
||||
####################################################################################################################################
|
||||
use constant REGEX_ARCHIVE_DIR_DB_VERSION => '^[0-9]+(\.[0-9]+)*-[0-9]+$';
|
||||
push @EXPORT, qw(REGEX_ARCHIVE_DIR_DB_VERSION);
|
||||
use constant REGEX_ARCHIVE_DIR_WAL => '^[0-F]{16}$';
|
||||
push @EXPORT, qw(REGEX_ARCHIVE_DIR_WAL);
|
||||
|
||||
####################################################################################################################################
|
||||
# WAL segment size
|
||||
####################################################################################################################################
|
||||
use constant PG_WAL_SEGMENT_SIZE => 16777216;
|
||||
push @EXPORT, qw(PG_WAL_SEGMENT_SIZE);
|
||||
|
||||
####################################################################################################################################
|
||||
# Archive info constants
|
||||
####################################################################################################################################
|
||||
use constant INFO_ARCHIVE_SECTION_DB => INFO_BACKUP_SECTION_DB;
|
||||
push @EXPORT, qw(INFO_ARCHIVE_SECTION_DB);
|
||||
use constant INFO_ARCHIVE_SECTION_DB_HISTORY => INFO_BACKUP_SECTION_DB_HISTORY;
|
||||
push @EXPORT, qw(INFO_ARCHIVE_SECTION_DB_HISTORY);
|
||||
|
||||
use constant INFO_ARCHIVE_KEY_DB_VERSION => MANIFEST_KEY_DB_VERSION;
|
||||
push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_VERSION);
|
||||
use constant INFO_ARCHIVE_KEY_DB_ID => MANIFEST_KEY_DB_ID;
|
||||
push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_ID);
|
||||
use constant INFO_ARCHIVE_KEY_DB_SYSTEM_ID => MANIFEST_KEY_SYSTEM_ID;
|
||||
push @EXPORT, qw(INFO_ARCHIVE_KEY_DB_SYSTEM_ID);
|
||||
|
||||
####################################################################################################################################
|
||||
# Global variables
|
||||
####################################################################################################################################
|
||||
my $strArchiveInfoMissingMsg =
|
||||
ARCHIVE_INFO_FILE . " does not exist but is required to push/get WAL segments\n" .
|
||||
"HINT: is archive_command configured in postgresql.conf?\n" .
|
||||
"HINT: has a stanza-create been performed?\n" .
|
||||
"HINT: use --no-archive-check to disable archive checks during backup if you have an alternate archiving scheme.";
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift; # Class name
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strArchiveClusterPath, # Archive cluster path
|
||||
$bRequired, # Is archive info required?
|
||||
$bLoad, # Should the file attempt to be loaded?
|
||||
$bIgnoreMissing, # Don't error on missing files
|
||||
$strCipherPassSub, # Passphrase to encrypt the subsequent archive files if repo is encrypted
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strArchiveClusterPath'},
|
||||
{name => 'bRequired', default => true},
|
||||
{name => 'bLoad', optional => true, default => true},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
{name => 'strCipherPassSub', optional => true},
|
||||
);
|
||||
|
||||
# Build the archive info path/file name
|
||||
my $strArchiveInfoFile = "${strArchiveClusterPath}/" . ARCHIVE_INFO_FILE;
|
||||
my $self = {};
|
||||
my $iResult = 0;
|
||||
my $strResultMessage;
|
||||
|
||||
# Init object and store variables
|
||||
eval
|
||||
{
|
||||
$self = $class->SUPER::new(
|
||||
storageRepo(), $strArchiveInfoFile,
|
||||
{bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => $strCipherPassSub});
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
# Capture error information
|
||||
$iResult = exceptionCode($EVAL_ERROR);
|
||||
$strResultMessage = exceptionMessage($EVAL_ERROR);
|
||||
};
|
||||
|
||||
if ($iResult != 0)
|
||||
{
|
||||
# If the file does not exist but is required to exist, then error
|
||||
# The archive 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, $strArchiveInfoMissingMsg, ERROR_FILE_MISSING);
|
||||
}
|
||||
}
|
||||
elsif ($iResult == ERROR_CRYPTO && $strResultMessage =~ "^unable to flush")
|
||||
{
|
||||
confess &log(ERROR, "unable to parse '$strArchiveInfoFile'\nHINT: is or was the repo encrypted?", $iResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
confess $EVAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
$self->{strArchiveClusterPath} = $strArchiveClusterPath;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# check
|
||||
#
|
||||
# Check archive info file and make sure it is compatible with the current version of the database for the stanza. If the file does
|
||||
# not exist an error will occur.
|
||||
####################################################################################################################################
|
||||
sub check
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$ullDbSysId,
|
||||
$bRequired,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->check', \@_,
|
||||
{name => 'strDbVersion'},
|
||||
{name => 'ullDbSysId'},
|
||||
{name => 'bRequired', default => true},
|
||||
);
|
||||
|
||||
# ??? remove bRequired after stanza-upgrade
|
||||
if ($bRequired)
|
||||
{
|
||||
# Confirm the info file exists with the DB section
|
||||
$self->confirmExists();
|
||||
}
|
||||
|
||||
my $strError = undef;
|
||||
|
||||
if (!$self->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef, $strDbVersion))
|
||||
{
|
||||
$strError = "WAL segment version ${strDbVersion} does not match archive version " .
|
||||
$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION);
|
||||
}
|
||||
|
||||
if (!$self->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef, $ullDbSysId))
|
||||
{
|
||||
$strError = (defined($strError) ? ($strError . "\n") : "") .
|
||||
"WAL segment system-id ${ullDbSysId} does not match archive system-id " .
|
||||
$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID);
|
||||
}
|
||||
|
||||
if (defined($strError))
|
||||
{
|
||||
confess &log(ERROR, "${strError}\nHINT: are you archiving to the correct stanza?", ERROR_ARCHIVE_MISMATCH);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strArchiveId', value => $self->archiveId()}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# archiveId
|
||||
#
|
||||
# Get the archive id which is a combination of the DB version and the db-id setting (e.g. 9.4-1)
|
||||
####################################################################################################################################
|
||||
sub archiveId
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$ullDbSysId,
|
||||
) = logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->archiveId', \@_,
|
||||
{name => 'strDbVersion', optional => true},
|
||||
{name => 'ullDbSysId', optional => true},
|
||||
);
|
||||
|
||||
my $strArchiveId = undef;
|
||||
|
||||
# If neither optional version and system-id are passed then set the archive id to the current one
|
||||
if (!defined($strDbVersion) && !defined($ullDbSysId))
|
||||
{
|
||||
$strArchiveId = $self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION) . "-" .
|
||||
$self->get(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID);
|
||||
}
|
||||
# If both the optional version and system-id are passed
|
||||
elsif (defined($strDbVersion) && defined($ullDbSysId))
|
||||
{
|
||||
# Get the newest archiveId for the version/system-id passed
|
||||
$strArchiveId = ($self->archiveIdList($strDbVersion, $ullDbSysId))[0];
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strArchiveId', value => $strArchiveId}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# archiveIdList
|
||||
#
|
||||
# Get a sorted list of the archive ids for the db-version and db-system-id passed.
|
||||
####################################################################################################################################
|
||||
sub archiveIdList
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$ullDbSysId,
|
||||
) = logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->archiveIdList', \@_,
|
||||
{name => 'strDbVersion'},
|
||||
{name => 'ullDbSysId'},
|
||||
);
|
||||
|
||||
my @stryArchiveId;
|
||||
|
||||
# Get the version and system-id for all known databases
|
||||
my $hDbList = $self->dbHistoryList();
|
||||
|
||||
foreach my $iDbHistoryId (sort {$a <=> $b} keys %$hDbList)
|
||||
{
|
||||
# If the version and system-id match then construct the archive id so that the constructed array has the newest match first
|
||||
if (($hDbList->{$iDbHistoryId}{&INFO_DB_VERSION} eq $strDbVersion) &&
|
||||
($hDbList->{$iDbHistoryId}{&INFO_SYSTEM_ID} eq $ullDbSysId))
|
||||
{
|
||||
unshift(@stryArchiveId, $strDbVersion . "-" . $iDbHistoryId);
|
||||
}
|
||||
}
|
||||
|
||||
# If the archive id has still not been found, then error
|
||||
if (@stryArchiveId == 0)
|
||||
{
|
||||
confess &log(
|
||||
ERROR, "unable to retrieve the archive id for database version '$strDbVersion' and system-id '$ullDbSysId'",
|
||||
ERROR_ARCHIVE_MISMATCH);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'stryArchiveId', value => \@stryArchiveId}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# create
|
||||
#
|
||||
# Creates the archive.info file. WARNING - this function should only be called from stanza-create or tests.
|
||||
####################################################################################################################################
|
||||
sub create
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$ullDbSysId,
|
||||
$bSave,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->create', \@_,
|
||||
{name => 'strDbVersion'},
|
||||
{name => 'ullDbSysId'},
|
||||
{name => 'bSave', default => true},
|
||||
);
|
||||
|
||||
# Fill db section and db history section
|
||||
$self->dbSectionSet($strDbVersion, $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
|
||||
(
|
||||
__PACKAGE__ . '->dbHistoryIdGet', \@_,
|
||||
{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_ARCHIVE_SECTION_DB))
|
||||
? 1 : $self->numericGet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iDbHistoryId', value => $iDbHistoryId}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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_ARCHIVE_SECTION_DB_HISTORY))
|
||||
{
|
||||
$hDbHash{$iHistoryId}{&INFO_DB_VERSION} =
|
||||
$self->get(INFO_ARCHIVE_SECTION_DB_HISTORY, $iHistoryId, INFO_ARCHIVE_KEY_DB_VERSION);
|
||||
$hDbHash{$iHistoryId}{&INFO_SYSTEM_ID} =
|
||||
$self->get(INFO_ARCHIVE_SECTION_DB_HISTORY, $iHistoryId, INFO_ARCHIVE_KEY_DB_ID);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'hDbHash', value => \%hDbHash}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# dbSectionSet
|
||||
#
|
||||
# Set the db and db:history sections.
|
||||
####################################################################################################################################
|
||||
sub dbSectionSet
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$ullDbSysId,
|
||||
$iDbHistoryId,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->dbSectionSet', \@_,
|
||||
{name => 'strDbVersion', trace => true},
|
||||
{name => 'ullDbSysId', trace => true},
|
||||
{name => 'iDbHistoryId', trace => true}
|
||||
);
|
||||
|
||||
# Fill db section
|
||||
$self->numericSet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_SYSTEM_ID, undef, $ullDbSysId);
|
||||
# Force the version to a string since newer versions of JSON::PP lose track of the fact that it is one
|
||||
$self->set(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef, $strDbVersion . '');
|
||||
$self->numericSet(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_ID, undef, $iDbHistoryId);
|
||||
|
||||
# Fill db history
|
||||
$self->numericSet(INFO_ARCHIVE_SECTION_DB_HISTORY, $iDbHistoryId, INFO_ARCHIVE_KEY_DB_ID, $ullDbSysId);
|
||||
# Force the version to a string since newer versions of JSON::PP lose track of the fact that it is one
|
||||
$self->set(INFO_ARCHIVE_SECTION_DB_HISTORY, $iDbHistoryId, INFO_ARCHIVE_KEY_DB_VERSION, $strDbVersion . '');
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# confirmExists
|
||||
#
|
||||
# Ensure that the archive.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_ARCHIVE_SECTION_DB) || !$self->{bExists})
|
||||
{
|
||||
confess &log(ERROR, $strArchiveInfoMissingMsg, ERROR_FILE_MISSING);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -0,0 +1,898 @@
|
||||
####################################################################################################################################
|
||||
# BACKUP INFO MODULE
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Env::BackupInfo;
|
||||
use parent 'BackRestDoc::Common::Ini';
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
use English '-no_match_vars';
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname basename);
|
||||
use File::stat;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::InfoCommon;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Backup type constants
|
||||
####################################################################################################################################
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_FULL => 'full';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_FULL);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_DIFF => 'diff';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_DIFF);
|
||||
use constant CFGOPTVAL_BACKUP_TYPE_INCR => 'incr';
|
||||
push @EXPORT, qw(CFGOPTVAL_BACKUP_TYPE_INCR);
|
||||
|
||||
####################################################################################################################################
|
||||
# File/path constants
|
||||
####################################################################################################################################
|
||||
use constant FILE_BACKUP_INFO => 'backup.info';
|
||||
push @EXPORT, qw(FILE_BACKUP_INFO);
|
||||
|
||||
####################################################################################################################################
|
||||
# Backup info constants
|
||||
####################################################################################################################################
|
||||
use constant INFO_BACKUP_SECTION_BACKUP => MANIFEST_SECTION_BACKUP;
|
||||
push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP);
|
||||
use constant INFO_BACKUP_SECTION_BACKUP_CURRENT => INFO_BACKUP_SECTION_BACKUP . ':current';
|
||||
push @EXPORT, qw(INFO_BACKUP_SECTION_BACKUP_CURRENT);
|
||||
|
||||
use constant INFO_BACKUP_KEY_ARCHIVE_CHECK => MANIFEST_KEY_ARCHIVE_CHECK;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_CHECK);
|
||||
use constant INFO_BACKUP_KEY_ARCHIVE_COPY => MANIFEST_KEY_ARCHIVE_COPY;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_COPY);
|
||||
use constant INFO_BACKUP_KEY_ARCHIVE_START => MANIFEST_KEY_ARCHIVE_START;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_START);
|
||||
use constant INFO_BACKUP_KEY_ARCHIVE_STOP => MANIFEST_KEY_ARCHIVE_STOP;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_ARCHIVE_STOP);
|
||||
use constant INFO_BACKUP_KEY_BACKUP_STANDBY => MANIFEST_KEY_BACKUP_STANDBY;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_STANDBY);
|
||||
use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE => 'backup-info-repo-size';
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE);
|
||||
use constant INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA => 'backup-info-repo-size-delta';
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_REPO_SIZE_DELTA);
|
||||
use constant INFO_BACKUP_KEY_BACKUP_SIZE => 'backup-info-size';
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE);
|
||||
use constant INFO_BACKUP_KEY_BACKUP_SIZE_DELTA => 'backup-info-size-delta';
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_BACKUP_SIZE_DELTA);
|
||||
use constant INFO_BACKUP_KEY_CATALOG => MANIFEST_KEY_CATALOG;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_CATALOG);
|
||||
use constant INFO_BACKUP_KEY_CONTROL => MANIFEST_KEY_CONTROL;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_CONTROL);
|
||||
use constant INFO_BACKUP_KEY_COMPRESS => MANIFEST_KEY_COMPRESS;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_COMPRESS);
|
||||
use constant INFO_BACKUP_KEY_CHECKSUM_PAGE => MANIFEST_KEY_CHECKSUM_PAGE;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_CHECKSUM_PAGE);
|
||||
use constant INFO_BACKUP_KEY_DB_VERSION => MANIFEST_KEY_DB_VERSION;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_DB_VERSION);
|
||||
use constant INFO_BACKUP_KEY_FORMAT => INI_KEY_FORMAT;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_FORMAT);
|
||||
use constant INFO_BACKUP_KEY_HARDLINK => MANIFEST_KEY_HARDLINK;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_HARDLINK);
|
||||
use constant INFO_BACKUP_KEY_HISTORY_ID => MANIFEST_KEY_DB_ID;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_HISTORY_ID);
|
||||
use constant INFO_BACKUP_KEY_LABEL => MANIFEST_KEY_LABEL;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_LABEL);
|
||||
use constant INFO_BACKUP_KEY_PRIOR => MANIFEST_KEY_PRIOR;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_PRIOR);
|
||||
use constant INFO_BACKUP_KEY_REFERENCE => 'backup-reference';
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_REFERENCE);
|
||||
use constant INFO_BACKUP_KEY_ONLINE => MANIFEST_KEY_ONLINE;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_ONLINE);
|
||||
use constant INFO_BACKUP_KEY_SYSTEM_ID => MANIFEST_KEY_SYSTEM_ID;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_SYSTEM_ID);
|
||||
use constant INFO_BACKUP_KEY_TIMESTAMP_START => MANIFEST_KEY_TIMESTAMP_START;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_START);
|
||||
use constant INFO_BACKUP_KEY_TIMESTAMP_STOP => MANIFEST_KEY_TIMESTAMP_STOP;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_TIMESTAMP_STOP);
|
||||
use constant INFO_BACKUP_KEY_TYPE => MANIFEST_KEY_TYPE;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_TYPE);
|
||||
use constant INFO_BACKUP_KEY_VERSION => INI_KEY_VERSION;
|
||||
push @EXPORT, qw(INFO_BACKUP_KEY_VERSION);
|
||||
|
||||
####################################################################################################################################
|
||||
# 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?";
|
||||
|
||||
####################################################################################################################################
|
||||
# CONSTRUCTOR
|
||||
####################################################################################################################################
|
||||
sub new
|
||||
{
|
||||
my $class = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strBackupClusterPath,
|
||||
$bRequired,
|
||||
$oStorage,
|
||||
$bLoad, # Should the file attemp to be loaded?
|
||||
$bIgnoreMissing, # Don't error on missing files
|
||||
$strCipherPassSub, # Generated passphrase to encrypt manifest files if the repo is encrypted
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->new', \@_,
|
||||
{name => 'strBackupClusterPath'},
|
||||
{name => 'bRequired', default => true},
|
||||
{name => 'oStorage', optional => true, default => storageRepo()},
|
||||
{name => 'bLoad', optional => true, default => true},
|
||||
{name => 'bIgnoreMissing', optional => true, default => false},
|
||||
{name => 'strCipherPassSub', optional => true},
|
||||
);
|
||||
|
||||
# Build the backup info path/file name
|
||||
my $strBackupInfoFile = "${strBackupClusterPath}/" . FILE_BACKUP_INFO;
|
||||
my $self = {};
|
||||
my $iResult = 0;
|
||||
my $strResultMessage;
|
||||
|
||||
# Init object and store variables
|
||||
eval
|
||||
{
|
||||
$self = $class->SUPER::new(
|
||||
$oStorage, $strBackupInfoFile,
|
||||
{bLoad => $bLoad, bIgnoreMissing => $bIgnoreMissing, strCipherPassSub => $strCipherPassSub});
|
||||
return true;
|
||||
}
|
||||
or do
|
||||
{
|
||||
# Capture error information
|
||||
$iResult = exceptionCode($EVAL_ERROR);
|
||||
$strResultMessage = exceptionMessage($EVAL_ERROR);
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
elsif ($iResult == ERROR_CRYPTO && $strResultMessage =~ "^unable to flush")
|
||||
{
|
||||
confess &log(ERROR, "unable to parse '$strBackupInfoFile'\nHINT: is or was the repo encrypted?", $iResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
confess $EVAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
$self->{strBackupClusterPath} = $strBackupClusterPath;
|
||||
$self->{oStorage} = $oStorage;
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'self', value => $self}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# check
|
||||
#
|
||||
# Check db info and make sure it matches what is already in the repository. Return the db-id if everything matches.
|
||||
####################################################################################################################################
|
||||
sub check
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strDbVersion,
|
||||
$iControlVersion,
|
||||
$iCatalogVersion,
|
||||
$ullDbSysId,
|
||||
$bRequired,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->check', \@_,
|
||||
{name => 'strDbVersion', trace => true},
|
||||
{name => 'iControlVersion', trace => true},
|
||||
{name => 'iCatalogVersion', trace => true},
|
||||
{name => 'ullDbSysId', trace => true},
|
||||
{name => 'bRequired', default => true},
|
||||
);
|
||||
|
||||
# Confirm the info file exists with the DB section
|
||||
if ($bRequired)
|
||||
{
|
||||
$self->confirmExists();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'iDbHistoryId', value => $self->numericGet(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_HISTORY_ID)}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# add
|
||||
#
|
||||
# Add a backup to the info file.
|
||||
####################################################################################################################################
|
||||
sub add
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oBackupManifest,
|
||||
$bSave,
|
||||
$bRequired,
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->add', \@_,
|
||||
{name => 'oBackupManifest', trace => true},
|
||||
{name => 'bSave', default => true, trace => true},
|
||||
{name => 'bRequired', default => true, trace => true},
|
||||
);
|
||||
|
||||
# Confirm the info file exists with the DB section
|
||||
if ($bRequired)
|
||||
{
|
||||
$self->confirmExists();
|
||||
}
|
||||
|
||||
# Get the backup label
|
||||
my $strBackupLabel = $oBackupManifest->get(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_LABEL);
|
||||
|
||||
# Calculate backup sizes and references
|
||||
my $lBackupSize = 0;
|
||||
my $lBackupSizeDelta = 0;
|
||||
my $lBackupRepoSize = 0;
|
||||
my $lBackupRepoSizeDelta = 0;
|
||||
my $oReferenceHash = undef;
|
||||
|
||||
foreach my $strFileKey ($oBackupManifest->keys(MANIFEST_SECTION_TARGET_FILE))
|
||||
{
|
||||
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))
|
||||
{
|
||||
$$oReferenceHash{$strFileReference} = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$lBackupSizeDelta += $lFileSize;
|
||||
$lBackupRepoSizeDelta += $lRepoSize;
|
||||
}
|
||||
}
|
||||
|
||||
# Set backup size info
|
||||
$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,
|
||||
$lBackupRepoSizeDelta);
|
||||
|
||||
$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));
|
||||
$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));
|
||||
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_BACKUP_STANDBY,
|
||||
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_BACKUP_STANDBY));
|
||||
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_CHECKSUM_PAGE,
|
||||
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_CHECKSUM_PAGE));
|
||||
$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));
|
||||
$self->boolSet(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel, INFO_BACKUP_KEY_ONLINE,
|
||||
$oBackupManifest->boolGet(MANIFEST_SECTION_BACKUP_OPTION, MANIFEST_KEY_ONLINE));
|
||||
$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));
|
||||
$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));
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
if (!$oBackupManifest->test(MANIFEST_SECTION_BACKUP, MANIFEST_KEY_TYPE, undef, CFGOPTVAL_BACKUP_TYPE_FULL))
|
||||
{
|
||||
my @stryReference = sort(keys(%$oReferenceHash));
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
if ($bSave)
|
||||
{
|
||||
$self->save();
|
||||
}
|
||||
|
||||
# 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
|
||||
(
|
||||
__PACKAGE__ . '->current', \@_,
|
||||
{name => 'strBackup'}
|
||||
);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'bTest', value => $self->test(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackup)}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# list
|
||||
#
|
||||
# Get backup keys.
|
||||
####################################################################################################################################
|
||||
sub list
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strFilter,
|
||||
$strOrder
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->list', \@_,
|
||||
{name => 'strFilter', required => false},
|
||||
{name => 'strOrder', default => 'forward'}
|
||||
);
|
||||
|
||||
# List of backups
|
||||
my @stryBackup;
|
||||
|
||||
# Iterate through the backups and filter
|
||||
for my $strBackup ($self->keys(INFO_BACKUP_SECTION_BACKUP_CURRENT))
|
||||
{
|
||||
if (!defined($strFilter) || $strBackup =~ $strFilter)
|
||||
{
|
||||
if ($strOrder eq 'reverse')
|
||||
{
|
||||
unshift(@stryBackup, $strBackup)
|
||||
}
|
||||
else
|
||||
{
|
||||
push(@stryBackup, $strBackup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'stryBackup', value => \@stryBackup}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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
|
||||
my $oArchiveInfo = new pgBackRestTest::Env::ArchiveInfo($strPathBackupArchive, true);
|
||||
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);
|
||||
|
||||
# Get the DB system ID to map back to the backup info if it exists in the archive info file
|
||||
if (exists($hDbListArchive->{$iDbIdArchive}))
|
||||
{
|
||||
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
|
||||
# Sort from newest (highest db-id) to oldest
|
||||
foreach my $iDbIdBackup (sort {$b <=> $a} keys %{$hDbListBackup})
|
||||
{
|
||||
if ($$hDbListBackup{$iDbIdBackup}{&INFO_SYSTEM_ID} == $ullDbSysIdArchive &&
|
||||
$$hDbListBackup{$iDbIdBackup}{&INFO_DB_VERSION} eq $strDbVersionArchive)
|
||||
{
|
||||
$iDbHistoryId = $iDbIdBackup;
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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
|
||||
(
|
||||
__PACKAGE__ . '->last', \@_,
|
||||
{name => 'strType'}
|
||||
);
|
||||
|
||||
my $strFilter = backupRegExpGet(true, $strType ne CFGOPTVAL_BACKUP_TYPE_FULL, $strType eq CFGOPTVAL_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}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# delete
|
||||
#
|
||||
# Delete a backup from the info file.
|
||||
####################################################################################################################################
|
||||
sub delete
|
||||
{
|
||||
my $self = shift;
|
||||
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strBackupLabel
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '->delete', \@_,
|
||||
{name => 'strBackupLabel'}
|
||||
);
|
||||
|
||||
$self->remove(INFO_BACKUP_SECTION_BACKUP_CURRENT, $strBackupLabel);
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn($strOperation);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# create
|
||||
#
|
||||
# Create the info file. WARNING - this file should only be called from stanza-create or test modules.
|
||||
####################################################################################################################################
|
||||
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
|
||||
(
|
||||
__PACKAGE__ . '->dbHistoryIdGet', \@_,
|
||||
{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}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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);
|
||||
# Force the version to a string since newer versions of JSON::PP lose track of the fact that it is one
|
||||
$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);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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 database 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}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# 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);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
@@ -14,22 +14,23 @@ use Carp qw(confess);
|
||||
use Fcntl qw(O_RDONLY);
|
||||
use File::Basename qw(basename);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
@@ -216,20 +217,20 @@ sub stanzaSet
|
||||
if (!$bStanzaUpgrade)
|
||||
{
|
||||
$oArchiveInfo =
|
||||
new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath(), false,
|
||||
new pgBackRestTest::Env::ArchiveInfo($self->{oHostBackup}->repoArchivePath(), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
$oBackupInfo =
|
||||
new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath(), false,
|
||||
new pgBackRestTest::Env::BackupInfo($self->{oHostBackup}->repoBackupPath(), false,
|
||||
{bIgnoreMissing => true, strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
}
|
||||
# Else get the info data from disk
|
||||
else
|
||||
{
|
||||
$oArchiveInfo =
|
||||
new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath(),
|
||||
new pgBackRestTest::Env::ArchiveInfo($self->{oHostBackup}->repoArchivePath(),
|
||||
{strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_ARCHIVE : undef});
|
||||
$oBackupInfo =
|
||||
new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath(),
|
||||
new pgBackRestTest::Env::BackupInfo($self->{oHostBackup}->repoBackupPath(),
|
||||
{strCipherPassSub => $self->{oHostBackup}->repoEncrypt() ? ENCRYPTION_KEY_MANIFEST : undef});
|
||||
}
|
||||
|
||||
@@ -384,7 +385,7 @@ sub backupCreate
|
||||
|
||||
# Get passphrase (returns undefined if repo not encrypted) to access the manifest
|
||||
my $strCipherPassManifest =
|
||||
(new pgBackRest::Backup::Info($self->{oHostBackup}->repoBackupPath()))->cipherPassSub();
|
||||
(new pgBackRestTest::Env::BackupInfo($self->{oHostBackup}->repoBackupPath()))->cipherPassSub();
|
||||
my $strCipherPassBackupSet;
|
||||
|
||||
# If repo is encrypted then get passphrase for accessing the backup files from the last manifest if it exists provide one
|
||||
@@ -396,7 +397,7 @@ sub backupCreate
|
||||
|
||||
my $strManifestFile = "$$oStanza{strBackupClusterPath}/${strBackupLabel}/" . FILE_MANIFEST;
|
||||
|
||||
my $oManifest = new pgBackRest::Manifest($strManifestFile, {bLoad => false, strDbVersion => PG_VERSION_93,
|
||||
my $oManifest = new pgBackRestTest::Env::Manifest($strManifestFile, {bLoad => false, strDbVersion => PG_VERSION_93,
|
||||
iDbCatalogVersion => $self->dbCatalogVersion(PG_VERSION_93),
|
||||
strCipherPass => $strCipherPassManifest, strCipherPassSub => $strCipherPassBackupSet});
|
||||
|
||||
@@ -433,7 +434,7 @@ sub backupCreate
|
||||
$$oStanza{oManifest} = $oManifest;
|
||||
|
||||
# Add the backup to info
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($$oStanza{strBackupClusterPath}, false);
|
||||
my $oBackupInfo = new pgBackRestTest::Env::BackupInfo($$oStanza{strBackupClusterPath}, false);
|
||||
|
||||
$oBackupInfo->check($$oStanza{strDbVersion}, $$oStanza{iControlVersion}, $$oStanza{iCatalogVersion}, $$oStanza{ullDbSysId});
|
||||
$oBackupInfo->add($oManifest);
|
||||
@@ -531,7 +532,7 @@ sub archiveCreate
|
||||
|
||||
# Get passphrase (returns undefined if repo not encrypted) to access the archive files
|
||||
my $strCipherPass =
|
||||
(new pgBackRest::Archive::Info($self->{oHostBackup}->repoArchivePath()))->cipherPassSub();
|
||||
(new pgBackRestTest::Env::ArchiveInfo($self->{oHostBackup}->repoArchivePath()))->cipherPassSub();
|
||||
|
||||
push(my @stryArchive, $strArchive);
|
||||
|
||||
|
||||
@@ -18,25 +18,32 @@ use File::Basename qw(dirname);
|
||||
use File::stat qw{lstat};
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Latest backup link constant
|
||||
####################################################################################################################################
|
||||
use constant LINK_LATEST => 'latest';
|
||||
push @EXPORT, qw(LINK_LATEST);
|
||||
|
||||
####################################################################################################################################
|
||||
# Host defaults
|
||||
####################################################################################################################################
|
||||
@@ -183,6 +190,93 @@ sub new
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# timestampFileFormat
|
||||
####################################################################################################################################
|
||||
sub timestampFileFormat
|
||||
{
|
||||
my $strFormat = shift;
|
||||
my $lTime = shift;
|
||||
|
||||
return timestampFormat(defined($strFormat) ? $strFormat : '%4d%02d%02d-%02d%02d%02d', $lTime);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(timestampFileFormat);
|
||||
|
||||
####################################################################################################################################
|
||||
# backupLabelFormat
|
||||
#
|
||||
# Format the label for a backup.
|
||||
####################################################################################################################################
|
||||
sub backupLabelFormat
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$strType,
|
||||
$strBackupLabelLast,
|
||||
$lTimestampStart
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::backupLabelFormat', \@_,
|
||||
{name => 'strType', trace => true},
|
||||
{name => 'strBackupLabelLast', required => false, trace => true},
|
||||
{name => 'lTimestampTart', trace => true}
|
||||
);
|
||||
|
||||
# Full backup label
|
||||
my $strBackupLabel;
|
||||
|
||||
if ($strType eq CFGOPTVAL_BACKUP_TYPE_FULL)
|
||||
{
|
||||
# Last backup label must not be defined
|
||||
if (defined($strBackupLabelLast))
|
||||
{
|
||||
confess &log(ASSERT, "strBackupLabelLast must not be defined when strType = '${strType}'");
|
||||
}
|
||||
|
||||
# Format the timestamp and add the full indicator
|
||||
$strBackupLabel = timestampFileFormat(undef, $lTimestampStart) . 'F';
|
||||
}
|
||||
# Else diff or incr label
|
||||
else
|
||||
{
|
||||
# Last backup label must be defined
|
||||
if (!defined($strBackupLabelLast))
|
||||
{
|
||||
confess &log(ASSERT, "strBackupLabelLast must be defined when strType = '${strType}'");
|
||||
}
|
||||
|
||||
# Get the full backup portion of the last backup label
|
||||
$strBackupLabel = substr($strBackupLabelLast, 0, 16);
|
||||
|
||||
# Format the timestamp
|
||||
$strBackupLabel .= '_' . timestampFileFormat(undef, $lTimestampStart);
|
||||
|
||||
# Add the diff indicator
|
||||
if ($strType eq CFGOPTVAL_BACKUP_TYPE_DIFF)
|
||||
{
|
||||
$strBackupLabel .= 'D';
|
||||
}
|
||||
# Else incr indicator
|
||||
else
|
||||
{
|
||||
$strBackupLabel .= 'I';
|
||||
}
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strBackupLabel', value => $strBackupLabel, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
push @EXPORT, qw(backupLabelFormat);
|
||||
|
||||
####################################################################################################################################
|
||||
# backupBegin
|
||||
####################################################################################################################################
|
||||
@@ -485,7 +579,7 @@ sub backupCompare
|
||||
|
||||
${$oExpectedManifest}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_LABEL} = $strBackup;
|
||||
|
||||
my $oActualManifest = new pgBackRest::Manifest(
|
||||
my $oActualManifest = new pgBackRestTest::Env::Manifest(
|
||||
$self->repoBackupPath("${strBackup}/" . FILE_MANIFEST), {strCipherPass => $self->cipherPassManifest()});
|
||||
|
||||
${$oExpectedManifest}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_TIMESTAMP_START} =
|
||||
@@ -823,7 +917,7 @@ sub stanzaCreate
|
||||
}
|
||||
|
||||
# Get the passphrase for accessing the manifest file
|
||||
$self->{strCipherPassManifest} = (new pgBackRest::Backup::Info($self->repoBackupPath()))->cipherPassSub();
|
||||
$self->{strCipherPassManifest} = (new pgBackRestTest::Env::BackupInfo($self->repoBackupPath()))->cipherPassSub();
|
||||
}
|
||||
|
||||
if (storageRepo()->exists('archive/' . $self->stanza() . qw{/} . ARCHIVE_INFO_FILE))
|
||||
@@ -837,7 +931,7 @@ sub stanzaCreate
|
||||
|
||||
# Get the passphrase for accessing the archived files
|
||||
$self->{strCipherPassArchive} =
|
||||
(new pgBackRest::Archive::Info($self->repoArchivePath()))->cipherPassSub();
|
||||
(new pgBackRestTest::Env::ArchiveInfo($self->repoArchivePath()))->cipherPassSub();
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
@@ -1332,13 +1426,13 @@ sub infoMunge
|
||||
# If the original file content does not exist then load it
|
||||
if (!defined($self->{hInfoFile}{$strFileName}))
|
||||
{
|
||||
$self->{hInfoFile}{$strFileName} = new pgBackRest::Common::Ini(
|
||||
$self->{hInfoFile}{$strFileName} = new BackRestDoc::Common::Ini(
|
||||
storageRepo(), $strFileName,
|
||||
{strCipherPass => !$bManifest ? undef : $self->cipherPassManifest()});
|
||||
}
|
||||
|
||||
# Make a copy of the original file contents
|
||||
my $oMungeIni = new pgBackRest::Common::Ini(
|
||||
my $oMungeIni = new BackRestDoc::Common::Ini(
|
||||
storageRepo(), $strFileName,
|
||||
{bLoad => false, strContent => iniRender($self->{hInfoFile}{$strFileName}->{oContent}),
|
||||
strCipherPass => !$bManifest ? undef : $self->cipherPassManifest()});
|
||||
@@ -1632,7 +1726,7 @@ sub restore
|
||||
if (!defined($rhExpectedManifest))
|
||||
{
|
||||
# Load the manifest from the backup expected to be chosen/processed by restore
|
||||
my $oExpectedManifest = new pgBackRest::Manifest(
|
||||
my $oExpectedManifest = new pgBackRestTest::Env::Manifest(
|
||||
$self->repoBackupPath($strBackupExpected . qw{/} . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
|
||||
@@ -1742,7 +1836,7 @@ sub restoreCompare
|
||||
if (defined(${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR}))
|
||||
{
|
||||
my $oExpectedManifest =
|
||||
new pgBackRest::Manifest(
|
||||
new pgBackRestTest::Env::Manifest(
|
||||
$self->repoBackupPath(
|
||||
($strBackup eq 'latest' ? $oHostBackup->backupLast() : $strBackup) . '/' . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
@@ -1752,7 +1846,7 @@ sub restoreCompare
|
||||
$oExpectedManifest->get(MANIFEST_SECTION_BACKUP_OPTION, &MANIFEST_KEY_DELTA);
|
||||
|
||||
$oLastManifest =
|
||||
new pgBackRest::Manifest(
|
||||
new pgBackRestTest::Env::Manifest(
|
||||
$self->repoBackupPath(
|
||||
${$oExpectedManifestRef}{&MANIFEST_SECTION_BACKUP}{&MANIFEST_KEY_PRIOR} . qw{/} . FILE_MANIFEST),
|
||||
{strCipherPass => $oHostBackup->cipherPassManifest()});
|
||||
@@ -1807,7 +1901,7 @@ sub restoreCompare
|
||||
}
|
||||
}
|
||||
|
||||
my $oActualManifest = new pgBackRest::Manifest(
|
||||
my $oActualManifest = new pgBackRestTest::Env::Manifest(
|
||||
"${strTestPath}/" . FILE_MANIFEST,
|
||||
{bLoad => false, strDbVersion => $oExpectedManifestRef->{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_DB_VERSION},
|
||||
iDbCatalogVersion => $oExpectedManifestRef->{&MANIFEST_SECTION_BACKUP_DB}{&MANIFEST_KEY_CATALOG},
|
||||
|
||||
@@ -16,14 +16,15 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::JobTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
|
||||
####################################################################################################################################
|
||||
|
||||
@@ -16,21 +16,22 @@ use Exporter qw(import);
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Test WAL size
|
||||
|
||||
@@ -17,21 +17,22 @@ use Fcntl ':mode';
|
||||
use File::Basename qw(basename dirname);
|
||||
use File::stat;
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostDbCommonTest;
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# new
|
||||
|
||||
@@ -16,20 +16,21 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use File::Basename qw(basename);
|
||||
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::String;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostDbCommonTest;
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Db defaults
|
||||
|
||||
@@ -17,20 +17,20 @@ use Exporter qw(import);
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# S3 defaults
|
||||
|
||||
@@ -16,22 +16,22 @@ use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Common;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostDbCommonTest;
|
||||
use pgBackRestTest::Env::Host::HostDbTest;
|
||||
use pgBackRestTest::Env::Host::HostDbSyntheticTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::HostGroupTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Constants
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
####################################################################################################################################
|
||||
# INFO MODULE
|
||||
# Constants, variables and functions common to the info files
|
||||
####################################################################################################################################
|
||||
package pgBackRestTest::Env::InfoCommon;
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => qw(all);
|
||||
use Carp qw(confess);
|
||||
|
||||
use Exporter qw(import);
|
||||
our @EXPORT = qw();
|
||||
|
||||
####################################################################################################################################
|
||||
# DB section constants
|
||||
####################################################################################################################################
|
||||
use constant INFO_BACKUP_SECTION_DB => 'db';
|
||||
push @EXPORT, qw(INFO_BACKUP_SECTION_DB);
|
||||
use constant INFO_BACKUP_SECTION_DB_HISTORY => INFO_BACKUP_SECTION_DB . ':history';
|
||||
push @EXPORT, qw(INFO_BACKUP_SECTION_DB_HISTORY);
|
||||
|
||||
####################################################################################################################################
|
||||
# History section constants
|
||||
####################################################################################################################################
|
||||
use constant INFO_HISTORY_ID => 'id';
|
||||
push @EXPORT, qw(INFO_HISTORY_ID);
|
||||
use constant INFO_DB_VERSION => 'version';
|
||||
push @EXPORT, qw(INFO_DB_VERSION);
|
||||
use constant INFO_SYSTEM_ID => 'system-id';
|
||||
push @EXPORT, qw(INFO_SYSTEM_ID);
|
||||
|
||||
1;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,27 +13,173 @@ use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(basename dirname);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Common;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
use BackRestDoc::Common::String;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::InfoCommon;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# backupRegExpGet
|
||||
#
|
||||
# Generate a regexp depending on the backups that need to be found.
|
||||
####################################################################################################################################
|
||||
sub backupRegExpGet
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$bFull,
|
||||
$bDifferential,
|
||||
$bIncremental,
|
||||
$bAnchor
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::backupRegExpGet', \@_,
|
||||
{name => 'bFull', default => false},
|
||||
{name => 'bDifferential', default => false},
|
||||
{name => 'bIncremental', default => false},
|
||||
{name => 'bAnchor', default => true}
|
||||
);
|
||||
|
||||
# One of the types must be selected
|
||||
if (!($bFull || $bDifferential || $bIncremental))
|
||||
{
|
||||
confess &log(ASSERT, 'at least one backup type must be selected');
|
||||
}
|
||||
|
||||
# Standard regexp to match date and time formatting
|
||||
my $strDateTimeRegExp = "[0-9]{8}\\-[0-9]{6}";
|
||||
# Start the expression with the anchor if requested, date/time regexp and full backup indicator
|
||||
my $strRegExp = ($bAnchor ? '^' : '') . $strDateTimeRegExp . 'F';
|
||||
|
||||
# Add the diff and/or incr expressions if requested
|
||||
if ($bDifferential || $bIncremental)
|
||||
{
|
||||
# If full requested then diff/incr is optional
|
||||
if ($bFull)
|
||||
{
|
||||
$strRegExp .= "(\\_";
|
||||
}
|
||||
# Else diff/incr is required
|
||||
else
|
||||
{
|
||||
$strRegExp .= "\\_";
|
||||
}
|
||||
|
||||
# Append date/time regexp for diff/incr
|
||||
$strRegExp .= $strDateTimeRegExp;
|
||||
|
||||
# Filter on both diff/incr
|
||||
if ($bDifferential && $bIncremental)
|
||||
{
|
||||
$strRegExp .= '(D|I)';
|
||||
}
|
||||
# Else just diff
|
||||
elsif ($bDifferential)
|
||||
{
|
||||
$strRegExp .= 'D';
|
||||
}
|
||||
# Else just incr
|
||||
else
|
||||
{
|
||||
$strRegExp .= 'I';
|
||||
}
|
||||
|
||||
# If full requested then diff/incr is optional
|
||||
if ($bFull)
|
||||
{
|
||||
$strRegExp .= '){0,1}';
|
||||
}
|
||||
}
|
||||
|
||||
# Append the end anchor if requested
|
||||
$strRegExp .= $bAnchor ? "\$" : '';
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strRegExp', value => $strRegExp}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# backupLabel
|
||||
#
|
||||
# Get unique backup label.
|
||||
####################################################################################################################################
|
||||
sub backupLabel
|
||||
{
|
||||
# Assign function parameters, defaults, and log debug info
|
||||
my
|
||||
(
|
||||
$strOperation,
|
||||
$oStorageRepo,
|
||||
$strRepoBackupPath,
|
||||
$strType,
|
||||
$strBackupLabelLast,
|
||||
$lTimestampStart
|
||||
) =
|
||||
logDebugParam
|
||||
(
|
||||
__PACKAGE__ . '::backupLabelFormat', \@_,
|
||||
{name => 'oStorageRepo', trace => true},
|
||||
{name => 'strRepoBackupPath', trace => true},
|
||||
{name => 'strType', trace => true},
|
||||
{name => 'strBackupLabelLast', required => false, trace => true},
|
||||
{name => 'lTimestampStart', trace => true}
|
||||
);
|
||||
|
||||
# Create backup label
|
||||
my $strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, $lTimestampStart);
|
||||
|
||||
# Make sure that the timestamp has not already been used by a prior backup. This is unlikely for online backups since there is
|
||||
# already a wait after the manifest is built but it's still possible if the remote and local systems don't have synchronized
|
||||
# clocks. In practice this is most useful for making offline testing faster since it allows the wait after manifest build to
|
||||
# be skipped by dealing with any backup label collisions here.
|
||||
if ($oStorageRepo->list(
|
||||
$strRepoBackupPath,
|
||||
{strExpression =>
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)$')}) ||
|
||||
$oStorageRepo->list(
|
||||
"${strRepoBackupPath}/" . PATH_BACKUP_HISTORY . '/' . timestampFormat('%4d', $lTimestampStart),
|
||||
{strExpression =>
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? '^' : '_') . timestampFileFormat(undef, $lTimestampStart) .
|
||||
($strType eq CFGOPTVAL_BACKUP_TYPE_FULL ? 'F' : '(D|I)\.manifest\.gz$'),
|
||||
bIgnoreMissing => true}))
|
||||
{
|
||||
waitRemainder();
|
||||
$strBackupLabel = backupLabelFormat($strType, $strBackupLabelLast, time());
|
||||
}
|
||||
|
||||
# Return from function and log return values if any
|
||||
return logDebugReturn
|
||||
(
|
||||
$strOperation,
|
||||
{name => 'strBackupLabel', value => $strBackupLabel, trace => true}
|
||||
);
|
||||
}
|
||||
|
||||
####################################################################################################################################
|
||||
# Build PostgreSQL pages for testing
|
||||
|
||||
@@ -13,21 +13,21 @@ use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
|
||||
@@ -13,21 +13,21 @@ use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# archiveCheck
|
||||
|
||||
@@ -14,23 +14,23 @@ use Carp qw(confess);
|
||||
use File::Basename qw(dirname);
|
||||
use Storable qw(dclone);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::ExpireEnvTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostS3Test;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
|
||||
@@ -13,24 +13,24 @@ use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Base;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Env::InfoCommon;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::StorageBase;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
|
||||
####################################################################################################################################
|
||||
# run
|
||||
@@ -214,8 +214,8 @@ sub run
|
||||
forceStorageMove(storageRepo(), $strArchiveInfoCopyOldFile, $strArchiveInfoFile, {bRecurse => false});
|
||||
|
||||
# Confirm versions
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
my $oArchiveInfo = new pgBackRestTest::Env::ArchiveInfo($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRestTest::Env::BackupInfo($oHostBackup->repoBackupPath());
|
||||
$self->testResult(sub {$oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
||||
PG_VERSION_93)}, true, 'archive at old pg version');
|
||||
$self->testResult(sub {$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef,
|
||||
|
||||
@@ -15,7 +15,7 @@ use English '-no_match_vars';
|
||||
use Storable qw(dclone);
|
||||
use Time::HiRes qw(gettimeofday);
|
||||
|
||||
use pgBackRest::Common::Log;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
|
||||
@@ -13,29 +13,31 @@ use Carp qw(confess);
|
||||
|
||||
use File::Basename qw(dirname);
|
||||
|
||||
use pgBackRest::Archive::Info;
|
||||
use pgBackRest::Backup::Info;
|
||||
use pgBackRest::DbVersion;
|
||||
use pgBackRest::Common::Exception;
|
||||
use pgBackRest::Common::Ini;
|
||||
use pgBackRest::Common::Log;
|
||||
use pgBackRest::Common::Wait;
|
||||
use pgBackRest::InfoCommon;
|
||||
use pgBackRest::Manifest;
|
||||
use pgBackRest::Storage::Helper;
|
||||
use pgBackRest::Version;
|
||||
|
||||
use BackRestDoc::Common::Exception;
|
||||
use BackRestDoc::Common::Ini;
|
||||
use BackRestDoc::Common::Log;
|
||||
|
||||
use pgBackRestTest::Common::ContainerTest;
|
||||
use pgBackRestTest::Common::DbVersion;
|
||||
use pgBackRestTest::Common::ExecuteTest;
|
||||
use pgBackRestTest::Common::FileTest;
|
||||
use pgBackRestTest::Common::RunTest;
|
||||
use pgBackRestTest::Common::VmTest;
|
||||
use pgBackRestTest::Common::Storage;
|
||||
use pgBackRestTest::Common::StoragePosix;
|
||||
use pgBackRestTest::Common::StorageRepo;
|
||||
use pgBackRestTest::Common::Wait;
|
||||
use pgBackRestTest::Env::ArchiveInfo;
|
||||
use pgBackRestTest::Env::BackupInfo;
|
||||
use pgBackRestTest::Env::InfoCommon;
|
||||
use pgBackRestTest::Env::Host::HostBaseTest;
|
||||
use pgBackRestTest::Env::Host::HostBackupTest;
|
||||
use pgBackRestTest::Env::Host::HostDbTest;
|
||||
use pgBackRestTest::Env::Host::HostDbTest;
|
||||
use pgBackRestTest::Env::HostEnvTest;
|
||||
use pgBackRestTest::Common::Storage;
|
||||
use pgBackRestTest::Common::StoragePosix;
|
||||
use pgBackRestTest::Env::Manifest;
|
||||
|
||||
####################################################################################################################################
|
||||
# Backup advisory lock
|
||||
@@ -129,10 +131,10 @@ sub run
|
||||
|
||||
# Get passphrase to access the Manifest file from backup.info - returns undefined if repo not encrypted
|
||||
my $strCipherPass =
|
||||
(new pgBackRest::Backup::Info($oHostBackup->repoBackupPath()))->cipherPassSub();
|
||||
(new pgBackRestTest::Env::BackupInfo($oHostBackup->repoBackupPath()))->cipherPassSub();
|
||||
|
||||
# Create a manifest with the pg version to get version-specific paths
|
||||
my $oManifest = new pgBackRest::Manifest(BOGUS, {bLoad => false, strDbVersion => $self->pgVersion(),
|
||||
my $oManifest = new pgBackRestTest::Env::Manifest(BOGUS, {bLoad => false, strDbVersion => $self->pgVersion(),
|
||||
iDbCatalogVersion => $self->dbCatalogVersion($self->pgVersion()),
|
||||
strCipherPass => $strCipherPass, strCipherPassSub => $bRepoEncrypt ? ENCRYPTION_KEY_BACKUPSET : undef});
|
||||
|
||||
@@ -351,8 +353,8 @@ sub run
|
||||
# Run stanza-create offline to create files needing to be upgraded (using new pg-path)
|
||||
$oHostBackup->stanzaCreate('successfully create stanza files to be upgraded',
|
||||
{strOptionalParam => ' --pg1-path=' . $oHostDbMaster->dbPath() . '/testbase/ --no-online --force'});
|
||||
my $oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
my $oArchiveInfo = new pgBackRestTest::Env::ArchiveInfo($oHostBackup->repoArchivePath());
|
||||
my $oBackupInfo = new pgBackRestTest::Env::BackupInfo($oHostBackup->repoBackupPath());
|
||||
|
||||
# Read info files to confirm the files were created with a different database version
|
||||
if ($self->pgVersion() eq PG_VERSION_94)
|
||||
@@ -374,8 +376,8 @@ sub run
|
||||
$oHostBackup->stanzaUpgrade('upgrade stanza files online');
|
||||
|
||||
# Reread the info files and confirm the result
|
||||
$oArchiveInfo = new pgBackRest::Archive::Info($oHostBackup->repoArchivePath());
|
||||
$oBackupInfo = new pgBackRest::Backup::Info($oHostBackup->repoBackupPath());
|
||||
$oArchiveInfo = new pgBackRestTest::Env::ArchiveInfo($oHostBackup->repoArchivePath());
|
||||
$oBackupInfo = new pgBackRestTest::Env::BackupInfo($oHostBackup->repoBackupPath());
|
||||
$self->testResult(sub {$oArchiveInfo->test(INFO_ARCHIVE_SECTION_DB, INFO_ARCHIVE_KEY_DB_VERSION, undef,
|
||||
$self->pgVersion())}, true, 'archive upgrade online corrects db');
|
||||
$self->testResult(sub {$oBackupInfo->test(INFO_BACKUP_SECTION_DB, INFO_BACKUP_KEY_DB_VERSION, undef,
|
||||
@@ -777,7 +779,7 @@ sub run
|
||||
else
|
||||
{
|
||||
# Backup info will have the catalog number
|
||||
my $oBackupInfo = new pgBackRest::Common::Ini(
|
||||
my $oBackupInfo = new BackRestDoc::Common::Ini(
|
||||
storageRepo(), $oHostBackup->repoBackupPath(FILE_BACKUP_INFO),
|
||||
{bLoad => false, strContent => ${storageRepo()->get($oHostBackup->repoBackupPath(FILE_BACKUP_INFO))}});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user