2015-08-05 14:43:41 +02:00
|
|
|
####################################################################################################################################
|
2017-06-09 23:51:41 +02:00
|
|
|
# Protocol Minion Base
|
2015-08-05 14:43:41 +02:00
|
|
|
####################################################################################################################################
|
2017-06-09 23:51:41 +02:00
|
|
|
package pgBackRest::Protocol::Base::Minion;
|
2015-08-05 14:43:41 +02:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings FATAL => qw(all);
|
|
|
|
use Carp qw(confess);
|
2016-09-06 15:44:50 +02:00
|
|
|
use English '-no_match_vars';
|
2015-08-05 14:43:41 +02:00
|
|
|
|
2017-08-30 14:41:46 +02:00
|
|
|
use Exporter qw(import);
|
|
|
|
our @EXPORT = qw();
|
2016-12-04 00:34:51 +02:00
|
|
|
use JSON::PP;
|
|
|
|
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Exception;
|
|
|
|
use pgBackRest::Common::Ini;
|
2017-10-21 20:11:33 +02:00
|
|
|
use pgBackRest::Common::Lock;
|
2016-04-14 15:30:54 +02:00
|
|
|
use pgBackRest::Common::Log;
|
|
|
|
use pgBackRest::Common::String;
|
2017-06-09 23:51:41 +02:00
|
|
|
use pgBackRest::Protocol::Base::Master;
|
|
|
|
use pgBackRest::Protocol::Helper;
|
2016-12-04 00:34:51 +02:00
|
|
|
use pgBackRest::Version;
|
2015-08-05 14:43:41 +02:00
|
|
|
|
2017-08-30 14:41:46 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Constant used to define code to run after each operation
|
|
|
|
####################################################################################################################################
|
|
|
|
use constant OP_POST => 'post';
|
|
|
|
push @EXPORT, qw(OP_POST);
|
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# CONSTRUCTOR
|
|
|
|
####################################################################################################################################
|
|
|
|
sub new
|
|
|
|
{
|
|
|
|
my $class = shift; # Class name
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Create the class hash
|
|
|
|
my $self = {};
|
|
|
|
bless $self, $class;
|
|
|
|
|
2015-08-29 20:20:46 +02:00
|
|
|
# Assign function parameters, defaults, and log debug info
|
|
|
|
(
|
2017-06-09 23:51:41 +02:00
|
|
|
my $strOperation,
|
|
|
|
$self->{strName},
|
|
|
|
$self->{oIo},
|
2015-08-29 20:20:46 +02:00
|
|
|
) =
|
|
|
|
logDebugParam
|
|
|
|
(
|
2016-08-11 23:32:28 +02:00
|
|
|
__PACKAGE__ . '->new', \@_,
|
2017-01-27 17:06:16 +02:00
|
|
|
{name => 'strName', trace => true},
|
2017-06-09 23:51:41 +02:00
|
|
|
{name => 'oIo', trace => true},
|
2015-08-29 20:20:46 +02:00
|
|
|
);
|
2015-08-05 14:43:41 +02:00
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
# Create JSON object
|
|
|
|
$self->{oJSON} = JSON::PP->new()->allow_nonref();
|
2015-08-05 14:43:41 +02:00
|
|
|
|
|
|
|
# Write the greeting so master process knows who we are
|
|
|
|
$self->greetingWrite();
|
|
|
|
|
2016-09-06 15:15:22 +02:00
|
|
|
# Initialize module variables
|
2017-06-09 23:51:41 +02:00
|
|
|
$self->{hCommandMap} = $self->can('init') ? $self->init() : undef;
|
2016-09-06 15:15:22 +02:00
|
|
|
|
2016-08-11 23:32:28 +02:00
|
|
|
# Return from function and log return values if any
|
|
|
|
return logDebugReturn
|
|
|
|
(
|
|
|
|
$strOperation,
|
2017-01-27 17:06:16 +02:00
|
|
|
{name => 'self', value => $self, trace => true}
|
2016-08-11 23:32:28 +02:00
|
|
|
);
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# greetingWrite
|
|
|
|
#
|
|
|
|
# Send a greeting to the master process.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub greetingWrite
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2016-12-04 00:34:51 +02:00
|
|
|
# Write the greeting
|
2017-06-09 23:51:41 +02:00
|
|
|
$self->io()->writeLine((JSON::PP->new()->canonical()->allow_nonref())->encode(
|
2016-12-04 00:34:51 +02:00
|
|
|
{name => BACKREST_NAME, service => $self->{strName}, version => BACKREST_VERSION}));
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# errorWrite
|
|
|
|
#
|
|
|
|
# Write errors with error codes in protocol format, otherwise write to stderr and exit with error.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub errorWrite
|
|
|
|
{
|
|
|
|
my $self = shift;
|
2016-09-06 15:44:50 +02:00
|
|
|
my $oException = shift;
|
2015-08-05 14:43:41 +02:00
|
|
|
|
2016-12-04 00:34:51 +02:00
|
|
|
# Throw hard error if this is not a standard exception
|
2017-10-16 16:47:31 +02:00
|
|
|
if (!isException(\$oException))
|
2015-08-05 14:43:41 +02:00
|
|
|
{
|
2016-09-06 15:44:50 +02:00
|
|
|
confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
2016-12-04 00:34:51 +02:00
|
|
|
# Write error code and message
|
2017-06-09 23:51:41 +02:00
|
|
|
$self->io()->writeLine($self->{oJSON}->encode({err => $oException->code(), out => $oException->message()}));
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# outputWrite
|
|
|
|
#
|
|
|
|
# Write output for the master process.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub outputWrite
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
$self->io()->writeLine($self->{oJSON}->encode({out => \@_}));
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# cmdRead
|
|
|
|
#
|
|
|
|
# Read command sent by the master process.
|
|
|
|
####################################################################################################################################
|
|
|
|
sub cmdRead
|
|
|
|
{
|
|
|
|
my $self = shift;
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
my $hCommand = $self->{oJSON}->decode($self->io()->readLine());
|
2016-09-06 15:15:22 +02:00
|
|
|
|
2016-12-04 00:34:51 +02:00
|
|
|
return $hCommand->{cmd}, $hCommand->{param};
|
2016-09-06 15:15:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
####################################################################################################################################
|
|
|
|
# process
|
|
|
|
####################################################################################################################################
|
|
|
|
sub process
|
|
|
|
{
|
|
|
|
my $self = shift;
|
2017-10-21 20:11:33 +02:00
|
|
|
my $strLockName = shift;
|
2016-09-06 15:15:22 +02:00
|
|
|
|
2016-12-05 00:51:00 +02:00
|
|
|
# Reset stderr log level so random errors do not get output
|
|
|
|
logLevelSet(undef, undef, OFF);
|
|
|
|
|
2017-10-21 20:11:33 +02:00
|
|
|
# A permanent error will be returned from every command once it has been set. In some cases this is a more graceful way to
|
|
|
|
# exit than a hard error.
|
|
|
|
my $oPermanentError;
|
|
|
|
|
2016-09-06 15:15:22 +02:00
|
|
|
# Loop until the exit command is received
|
2016-10-05 15:09:30 +02:00
|
|
|
eval
|
2016-09-06 15:15:22 +02:00
|
|
|
{
|
2017-10-21 20:11:33 +02:00
|
|
|
# Aquire a lock if a lock name is defined. This is done here so any errors will be transmitted through the protocol layer
|
|
|
|
# and cause a graceful shutdown rather than a remote abort.
|
|
|
|
if (defined($strLockName))
|
|
|
|
{
|
|
|
|
eval
|
|
|
|
{
|
|
|
|
lockAcquire($strLockName, undef, true);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
or do
|
|
|
|
{
|
|
|
|
$oPermanentError = $EVAL_ERROR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-04 00:34:51 +02:00
|
|
|
while (true)
|
2016-09-06 15:15:22 +02:00
|
|
|
{
|
2016-12-04 00:34:51 +02:00
|
|
|
my ($strCommand, $rParam) = $self->cmdRead();
|
|
|
|
|
|
|
|
last if ($strCommand eq OP_EXIT);
|
2016-10-05 15:09:30 +02:00
|
|
|
|
2017-10-21 20:11:33 +02:00
|
|
|
# If permanent error is set then always return it
|
|
|
|
if (defined($oPermanentError))
|
2016-09-06 15:15:22 +02:00
|
|
|
{
|
2017-10-21 20:11:33 +02:00
|
|
|
$self->errorWrite($oPermanentError);
|
|
|
|
}
|
|
|
|
# Else process as usual
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eval
|
2016-12-04 00:34:51 +02:00
|
|
|
{
|
2017-10-21 20:11:33 +02:00
|
|
|
# Check for the command in the map and run it if found
|
|
|
|
if (defined($self->{hCommandMap}{$strCommand}))
|
|
|
|
{
|
|
|
|
$self->outputWrite($self->{hCommandMap}{$strCommand}->($rParam));
|
|
|
|
}
|
|
|
|
# Run the standard NOOP command. This this can be overridden in hCommandMap to implement a custom NOOP.
|
|
|
|
elsif ($strCommand eq OP_NOOP)
|
|
|
|
{
|
|
|
|
protocolKeepAlive();
|
|
|
|
$self->outputWrite();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
confess "invalid command: ${strCommand}";
|
|
|
|
}
|
|
|
|
|
|
|
|
# Run the post command if defined
|
|
|
|
if (defined($self->{hCommandMap}{&OP_POST}))
|
|
|
|
{
|
|
|
|
$self->{hCommandMap}{&OP_POST}->();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-12-04 00:34:51 +02:00
|
|
|
}
|
2017-10-21 20:11:33 +02:00
|
|
|
# Process errors
|
|
|
|
or do
|
2017-08-30 14:41:46 +02:00
|
|
|
{
|
2017-10-21 20:11:33 +02:00
|
|
|
$self->errorWrite($EVAL_ERROR);
|
|
|
|
};
|
2016-10-05 15:09:30 +02:00
|
|
|
}
|
2016-09-06 15:44:50 +02:00
|
|
|
}
|
2016-10-05 15:09:30 +02:00
|
|
|
|
|
|
|
return true;
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
2016-10-05 15:09:30 +02:00
|
|
|
or do
|
|
|
|
{
|
|
|
|
my $oException = $EVAL_ERROR;
|
|
|
|
|
|
|
|
# Change log level so error will go to stderr
|
2016-12-05 00:51:00 +02:00
|
|
|
logLevelSet(undef, undef, PROTOCOL);
|
2016-10-05 15:09:30 +02:00
|
|
|
|
|
|
|
# If standard exception
|
2017-10-16 16:47:31 +02:00
|
|
|
if (isException(\$oException))
|
2016-10-05 15:09:30 +02:00
|
|
|
{
|
|
|
|
confess &log($oException->level(), $oException->message(), $oException->code());
|
|
|
|
}
|
|
|
|
|
|
|
|
# Else unexpected Perl exception
|
|
|
|
confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);
|
|
|
|
};
|
2015-08-05 14:43:41 +02:00
|
|
|
|
2016-09-06 15:15:22 +02:00
|
|
|
return 0;
|
2015-08-05 14:43:41 +02:00
|
|
|
}
|
|
|
|
|
2017-06-09 23:51:41 +02:00
|
|
|
####################################################################################################################################
|
|
|
|
# Getters
|
|
|
|
####################################################################################################################################
|
|
|
|
sub io {shift->{oIo}}
|
|
|
|
sub master {false}
|
|
|
|
|
2015-08-05 14:43:41 +02:00
|
|
|
1;
|