From 4855a9c7b0b5f67b3c6fba667c5c1892eb58199c Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Mon, 22 Apr 2019 20:58:53 +0900
Subject: [PATCH 2/4] Allow TAP test to excecise tablespace.

To perform tablespace related checks, this patch lets
PostgresNode::backup have a new parameter "tablespace_mapping", and
make init_from_backup handle capable to handle a backup created using
tablespace_mapping.
---
 src/test/perl/PostgresNode.pm  | 45 +++++++++++++++++++++++++++++++++++++-----
 src/test/perl/RecursiveCopy.pm | 38 +++++++++++++++++++++++++++++++----
 2 files changed, 74 insertions(+), 9 deletions(-)

diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 76874141c5..e951acc461 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -157,6 +157,7 @@ sub new
 		_host    => $pghost,
 		_basedir => "$TestLib::tmp_check/t_${testname}_${name}_data",
 		_name    => $name,
+		_tablespaces => [],
 		_logfile_generation => 0,
 		_logfile_base       => "$TestLib::log_path/${testname}_${name}",
 		_logfile            => "$TestLib::log_path/${testname}_${name}.log"
@@ -342,6 +343,26 @@ sub backup_dir
 
 =pod
 
+=item $node->make_tablespace_dir()
+
+make a tablespace directory 
+
+=cut
+
+sub make_tablespace_dir
+{
+	my ($self, $name) = @_;
+	my $basedir = $self->basedir;
+
+	die "tablespace name contains '/'" if ($name =~ m#/#);
+	my $reldir = "../$name";
+	mkdir $self->data_dir() . "/". $reldir;
+	push($self->{_tablespaces}, $reldir);
+	return $reldir;
+}
+
+=pod
+
 =item $node->info()
 
 Return a string containing human-readable diagnostic information (paths, etc)
@@ -540,13 +561,27 @@ target server since it isn't done by default.
 
 sub backup
 {
-	my ($self, $backup_name) = @_;
-	my $backup_path = $self->backup_dir . '/' . $backup_name;
+	my ($self, $backup_name, %params) = @_;
+	my $backup_path = $self->backup_dir . '/' . $backup_name . '/' . "pgdata";
 	my $name        = $self->name;
+	my @rest = ();
+
+	if (defined $params{tablespace_mapping})
+	{
+		foreach my $p (split /,/, $params{tablespace_mapping})
+		{
+			push(@rest, "--tablespace-mapping=$p");
+		}
+	}
+
+	foreach my $p ($self->{_tablespaces})
+	{
+		mkdir "$backup_path/$p";
+	}
 
 	print "# Taking pg_basebackup $backup_name from node \"$name\"\n";
 	TestLib::system_or_bail('pg_basebackup', '-D', $backup_path, '-h',
-		$self->host, '-p', $self->port, '--no-sync');
+		$self->host, '-p', $self->port, '--no-sync', @rest);
 	print "# Backup finished\n";
 	return;
 }
@@ -592,7 +627,7 @@ sub backup_fs_cold
 sub _backup_fs
 {
 	my ($self, $backup_name, $hot) = @_;
-	my $backup_path = $self->backup_dir . '/' . $backup_name;
+	my $backup_path = $self->backup_dir . '/' . $backup_name . '/' . "pgdata";
 	my $port        = $self->port;
 	my $name        = $self->name;
 
@@ -655,7 +690,7 @@ unconditionally set to enable replication connections.
 sub init_from_backup
 {
 	my ($self, $root_node, $backup_name, %params) = @_;
-	my $backup_path = $root_node->backup_dir . '/' . $backup_name;
+	my $backup_path = $root_node->backup_dir . '/' . $backup_name . '/' . "pgdata";
 	my $host        = $self->host;
 	my $port        = $self->port;
 	my $node_name   = $self->name;
diff --git a/src/test/perl/RecursiveCopy.pm b/src/test/perl/RecursiveCopy.pm
index baf5d0ac63..f165db7348 100644
--- a/src/test/perl/RecursiveCopy.pm
+++ b/src/test/perl/RecursiveCopy.pm
@@ -22,6 +22,7 @@ use warnings;
 use Carp;
 use File::Basename;
 use File::Copy;
+use TestLib;
 
 =pod
 
@@ -97,14 +98,43 @@ sub _copypath_recurse
 	# invoke the filter and skip all further operation if it returns false
 	return 1 unless &$filterfn($curr_path);
 
-	# Check for symlink -- needed only on source dir
-	# (note: this will fall through quietly if file is already gone)
-	croak "Cannot operate on symlink \"$srcpath\"" if -l $srcpath;
-
 	# Abort if destination path already exists.  Should we allow directories
 	# to exist already?
 	croak "Destination path \"$destpath\" already exists" if -e $destpath;
 
+	# Check for symlink -- needed only on source dir
+	# (note: this will fall through quietly if file is already gone)
+	if (-l $srcpath)
+	{
+		croak "Cannot operate on symlink \"$srcpath\""
+		  if ($srcpath !~ /\/(pg_tblspc\/[0-9]+)$/);
+
+		# We have mapped tablespaces. Copy them individually
+		my $linkname = $1;
+		my $rpath = my $target = readlink($srcpath);
+
+		#convert to pgdata-based if relative
+		$rpath =~ s#^\.\./##; 
+
+		my $srcrealdir = "$base_src_dir/$rpath";
+		my $dstrealdir = "$base_dest_dir/$rpath";
+
+		mkdir $dstrealdir;
+		opendir(my $dh, $srcrealdir);
+		while (readdir $dh)
+		{
+			next if (/^\.\.?$/);
+			my $spath = "$srcrealdir/$_";
+			my $dpath = "$dstrealdir/$_";
+
+			copypath($spath, $dpath);
+		}
+		closedir $dh;
+
+		symlink $target, $destpath;
+		return 1;
+	}
+
 	# If this source path is a file, simply copy it to destination with the
 	# same name and we're done.
 	if (-f $srcpath)
-- 
2.16.3

