mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2024-12-16 10:20:02 +02:00
ba098d7b91
Keepalives are now used to make sure the remote for the main process does not timeout while the thread remotes do all the work. The error messages for timeouts was also improved to make debugging easier.
296 lines
12 KiB
Perl
296 lines
12 KiB
Perl
####################################################################################################################################
|
|
# PROTOCOL REMOTE MINION MODULE
|
|
####################################################################################################################################
|
|
package BackRest::Protocol::RemoteMinion;
|
|
use parent 'BackRest::Protocol::CommonMinion';
|
|
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use File::Basename qw(dirname);
|
|
|
|
use lib dirname($0) . '/../lib';
|
|
use BackRest::Common::Exception;
|
|
use BackRest::Common::Log;
|
|
use BackRest::Archive;
|
|
use BackRest::Config::Config;
|
|
use BackRest::Db;
|
|
use BackRest::File;
|
|
use BackRest::Info;
|
|
use BackRest::Protocol::Common;
|
|
use BackRest::Protocol::CommonMinion;
|
|
|
|
####################################################################################################################################
|
|
# Operation constants
|
|
####################################################################################################################################
|
|
use constant OP_PROTOCOL_REMOTE_MINION => 'Protocol::RemoteMinion';
|
|
|
|
use constant OP_PROTOCOL_REMOTE_MINION_NEW => OP_PROTOCOL_REMOTE_MINION . "->new";
|
|
|
|
####################################################################################################################################
|
|
# CONSTRUCTOR
|
|
####################################################################################################################################
|
|
sub new
|
|
{
|
|
my $class = shift; # Class name
|
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
my
|
|
(
|
|
$strOperation,
|
|
$strCommand, # Command the master process is running
|
|
$iBufferMax, # Maximum buffer size
|
|
$iCompressLevel, # Set compression level
|
|
$iCompressLevelNetwork, # Set compression level for network only compression,
|
|
$iProtocolTimeout # Protocol timeout
|
|
) =
|
|
logDebugParam
|
|
(
|
|
OP_PROTOCOL_REMOTE_MINION_NEW, \@_,
|
|
{name => 'strCommand'},
|
|
{name => 'iBufferMax'},
|
|
{name => 'iCompressLevel'},
|
|
{name => 'iCompressNetworkLevel'},
|
|
{name => 'iProtocolTimeout'}
|
|
);
|
|
|
|
# Init object and store variables
|
|
my $self = $class->SUPER::new(CMD_REMOTE, $strCommand, $iBufferMax, $iCompressLevel,
|
|
$iCompressLevelNetwork, $iProtocolTimeout);
|
|
bless $self, $class;
|
|
|
|
# Return from function and log return values if any
|
|
return logDebugReturn
|
|
(
|
|
$strOperation,
|
|
{name => 'self', value => $self}
|
|
);
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# paramGet
|
|
#
|
|
# Helper function that returns the param or an error if required and it does not exist.
|
|
####################################################################################################################################
|
|
sub paramGet
|
|
{
|
|
my $oParamHashRef = shift;
|
|
my $strParam = shift;
|
|
my $bRequired = shift;
|
|
|
|
my $strValue = ${$oParamHashRef}{$strParam};
|
|
|
|
if (!defined($strValue) && (!defined($bRequired) || $bRequired))
|
|
{
|
|
confess "${strParam} must be defined";
|
|
}
|
|
|
|
return $strValue;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# process
|
|
####################################################################################################################################
|
|
sub process
|
|
{
|
|
my $self = shift;
|
|
|
|
# Create the file object
|
|
my $oFile = new BackRest::File
|
|
(
|
|
optionGet(OPTION_STANZA, false),
|
|
optionGet(OPTION_REPO_REMOTE_PATH, false),
|
|
undef,
|
|
$self,
|
|
);
|
|
|
|
# Create objects
|
|
my $oArchive = new BackRest::Archive();
|
|
my $oInfo = new BackRest::Info();
|
|
my $oJSON = JSON::PP->new();
|
|
my $oDb = new BackRest::Db();
|
|
|
|
# Command string
|
|
my $strCommand = OP_NOOP;
|
|
|
|
# Loop until the exit command is received
|
|
while ($strCommand ne OP_EXIT)
|
|
{
|
|
my %oParamHash;
|
|
|
|
$strCommand = $self->cmdRead(\%oParamHash);
|
|
|
|
eval
|
|
{
|
|
# Copy file
|
|
if ($strCommand eq OP_FILE_COPY ||
|
|
$strCommand eq OP_FILE_COPY_IN ||
|
|
$strCommand eq OP_FILE_COPY_OUT)
|
|
{
|
|
my $bResult;
|
|
my $strChecksum;
|
|
my $iFileSize;
|
|
|
|
# Copy a file locally
|
|
if ($strCommand eq OP_FILE_COPY)
|
|
{
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
$oFile->copy(PATH_ABSOLUTE, paramGet(\%oParamHash, 'source_file'),
|
|
PATH_ABSOLUTE, paramGet(\%oParamHash, 'destination_file'),
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
paramGet(\%oParamHash, 'destination_compress'),
|
|
paramGet(\%oParamHash, 'ignore_missing_source', false),
|
|
undef,
|
|
paramGet(\%oParamHash, 'mode', false),
|
|
paramGet(\%oParamHash, 'destination_path_create') ? 'Y' : 'N',
|
|
paramGet(\%oParamHash, 'user', false),
|
|
paramGet(\%oParamHash, 'group', false),
|
|
paramGet(\%oParamHash, 'append_checksum', false));
|
|
}
|
|
# Copy a file from STDIN
|
|
elsif ($strCommand eq OP_FILE_COPY_IN)
|
|
{
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
$oFile->copy(PIPE_STDIN, undef,
|
|
PATH_ABSOLUTE, paramGet(\%oParamHash, 'destination_file'),
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
paramGet(\%oParamHash, 'destination_compress'),
|
|
undef, undef,
|
|
paramGet(\%oParamHash, 'mode', false),
|
|
paramGet(\%oParamHash, 'destination_path_create'),
|
|
paramGet(\%oParamHash, 'user', false),
|
|
paramGet(\%oParamHash, 'group', false),
|
|
paramGet(\%oParamHash, 'append_checksum', false));
|
|
}
|
|
# Copy a file to STDOUT
|
|
elsif ($strCommand eq OP_FILE_COPY_OUT)
|
|
{
|
|
($bResult, $strChecksum, $iFileSize) =
|
|
$oFile->copy(PATH_ABSOLUTE, paramGet(\%oParamHash, 'source_file'),
|
|
PIPE_STDOUT, undef,
|
|
paramGet(\%oParamHash, 'source_compressed'),
|
|
paramGet(\%oParamHash, 'destination_compress'));
|
|
}
|
|
|
|
$self->outputWrite(($bResult ? 'Y' : 'N') . " " . (defined($strChecksum) ? $strChecksum : '?') . " " .
|
|
(defined($iFileSize) ? $iFileSize : '?'));
|
|
}
|
|
# List files in a path
|
|
elsif ($strCommand eq OP_FILE_LIST)
|
|
{
|
|
my $strOutput;
|
|
|
|
foreach my $strFile ($oFile->list(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'),
|
|
paramGet(\%oParamHash, 'expression', false),
|
|
paramGet(\%oParamHash, 'sort_order'),
|
|
paramGet(\%oParamHash, 'ignore_missing')))
|
|
{
|
|
if (defined($strOutput))
|
|
{
|
|
$strOutput .= "\n";
|
|
}
|
|
|
|
$strOutput .= $strFile;
|
|
}
|
|
|
|
$self->outputWrite($strOutput);
|
|
}
|
|
# Create a path
|
|
elsif ($strCommand eq OP_FILE_PATH_CREATE)
|
|
{
|
|
$oFile->pathCreate(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'), paramGet(\%oParamHash, 'mode', false));
|
|
$self->outputWrite();
|
|
}
|
|
# Check if a file/path exists
|
|
elsif ($strCommand eq OP_FILE_EXISTS)
|
|
{
|
|
$self->outputWrite($oFile->exists(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path')) ? 'Y' : 'N');
|
|
}
|
|
# Wait
|
|
elsif ($strCommand eq OP_FILE_WAIT)
|
|
{
|
|
$self->outputWrite($oFile->wait(PATH_ABSOLUTE));
|
|
}
|
|
# Generate a manifest
|
|
elsif ($strCommand eq OP_FILE_MANIFEST)
|
|
{
|
|
my %oManifestHash;
|
|
|
|
$oFile->manifest(PATH_ABSOLUTE, paramGet(\%oParamHash, 'path'), \%oManifestHash);
|
|
|
|
my $strOutput = "name\ttype\tuser\tgroup\tmode\tmodification_time\tinode\tsize\tlink_destination";
|
|
|
|
foreach my $strName (sort(keys(%{$oManifestHash{name}})))
|
|
{
|
|
$strOutput .= "\n${strName}\t" .
|
|
$oManifestHash{name}{"${strName}"}{type} . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{user}) ? $oManifestHash{name}{"${strName}"}{user} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{group}) ? $oManifestHash{name}{"${strName}"}{group} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{mode}) ? $oManifestHash{name}{"${strName}"}{mode} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{modification_time}) ?
|
|
$oManifestHash{name}{"${strName}"}{modification_time} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{inode}) ? $oManifestHash{name}{"${strName}"}{inode} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{size}) ? $oManifestHash{name}{"${strName}"}{size} : "") . "\t" .
|
|
(defined($oManifestHash{name}{"${strName}"}{link_destination}) ?
|
|
$oManifestHash{name}{"${strName}"}{link_destination} : "");
|
|
}
|
|
|
|
$self->outputWrite($strOutput);
|
|
}
|
|
# Archive push checks
|
|
elsif ($strCommand eq OP_ARCHIVE_PUSH_CHECK)
|
|
{
|
|
my ($strArchiveId, $strChecksum) = $oArchive->pushCheck($oFile,
|
|
paramGet(\%oParamHash, 'wal-segment'),
|
|
undef,
|
|
paramGet(\%oParamHash, 'db-version'),
|
|
paramGet(\%oParamHash, 'db-sys-id'));
|
|
|
|
$self->outputWrite("${strArchiveId}\t" . (defined($strChecksum) ? $strChecksum : 'Y'));
|
|
}
|
|
elsif ($strCommand eq OP_ARCHIVE_GET_CHECK)
|
|
{
|
|
$self->outputWrite($oArchive->getCheck($oFile));
|
|
}
|
|
# Info list stanza
|
|
elsif ($strCommand eq OP_INFO_STANZA_LIST)
|
|
{
|
|
$self->outputWrite(
|
|
$oJSON->encode(
|
|
$oInfo->stanzaList($oFile,
|
|
paramGet(\%oParamHash, 'stanza', false))));
|
|
}
|
|
elsif ($strCommand eq OP_DB_INFO)
|
|
{
|
|
my ($strDbVersion, $iControlVersion, $iCatalogVersion, $ullDbSysId) =
|
|
$oDb->info($oFile, paramGet(\%oParamHash, 'db-path'));
|
|
|
|
$self->outputWrite("${strDbVersion}\t${iControlVersion}\t${iCatalogVersion}\t${ullDbSysId}");
|
|
}
|
|
elsif ($strCommand eq OP_DB_EXECUTE_SQL)
|
|
{
|
|
$self->outputWrite($oDb->executeSql(paramGet(\%oParamHash, 'script'),
|
|
paramGet(\%oParamHash, 'ignore-error', false)));
|
|
}
|
|
elsif ($strCommand eq OP_NOOP)
|
|
{
|
|
$self->outputWrite();
|
|
}
|
|
# Continue if exit
|
|
elsif ($strCommand ne OP_EXIT)
|
|
{
|
|
confess "invalid command: ${strCommand}";
|
|
}
|
|
};
|
|
|
|
# Process errors
|
|
if ($@)
|
|
{
|
|
$self->errorWrite($@);
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|