You've already forked pgbackrest
mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-12-23 23:51:07 +02:00
* Added restore functionality. * All options can now be set on the command-line making pg_backrest.conf optional. * De/compression is now performed without threads and checksum/size is calculated in stream. That means file checksums are no longer optional. * Added option `--no-start-stop` to allow backups when Postgres is shut down. If `postmaster.pid` is present then `--force` is required to make the backup run (though if Postgres is running an inconsistent backup will likely be created). This option was added primarily for the purpose of unit testing, but there may be applications in the real world as well. * Fixed broken checksums and now they work with normal and resumed backups. Finally realized that checksums and checksum deltas should be functionally separated and this simplied a number of things. Issue #28 has been created for checksum deltas. * Fixed an issue where a backup could be resumed from an aborted backup that didn't have the same type and prior backup. * Removed dependency on Moose. It wasn't being used extensively and makes for longer startup times. * Checksum for backup.manifest to detect corrupted/modified manifest. * Link `latest` always points to the last backup. This has been added for convenience and to make restores simpler. * More comprehensive unit tests in all areas.
167 lines
6.4 KiB
Perl
167 lines
6.4 KiB
Perl
####################################################################################################################################
|
|
# DB MODULE
|
|
####################################################################################################################################
|
|
package BackRest::Db;
|
|
|
|
use strict;
|
|
use warnings FATAL => qw(all);
|
|
use Carp qw(confess);
|
|
|
|
use Net::OpenSSH;
|
|
use File::Basename;
|
|
use IPC::System::Simple qw(capture);
|
|
use Exporter qw(import);
|
|
|
|
use lib dirname($0);
|
|
use BackRest::Utility;
|
|
|
|
####################################################################################################################################
|
|
# Postmaster process Id file
|
|
####################################################################################################################################
|
|
use constant FILE_POSTMASTER_PID => 'postmaster.pid';
|
|
|
|
our @EXPORT = qw(FILE_POSTMASTER_PID);
|
|
|
|
####################################################################################################################################
|
|
# CONSTRUCTOR
|
|
####################################################################################################################################
|
|
sub new
|
|
{
|
|
my $class = shift; # Class name
|
|
my $strCommandPsql = shift; # PSQL command
|
|
my $strDbHost = shift; # Database host name
|
|
my $strDbUser = shift; # Database user name (generally postgres)
|
|
|
|
# Create the class hash
|
|
my $self = {};
|
|
bless $self, $class;
|
|
|
|
# Initialize variables
|
|
$self->{strCommandPsql} = $strCommandPsql;
|
|
$self->{strDbHost} = $strDbHost;
|
|
$self->{strDbUser} = $strDbUser;
|
|
|
|
# Connect SSH object if db host is defined
|
|
if (defined($self->{strDbHost}) && !defined($self->{oDbSSH}))
|
|
{
|
|
my $strOptionSSHRequestTTY = 'RequestTTY=yes';
|
|
|
|
&log(TRACE, "connecting to database ssh host $self->{strDbHost}");
|
|
|
|
# !!! This could be improved by redirecting stderr to a file to get a better error message
|
|
$self->{oDbSSH} = Net::OpenSSH->new($self->{strDbHost}, user => $self->{strDbUser},
|
|
master_opts => [-o => $strOptionSSHRequestTTY]);
|
|
$self->{oDbSSH}->error and confess &log(ERROR, "unable to connect to $self->{strDbHost}: " . $self->{oDbSSH}->error);
|
|
}
|
|
|
|
return $self;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# IS_REMOTE
|
|
#
|
|
# Determine whether database operations are remote.
|
|
####################################################################################################################################
|
|
sub is_remote
|
|
{
|
|
my $self = shift;
|
|
|
|
# If the SSH object is defined then db is remote
|
|
return defined($self->{oDbSSH}) ? true : false;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# PSQL_EXECUTE
|
|
####################################################################################################################################
|
|
sub psql_execute
|
|
{
|
|
my $self = shift;
|
|
my $strScript = shift; # psql script to execute
|
|
|
|
# Get the user-defined command for psql
|
|
my $strCommand = $self->{strCommandPsql} . " -c \"${strScript}\" postgres";
|
|
my $strResult;
|
|
|
|
# !!! Need to capture error output with open3 and log it
|
|
|
|
# Run remotely
|
|
if ($self->is_remote())
|
|
{
|
|
&log(TRACE, "psql execute: remote ${strScript}");
|
|
|
|
$strResult = $self->{oDbSSH}->capture($strCommand)
|
|
or confess &log(ERROR, "unable to execute remote psql command '${strCommand}'");
|
|
}
|
|
# Else run locally
|
|
else
|
|
{
|
|
&log(TRACE, "psql execute: ${strScript}");
|
|
$strResult = capture($strCommand) or confess &log(ERROR, "unable to execute local psql command '${strCommand}'");
|
|
}
|
|
|
|
return $strResult;
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# TABLESPACE_MAP_GET - Get the mapping between oid and tablespace name
|
|
####################################################################################################################################
|
|
sub tablespace_map_get
|
|
{
|
|
my $self = shift;
|
|
my $oHashRef = shift;
|
|
|
|
data_hash_build($oHashRef, "oid\tname\n" . $self->psql_execute(
|
|
'copy (select oid, spcname from pg_tablespace) to stdout'), "\t");
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# DB_VERSION_GET
|
|
####################################################################################################################################
|
|
sub db_version_get
|
|
{
|
|
my $self = shift;
|
|
|
|
if (defined($self->{fVersion}))
|
|
{
|
|
return $self->{fVersion};
|
|
}
|
|
|
|
$self->{fVersion} =
|
|
trim($self->psql_execute("copy (select (regexp_matches(split_part(version(), ' ', 2), '^[0-9]+\.[0-9]+'))[1]) to stdout"));
|
|
|
|
&log(DEBUG, "database version is $self->{fVersion}");
|
|
|
|
return $self->{fVersion};
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BACKUP_START
|
|
####################################################################################################################################
|
|
sub backup_start
|
|
{
|
|
my $self = shift;
|
|
my $strLabel = shift;
|
|
my $bStartFast = shift;
|
|
|
|
my @stryField = split("\t", trim($self->psql_execute("set client_min_messages = 'warning';" .
|
|
"copy (select to_char(current_timestamp, 'YYYY-MM-DD HH24:MI:SS.US TZ'), pg_xlogfile_name(xlog) from pg_start_backup('${strLabel}'" .
|
|
($bStartFast ? ', true' : '') . ') as xlog) to stdout')));
|
|
|
|
return $stryField[1], $stryField[0];
|
|
}
|
|
|
|
####################################################################################################################################
|
|
# BACKUP_STOP
|
|
####################################################################################################################################
|
|
sub backup_stop
|
|
{
|
|
my $self = shift;
|
|
|
|
my @stryField = split("\t", trim($self->psql_execute("set client_min_messages = 'warning';" .
|
|
"copy (select to_char(clock_timestamp(), 'YYYY-MM-DD HH24:MI:SS.US TZ'), pg_xlogfile_name(xlog) from pg_stop_backup() as xlog) to stdout")));
|
|
|
|
return $stryField[1], $stryField[0];
|
|
}
|
|
|
|
1;
|