@@ -777,7 +777,7 @@ sub backup_fs_cold
777
777
778
778
=pod
779
779
780
- =item $node->init_from_backup(root_node, backup_name)
780
+ =item $node->init_from_backup(root_node, backup_name, %params )
781
781
782
782
Initialize a node from a backup, which may come from this node or a different
783
783
node. root_node must be a PostgreSQL::Test::Cluster reference, backup_name the string name
@@ -787,8 +787,13 @@ Does not start the node after initializing it.
787
787
788
788
By default, the backup is assumed to be plain format. To restore from
789
789
a tar-format backup, pass the name of the tar program to use in the
790
- keyword parameter tar_program. Note that tablespace tar files aren't
791
- handled here.
790
+ keyword parameter tar_program.
791
+
792
+ If there are tablespace present in the backup, include tablespace_map as
793
+ a keyword parameter whose values is a hash. When tar_program is used, the
794
+ hash keys are tablespace OIDs; otherwise, they are the tablespace pathnames
795
+ used in the backup. In either case, the values are the tablespace pathnames
796
+ that should be used for the target cluster.
792
797
793
798
To restore from an incremental backup, pass the parameter combine_with_prior
794
799
as a reference to an array of prior backup names with which this backup
@@ -843,24 +848,98 @@ sub init_from_backup
843
848
}
844
849
845
850
local %ENV =$self -> _get_env();
846
- PostgreSQL::Test::Utils::system_or_bail(' pg_combinebackup' ,' -d' ,
847
- @prior_backup_path ,$backup_path ,' -o' ,$data_path );
851
+ my @combineargs = (' pg_combinebackup' ,' -d' );
852
+ if (exists $params {tablespace_map })
853
+ {
854
+ while (my ($olddir ,$newdir ) =each %{$params {tablespace_map }})
855
+ {
856
+ push @combineargs ," -T$olddir =$newdir " ;
857
+ }
858
+ }
859
+ push @combineargs ,@prior_backup_path ,$backup_path ,' -o' ,$data_path ;
860
+ PostgreSQL::Test::Utils::system_or_bail(@combineargs );
848
861
}
849
862
elsif (defined $params {tar_program })
850
863
{
851
- mkdir ($data_path );
864
+ mkdir ($data_path ) || die " mkdir $data_path : $! " ;
852
865
PostgreSQL::Test::Utils::system_or_bail($params {tar_program },' xf' ,
853
866
$backup_path .' /base.tar' ,
854
867
' -C' ,$data_path );
855
868
PostgreSQL::Test::Utils::system_or_bail(
856
869
$params {tar_program },' xf' ,
857
870
$backup_path .' /pg_wal.tar' ,' -C' ,
858
871
$data_path .' /pg_wal' );
872
+
873
+ # We need to generate a tablespace_map file.
874
+ open (my $tsmap ," >" ," $data_path /tablespace_map" )
875
+ ||die " $data_path /tablespace_map:$! " ;
876
+
877
+ # Extract tarfiles and add tablespace_map entries
878
+ my @tstars =grep {/ ^\d +.tar/ }
879
+ PostgreSQL::Test::Utils::slurp_dir($backup_path );
880
+ for my $tstar (@tstars )
881
+ {
882
+ my $tsoid =$tstar ;
883
+ $tsoid =~s /\. tar$// ;
884
+
885
+ die " no tablespace mapping for$tstar "
886
+ if !exists $params {tablespace_map } ||
887
+ !exists $params {tablespace_map }{$tsoid };
888
+ my $newdir =$params {tablespace_map }{$tsoid };
889
+
890
+ mkdir ($newdir ) ||die " mkdir$newdir :$! " ;
891
+ PostgreSQL::Test::Utils::system_or_bail($params {tar_program },' xf' ,
892
+ $backup_path .' /' .$tstar ,' -C' ,$newdir );
893
+
894
+ my $escaped_newdir =$newdir ;
895
+ $escaped_newdir =~s /\\ / \\\\ / g ;
896
+ print $tsmap " $tsoid $escaped_newdir \n " ;
897
+ }
898
+
899
+ # Close tablespace_map.
900
+ close ($tsmap );
859
901
}
860
902
else
861
903
{
904
+ my @tsoids ;
862
905
rmdir ($data_path );
863
- PostgreSQL::Test::RecursiveCopy::copypath($backup_path ,$data_path );
906
+
907
+ # Copy the main backup. Exclude tablespace links, but remember them.
908
+ PostgreSQL::Test::RecursiveCopy::copypath($backup_path ,$data_path ,
909
+ ' filterfn' => sub {
910
+ my ($path ) =@_ ;
911
+ if ($path =~/ ^pg_tblspc\/ (\d +)$ / &&-l " $backup_path /$path " )
912
+ {
913
+ push @tsoids ,$1 ;
914
+ return 0;
915
+ }
916
+ return 1;
917
+ });
918
+
919
+ # We need to generate a tablespace_map file.
920
+ open (my $tsmap ," >" ," $data_path /tablespace_map" )
921
+ ||die " $data_path /tablespace_map:$! " ;
922
+
923
+ # Now use the list of tablespace links to copy each tablespace.
924
+ for my $tsoid (@tsoids )
925
+ {
926
+ my $olddir =readlink (" $backup_path /pg_tblspc/$tsoid " )
927
+ ||die " readlink$backup_path /pg_tblspc/$tsoid :$! " ;
928
+
929
+ die " no tablespace mapping for$olddir "
930
+ if !exists $params {tablespace_map } ||
931
+ !exists $params {tablespace_map }{$olddir };
932
+
933
+ my $newdir =$params {tablespace_map }{$olddir };
934
+ PostgreSQL::Test::RecursiveCopy::copypath($olddir ,$newdir );
935
+
936
+ my $escaped_newdir =$newdir ;
937
+ $escaped_newdir =~s /\\ / \\\\ / g ;
938
+ print $tsmap " $tsoid $escaped_newdir \n " ;
939
+ }
940
+
941
+ # Close tablespace_map.
942
+ close ($tsmap );
864
943
}
865
944
chmod (0700,$data_path )or die $! ;
866
945