1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2025-01-20 04:59:25 +02:00
pgbackrest/lib/pgBackRest/Archive/ArchivePushFile.pm
David Steele de7fc37f88 Storage and IO layer refactor:
Refactor storage layer to allow for new repository filesystems using drivers. (Reviewed by Cynthia Shang.)
Refactor IO layer to allow for new compression formats, checksum types, and other capabilities using filters. (Reviewed by Cynthia Shang.)
2017-06-09 17:51:41 -04:00

198 lines
6.6 KiB
Perl

####################################################################################################################################
# ARCHIVE PUSH FILE MODULE
####################################################################################################################################
package pgBackRest::Archive::ArchivePushFile;
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(basename dirname);
use pgBackRest::Archive::ArchiveCommon;
use pgBackRest::Archive::ArchiveInfo;
use pgBackRest::Common::Exception;
use pgBackRest::Common::Log;
use pgBackRest::Config::Config;
use pgBackRest::Protocol::Helper;
use pgBackRest::Protocol::Storage::Helper;
use pgBackRest::Storage::Filter::Gzip;
use pgBackRest::Storage::Filter::Sha;
use pgBackRest::Storage::Helper;
####################################################################################################################################
# archivePushCheck
#
# Check that a WAL segment does not already exist in the archive be pushing. Files that are not segments (e.g. .history, .backup)
# will always be reported as not present and will be overwritten by archivePushFile().
####################################################################################################################################
sub archivePushCheck
{
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strArchiveFile,
$strDbVersion,
$ullDbSysId,
$strWalFile,
) =
logDebugParam
(
__PACKAGE__ . '::archivePushCheck', \@_,
{name => 'strArchiveFile'},
{name => 'strDbVersion', required => false},
{name => 'ullDbSysId', required => false},
{name => 'strWalFile', required => false},
);
# Set operation and debug strings
my $oStorageRepo = storageRepo();
my $strArchiveId;
my $strChecksum;
# WAL file is segment?
my $bWalSegment = walIsSegment($strArchiveFile);
if (!isRepoLocal())
{
# Execute the command
($strArchiveId, $strChecksum) = protocolGet(BACKUP)->cmdExecute(
OP_ARCHIVE_PUSH_CHECK, [$strArchiveFile, $strDbVersion, $ullDbSysId], true);
}
else
{
# If a segment check db version and system-id
if ($bWalSegment)
{
# If the info file exists check db version and system-id else error
$strArchiveId = (new pgBackRest::Archive::ArchiveInfo(
$oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE)))->check($strDbVersion, $ullDbSysId);
# Check if the WAL segment already exists in the archive
my $strFoundFile = walSegmentFind($oStorageRepo, $strArchiveId, $strArchiveFile);
if (defined($strFoundFile))
{
$strChecksum = substr($strFoundFile, length($strArchiveFile) + 1, 40);
}
}
# Else just get the archive id
else
{
$strArchiveId = (new pgBackRest::Archive::ArchiveInfo($oStorageRepo->pathGet(STORAGE_REPO_ARCHIVE)))->archiveId();
}
}
my $strWarning;
if (defined($strChecksum) && !commandTest(CMD_REMOTE))
{
my ($strChecksumNew) = storageDb()->hashSize($strWalFile);
if ($strChecksumNew ne $strChecksum)
{
confess &log(ERROR, "WAL segment " . basename($strWalFile) . " already exists in the archive", ERROR_ARCHIVE_DUPLICATE);
}
$strWarning =
"WAL segment " . basename($strWalFile) . " already exists in the archive with the same checksum\n" .
"HINT: this is valid in some recovery scenarios but may also indicate a problem.";
&log(WARN, $strWarning);
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strArchiveId', value => $strArchiveId},
{name => 'strChecksum', value => $strChecksum},
{name => 'strWarning', value => $strWarning}
);
}
push @EXPORT, qw(archivePushCheck);
####################################################################################################################################
# archivePushFile
#
# Copy a file from the WAL directory to the archive.
####################################################################################################################################
sub archivePushFile
{
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strWalPath,
$strWalFile,
$bCompress,
) =
logDebugParam
(
__PACKAGE__ . '::archivePushFile', \@_,
{name => 'strWalPath'},
{name => 'strWalFile'},
{name => 'bCompress'},
);
# Get cluster info from the WAL
my $oStorageRepo = storageRepo();
my $strDbVersion;
my $ullDbSysId;
if (walIsSegment($strWalFile))
{
($strDbVersion, $ullDbSysId) = walInfo("${strWalPath}/${strWalFile}");
}
# Check if the WAL already exists in the repo
my ($strArchiveId, $strChecksum, $strWarning) = archivePushCheck(
$strWalFile, $strDbVersion, $ullDbSysId, walIsSegment($strWalFile) ? "${strWalPath}/${strWalFile}" : undef);
# Only copy the WAL segment if checksum is not defined. If checksum is defined it means that the WAL segment already exists
# in the repository with the same checksum (else there would have been an error on checksum mismatch).
if (!defined($strChecksum))
{
my $strArchiveFile = "${strArchiveId}/${strWalFile}";
# If a WAL segment
if (walIsSegment($strWalFile))
{
# Get hash
my ($strSourceHash) = storageDb()->hashSize("${strWalPath}/${strWalFile}");
$strArchiveFile .= "-${strSourceHash}";
# Add compress extension
if ($bCompress)
{
$strArchiveFile .= qw{.} . COMPRESS_EXT;
}
}
# Copy
$oStorageRepo->copy(
storageDb()->openRead("${strWalPath}/${strWalFile}",
{rhyFilter => walIsSegment($strWalFile) && $bCompress ? [{strClass => STORAGE_FILTER_GZIP}] : undef}),
$oStorageRepo->openWrite(
STORAGE_REPO_ARCHIVE . "/${strArchiveFile}",
{bPathCreate => true, bAtomic => true, bProtocolCompress => !walIsSegment($strWalFile) || !$bCompress}));
}
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'strWarning', value => $strWarning}
);
}
push @EXPORT, qw(archivePushFile);
1;