From 4075252c30fd5728913ef78b99f6c6cc70875ecd Mon Sep 17 00:00:00 2001 From: Asim R P Date: Fri, 20 Sep 2019 17:31:25 +0530 Subject: [PATCH v11 1/4] Support node initialization from backup with tablespaces User defined tablespaces appear as symlinks in in the backup. This commit tweaks recursive copy subroutine to allow for symlinks specific to tablespaces. Authored by Kyotaro Horiguchi --- src/test/perl/PostgresNode.pm | 29 ++++++++++++++++++++++++++- src/test/perl/RecursiveCopy.pm | 45 +++++++++++++++++++++++++++++++++++------- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm index 1e96357d7e..e27120e975 100644 --- a/src/test/perl/PostgresNode.pm +++ b/src/test/perl/PostgresNode.pm @@ -607,6 +607,32 @@ sub backup_fs_cold return; } +sub _srcsymlink +{ + my ($srcpath, $destpath) = @_; + + croak "Cannot operate on symlink \"$srcpath\"" + if ($srcpath !~ qr{/(pg_tblspc/[0-9]+)$}); + + # We have mapped tablespaces. Copy them individually + my $tmpdir = TestLib::tempdir; + my $dstrealdir = TestLib::perl2host($tmpdir); + my $srcrealdir = readlink($srcpath); + + opendir(my $dh, $srcrealdir); + while (my $entry = (readdir $dh)) + { + next if ($entry eq '.' or $entry eq '..'); + my $spath = "$srcrealdir/$entry"; + my $dpath = "$dstrealdir/$entry"; + RecursiveCopy::copypath($spath, $dpath); + } + closedir $dh; + + symlink $dstrealdir, $destpath; + + return 1; +} # Common sub of backup_fs_hot and backup_fs_cold sub _backup_fs @@ -715,7 +741,8 @@ sub init_from_backup else { rmdir($data_path); - RecursiveCopy::copypath($backup_path, $data_path); + RecursiveCopy::copypath($backup_path, $data_path, + srcsymlinkfn => \&_srcsymlink); } chmod(0700, $data_path); diff --git a/src/test/perl/RecursiveCopy.pm b/src/test/perl/RecursiveCopy.pm index baf5d0ac63..aaa3ce8a1b 100644 --- a/src/test/perl/RecursiveCopy.pm +++ b/src/test/perl/RecursiveCopy.pm @@ -47,6 +47,11 @@ This subroutine will be called for each entry in the source directory with its relative path as only parameter; if the subroutine returns true the entry is copied, otherwise the file is skipped. +If the B parameter is given, it must be a subroutine reference. +This subroutine will be called when the source directory is a symlink. It +determines the mechanism that copies files from the source directory to the +destination directory. + On failure the target directory may be in some incomplete state; no cleanup is attempted. @@ -66,6 +71,7 @@ sub copypath { my ($base_src_dir, $base_dest_dir, %params) = @_; my $filterfn; + my $srcsymlinkfn; if (defined $params{filterfn}) { @@ -80,31 +86,55 @@ sub copypath $filterfn = sub { return 1; }; } + if (defined $params{srcsymlinkfn}) + { + croak "if specified, srcsymlinkfn must be a subroutine reference" + unless defined(ref $params{srcsymlinkfn}) + and (ref $params{srcsymlinkfn} eq 'CODE'); + + $srcsymlinkfn = $params{srcsymlinkfn}; + } + else + { + $srcsymlinkfn = undef; + } + # Complain if original path is bogus, because _copypath_recurse won't. croak "\"$base_src_dir\" does not exist" if !-e $base_src_dir; # Start recursive copy from current directory - return _copypath_recurse($base_src_dir, $base_dest_dir, "", $filterfn); + return _copypath_recurse($base_src_dir, $base_dest_dir, "", $filterfn, $srcsymlinkfn); } # Recursive private guts of copypath sub _copypath_recurse { - my ($base_src_dir, $base_dest_dir, $curr_path, $filterfn) = @_; + my ($base_src_dir, $base_dest_dir, $curr_path, $filterfn, + $srcsymlinkfn) = @_; my $srcpath = "$base_src_dir/$curr_path"; my $destpath = "$base_dest_dir/$curr_path"; # 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 + # If caller provided us with a callback, call it; otherwise we're out. + if (-l $srcpath) + { + if (defined $srcsymlinkfn) + { + return &$srcsymlinkfn($srcpath, $destpath); + } + else + { + croak "Cannot operate on symlink \"$srcpath\""; + } + } + # If this source path is a file, simply copy it to destination with the # same name and we're done. if (-f $srcpath) @@ -137,7 +167,8 @@ sub _copypath_recurse { next if ($entry eq '.' or $entry eq '..'); _copypath_recurse($base_src_dir, $base_dest_dir, - $curr_path eq '' ? $entry : "$curr_path/$entry", $filterfn) + $curr_path eq '' ? $entry : "$curr_path/$entry", $filterfn, + $srcsymlinkfn) or die "copypath $srcpath/$entry -> $destpath/$entry failed"; } -- 2.14.3