Skip to content

Commit 081876d

Browse files
committed
Add end-to-end testing of pg_basebackup's tar-format output.
The existing test script does run pg_basebackup with the -Ft option, but it makes no real attempt to verify the sanity of the results. We wouldn't know if the output is incompatible with standard "tar" programs, nor if the server fails to start from the restored output. Notably, this means that xlog.c's read_tablespace_map() is not being meaningfully tested, since that code is used only in the tar-format case. (We do have reasonable coverage of restoring from plain-format output, though it's over in src/test/recovery not here.) Hence, attempt to untar the output and start a server from it, rather just hoping it's OK. This test assumes that the local "tar" has the "-C directory" switch. Although that's not promised by POSIX, my research suggests that all non-extinct tar implementations have it. Should the buildfarm's opinion differ, we can complicate the test a bit to avoid requiring that. Possibly this should be back-patched, but I'm unsure about whether it could work on Windows before d66b23b.
1 parent c783e65 commit 081876d

File tree

3 files changed

+78
-14
lines changed

3 files changed

+78
-14
lines changed

src/bin/pg_basebackup/Makefile

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ subdir = src/bin/pg_basebackup
1818
top_builddir = ../../..
1919
include $(top_builddir)/src/Makefile.global
2020

21+
# make this available to TAP test scripts
22+
export TAR
23+
2124
override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
2225
LDFLAGS_INTERNAL += -L$(top_builddir)/src/fe_utils -lpgfeutils $(libpq_pgport)
2326

src/bin/pg_basebackup/t/010_pg_basebackup.pl

+47-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
use File::Path qw(rmtree);
77
use PostgresNode;
88
use TestLib;
9-
use Test::More tests => 109;
9+
use Test::More tests => 110;
1010

1111
program_help_ok('pg_basebackup');
1212
program_version_ok('pg_basebackup');
@@ -229,6 +229,7 @@
229229

230230
$node->start;
231231

232+
# Test backup of a tablespace using tar format.
232233
# Create a temporary directory in the system location and symlink it
233234
# to our physical temp location. That way we can use shorter names
234235
# for the tablespace directories, which hopefully won't run afoul of
@@ -242,14 +243,52 @@
242243
$node->safe_psql('postgres',
243244
"CREATE TABLESPACE tblspc1 LOCATION '$realTsDir';");
244245
$node->safe_psql('postgres',
245-
"CREATE TABLE test1 (a int) TABLESPACE tblspc1;");
246-
$node->command_ok(
247-
[ 'pg_basebackup', '-D', "$real_tempdir/tarbackup2", '-Ft' ],
248-
'tar format with tablespaces');
249-
ok(-f "$tempdir/tarbackup2/base.tar", 'backup tar was created');
250-
my @tblspc_tars = glob "$tempdir/tarbackup2/[0-9]*.tar";
246+
"CREATE TABLE test1 (a int) TABLESPACE tblspc1;"
247+
. "INSERT INTO test1 VALUES (1234);");
248+
$node->backup('tarbackup2', backup_options => ['-Ft']);
249+
# empty test1, just so that it's different from the to-be-restored data
250+
$node->safe_psql('postgres', "TRUNCATE TABLE test1;");
251+
252+
# basic checks on the output
253+
my $backupdir = $node->backup_dir . '/tarbackup2';
254+
ok(-f "$backupdir/base.tar", 'backup tar was created');
255+
ok(-f "$backupdir/pg_wal.tar", 'WAL tar was created');
256+
my @tblspc_tars = glob "$backupdir/[0-9]*.tar";
251257
is(scalar(@tblspc_tars), 1, 'one tablespace tar was created');
252-
rmtree("$tempdir/tarbackup2");
258+
259+
# Try to verify the tar-format backup by restoring it.
260+
# For this, we use the tar program identified by configure.
261+
SKIP:
262+
{
263+
my $tar = $ENV{TAR};
264+
skip "no tar program available", 1
265+
if (!defined $tar || $tar eq '');
266+
267+
my $node2 = get_new_node('replica');
268+
269+
# Recover main data directory
270+
$node2->init_from_backup($node, 'tarbackup2', tar_program => $tar);
271+
272+
# Recover tablespace into a new directory (not where it was!)
273+
mkdir "$tempdir/tblspc1replica";
274+
my $realRepTsDir = TestLib::perl2host("$shorter_tempdir/tblspc1replica");
275+
TestLib::system_or_bail($tar, 'xf', $tblspc_tars[0], '-C', $realRepTsDir);
276+
277+
# Update tablespace map to point to new directory.
278+
# XXX Ideally pg_basebackup would handle this.
279+
$tblspc_tars[0] =~ m|/([0-9]*)\.tar$|;
280+
my $tblspcoid = $1;
281+
my $escapedRepTsDir = $realRepTsDir;
282+
$escapedRepTsDir =~ s/\\/\\\\/g;
283+
open my $mapfile, '>', $node2->data_dir . '/tablespace_map';
284+
print $mapfile "$tblspcoid $escapedRepTsDir\n";
285+
close $mapfile;
286+
287+
$node2->start;
288+
my $result = $node2->safe_psql('postgres', 'SELECT * FROM test1');
289+
is($result, '1234', "tablespace data restored from tar-format backup");
290+
$node2->stop;
291+
}
253292

254293
# Create an unlogged table to test that forks other than init are not copied.
255294
$node->safe_psql('postgres',

src/test/perl/PostgresNode.pm

+28-6
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,11 @@ sub append_conf
538538
=item $node->backup(backup_name)
539539
540540
Create a hot backup with B<pg_basebackup> in subdirectory B<backup_name> of
541-
B<< $node->backup_dir >>, including the WAL. WAL files
542-
fetched at the end of the backup, not streamed.
541+
B<< $node->backup_dir >>, including the WAL.
542+
543+
By default, WAL files are fetched at the end of the backup, not streamed.
544+
You can adjust that and other things by passing an array of additional
545+
B<pg_basebackup> command line options in the keyword parameter backup_options.
543546
544547
You'll have to configure a suitable B<max_wal_senders> on the
545548
target server since it isn't done by default.
@@ -548,15 +551,16 @@ target server since it isn't done by default.
548551

549552
sub backup
550553
{
551-
my ($self, $backup_name) = @_;
554+
my ($self, $backup_name, %params) = @_;
552555
my $backup_path = $self->backup_dir . '/' . $backup_name;
553556
my $name = $self->name;
554557

555558
print "# Taking pg_basebackup $backup_name from node \"$name\"\n";
556559
TestLib::system_or_bail(
557560
'pg_basebackup', '-D', $backup_path, '-h',
558561
$self->host, '-p', $self->port, '--checkpoint',
559-
'fast', '--no-sync');
562+
'fast', '--no-sync',
563+
@{ $params{backup_options} });
560564
print "# Backup finished\n";
561565
return;
562566
}
@@ -650,6 +654,11 @@ of a backup previously created on that node with $node->backup.
650654
651655
Does not start the node after initializing it.
652656
657+
By default, the backup is assumed to be plain format. To restore from
658+
a tar-format backup, pass the name of the tar program to use in the
659+
keyword parameter tar_program. Note that tablespace tar files aren't
660+
handled here.
661+
653662
Streaming replication can be enabled on this node by passing the keyword
654663
parameter has_streaming => 1. This is disabled by default.
655664
@@ -687,8 +696,21 @@ sub init_from_backup
687696
mkdir $self->archive_dir;
688697

689698
my $data_path = $self->data_dir;
690-
rmdir($data_path);
691-
RecursiveCopy::copypath($backup_path, $data_path);
699+
if (defined $params{tar_program})
700+
{
701+
mkdir($data_path);
702+
TestLib::system_or_bail($params{tar_program}, 'xf',
703+
$backup_path . '/base.tar',
704+
'-C', $data_path);
705+
TestLib::system_or_bail($params{tar_program}, 'xf',
706+
$backup_path . '/pg_wal.tar',
707+
'-C', $data_path . '/pg_wal');
708+
}
709+
else
710+
{
711+
rmdir($data_path);
712+
RecursiveCopy::copypath($backup_path, $data_path);
713+
}
692714
chmod(0700, $data_path);
693715

694716
# Base configuration for this node

0 commit comments

Comments
 (0)