@@ -1666,6 +1666,141 @@ def test_losing_file_after_failed_merge(self):
1666
1666
1667
1667
self .del_test_dir (module_name , fname )
1668
1668
1669
+ def test_failed_merge_after_delete (self ):
1670
+ """
1671
+ """
1672
+ fname = self .id ().split ('.' )[3 ]
1673
+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
1674
+ node = self .make_simple_node (
1675
+ base_dir = os .path .join (module_name , fname , 'node' ),
1676
+ set_replication = True ,
1677
+ initdb_params = ['--data-checksums' ],
1678
+ pg_options = {'autovacuum' : 'off' })
1679
+
1680
+ self .init_pb (backup_dir )
1681
+ self .add_instance (backup_dir , 'node' , node )
1682
+ self .set_archiving (backup_dir , 'node' , node )
1683
+ node .slow_start ()
1684
+
1685
+ # add database
1686
+ node .safe_psql (
1687
+ 'postgres' ,
1688
+ 'CREATE DATABASE testdb' )
1689
+
1690
+ dboid = node .safe_psql (
1691
+ "postgres" ,
1692
+ "select oid from pg_database where datname = 'testdb'" ).rstrip ()
1693
+
1694
+ # take FULL backup
1695
+ full_id = self .backup_node (
1696
+ backup_dir , 'node' , node , options = ['--stream' ])
1697
+
1698
+ # drop database
1699
+ node .safe_psql (
1700
+ 'postgres' ,
1701
+ 'DROP DATABASE testdb' )
1702
+
1703
+ # take PAGE backup
1704
+ page_id = self .backup_node (
1705
+ backup_dir , 'node' , node , backup_type = 'page' )
1706
+
1707
+ gdb = self .merge_backup (
1708
+ backup_dir , 'node' , page_id ,
1709
+ gdb = True , options = ['--log-level-console=verbose' ])
1710
+
1711
+ gdb .set_breakpoint ('delete_backup_files' )
1712
+ gdb .run_until_break ()
1713
+
1714
+ gdb .set_breakpoint ('parray_bsearch' )
1715
+ gdb .continue_execution_until_break ()
1716
+
1717
+ gdb .set_breakpoint ('pgFileDelete' )
1718
+ gdb .continue_execution_until_break (20 )
1719
+
1720
+ gdb ._execute ('signal SIGKILL' )
1721
+
1722
+ # backup half-merged
1723
+ self .assertEqual (
1724
+ 'OK' , self .show_pb (backup_dir , 'node' )[0 ]['status' ])
1725
+
1726
+ self .assertEqual (
1727
+ full_id , self .show_pb (backup_dir , 'node' )[0 ]['id' ])
1728
+
1729
+ db_path = os .path .join (
1730
+ backup_dir , 'backups' , 'node' ,
1731
+ full_id , 'database' , 'base' , dboid )
1732
+
1733
+ self .assertFalse (
1734
+ os .path .isdir (db_path ),
1735
+ 'Directory {0} should not exist' .format (
1736
+ db_path , full_id ))
1737
+
1738
+ self .del_test_dir (module_name , fname )
1739
+
1740
+ def test_failed_merge_after_delete_1 (self ):
1741
+ """
1742
+ """
1743
+ fname = self .id ().split ('.' )[3 ]
1744
+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
1745
+ node = self .make_simple_node (
1746
+ base_dir = os .path .join (module_name , fname , 'node' ),
1747
+ set_replication = True ,
1748
+ initdb_params = ['--data-checksums' ],
1749
+ pg_options = {'autovacuum' : 'off' })
1750
+
1751
+ self .init_pb (backup_dir )
1752
+ self .add_instance (backup_dir , 'node' , node )
1753
+ self .set_archiving (backup_dir , 'node' , node )
1754
+ node .slow_start ()
1755
+
1756
+ # add database
1757
+ node .pgbench_init (scale = 1 )
1758
+
1759
+ # take FULL backup
1760
+ full_id = self .backup_node (
1761
+ backup_dir , 'node' , node , options = ['--stream' ])
1762
+
1763
+ pgdata = self .pgdata_content (node .data_dir )
1764
+
1765
+ # drop database
1766
+ pgbench = node .pgbench (options = ['-T' , '10' , '-c' , '2' , '--no-vacuum' ])
1767
+ pgbench .wait ()
1768
+
1769
+ # take PAGE backup
1770
+ page_id = self .backup_node (
1771
+ backup_dir , 'node' , node , backup_type = 'page' )
1772
+
1773
+ gdb = self .merge_backup (
1774
+ backup_dir , 'node' , page_id ,
1775
+ gdb = True , options = ['--log-level-console=verbose' ])
1776
+
1777
+ gdb .set_breakpoint ('delete_backup_files' )
1778
+ gdb .run_until_break ()
1779
+
1780
+ gdb .set_breakpoint ('parray_bsearch' )
1781
+ gdb .continue_execution_until_break ()
1782
+
1783
+ gdb .set_breakpoint ('pgFileDelete' )
1784
+ gdb .continue_execution_until_break (30 )
1785
+
1786
+ gdb ._execute ('signal SIGKILL' )
1787
+
1788
+ # backup half-merged
1789
+ self .assertEqual (
1790
+ 'OK' , self .show_pb (backup_dir , 'node' )[0 ]['status' ])
1791
+
1792
+ self .assertEqual (
1793
+ full_id , self .show_pb (backup_dir , 'node' )[0 ]['id' ])
1794
+
1795
+ # restore
1796
+ node .cleanup ()
1797
+ self .restore_node (backup_dir , 'node' , node )
1798
+
1799
+ pgdata_restored = self .pgdata_content (node .data_dir )
1800
+ self .compare_pgdata (pgdata , pgdata_restored )
1801
+
1802
+ self .del_test_dir (module_name , fname )
1803
+
1669
1804
# @unittest.skip("skip")
1670
1805
def test_merge_backup_from_future (self ):
1671
1806
"""
@@ -1906,6 +2041,66 @@ def test_merge_multiple_descendants(self):
1906
2041
# Clean after yourself
1907
2042
self .del_test_dir (module_name , fname )
1908
2043
2044
+ # @unittest.skip("skip")
2045
+ def test_smart_merge (self ):
2046
+ """
2047
+ make node, create database, take full backup, drop database,
2048
+ take PAGE backup and merge it into FULL,
2049
+ make sure that files from dropped database are not
2050
+ copied during restore
2051
+ https://github.com/postgrespro/pg_probackup/issues/63
2052
+ """
2053
+ fname = self .id ().split ('.' )[3 ]
2054
+ node = self .make_simple_node (
2055
+ base_dir = os .path .join (module_name , fname , 'node' ),
2056
+ set_replication = True ,
2057
+ initdb_params = ['--data-checksums' ])
2058
+
2059
+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
2060
+ self .init_pb (backup_dir )
2061
+ self .add_instance (backup_dir , 'node' , node )
2062
+ self .set_archiving (backup_dir , 'node' , node )
2063
+ node .slow_start ()
2064
+
2065
+ # create database
2066
+ node .safe_psql (
2067
+ "postgres" ,
2068
+ "CREATE DATABASE testdb" )
2069
+
2070
+ # take FULL backup
2071
+ full_id = self .backup_node (backup_dir , 'node' , node )
2072
+
2073
+ # drop database
2074
+ node .safe_psql (
2075
+ "postgres" ,
2076
+ "DROP DATABASE testdb" )
2077
+
2078
+ # take PAGE backup
2079
+ page_id = self .backup_node (
2080
+ backup_dir , 'node' , node , backup_type = 'page' )
2081
+
2082
+ # get delta between FULL and PAGE filelists
2083
+ filelist_full = self .get_backup_filelist (
2084
+ backup_dir , 'node' , full_id )
2085
+
2086
+ filelist_page = self .get_backup_filelist (
2087
+ backup_dir , 'node' , page_id )
2088
+
2089
+ filelist_diff = self .get_backup_filelist_diff (
2090
+ filelist_full , filelist_page )
2091
+
2092
+ # merge PAGE backup
2093
+ self .merge_backup (
2094
+ backup_dir , 'node' , page_id ,
2095
+ options = ['--log-level-file=VERBOSE' ])
2096
+
2097
+ logfile = os .path .join (backup_dir , 'log' , 'pg_probackup.log' )
2098
+ with open (logfile , 'r' ) as f :
2099
+ logfile_content = f .read ()
2100
+
2101
+ # Clean after yourself
2102
+ self .del_test_dir (module_name , fname )
2103
+
1909
2104
1910
2105
# 1. always use parent link when merging (intermediates may be from different chain)
1911
2106
# 2. page backup we are merging with may disappear after failed merge,
0 commit comments