1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-14 10:13:05 +02:00
pgbackrest/lib/BackRest/Db.pm
David Steele 5185d49873 v0.60: better version support and WAL improvements
* Pushing duplicate WAL now generates an error.  This worked before only if checksums were disabled.

* Database System IDs are used to make sure that all WAL in an archive matches up.  This should help prevent misconfigurations that send WAL from multiple clusters to the same archive.

* Regression tests working back to PostgreSQL 8.3.

* Improved threading model by starting threads early and terminating them late.
2015-04-19 17:53:29 -04:00

198 lines
7.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::Exception;
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 $strDbPath = shift; # Database path
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;
}
####################################################################################################################################
# versionSupport
#
# Returns an array of the supported Postgres versions.
####################################################################################################################################
sub versionSupport
{
my @strySupportVersion = ('8.3', '8.4', '9.0', '9.1', '9.2', '9.3', '9.4');
return \@strySupportVersion;
}
push @EXPORT, qw(versionSupport);
####################################################################################################################################
# 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}");
my $strVersionSupport = versionSupport();
if ($self->{fVersion} < ${$strVersionSupport}[0])
{
confess &log(ERROR, "unsupported Postgres version ${$strVersionSupport}[0]", ERROR_VERSION_NOT_SUPPORTED);
}
return $self->{fVersion};
}
####################################################################################################################################
# BACKUP_START
####################################################################################################################################
sub backup_start
{
my $self = shift;
my $strLabel = shift;
my $bStartFast = shift;
$self->db_version_get();
if ($self->{fVersion} < 8.4 && $bStartFast)
{
&log(WARN, 'start-fast option is only available in PostgreSQL >= 8.4');
$bStartFast = false;
}
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;