1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-16 10:20:02 +02:00
pgbackrest/lib/pgBackRest/Protocol/CommonMinion.pm

279 lines
8.4 KiB
Perl
Raw Normal View History

####################################################################################################################################
# PROTOCOL COMMON MINION MODULE
####################################################################################################################################
New simpler configuration and consistent project/exe/path naming. * The repo-path option now always refers to the repository where backups and archive are stored, whether local or remote, so the repo-remote-path option has been removed. The new spool-path option can be used to define a location for queueing WAL segments when archiving asynchronously. Otherwise, a local repository is no longer required. * Implemented a new config format which should be far simpler to use. See the User Guide and Configuration Reference for details but for a simple configuration all options can now be placed in the stanza section. Options that are shared between stanzas can be placed in the [global] section. More complex configurations can still make use of command sections though this should be a rare use case. * The default configuration filename is now pgbackrest.conf instead of pg_backrest.conf. This was done for consistency with other naming changes but also to prevent old config files from being loaded accidentally. * The default repository name was changed from /var/lib/backup to /var/lib/pgbackrest. * Lock files are now stored in /tmp/pgbackrest by default. These days /run/pgbackrest would be the preferred location but that would require init scripts which are not part of this release. The lock-path option can be used to configure the lock directory. * Log files are now stored in /var/log/pgbackrest by default and no longer have the date appended so they can be managed with logrotate. The log-path option can be used to configure the lock directory. * Executable filename changed from pg_backrest to pgbackrest.
2016-04-14 15:30:54 +02:00
package pgBackRest::Protocol::CommonMinion;
use parent 'pgBackRest::Protocol::Common';
use strict;
use warnings FATAL => qw(all);
use Carp qw(confess);
use English '-no_match_vars';
New simpler configuration and consistent project/exe/path naming. * The repo-path option now always refers to the repository where backups and archive are stored, whether local or remote, so the repo-remote-path option has been removed. The new spool-path option can be used to define a location for queueing WAL segments when archiving asynchronously. Otherwise, a local repository is no longer required. * Implemented a new config format which should be far simpler to use. See the User Guide and Configuration Reference for details but for a simple configuration all options can now be placed in the stanza section. Options that are shared between stanzas can be placed in the [global] section. More complex configurations can still make use of command sections though this should be a rare use case. * The default configuration filename is now pgbackrest.conf instead of pg_backrest.conf. This was done for consistency with other naming changes but also to prevent old config files from being loaded accidentally. * The default repository name was changed from /var/lib/backup to /var/lib/pgbackrest. * Lock files are now stored in /tmp/pgbackrest by default. These days /run/pgbackrest would be the preferred location but that would require init scripts which are not part of this release. The lock-path option can be used to configure the lock directory. * Log files are now stored in /var/log/pgbackrest by default and no longer have the date appended so they can be managed with logrotate. The log-path option can be used to configure the lock directory. * Executable filename changed from pg_backrest to pgbackrest.
2016-04-14 15:30:54 +02:00
use pgBackRest::Common::Exception;
use pgBackRest::Common::Ini;
use pgBackRest::Common::Log;
use pgBackRest::Common::String;
use pgBackRest::Protocol::Common;
use pgBackRest::Protocol::IO;
####################################################################################################################################
# CONSTRUCTOR
####################################################################################################################################
sub new
{
my $class = shift; # Class name
# Assign function parameters, defaults, and log debug info
my
(
$strOperation,
$strName, # Name of the protocol
$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
(
__PACKAGE__ . '->new', \@_,
{name => 'strName'},
{name => 'strCommand'},
{name => 'iBufferMax'},
{name => 'iCompressLevel'},
{name => 'iCompressLevelNetwork'},
{name => 'iProtocolTimeout'},
);
# Create the class hash
my $self = $class->SUPER::new($iBufferMax, $iCompressLevel, $iCompressLevelNetwork, $iProtocolTimeout, $strName);
bless $self, $class;
$self->{strCommand} = $strCommand;
# Create the IO object with std io
$self->{io} = new pgBackRest::Protocol::IO(*STDIN, *STDOUT, *STDERR, undef, undef, $iProtocolTimeout, $iBufferMax);
# Write the greeting so master process knows who we are
$self->greetingWrite();
# Initialize module variables
$self->init();
# Return from function and log return values if any
return logDebugReturn
(
$strOperation,
{name => 'self', value => $self}
);
}
####################################################################################################################################
# greetingWrite
#
# Send a greeting to the master process.
####################################################################################################################################
sub greetingWrite
{
my $self = shift;
$self->{io}->lineWrite($self->{strGreeting});
$self->{io}->lineWrite('OK');
}
####################################################################################################################################
# textWrite
#
# Write text out to the protocol layer prefixing each line with a period.
####################################################################################################################################
sub textWrite
{
my $self = shift;
my $strBuffer = shift;
$strBuffer =~ s/\n/\n\./g;
$self->{io}->lineWrite('.' . $strBuffer);
}
####################################################################################################################################
# binaryXferAbort
#
# Abort transfer when source file does not exist.
####################################################################################################################################
sub binaryXferAbort
{
my $self = shift;
# Only allow in the backend process
$self->{io}->lineWrite('block -1');
}
####################################################################################################################################
# errorWrite
#
# Write errors with error codes in protocol format, otherwise write to stderr and exit with error.
####################################################################################################################################
sub errorWrite
{
my $self = shift;
my $oException = shift;
my $iCode;
my $strMessage;
# If the message is blessed it may be a standard exception
if (isException($oException))
{
$iCode = $oException->code();
$strMessage = $oException->message();
}
# Else terminate the process with an error
else
{
confess &log(ERROR, 'unknown error: ' . $oException, ERROR_UNKNOWN);
}
# Write the message text into protocol
if (defined($strMessage))
{
$self->textWrite(trim($strMessage));
}
# Indicate that an error ocurred and provide the code
$self->{io}->lineWrite("ERROR" . (defined($iCode) ? " $iCode" : ''));
}
####################################################################################################################################
# outputWrite
#
# Write output for the master process.
####################################################################################################################################
sub outputWrite
{
my $self = shift;
my $strOutput = shift;
if (defined($strOutput))
{
$self->textWrite($strOutput);
}
$self->{io}->lineWrite('OK');
}
####################################################################################################################################
# cmdRead
#
# Read command sent by the master process.
####################################################################################################################################
sub cmdRead
{
my $self = shift;
my $strLine;
my $strCommand;
my $hParam = {};
while ($strLine = $self->{io}->lineRead())
{
if (!defined($strCommand))
{
if ($strLine =~ /:$/)
{
$strCommand = substr($strLine, 0, length($strLine) - 1);
}
else
{
$strCommand = $strLine;
last;
}
}
else
{
if ($strLine eq 'end')
{
last;
}
my $iPos = index($strLine, '=');
if ($iPos == -1)
{
confess "param \"${strLine}\" is missing = character";
}
my $strParam = substr($strLine, 0, $iPos);
my $strValue = substr($strLine, $iPos + 1);
$hParam->{$strParam} = ${strValue};
}
}
return $strCommand, $hParam;
}
####################################################################################################################################
# paramGet
#
# Helper function that returns the param or an error if required and it does not exist.
####################################################################################################################################
sub paramGet
{
my $self = shift;
my $strParam = shift;
my $bRequired = shift;
my $strValue = $self->{hParam}{$strParam};
if (!defined($strValue) && (!defined($bRequired) || $bRequired))
{
confess "${strParam} must be defined";
}
return $strValue;
}
####################################################################################################################################
# process
####################################################################################################################################
sub process
{
my $self = shift;
# Command string
my $strCommand = OP_NOOP;
# Loop until the exit command is received
while ($strCommand ne OP_EXIT)
{
($strCommand, $self->{hParam}) = $self->cmdRead();
eval
{
if (!$self->commandProcess($strCommand))
{
if ($strCommand eq OP_NOOP)
{
$self->outputWrite();
}
elsif ($strCommand ne OP_EXIT)
{
confess "invalid command: ${strCommand}";
}
}
return true;
}
# Process errors
or do
{
$self->errorWrite($EVAL_ERROR);
};
}
return 0;
}
1;