# === Purpose === # # Verify that disk full/out of space errors generated during the flush # stage of binlog commit are properly handled by the server. # # === Implementation === # # Simulate tempoary file write failures in below scenarios and verify the # failures can be handled correctly. # - Simulate binlog cache write failure in an INSERT which write data more than # cache size. # - Simulate my_b_flush_io_cache failure in an ROLLBACK TO. # - Simulate my_b_flush_io_cache failure when reseting binlog cache in a # ROLLBACK. # - Simulate my_b_flush_io_cache failure when reseting binlog cache in a # COMMIT # - Simulate write failure # - Simulate my_b_flush_io_cache failure when reseting binlog cache in # disconnect # - Simulate a binlog cache write failure when reinitializing it for # copying to binlog. It should cause server abort if binlog_error_action # is ABORT_SERVER # # === References === # # Bug #27399620 BINLOG AND ENGINE BECOME INCONSISTENT WHEN BINLOG CACHE FILE # GETS OUT OF SPACE --source include/have_binlog_format_row.inc --source include/have_log_bin.inc --source include/have_debug.inc # Don't test this under valgrind, memory leaks will occur --source include/not_valgrind.inc # Avoid CrashReporter popup on Mac --source include/not_crashrep.inc call mtr.add_suppression("An error occurred during flush stage of the commit"); call mtr.add_suppression("Attempting backtrace. You can use the following information to find out*"); call mtr.add_suppression(".*Error writing file.*"); RESET MASTER; CREATE TABLE t1(c1 varchar(8192)); CREATE TABLE t2(c1 varchar(8192)); CREATE TABLE t3(c1 varchar(8192)); SET GLOBAL binlog_cache_size = 4096; connect(con1,localhost,root,,); --echo --echo # Case 1 Simulate my_b_flush_io_cache failure when truncating binlog --echo # cache. ROLLBACK TO triggers binlog cache truncation process. --source include/save_binlog_position.inc BEGIN; INSERT INTO t1 VALUES (repeat('a', 2048)); # Below statemens in sp1 should not be binlogged SAVEPOINT sp1; INSERT INTO t2 VALUES (repeat('a', 4096)); INSERT INTO t3 VALUES (repeat('b', 4096)); # ROLLBACK to savepoint should not call my_b_flush_io_cache which # caused extra events were logged before the fix. SET SESSION debug = "+d,simulate_error_during_flush_cache_to_file"; ROLLBACK TO sp1; SET SESSION debug = "-d,simulate_error_during_flush_cache_to_file"; INSERT INTO t1 VALUES (repeat('c', 8192)); COMMIT; # The transaction should be binlogged correctly --let $binlog_start= $binlog_position --source include/show_binlog_events.inc --echo --echo # Case 2 Simulate my_b_flush_io_cache failure when reseting binlog cache --echo # in ROLLBACK statement BEGIN; INSERT INTO t1 VALUES (repeat('a', 8192)); # When reseting binlog cache, it should not call my_b_flush_io_cache to flush # data in binlog cache to temporary file. It caused assertion failure: # binlog_cache_data::reset(): Assertion `is_binlog_empty()' before the fix. SET SESSION debug = "+d,simulate_error_during_flush_cache_to_file"; ROLLBACK; SET SESSION debug = "-d,simulate_error_during_flush_cache_to_file"; --echo --echo # Case 3 CLIENT DISCONNECT. it is same to ROLLBACK BEGIN; INSERT INTO t1 VALUES (repeat('a', 8192)); SET SESSION debug = "+d,simulate_error_during_flush_cache_to_file"; --disconnect con1 --echo --echo # Case 4 Simulate write failure when reinitializing binlog cache for --echo # copying to binlog. The error should be ignored and cache --echo # is cleared correctly if binlog_error_action is IGNORE_ERROR --echo # --connect(con1,localhost,root,,) TRUNCATE t1; --source include/save_binlog_position.inc SET GLOBAL binlog_error_action = IGNORE_ERROR; BEGIN; INSERT INTO t1 VALUES (repeat('a', 8192)); SET SESSION debug = "+d,simulate_tmpdir_partition_full"; --replace_regex /.*Error writing file.*/Error writing file (Errcode: ##)/ COMMIT; SET SESSION debug = "-d,simulate_tmpdir_partition_full"; #SET SESSION debug = "-d,simulate_no_free_space_error"; # Check that transaction is committed --let $assert_cond = COUNT(*) = 1 FROM t1; --let $assert_text = Count of elements in t1 should be 1. # Check that error is present in error log --let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.1.err --let $assert_only_after = CURRENT_TEST: xengine_binlog.binlog_cache_write_failure --let $assert_count = 1 --let $assert_select = An error occurred during flush stage of the commit. 'binlog_error_action' is set to 'IGNORE_ERROR'. --let $assert_text = An error occurred during flush stage of the commit. 'binlog_error_action' is set to 'IGNORE_ERROR'. --source include/assert_grep.inc # Restart so that binary log is enabled again and we can do the below test --disconnect con1 --connection default --source include/restart_mysqld.inc # Nothing should be logged --let $binlog_start= $binlog_position --source include/show_binlog_events.inc --echo --echo # Case 5 Simulate write failure when reinitializing binlog cache for --echo # copying to binlog with ABORT_SERVER --echo # SET GLOBAL binlog_cache_size = 4096; --connect(con1,localhost,root,,) select @@global.binlog_cache_size; TRUNCATE t2; --source include/save_binlog_position.inc SET GLOBAL binlog_error_action = ABORT_SERVER; BEGIN; INSERT INTO t2 VALUES (repeat('b', 8192)); --exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect SET SESSION debug = "+d,simulate_tmpdir_partition_full"; --error ER_BINLOG_LOGGING_IMPOSSIBLE COMMIT; --exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --enable_reconnect --source include/wait_until_connected_again.inc # Restart so that binary log is enabled again and we can do the below test --source include/restart_mysqld.inc select * from t2; # Check that transaction is not committed --let $assert_cond = COUNT(*) = 0 FROM t2; --let $assert_text = Count of elements in t2 should be 0. --source include/assert.inc # Nothing should be logged --let $binlog_start= $binlog_position --source include/show_binlog_events.inc # Cleanup --disconnect con1 --connection default --enable_reconnect DROP TABLE t1, t2, t3; RESET MASTER;