@@ -1666,6 +1666,152 @@ 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
+ gdb .set_breakpoint ('delete_backup_files' )
1711
+ gdb .run_until_break ()
1712
+
1713
+ gdb .set_breakpoint ('parray_bsearch' )
1714
+ gdb .continue_execution_until_break ()
1715
+
1716
+ gdb .set_breakpoint ('pgFileDelete' )
1717
+ gdb .continue_execution_until_break (30 )
1718
+
1719
+ gdb ._execute ('signal SIGKILL' )
1720
+
1721
+ # backup half-merged
1722
+ self .assertEqual (
1723
+ 'OK' , self .show_pb (backup_dir , 'node' )[0 ]['status' ])
1724
+
1725
+ self .assertEqual (
1726
+ full_id , self .show_pb (backup_dir , 'node' )[0 ]['id' ])
1727
+
1728
+ db_path = os .path .join (
1729
+ backup_dir , 'backups' , 'node' ,
1730
+ full_id , 'database' , 'base' , dboid )
1731
+
1732
+ self .assertNotTrue (
1733
+ os .path .isdir (db_path ))
1734
+
1735
+ exit (1 )
1736
+
1737
+ # try to continue failed MERGE
1738
+ self .merge_backup (backup_dir , "node" , backup_id )
1739
+
1740
+ self .assertEqual (
1741
+ 'OK' , self .show_pb (backup_dir , 'node' )[0 ]['status' ])
1742
+
1743
+ node .cleanup ()
1744
+
1745
+ self .restore_node (backup_dir , 'node' , node )
1746
+
1747
+ pgdata_restored = self .pgdata_content (node .data_dir )
1748
+ self .compare_pgdata (pgdata , pgdata_restored )
1749
+
1750
+ self .del_test_dir (module_name , fname )
1751
+
1752
+ def test_failed_merge_after_delete_1 (self ):
1753
+ """
1754
+ """
1755
+ fname = self .id ().split ('.' )[3 ]
1756
+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
1757
+ node = self .make_simple_node (
1758
+ base_dir = os .path .join (module_name , fname , 'node' ),
1759
+ set_replication = True ,
1760
+ initdb_params = ['--data-checksums' ],
1761
+ pg_options = {'autovacuum' : 'off' })
1762
+
1763
+ self .init_pb (backup_dir )
1764
+ self .add_instance (backup_dir , 'node' , node )
1765
+ self .set_archiving (backup_dir , 'node' , node )
1766
+ node .slow_start ()
1767
+
1768
+ # add database
1769
+ node .pgbench_init (scale = 1 )
1770
+
1771
+ # take FULL backup
1772
+ full_id = self .backup_node (
1773
+ backup_dir , 'node' , node , options = ['--stream' ])
1774
+
1775
+ pgdata = self .pgdata_content (node .data_dir )
1776
+
1777
+ # drop database
1778
+ pgbench = node .pgbench (options = ['-T' , '10' , '-c' , '2' , '--no-vacuum' ])
1779
+ pgbench .wait ()
1780
+
1781
+ # take PAGE backup
1782
+ page_id = self .backup_node (
1783
+ backup_dir , 'node' , node , backup_type = 'page' )
1784
+
1785
+ gdb = self .merge_backup (
1786
+ backup_dir , 'node' , page_id ,
1787
+ gdb = True , options = ['--log-level-console=verbose' ])
1788
+ gdb .set_breakpoint ('delete_backup_files' )
1789
+ gdb .run_until_break ()
1790
+
1791
+ gdb .set_breakpoint ('parray_bsearch' )
1792
+ gdb .continue_execution_until_break ()
1793
+
1794
+ gdb .set_breakpoint ('pgFileDelete' )
1795
+ gdb .continue_execution_until_break (30 )
1796
+
1797
+ gdb ._execute ('signal SIGKILL' )
1798
+
1799
+ # backup half-merged
1800
+ self .assertEqual (
1801
+ 'OK' , self .show_pb (backup_dir , 'node' )[0 ]['status' ])
1802
+
1803
+ self .assertEqual (
1804
+ full_id , self .show_pb (backup_dir , 'node' )[0 ]['id' ])
1805
+
1806
+ # restore
1807
+ node .cleanup ()
1808
+ self .restore_node (backup_dir , 'node' , node )
1809
+
1810
+ pgdata_restored = self .pgdata_content (node .data_dir )
1811
+ self .compare_pgdata (pgdata , pgdata_restored )
1812
+
1813
+ self .del_test_dir (module_name , fname )
1814
+
1669
1815
# @unittest.skip("skip")
1670
1816
def test_merge_backup_from_future (self ):
1671
1817
"""
@@ -1906,6 +2052,66 @@ def test_merge_multiple_descendants(self):
1906
2052
# Clean after yourself
1907
2053
self .del_test_dir (module_name , fname )
1908
2054
2055
+ # @unittest.skip("skip")
2056
+ def test_smart_merge (self ):
2057
+ """
2058
+ make node, create database, take full backup, drop database,
2059
+ take PAGE backup and merge it into FULL,
2060
+ make sure that files from dropped database are not
2061
+ copied during restore
2062
+ https://github.com/postgrespro/pg_probackup/issues/63
2063
+ """
2064
+ fname = self .id ().split ('.' )[3 ]
2065
+ node = self .make_simple_node (
2066
+ base_dir = os .path .join (module_name , fname , 'node' ),
2067
+ set_replication = True ,
2068
+ initdb_params = ['--data-checksums' ])
2069
+
2070
+ backup_dir = os .path .join (self .tmp_path , module_name , fname , 'backup' )
2071
+ self .init_pb (backup_dir )
2072
+ self .add_instance (backup_dir , 'node' , node )
2073
+ self .set_archiving (backup_dir , 'node' , node )
2074
+ node .slow_start ()
2075
+
2076
+ # create database
2077
+ node .safe_psql (
2078
+ "postgres" ,
2079
+ "CREATE DATABASE testdb" )
2080
+
2081
+ # take FULL backup
2082
+ full_id = self .backup_node (backup_dir , 'node' , node )
2083
+
2084
+ # drop database
2085
+ node .safe_psql (
2086
+ "postgres" ,
2087
+ "DROP DATABASE testdb" )
2088
+
2089
+ # take PAGE backup
2090
+ page_id = self .backup_node (
2091
+ backup_dir , 'node' , node , backup_type = 'page' )
2092
+
2093
+ # get delta between FULL and PAGE filelists
2094
+ filelist_full = self .get_backup_filelist (
2095
+ backup_dir , 'node' , full_id )
2096
+
2097
+ filelist_page = self .get_backup_filelist (
2098
+ backup_dir , 'node' , page_id )
2099
+
2100
+ filelist_diff = self .get_backup_filelist_diff (
2101
+ filelist_full , filelist_page )
2102
+
2103
+ # merge PAGE backup
2104
+ self .merge_backup (
2105
+ backup_dir , 'node' , page_id ,
2106
+ options = ['--log-level-file=VERBOSE' ])
2107
+
2108
+ logfile = os .path .join (backup_dir , 'log' , 'pg_probackup.log' )
2109
+ with open (logfile , 'r' ) as f :
2110
+ logfile_content = f .read ()
2111
+
2112
+ # Clean after yourself
2113
+ self .del_test_dir (module_name , fname )
2114
+
1909
2115
1910
2116
# 1. always use parent link when merging (intermediates may be from different chain)
1911
2117
# 2. page backup we are merging with may disappear after failed merge,
0 commit comments