@@ -1179,10 +1179,8 @@ def test_json():
1179
1179
1180
1180
1181
1181
def test_string_primary_key (monkeypatch ):
1182
- monkeypatch .setattr (DbReplicatorInitial , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1183
-
1184
1182
cfg = config .Settings ()
1185
- cfg .load (CONFIG_FILE )
1183
+ cfg .load ('tests_config_string_primary_key.yaml' )
1186
1184
1187
1185
mysql = mysql_api .MySQLApi (
1188
1186
database = None ,
@@ -1217,9 +1215,9 @@ def test_string_primary_key(monkeypatch):
1217
1215
commit = True ,
1218
1216
)
1219
1217
1220
- binlog_replicator_runner = BinlogReplicatorRunner ()
1218
+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = 'tests_config_string_primary_key.yaml' )
1221
1219
binlog_replicator_runner .run ()
1222
- db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1220
+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = 'tests_config_string_primary_key.yaml' )
1223
1221
db_replicator_runner .run ()
1224
1222
1225
1223
assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
@@ -1241,10 +1239,8 @@ def test_string_primary_key(monkeypatch):
1241
1239
1242
1240
1243
1241
def test_if_exists_if_not_exists (monkeypatch ):
1244
- monkeypatch .setattr (DbReplicatorInitial , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1245
-
1246
1242
cfg = config .Settings ()
1247
- cfg .load (CONFIG_FILE )
1243
+ cfg .load ('tests_config_string_primary_key.yaml' )
1248
1244
1249
1245
mysql = mysql_api .MySQLApi (
1250
1246
database = None ,
@@ -1258,9 +1254,9 @@ def test_if_exists_if_not_exists(monkeypatch):
1258
1254
1259
1255
prepare_env (cfg , mysql , ch )
1260
1256
1261
- binlog_replicator_runner = BinlogReplicatorRunner ()
1257
+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = 'tests_config_string_primary_key.yaml' )
1262
1258
binlog_replicator_runner .run ()
1263
- db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1259
+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = 'tests_config_string_primary_key.yaml' )
1264
1260
db_replicator_runner .run ()
1265
1261
1266
1262
assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
@@ -1282,10 +1278,8 @@ def test_if_exists_if_not_exists(monkeypatch):
1282
1278
1283
1279
1284
1280
def test_percona_migration (monkeypatch ):
1285
- monkeypatch .setattr (DbReplicatorInitial , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1286
-
1287
1281
cfg = config .Settings ()
1288
- cfg .load (CONFIG_FILE )
1282
+ cfg .load ('tests_config_string_primary_key.yaml' )
1289
1283
1290
1284
mysql = mysql_api .MySQLApi (
1291
1285
database = None ,
@@ -1310,9 +1304,9 @@ def test_percona_migration(monkeypatch):
1310
1304
commit = True ,
1311
1305
)
1312
1306
1313
- binlog_replicator_runner = BinlogReplicatorRunner ()
1307
+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = 'tests_config_string_primary_key.yaml' )
1314
1308
binlog_replicator_runner .run ()
1315
- db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1309
+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = 'tests_config_string_primary_key.yaml' )
1316
1310
db_replicator_runner .run ()
1317
1311
1318
1312
assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
@@ -1360,10 +1354,8 @@ def test_percona_migration(monkeypatch):
1360
1354
1361
1355
1362
1356
def test_add_column_first_after_and_drop_column (monkeypatch ):
1363
- monkeypatch .setattr (DbReplicatorInitial , 'INITIAL_REPLICATION_BATCH_SIZE' , 1 )
1364
-
1365
1357
cfg = config .Settings ()
1366
- cfg .load (CONFIG_FILE )
1358
+ cfg .load ('tests_config_string_primary_key.yaml' )
1367
1359
1368
1360
mysql = mysql_api .MySQLApi (
1369
1361
database = None ,
@@ -1388,9 +1380,9 @@ def test_add_column_first_after_and_drop_column(monkeypatch):
1388
1380
commit = True ,
1389
1381
)
1390
1382
1391
- binlog_replicator_runner = BinlogReplicatorRunner ()
1383
+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = 'tests_config_string_primary_key.yaml' )
1392
1384
binlog_replicator_runner .run ()
1393
- db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME )
1385
+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = 'tests_config_string_primary_key.yaml' )
1394
1386
db_replicator_runner .run ()
1395
1387
1396
1388
assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
@@ -2912,3 +2904,124 @@ def test_timezone_conversion():
2912
2904
finally :
2913
2905
# Clean up temporary config file
2914
2906
os .unlink (temp_config_file )
2907
+
2908
+ def test_resume_initial_replication_with_ignore_deletes ():
2909
+ """
2910
+ Test that resuming initial replication works correctly with ignore_deletes=True.
2911
+
2912
+ This reproduces the bug from https://github.com/bakwc/mysql_ch_replicator/issues/172
2913
+ where resuming initial replication would fail with "Database sirocco_tmp does not exist"
2914
+ when ignore_deletes=True because the code would try to use the _tmp database instead
2915
+ of the target database directly.
2916
+ """
2917
+ # Create a temporary config file with ignore_deletes=True
2918
+ with tempfile .NamedTemporaryFile (mode = 'w' , suffix = '.yaml' , delete = False ) as temp_config_file :
2919
+ config_file = temp_config_file .name
2920
+
2921
+ # Read the original config
2922
+ with open (CONFIG_FILE , 'r' ) as original_config :
2923
+ config_data = yaml .safe_load (original_config )
2924
+
2925
+ # Add ignore_deletes=True
2926
+ config_data ['ignore_deletes' ] = True
2927
+
2928
+ # Set initial_replication_batch_size to 1 for testing
2929
+ config_data ['initial_replication_batch_size' ] = 1
2930
+
2931
+ # Write to the temp file
2932
+ yaml .dump (config_data , temp_config_file )
2933
+
2934
+ try :
2935
+ cfg = config .Settings ()
2936
+ cfg .load (config_file )
2937
+
2938
+ # Verify the ignore_deletes option was set
2939
+ assert cfg .ignore_deletes is True
2940
+
2941
+ mysql = mysql_api .MySQLApi (
2942
+ database = None ,
2943
+ mysql_settings = cfg .mysql ,
2944
+ )
2945
+
2946
+ ch = clickhouse_api .ClickhouseApi (
2947
+ database = TEST_DB_NAME ,
2948
+ clickhouse_settings = cfg .clickhouse ,
2949
+ )
2950
+
2951
+ prepare_env (cfg , mysql , ch )
2952
+
2953
+ # Create a table with many records to ensure initial replication takes time
2954
+ mysql .execute (f'''
2955
+ CREATE TABLE `{ TEST_TABLE_NAME } ` (
2956
+ id int NOT NULL AUTO_INCREMENT,
2957
+ name varchar(255),
2958
+ data varchar(1000),
2959
+ PRIMARY KEY (id)
2960
+ )
2961
+ ''' )
2962
+
2963
+ # Insert many records to make initial replication take longer
2964
+ for i in range (100 ):
2965
+ mysql .execute (
2966
+ f"INSERT INTO `{ TEST_TABLE_NAME } ` (name, data) VALUES ('test_{ i } ', 'data_{ i } ');" ,
2967
+ commit = True
2968
+ )
2969
+
2970
+ # Start binlog replicator
2971
+ binlog_replicator_runner = BinlogReplicatorRunner (cfg_file = config_file )
2972
+ binlog_replicator_runner .run ()
2973
+
2974
+ # Start db replicator for initial replication with test flag to exit early
2975
+ db_replicator_runner = DbReplicatorRunner (TEST_DB_NAME , cfg_file = config_file ,
2976
+ additional_arguments = '--initial-replication-test-fail-records 30' )
2977
+ db_replicator_runner .run ()
2978
+
2979
+ # Wait for initial replication to start
2980
+ assert_wait (lambda : TEST_DB_NAME in ch .get_databases ())
2981
+ ch .execute_command (f'USE `{ TEST_DB_NAME } `' )
2982
+ assert_wait (lambda : TEST_TABLE_NAME in ch .get_tables ())
2983
+
2984
+ # Wait for some records to be replicated but not all (should hit the 30 record limit)
2985
+ assert_wait (lambda : len (ch .select (TEST_TABLE_NAME )) > 0 )
2986
+
2987
+ # The db replicator should have stopped automatically due to the test flag
2988
+ # But we still call stop() to ensure proper cleanup
2989
+ db_replicator_runner .stop ()
2990
+
2991
+ # Verify the state is still PERFORMING_INITIAL_REPLICATION
2992
+ state_path = os .path .join (cfg .binlog_replicator .data_dir , TEST_DB_NAME , 'state.pckl' )
2993
+ state = DbReplicatorState (state_path )
2994
+ assert state .status .value == 2 # PERFORMING_INITIAL_REPLICATION
2995
+
2996
+ # Add more records while replication is stopped
2997
+ for i in range (100 , 150 ):
2998
+ mysql .execute (
2999
+ f"INSERT INTO `{ TEST_TABLE_NAME } ` (name, data) VALUES ('test_{ i } ', 'data_{ i } ');" ,
3000
+ commit = True
3001
+ )
3002
+
3003
+ # Verify that sirocco_tmp database does NOT exist (it should use sirocco directly)
3004
+ assert f"{ TEST_DB_NAME } _tmp" not in ch .get_databases (), "Temporary database should not exist with ignore_deletes=True"
3005
+
3006
+ # Resume initial replication - this should NOT fail with "Database sirocco_tmp does not exist"
3007
+ db_replicator_runner_2 = DbReplicatorRunner (TEST_DB_NAME , cfg_file = config_file )
3008
+ db_replicator_runner_2 .run ()
3009
+
3010
+ # Wait for all records to be replicated (100 original + 50 extra = 150)
3011
+ assert_wait (lambda : len (ch .select (TEST_TABLE_NAME )) == 150 , max_wait_time = 30 )
3012
+
3013
+ # Verify the replication completed successfully
3014
+ records = ch .select (TEST_TABLE_NAME )
3015
+ assert len (records ) == 150 , f"Expected 150 records, got { len (records )} "
3016
+
3017
+ # Verify we can continue with realtime replication
3018
+ mysql .execute (f"INSERT INTO `{ TEST_TABLE_NAME } ` (name, data) VALUES ('realtime_test', 'realtime_data');" , commit = True )
3019
+ assert_wait (lambda : len (ch .select (TEST_TABLE_NAME )) == 151 )
3020
+
3021
+ # Clean up
3022
+ db_replicator_runner_2 .stop ()
3023
+ binlog_replicator_runner .stop ()
3024
+
3025
+ finally :
3026
+ # Clean up temp config file
3027
+ os .unlink (config_file )
0 commit comments