Commit b0e77d62 authored by Luis Soares's avatar Luis Soares

BUG#46166

Merging to latest mysql-5.5-bugteam.
parents 3237e490 16b2ca1f
#
# Takes the flag as an argument:
# -- let $io_thd_injection_fault_flag=+d,fault_injection_new_file_rotate_event
# -- source include/io_thd_fault_injection.inc
#
SET @old_debug=@@global.debug;
-- disable_warnings
-- source include/stop_slave.inc
-- enable_warnings
-- eval SET GLOBAL debug="+d,$io_thd_injection_fault_flag"
START SLAVE io_thread;
-- source include/wait_for_slave_io_to_stop.inc
-- source include/wait_for_slave_io_error.inc
-- eval SET GLOBAL debug="-d,$io_thd_injection_fault_flag"
SET GLOBAL debug=@old_debug;
# restart because slave is in bad shape
-- source include/restart_mysqld.inc
# Write file to make mysql-test-run.pl expect the "crash", but don't start # Write file to make mysql-test-run.pl expect the "crash", but don't start
# it until it's told to # it until it's told to
--exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --let $_server_id= `SELECT @@server_id`
--let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
--exec echo "wait" > $_expect_file_name
# Send shutdown to the connected server and give # Send shutdown to the connected server and give
# it 10 seconds to die before zapping it # it 10 seconds to die before zapping it
shutdown_server 10; shutdown_server 10;
# Write file to make mysql-test-run.pl start up the server again # Write file to make mysql-test-run.pl start up the server again
--exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect --exec echo "restart" > $_expect_file_name
# Turn on reconnect # Turn on reconnect
--enable_reconnect --enable_reconnect
......
...@@ -2,7 +2,9 @@ call mtr.add_suppression('Attempting backtrace'); ...@@ -2,7 +2,9 @@ call mtr.add_suppression('Attempting backtrace');
call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.'); call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.');
call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file'); call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file');
call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.'); call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.');
call mtr.add_suppression('Could not open .*');
call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.'); call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.');
RESET MASTER;
flush logs; flush logs;
flush logs; flush logs;
flush logs; flush logs;
...@@ -116,11 +118,31 @@ master-bin.000011 ...@@ -116,11 +118,31 @@ master-bin.000011
# This should put the server in unsafe state and stop # This should put the server in unsafe state and stop
# accepting any command. If we inject a fault at this # accepting any command. If we inject a fault at this
# point and continue the execution the server crashes. # point and continue the execution the server crashes.
# Besides the flush command does not report an error.
# #
SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
SELECT @index;
@index
master-bin.000006
master-bin.000007
master-bin.000008
master-bin.000009
master-bin.000010
master-bin.000011
# fault_injection_registering_index # fault_injection_registering_index
SET SESSION debug="+d,fault_injection_registering_index"; SET SESSION debug="+d,fault_injection_registering_index";
flush logs; flush logs;
ERROR HY000: Can't open file: './master-bin.000012' (errno: 1)
SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
SELECT @index;
@index
master-bin.000006
master-bin.000007
master-bin.000008
master-bin.000009
master-bin.000010
master-bin.000011
SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index'); SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
SELECT @index; SELECT @index;
@index @index
...@@ -135,6 +157,18 @@ master-bin.000012 ...@@ -135,6 +157,18 @@ master-bin.000012
# fault_injection_updating_index # fault_injection_updating_index
SET SESSION debug="+d,fault_injection_updating_index"; SET SESSION debug="+d,fault_injection_updating_index";
flush logs; flush logs;
ERROR HY000: Can't open file: './master-bin.000013' (errno: 1)
SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
SELECT @index;
@index
master-bin.000006
master-bin.000007
master-bin.000008
master-bin.000009
master-bin.000010
master-bin.000011
master-bin.000012
SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index'); SET @index=LOAD_FILE('MYSQLTEST_VARDIR/mysqld.1/data//master-bin.index');
SELECT @index; SELECT @index;
@index @index
......
...@@ -3,6 +3,5 @@ call mtr.add_suppression("Log filename extension number exhausted:"); ...@@ -3,6 +3,5 @@ call mtr.add_suppression("Log filename extension number exhausted:");
call mtr.add_suppression("Can't generate a unique log-filename"); call mtr.add_suppression("Can't generate a unique log-filename");
RESET MASTER; RESET MASTER;
FLUSH LOGS; FLUSH LOGS;
Warnings: ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
Warning 1098 Can't generate a unique log-filename master-bin.(1-999)
...@@ -10,9 +10,12 @@ call mtr.add_suppression('Attempting backtrace'); ...@@ -10,9 +10,12 @@ call mtr.add_suppression('Attempting backtrace');
call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.'); call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to process registered files that would be purged.');
call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file'); call mtr.add_suppression('MSYQL_BIN_LOG::open failed to sync the index file');
call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.'); call mtr.add_suppression('Turning logging off for the whole duration of the MySQL server process.');
call mtr.add_suppression('Could not open .*');
call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.'); call mtr.add_suppression('MSYQL_BIN_LOG::purge_logs failed to clean registers before purging logs.');
let $old=`select @@debug`; let $old=`select @@debug`;
RESET MASTER;
let $MYSQLD_DATADIR= `select @@datadir`; let $MYSQLD_DATADIR= `select @@datadir`;
let $INDEX=$MYSQLD_DATADIR/master-bin.index; let $INDEX=$MYSQLD_DATADIR/master-bin.index;
...@@ -205,12 +208,25 @@ SELECT @index; ...@@ -205,12 +208,25 @@ SELECT @index;
--echo # This should put the server in unsafe state and stop --echo # This should put the server in unsafe state and stop
--echo # accepting any command. If we inject a fault at this --echo # accepting any command. If we inject a fault at this
--echo # point and continue the execution the server crashes. --echo # point and continue the execution the server crashes.
--echo # Besides the flush command does not report an error.
--echo # --echo #
--chmod 0644 $INDEX
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval SET @index=LOAD_FILE('$index')
-- replace_regex /\.[\\\/]master/master/
SELECT @index;
--echo # fault_injection_registering_index --echo # fault_injection_registering_index
SET SESSION debug="+d,fault_injection_registering_index"; SET SESSION debug="+d,fault_injection_registering_index";
-- error ER_CANT_OPEN_FILE
flush logs; flush logs;
--chmod 0644 $INDEX
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval SET @index=LOAD_FILE('$index')
-- replace_regex /\.[\\\/]master/master/
SELECT @index;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
--chmod 0644 $INDEX --chmod 0644 $INDEX
...@@ -221,7 +237,15 @@ SELECT @index; ...@@ -221,7 +237,15 @@ SELECT @index;
--echo # fault_injection_updating_index --echo # fault_injection_updating_index
SET SESSION debug="+d,fault_injection_updating_index"; SET SESSION debug="+d,fault_injection_updating_index";
-- error ER_CANT_OPEN_FILE
flush logs; flush logs;
--chmod 0644 $INDEX
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval SET @index=LOAD_FILE('$index')
-- replace_regex /\.[\\\/]master/master/
SELECT @index;
--source include/restart_mysqld.inc --source include/restart_mysqld.inc
--chmod 0644 $INDEX --chmod 0644 $INDEX
......
...@@ -58,7 +58,8 @@ EOF ...@@ -58,7 +58,8 @@ EOF
# Assertion # Assertion
########### ###########
# assertion: should throw warning # assertion: should raise error
-- error ER_NO_UNIQUE_LOGFILE
FLUSH LOGS; FLUSH LOGS;
############## ##############
......
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
#######################################################################
####################### PART 1: MASTER TESTS ##########################
#######################################################################
include/stop_slave.inc
call mtr.add_suppression("Can't generate a unique log-filename");
call mtr.add_suppression("Writing one row to the row-based binary log failed.*");
call mtr.add_suppression("Error writing file .*");
SET @old_debug= @@global.debug;
SELECT repeat('x',8192) INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data';
SELECT repeat('x',10) INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug_46166-2.data';
RESET MASTER;
###################### TEST #1
FLUSH LOGS;
# assert: must show two binlogs
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
###################### TEST #2
RESET MASTER;
SET GLOBAL debug="+d,error_unique_log_filename";
FLUSH LOGS;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# assert: must show one binlog
show binary logs;
Log_name File_size
master-bin.000001 #
SET GLOBAL debug="";
RESET MASTER;
###################### TEST #3
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a TEXT) Engine=InnoDB;
CREATE TABLE t4 (a TEXT);
INSERT INTO t1 VALUES (1);
RESET MASTER;
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t2;
# assert: must show two binlog
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
###################### TEST #4
SET GLOBAL debug="+d,error_unique_log_filename";
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t2;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# assert: must show one entry
SELECT count(*) FROM t2;
count(*)
1
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
###################### TEST #5
SET GLOBAL debug="+d,error_unique_log_filename";
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166-2.data' INTO TABLE t2;
# assert: must show one entry
SELECT count(*) FROM t2;
count(*)
1
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
###################### TEST #6
SET GLOBAL debug="+d,error_unique_log_filename";
SET AUTOCOMMIT=0;
INSERT INTO t2 VALUES ('muse');
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t2;
INSERT INTO t2 VALUES ('muse');
COMMIT;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# assert: must show three entries
SELECT count(*) FROM t2;
count(*)
3
SET AUTOCOMMIT= 1;
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
###################### TEST #7
SET GLOBAL debug="+d,error_unique_log_filename";
SELECT count(*) FROM t4;
count(*)
0
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t4;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# assert: must show 1 entry
SELECT count(*) FROM t4;
count(*)
1
### check that the incident event is written to the current log
SET GLOBAL debug="-d,error_unique_log_filename";
FLUSH LOGS;
SHOW BINLOG EVENTS IN 'BINLOG_FILE' FROM <binlog_start> LIMIT 1;
Log_name Pos Event_type Server_id End_log_pos Info
BINLOG_FILE # Incident # # #1 (LOST_EVENTS)
DELETE FROM t4;
RESET MASTER;
###################### TEST #8
SET GLOBAL debug="+d,error_unique_log_filename";
# must show 0 entries
SELECT count(*) FROM t4;
count(*)
0
SELECT count(*) FROM t2;
count(*)
0
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t4;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug_46166.data' INTO TABLE t2;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc');
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# INFO: Count(*) Before Offending DELETEs
# assert: must show 1 entry
SELECT count(*) FROM t4;
count(*)
1
# assert: must show 4 entries
SELECT count(*) FROM t2;
count(*)
4
DELETE FROM t4;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
DELETE FROM t2;
ERROR HY000: Can't generate a unique log-filename master-bin.(1-999)
# INFO: Count(*) After Offending DELETEs
# assert: must show zero entries
SELECT count(*) FROM t4;
count(*)
0
SELECT count(*) FROM t2;
count(*)
0
SET GLOBAL debug="-d,error_unique_log_filename";
###################### TEST #9
SET GLOBAL debug="+d,error_unique_log_filename";
SET SQL_LOG_BIN=0;
INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc'), ('ddd');
INSERT INTO t4 VALUES ('eee'), ('fff'), ('ggg'), ('hhh');
# assert: must show four entries
SELECT count(*) FROM t2;
count(*)
4
SELECT count(*) FROM t4;
count(*)
4
DELETE FROM t2;
DELETE FROM t4;
# assert: must show zero entries
SELECT count(*) FROM t2;
count(*)
0
SELECT count(*) FROM t4;
count(*)
0
SET SQL_LOG_BIN=1;
SET GLOBAL debug="-d,error_unique_log_filename";
###################### TEST #10
call mtr.add_suppression("MSYQL_BIN_LOG::open failed to sync the index file.");
call mtr.add_suppression("Could not open .*");
RESET MASTER;
SHOW WARNINGS;
Level Code Message
SET GLOBAL debug="+d,fault_injection_registering_index";
FLUSH LOGS;
ERROR HY000: Can't open file: './master-bin.000002' (errno: 1)
SET GLOBAL debug="-d,fault_injection_registering_index";
SHOW BINARY LOGS;
ERROR HY000: You are not using binary logging
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
###################### TEST #11
SET GLOBAL debug="+d,fault_injection_openning_index";
FLUSH LOGS;
ERROR HY000: Can't open file: './master-bin.index' (errno: 1)
SET GLOBAL debug="-d,fault_injection_openning_index";
RESET MASTER;
ERROR HY000: Binlog closed, cannot RESET MASTER
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
###################### TEST #12
SET GLOBAL debug="+d,fault_injection_new_file_rotate_event";
FLUSH LOGS;
ERROR HY000: Can't open file: 'master-bin' (errno: 0)
SET GLOBAL debug="-d,fault_injection_new_file_rotate_event";
RESET MASTER;
ERROR HY000: Binlog closed, cannot RESET MASTER
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
SET GLOBAL debug= @old_debug;
DROP TABLE t1, t2, t4;
RESET MASTER;
include/start_slave.inc
#######################################################################
####################### PART 2: SLAVE TESTS ###########################
#######################################################################
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master.*");
call mtr.add_suppression("Error writing file .*");
call mtr.add_suppression("Could not open .*");
call mtr.add_suppression("MSYQL_BIN_LOG::open failed to sync the index file.");
call mtr.add_suppression("Can't generate a unique log-filename .*");
###################### TEST #13
SET @old_debug=@@global.debug;
include/stop_slave.inc
SET GLOBAL debug="+d,error_unique_log_filename";
START SLAVE io_thread;
Last_IO_Error = Relay log write failure: could not queue event from master
SET GLOBAL debug="-d,error_unique_log_filename";
SET GLOBAL debug=@old_debug;
###################### TEST #14
SET @old_debug=@@global.debug;
include/stop_slave.inc
SET GLOBAL debug="+d,fault_injection_new_file_rotate_event";
START SLAVE io_thread;
Last_IO_Error = Relay log write failure: could not queue event from master
SET GLOBAL debug="-d,fault_injection_new_file_rotate_event";
SET GLOBAL debug=@old_debug;
###################### TEST #15
SET @old_debug=@@global.debug;
include/stop_slave.inc
SET GLOBAL debug="+d,fault_injection_registering_index";
START SLAVE io_thread;
Last_IO_Error = Relay log write failure: could not queue event from master
SET GLOBAL debug="-d,fault_injection_registering_index";
SET GLOBAL debug=@old_debug;
###################### TEST #16
SET @old_debug=@@global.debug;
include/stop_slave.inc
SET GLOBAL debug="+d,fault_injection_openning_index";
START SLAVE io_thread;
Last_IO_Error = Relay log write failure: could not queue event from master
SET GLOBAL debug="-d,fault_injection_openning_index";
SET GLOBAL debug=@old_debug;
include/stop_slave.inc
SET GLOBAL debug=@old_debug;
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
# BUG#46166: MYSQL_BIN_LOG::new_file_impl is not propagating error
# when generating new name.
#
# WHY
# ===
#
# We want to check whether error is reported or not when
# new_file_impl fails (this may happen when rotation is not
# possible because there is some problem finding an
# unique filename).
#
# HOW
# ===
#
# Test cases are documented inline.
-- source include/master-slave.inc
-- source include/have_innodb.inc
-- source include/have_debug.inc
-- echo #######################################################################
-- echo ####################### PART 1: MASTER TESTS ##########################
-- echo #######################################################################
### ACTION: stopping slave as it is not needed for the first part of
### the test
-- connection slave
-- source include/stop_slave.inc
-- connection master
call mtr.add_suppression("Can't generate a unique log-filename");
call mtr.add_suppression("Writing one row to the row-based binary log failed.*");
call mtr.add_suppression("Error writing file .*");
SET @old_debug= @@global.debug;
### ACTION: create a large file (> 4096 bytes) that will be later used
### in LOAD DATA INFILE to check binlog errors in its vacinity
-- let $load_file= $MYSQLTEST_VARDIR/tmp/bug_46166.data
-- let $MYSQLD_DATADIR= `select @@datadir`
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval SELECT repeat('x',8192) INTO OUTFILE '$load_file'
### ACTION: create a small file (< 4096 bytes) that will be later used
### in LOAD DATA INFILE to check for absence of binlog errors
### when file loading this file does not force flushing and
### rotating the binary log
-- let $load_file2= $MYSQLTEST_VARDIR/tmp/bug_46166-2.data
-- let $MYSQLD_DATADIR= `select @@datadir`
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval SELECT repeat('x',10) INTO OUTFILE '$load_file2'
RESET MASTER;
-- echo ###################### TEST #1
### ASSERTION: no problem flushing logs (should show two binlogs)
FLUSH LOGS;
-- echo # assert: must show two binlogs
-- source include/show_binary_logs.inc
-- echo ###################### TEST #2
### ASSERTION: check that FLUSH LOGS actually fails and reports
### failure back to the user if find_uniq_filename fails
### (should show just one binlog)
RESET MASTER;
SET GLOBAL debug="+d,error_unique_log_filename";
-- error ER_NO_UNIQUE_LOGFILE
FLUSH LOGS;
-- echo # assert: must show one binlog
-- source include/show_binary_logs.inc
### ACTION: clean up and move to next test
SET GLOBAL debug="";
RESET MASTER;
-- echo ###################### TEST #3
### ACTION: create some tables (t1, t2, t4) and insert some values in
### table t1
CREATE TABLE t1 (a int);
CREATE TABLE t2 (a TEXT) Engine=InnoDB;
CREATE TABLE t4 (a TEXT);
INSERT INTO t1 VALUES (1);
RESET MASTER;
### ASSERTION: we force rotation of the binary log because it exceeds
### the max_binlog_size option (should show two binary
### logs)
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2
# shows two binary logs
-- echo # assert: must show two binlog
-- source include/show_binary_logs.inc
# clean up the table and the binlog to be used in next part of test
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
-- echo ###################### TEST #4
### ASSERTION: load the big file into a transactional table and check
### that it reports error. The table will contain the
### changes performed despite the fact that it reported an
### error.
SET GLOBAL debug="+d,error_unique_log_filename";
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- error ER_NO_UNIQUE_LOGFILE
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2
# show table
-- echo # assert: must show one entry
SELECT count(*) FROM t2;
# clean up the table and the binlog to be used in next part of test
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
-- echo ###################### TEST #5
### ASSERTION: load the small file into a transactional table and
### check that it succeeds
SET GLOBAL debug="+d,error_unique_log_filename";
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval LOAD DATA INFILE '$load_file2' INTO TABLE t2
# show table
-- echo # assert: must show one entry
SELECT count(*) FROM t2;
# clean up the table and the binlog to be used in next part of test
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
-- echo ###################### TEST #6
### ASSERTION: check that even if one is using a transactional table
### and explicit transactions (no autocommit) if rotation
### fails we get the error. Transaction is not rolledback
### because rotation happens after the commit.
SET GLOBAL debug="+d,error_unique_log_filename";
SET AUTOCOMMIT=0;
INSERT INTO t2 VALUES ('muse');
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2
INSERT INTO t2 VALUES ('muse');
-- error ER_NO_UNIQUE_LOGFILE
COMMIT;
### ACTION: Show the contents of the table after the test
-- echo # assert: must show three entries
SELECT count(*) FROM t2;
### ACTION: clean up and move to the next test
SET AUTOCOMMIT= 1;
SET GLOBAL debug="-d,error_unique_log_filename";
DELETE FROM t2;
RESET MASTER;
-- echo ###################### TEST #7
### ASSERTION: check that on a non-transactional table, if rotation
### fails then an error is reported and an incident event
### is written to the current binary log.
SET GLOBAL debug="+d,error_unique_log_filename";
SELECT count(*) FROM t4;
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- error ER_NO_UNIQUE_LOGFILE
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t4
-- echo # assert: must show 1 entry
SELECT count(*) FROM t4;
-- echo ### check that the incident event is written to the current log
SET GLOBAL debug="-d,error_unique_log_filename";
-- let $binlog_start= query_get_value(SHOW MASTER STATUS, Position, 1)
-- let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
# 53 is the size of the incident event, so we start from 22 bytes before the
# current position
-- let $binlog_start = `SELECT $binlog_start - 53`
FLUSH LOGS;
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start <binlog_start> $binlog_file BINLOG_FILE
-- replace_column 2 # 4 # 5 #
-- eval SHOW BINLOG EVENTS IN '$binlog_file' FROM $binlog_start LIMIT 1
# clean up and move to next test
DELETE FROM t4;
RESET MASTER;
-- echo ###################### TEST #8
### ASSERTION: check that statements end up in error but they succeed
### on changing the data.
SET GLOBAL debug="+d,error_unique_log_filename";
-- echo # must show 0 entries
SELECT count(*) FROM t4;
SELECT count(*) FROM t2;
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- error ER_NO_UNIQUE_LOGFILE
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t4
-- replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
-- error ER_NO_UNIQUE_LOGFILE
-- eval LOAD DATA INFILE '$load_file' INTO TABLE t2
-- error ER_NO_UNIQUE_LOGFILE
INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc');
-- echo # INFO: Count(*) Before Offending DELETEs
-- echo # assert: must show 1 entry
SELECT count(*) FROM t4;
-- echo # assert: must show 4 entries
SELECT count(*) FROM t2;
-- error ER_NO_UNIQUE_LOGFILE
DELETE FROM t4;
-- error ER_NO_UNIQUE_LOGFILE
DELETE FROM t2;
-- echo # INFO: Count(*) After Offending DELETEs
-- echo # assert: must show zero entries
SELECT count(*) FROM t4;
SELECT count(*) FROM t2;
# remove fault injection
SET GLOBAL debug="-d,error_unique_log_filename";
-- echo ###################### TEST #9
### ASSERTION: check that if we disable binlogging, then statements
### succeed.
SET GLOBAL debug="+d,error_unique_log_filename";
SET SQL_LOG_BIN=0;
INSERT INTO t2 VALUES ('aaa'), ('bbb'), ('ccc'), ('ddd');
INSERT INTO t4 VALUES ('eee'), ('fff'), ('ggg'), ('hhh');
-- echo # assert: must show four entries
SELECT count(*) FROM t2;
SELECT count(*) FROM t4;
DELETE FROM t2;
DELETE FROM t4;
-- echo # assert: must show zero entries
SELECT count(*) FROM t2;
SELECT count(*) FROM t4;
SET SQL_LOG_BIN=1;
SET GLOBAL debug="-d,error_unique_log_filename";
-- echo ###################### TEST #10
### ASSERTION: check that error is reported if there is a failure
### while registering the index file and the binary log
### file or failure to write the rotate event.
call mtr.add_suppression("MSYQL_BIN_LOG::open failed to sync the index file.");
call mtr.add_suppression("Could not open .*");
RESET MASTER;
SHOW WARNINGS;
# +d,fault_injection_registering_index => injects fault on MYSQL_BIN_LOG::open
SET GLOBAL debug="+d,fault_injection_registering_index";
-- error ER_CANT_OPEN_FILE
FLUSH LOGS;
SET GLOBAL debug="-d,fault_injection_registering_index";
-- error ER_NO_BINARY_LOGGING
SHOW BINARY LOGS;
# issue some statements and check that they don't fail
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
-- echo ###################### TEST #11
### ASSERTION: check that error is reported if there is a failure
### while opening the index file and the binary log file or
### failure to write the rotate event.
# restart the server so that we have binlog again
--source include/restart_mysqld.inc
# +d,fault_injection_openning_index => injects fault on MYSQL_BIN_LOG::open_index_file
SET GLOBAL debug="+d,fault_injection_openning_index";
-- error ER_CANT_OPEN_FILE
FLUSH LOGS;
SET GLOBAL debug="-d,fault_injection_openning_index";
-- error ER_FLUSH_MASTER_BINLOG_CLOSED
RESET MASTER;
# issue some statements and check that they don't fail
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
# restart the server so that we have binlog again
-- source include/restart_mysqld.inc
-- echo ###################### TEST #12
### ASSERTION: check that error is reported if there is a failure
### while writing the rotate event when creating a new log
### file.
# +d,fault_injection_new_file_rotate_event => injects fault on MYSQL_BIN_LOG::MYSQL_BIN_LOG::new_file_impl
SET GLOBAL debug="+d,fault_injection_new_file_rotate_event";
-- error ER_ERROR_ON_WRITE
FLUSH LOGS;
SET GLOBAL debug="-d,fault_injection_new_file_rotate_event";
-- error ER_FLUSH_MASTER_BINLOG_CLOSED
RESET MASTER;
# issue some statements and check that they don't fail
CREATE TABLE t5 (a INT);
INSERT INTO t4 VALUES ('bbbbb');
INSERT INTO t2 VALUES ('aaaaa');
DELETE FROM t4;
DELETE FROM t2;
DROP TABLE t5;
# restart the server so that we have binlog again
-- source include/restart_mysqld.inc
## clean up
SET GLOBAL debug= @old_debug;
DROP TABLE t1, t2, t4;
RESET MASTER;
# restart slave again
-- connection slave
-- source include/start_slave.inc
-- connection master
-- echo #######################################################################
-- echo ####################### PART 2: SLAVE TESTS ###########################
-- echo #######################################################################
### setup
-- connection master
# master-slave-reset starts the slave automatically
-- source include/master-slave-reset.inc
-- connection slave
# slave suppressions
call mtr.add_suppression("Slave I/O: Relay log write failure: could not queue event from master.*");
call mtr.add_suppression("Error writing file .*");
call mtr.add_suppression("Could not open .*");
call mtr.add_suppression("MSYQL_BIN_LOG::open failed to sync the index file.");
call mtr.add_suppression("Can't generate a unique log-filename .*");
-- echo ###################### TEST #13
#### ASSERTION: check against unique log filename error
-- let $io_thd_injection_fault_flag= error_unique_log_filename
-- let $slave_io_errno= 1595
-- let $show_slave_io_error= 1
-- source include/io_thd_fault_injection.inc
-- echo ###################### TEST #14
#### ASSERTION: check against rotate failing
-- let $io_thd_injection_fault_flag= fault_injection_new_file_rotate_event
-- let $slave_io_errno= 1595
-- let $show_slave_io_error= 1
-- source include/io_thd_fault_injection.inc
-- echo ###################### TEST #15
#### ASSERTION: check against relay log open failure
-- let $io_thd_injection_fault_flag= fault_injection_registering_index
-- let $slave_io_errno= 1595
-- let $show_slave_io_error= 1
-- source include/io_thd_fault_injection.inc
-- echo ###################### TEST #16
#### ASSERTION: check against relay log index open failure
-- let $io_thd_injection_fault_flag= fault_injection_openning_index
-- let $slave_io_errno= 1595
-- let $show_slave_io_error= 1
-- source include/io_thd_fault_injection.inc
### clean up
-- disable_warnings
-- source include/stop_slave.inc
-- enable_warnings
SET GLOBAL debug=@old_debug;
RESET SLAVE;
RESET MASTER;
-- source include/start_slave.inc
-- connection master
-- source include/master-slave-end.inc
...@@ -1237,7 +1237,11 @@ int ha_commit_trans(THD *thd, bool all) ...@@ -1237,7 +1237,11 @@ int ha_commit_trans(THD *thd, bool all)
error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0; error=ha_commit_one_phase(thd, all) ? (cookie ? 2 : 1) : 0;
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE();); DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (cookie) if (cookie)
tc_log->unlog(cookie, xid); if(tc_log->unlog(cookie, xid))
{
error= 2;
goto end;
}
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE();); DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
RUN_HOOK(transaction, after_commit, (thd, FALSE)); RUN_HOOK(transaction, after_commit, (thd, FALSE));
end: end:
......
...@@ -2185,7 +2185,8 @@ static int find_uniq_filename(char *name) ...@@ -2185,7 +2185,8 @@ static int find_uniq_filename(char *name)
*end='.'; *end='.';
length= (size_t) (end - start + 1); length= (size_t) (end - start + 1);
if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT)))) if ((DBUG_EVALUATE_IF("error_unique_log_filename", 1,
!(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))))
{ // This shouldn't happen { // This shouldn't happen
strmov(end,".1"); // use name+1 strmov(end,".1"); // use name+1
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -2212,7 +2213,11 @@ updating the index files.", max_found); ...@@ -2212,7 +2213,11 @@ updating the index files.", max_found);
} }
next= max_found + 1; next= max_found + 1;
sprintf(ext_buf, "%06lu", next); if (sprintf(ext_buf, "%06lu", next)<0)
{
error= 1;
goto end;
}
*end++='.'; *end++='.';
/* /*
...@@ -2229,7 +2234,11 @@ index files.", name, ext_buf, (strlen(ext_buf) + (end - name))); ...@@ -2229,7 +2234,11 @@ index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
goto end; goto end;
} }
sprintf(end, "%06lu", next); if (sprintf(end, "%06lu", next)<0)
{
error= 1;
goto end;
}
/* print warning if reaching the end of available extensions. */ /* print warning if reaching the end of available extensions. */
if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT))) if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
...@@ -2462,13 +2471,8 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name) ...@@ -2462,13 +2471,8 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
{ {
if (find_uniq_filename(new_name)) if (find_uniq_filename(new_name))
{ {
/* my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
This should be treated as error once propagation of error further MYF(ME_FATALERROR), log_name);
up in the stack gets proper handling.
*/
push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
log_name);
sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name); sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
return 1; return 1;
} }
...@@ -3453,7 +3457,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd) ...@@ -3453,7 +3457,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
if (!thd->slave_thread) if (!thd->slave_thread)
need_start_event=1; need_start_event=1;
if (!open_index_file(index_file_name, 0, FALSE)) if (!open_index_file(index_file_name, 0, FALSE))
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE); if ((error= open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE)))
goto err;
my_free((void *) save_name); my_free((void *) save_name);
err: err:
...@@ -4118,17 +4123,23 @@ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg) ...@@ -4118,17 +4123,23 @@ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
incapsulation 3) allows external access to the class without incapsulation 3) allows external access to the class without
a lock (which is not possible with private new_file_without_locking a lock (which is not possible with private new_file_without_locking
method). method).
@retval
nonzero - error
*/ */
void MYSQL_BIN_LOG::new_file() int MYSQL_BIN_LOG::new_file()
{ {
new_file_impl(1); return new_file_impl(1);
} }
/*
void MYSQL_BIN_LOG::new_file_without_locking() @retval
nonzero - error
*/
int MYSQL_BIN_LOG::new_file_without_locking()
{ {
new_file_impl(0); return new_file_impl(0);
} }
...@@ -4137,19 +4148,23 @@ void MYSQL_BIN_LOG::new_file_without_locking() ...@@ -4137,19 +4148,23 @@ void MYSQL_BIN_LOG::new_file_without_locking()
@param need_lock Set to 1 if caller has not locked LOCK_log @param need_lock Set to 1 if caller has not locked LOCK_log
@retval
nonzero - error
@note @note
The new file name is stored last in the index file The new file name is stored last in the index file
*/ */
void MYSQL_BIN_LOG::new_file_impl(bool need_lock) int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
{ {
char new_name[FN_REFLEN], *new_name_ptr, *old_name; int error= 0, close_on_error= FALSE;
char new_name[FN_REFLEN], *new_name_ptr, *old_name, *file_to_open;
DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl"); DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
if (!is_open()) if (!is_open())
{ {
DBUG_PRINT("info",("log is closed")); DBUG_PRINT("info",("log is closed"));
DBUG_VOID_RETURN; DBUG_RETURN(error);
} }
if (need_lock) if (need_lock)
...@@ -4187,7 +4202,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) ...@@ -4187,7 +4202,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
We have to do this here and not in open as we want to store the We have to do this here and not in open as we want to store the
new file name in the current binary log file. new file name in the current binary log file.
*/ */
if (generate_new_name(new_name, name)) if ((error= generate_new_name(new_name, name)))
goto end; goto end;
new_name_ptr=new_name; new_name_ptr=new_name;
...@@ -4201,7 +4216,13 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) ...@@ -4201,7 +4216,13 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
*/ */
Rotate_log_event r(new_name+dirname_length(new_name), Rotate_log_event r(new_name+dirname_length(new_name),
0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0); 0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
r.write(&log_file); if(DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error=close_on_error=TRUE), FALSE) ||
(error= r.write(&log_file)))
{
close_on_error= TRUE;
my_printf_error(ER_ERROR_ON_WRITE, ER(ER_CANT_OPEN_FILE), MYF(ME_FATALERROR), name, errno);
goto end;
}
bytes_written += r.data_written; bytes_written += r.data_written;
} }
/* /*
...@@ -4229,17 +4250,56 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock) ...@@ -4229,17 +4250,56 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
*/ */
/* reopen index binlog file, BUG#34582 */ /* reopen index binlog file, BUG#34582 */
if (!open_index_file(index_file_name, 0, FALSE)) file_to_open= index_file_name;
open(old_name, log_type, new_name_ptr, error= open_index_file(index_file_name, 0, FALSE);
io_cache_type, no_auto_events, max_size, 1, FALSE); if (!error)
{
/* reopen the binary log file. */
file_to_open= new_name_ptr;
error= open(old_name, log_type, new_name_ptr, io_cache_type,
no_auto_events, max_size, 1, FALSE);
}
/* handle reopening errors */
if (error)
{
my_printf_error(ER_CANT_OPEN_FILE, ER(ER_CANT_OPEN_FILE),
MYF(ME_FATALERROR), file_to_open, error);
close_on_error= TRUE;
}
my_free(old_name); my_free(old_name);
end: end:
if (error && close_on_error /* rotate or reopen failed */)
{
/*
Close whatever was left opened.
We are keeping the behavior as it exists today, ie,
we disable logging and move on (see: BUG#51014).
TODO: as part of WL#1790 consider other approaches:
- kill mysql (safety);
- try multiple locations for opening a log file;
- switch server to protected/readonly mode
- ...
*/
close(LOG_CLOSE_INDEX);
sql_print_error("Could not open %s for logging (error %d). "
"Turning logging off for the whole duration "
"of the MySQL server process. To turn it on "
"again: fix the cause, shutdown the MySQL "
"server and restart it.",
new_name_ptr, errno);
}
if (need_lock) if (need_lock)
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
mysql_mutex_unlock(&LOCK_index); mysql_mutex_unlock(&LOCK_index);
DBUG_VOID_RETURN; DBUG_RETURN(error);
} }
...@@ -4264,8 +4324,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev) ...@@ -4264,8 +4324,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev)
if (flush_and_sync(0)) if (flush_and_sync(0))
goto err; goto err;
if ((uint) my_b_append_tell(&log_file) > max_size) if ((uint) my_b_append_tell(&log_file) > max_size)
new_file_without_locking(); error= new_file_without_locking();
err: err:
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
signal_update(); // Safe as we don't call close signal_update(); // Safe as we don't call close
...@@ -4296,8 +4355,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...) ...@@ -4296,8 +4355,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
if (flush_and_sync(0)) if (flush_and_sync(0))
goto err; goto err;
if ((uint) my_b_append_tell(&log_file) > max_size) if ((uint) my_b_append_tell(&log_file) > max_size)
new_file_without_locking(); error= new_file_without_locking();
err: err:
if (!error) if (!error)
signal_update(); signal_update();
...@@ -4920,7 +4978,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info) ...@@ -4920,7 +4978,6 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
goto err; goto err;
error= 0; error= 0;
err: err:
if (event_info->use_direct_logging()) if (event_info->use_direct_logging())
{ {
...@@ -5025,8 +5082,19 @@ bool general_log_write(THD *thd, enum enum_server_command command, ...@@ -5025,8 +5082,19 @@ bool general_log_write(THD *thd, enum enum_server_command command,
return FALSE; return FALSE;
} }
void MYSQL_BIN_LOG::rotate_and_purge(uint flags) /**
@note
If rotation fails, for instance the server was unable
to create a new log file, we still try to write an
incident event to the current log.
@retval
nonzero - error
*/
int MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{ {
int error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge");
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
bool check_purge= false; bool check_purge= false;
#endif #endif
...@@ -5035,26 +5103,38 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags) ...@@ -5035,26 +5103,38 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
if ((flags & RP_FORCE_ROTATE) || if ((flags & RP_FORCE_ROTATE) ||
(my_b_tell(&log_file) >= (my_off_t) max_size)) (my_b_tell(&log_file) >= (my_off_t) max_size))
{ {
new_file_without_locking(); if ((error= new_file_without_locking()))
/**
Be conservative... There are possible lost events (eg,
failing to log the Execute_load_query_log_event
on a LOAD DATA while using a non-transactional
table)!
We give it a shot and try to write an incident event anyway
to the current log.
*/
if (!write_incident(current_thd, FALSE))
flush_and_sync(0);
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
check_purge= true; check_purge= true;
#endif #endif
} }
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED)) if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
/* /*
NOTE: Run purge_logs wo/ holding LOCK_log NOTE: Run purge_logs wo/ holding LOCK_log
as it otherwise will deadlock in ndbcluster_binlog_index_purge_file as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
*/ */
if (check_purge && expire_logs_days) if (!error && check_purge && expire_logs_days)
{ {
time_t purge_time= my_time(0) - expire_logs_days*24*60*60; time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0) if (purge_time >= 0)
purge_logs_before_date(purge_time); purge_logs_before_date(purge_time);
} }
#endif #endif
DBUG_RETURN(error);
} }
uint MYSQL_BIN_LOG::next_file_id() uint MYSQL_BIN_LOG::next_file_id()
...@@ -5240,6 +5320,10 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) ...@@ -5240,6 +5320,10 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
{ {
uint error= 0; uint error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::write_incident"); DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
if (!is_open())
DBUG_RETURN(error);
LEX_STRING const write_error_msg= LEX_STRING const write_error_msg=
{ C_STRING_WITH_LEN("error writing to the binary log") }; { C_STRING_WITH_LEN("error writing to the binary log") };
Incident incident= INCIDENT_LOST_EVENTS; Incident incident= INCIDENT_LOST_EVENTS;
...@@ -5252,7 +5336,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock) ...@@ -5252,7 +5336,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
if (!error && !(error= flush_and_sync(0))) if (!error && !(error= flush_and_sync(0)))
{ {
signal_update(); signal_update();
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
} }
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
} }
...@@ -5361,7 +5445,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event, ...@@ -5361,7 +5445,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
mysql_mutex_unlock(&LOCK_prep_xids); mysql_mutex_unlock(&LOCK_prep_xids);
} }
else else
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); if (rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED))
goto err;
} }
mysql_mutex_unlock(&LOCK_log); mysql_mutex_unlock(&LOCK_log);
...@@ -6194,7 +6279,7 @@ int TC_LOG_MMAP::sync() ...@@ -6194,7 +6279,7 @@ int TC_LOG_MMAP::sync()
cookie points directly to the memory where xid was logged. cookie points directly to the memory where xid was logged.
*/ */
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
{ {
PAGE *p=pages+(cookie/tc_log_page_size); PAGE *p=pages+(cookie/tc_log_page_size);
my_xid *x=(my_xid *)(data+cookie); my_xid *x=(my_xid *)(data+cookie);
...@@ -6212,6 +6297,7 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid) ...@@ -6212,6 +6297,7 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
if (p->waiters == 0) // the page is in pool and ready to rock if (p->waiters == 0) // the page is in pool and ready to rock
mysql_cond_signal(&COND_pool); // ping ... for overflow() mysql_cond_signal(&COND_pool); // ping ... for overflow()
mysql_mutex_unlock(&p->lock); mysql_mutex_unlock(&p->lock);
return 0;
} }
void TC_LOG_MMAP::close() void TC_LOG_MMAP::close()
...@@ -6454,8 +6540,9 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid) ...@@ -6454,8 +6540,9 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
!binlog_commit_flush_trx_cache(thd, cache_mngr, xid)); !binlog_commit_flush_trx_cache(thd, cache_mngr, xid));
} }
void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
{ {
DBUG_ENTER("TC_LOG_BINLOG::unlog");
mysql_mutex_lock(&LOCK_prep_xids); mysql_mutex_lock(&LOCK_prep_xids);
DBUG_ASSERT(prepared_xids > 0); DBUG_ASSERT(prepared_xids > 0);
if (--prepared_xids == 0) { if (--prepared_xids == 0) {
...@@ -6463,7 +6550,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid) ...@@ -6463,7 +6550,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
mysql_cond_signal(&COND_prep_xids); mysql_cond_signal(&COND_prep_xids);
} }
mysql_mutex_unlock(&LOCK_prep_xids); mysql_mutex_unlock(&LOCK_prep_xids);
rotate_and_purge(0); // as ::write() did not rotate DBUG_RETURN(rotate_and_purge(0)); // as ::write() did not rotate
} }
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle) int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
......
...@@ -45,7 +45,7 @@ class TC_LOG ...@@ -45,7 +45,7 @@ class TC_LOG
virtual int open(const char *opt_name)=0; virtual int open(const char *opt_name)=0;
virtual void close()=0; virtual void close()=0;
virtual int log_xid(THD *thd, my_xid xid)=0; virtual int log_xid(THD *thd, my_xid xid)=0;
virtual void unlog(ulong cookie, my_xid xid)=0; virtual int unlog(ulong cookie, my_xid xid)=0;
}; };
class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging class TC_LOG_DUMMY: public TC_LOG // use it to disable the logging
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
int open(const char *opt_name) { return 0; } int open(const char *opt_name) { return 0; }
void close() { } void close() { }
int log_xid(THD *thd, my_xid xid) { return 1; } int log_xid(THD *thd, my_xid xid) { return 1; }
void unlog(ulong cookie, my_xid xid) { } int unlog(ulong cookie, my_xid xid) { return 0; }
}; };
#ifdef HAVE_MMAP #ifdef HAVE_MMAP
...@@ -100,7 +100,7 @@ class TC_LOG_MMAP: public TC_LOG ...@@ -100,7 +100,7 @@ class TC_LOG_MMAP: public TC_LOG
int open(const char *opt_name); int open(const char *opt_name);
void close(); void close();
int log_xid(THD *thd, my_xid xid); int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid); int unlog(ulong cookie, my_xid xid);
int recover(); int recover();
private: private:
...@@ -334,8 +334,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG ...@@ -334,8 +334,8 @@ class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
new_file() is locking. new_file_without_locking() does not acquire new_file() is locking. new_file_without_locking() does not acquire
LOCK_log. LOCK_log.
*/ */
void new_file_without_locking(); int new_file_without_locking();
void new_file_impl(bool need_lock); int new_file_impl(bool need_lock);
public: public:
MYSQL_LOG::generate_name; MYSQL_LOG::generate_name;
...@@ -365,7 +365,7 @@ public: ...@@ -365,7 +365,7 @@ public:
int open(const char *opt_name); int open(const char *opt_name);
void close(); void close();
int log_xid(THD *thd, my_xid xid); int log_xid(THD *thd, my_xid xid);
void unlog(ulong cookie, my_xid xid); int unlog(ulong cookie, my_xid xid);
int recover(IO_CACHE *log, Format_description_log_event *fdle); int recover(IO_CACHE *log, Format_description_log_event *fdle);
#if !defined(MYSQL_CLIENT) #if !defined(MYSQL_CLIENT)
...@@ -408,7 +408,7 @@ public: ...@@ -408,7 +408,7 @@ public:
bool open_index_file(const char *index_file_name_arg, bool open_index_file(const char *index_file_name_arg,
const char *log_name, bool need_mutex); const char *log_name, bool need_mutex);
/* Use this to start writing a new log file */ /* Use this to start writing a new log file */
void new_file(); int new_file();
bool write(Log_event* event_info); // binary log write bool write(Log_event* event_info); // binary log write
bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident); bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
...@@ -432,7 +432,7 @@ public: ...@@ -432,7 +432,7 @@ public:
void make_log_name(char* buf, const char* log_ident); void make_log_name(char* buf, const char* log_ident);
bool is_active(const char* log_file_name); bool is_active(const char* log_file_name);
int update_log_index(LOG_INFO* linfo, bool need_update_threads); int update_log_index(LOG_INFO* linfo, bool need_update_threads);
void rotate_and_purge(uint flags); int rotate_and_purge(uint flags);
/** /**
Flush binlog cache and synchronize to disk. Flush binlog cache and synchronize to disk.
......
...@@ -2736,7 +2736,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused))) ...@@ -2736,7 +2736,7 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
case SIGHUP: case SIGHUP:
if (!abort_loop) if (!abort_loop)
{ {
bool not_used; int not_used;
mysql_print_status(); // Print some debug info mysql_print_status(); // Print some debug info
reload_acl_and_cache((THD*) 0, reload_acl_and_cache((THD*) 0,
(REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST |
......
...@@ -237,8 +237,7 @@ int injector::record_incident(THD *thd, Incident incident) ...@@ -237,8 +237,7 @@ int injector::record_incident(THD *thd, Incident incident)
Incident_log_event ev(thd, incident); Incident_log_event ev(thd, incident);
if (int error= mysql_bin_log.write(&ev)) if (int error= mysql_bin_log.write(&ev))
return error; return error;
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
return 0;
} }
int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message) int injector::record_incident(THD *thd, Incident incident, LEX_STRING const message)
...@@ -246,6 +245,5 @@ int injector::record_incident(THD *thd, Incident incident, LEX_STRING const mess ...@@ -246,6 +245,5 @@ int injector::record_incident(THD *thd, Incident incident, LEX_STRING const mess
Incident_log_event ev(thd, incident, message); Incident_log_event ev(thd, incident, message);
if (int error= mysql_bin_log.write(&ev)) if (int error= mysql_bin_log.write(&ev))
return error; return error;
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); return mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE);
return 0;
} }
...@@ -523,7 +523,8 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock) ...@@ -523,7 +523,8 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
if (flush_master_info(mi, TRUE, FALSE)) if (flush_master_info(mi, TRUE, FALSE))
DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS); DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
if (my_sync(mi->rli.relay_log.get_log_file()->file, MYF(MY_WME))) if (mi->rli.relay_log.is_open() &&
my_sync(mi->rli.relay_log.get_log_file()->file, MYF(MY_WME)))
DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS); DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
if (my_sync(mi->fd, MYF(MY_WME))) if (my_sync(mi->fd, MYF(MY_WME)))
...@@ -3632,8 +3633,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev) ...@@ -3632,8 +3633,7 @@ static int process_io_rotate(Master_info *mi, Rotate_log_event *rev)
Rotate the relay log makes binlog format detection easier (at next slave Rotate the relay log makes binlog format detection easier (at next slave
start or mysqlbinlog) start or mysqlbinlog)
*/ */
rotate_relay_log(mi); /* will take the right mutexes */ DBUG_RETURN(rotate_relay_log(mi) /* will take the right mutexes */);
DBUG_RETURN(0);
} }
/* /*
...@@ -4870,12 +4870,13 @@ err: ...@@ -4870,12 +4870,13 @@ err:
is void). is void).
*/ */
void rotate_relay_log(Master_info* mi) int rotate_relay_log(Master_info* mi)
{ {
DBUG_ENTER("rotate_relay_log"); DBUG_ENTER("rotate_relay_log");
Relay_log_info* rli= &mi->rli; Relay_log_info* rli= &mi->rli;
int error= 0;
DBUG_EXECUTE_IF("crash_before_rotate_relaylog", abort();); DBUG_EXECUTE_IF("crash_before_rotate_relaylog", DBUG_SUICIDE(););
/* /*
We need to test inited because otherwise, new_file() will attempt to lock We need to test inited because otherwise, new_file() will attempt to lock
...@@ -4888,7 +4889,8 @@ void rotate_relay_log(Master_info* mi) ...@@ -4888,7 +4889,8 @@ void rotate_relay_log(Master_info* mi)
} }
/* If the relay log is closed, new_file() will do nothing. */ /* If the relay log is closed, new_file() will do nothing. */
rli->relay_log.new_file(); if ((error= rli->relay_log.new_file()))
goto end;
/* /*
We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately
...@@ -4905,7 +4907,7 @@ void rotate_relay_log(Master_info* mi) ...@@ -4905,7 +4907,7 @@ void rotate_relay_log(Master_info* mi)
*/ */
rli->relay_log.harvest_bytes_written(&rli->log_space_total); rli->relay_log.harvest_bytes_written(&rli->log_space_total);
end: end:
DBUG_VOID_RETURN; DBUG_RETURN(error);
} }
......
...@@ -205,7 +205,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset, ...@@ -205,7 +205,7 @@ int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
const char** errmsg); const char** errmsg);
void set_slave_thread_options(THD* thd); void set_slave_thread_options(THD* thd);
void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli); void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
void rotate_relay_log(Master_info* mi); int rotate_relay_log(Master_info* mi);
int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli); int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli);
pthread_handler_t handle_slave_io(void *arg); pthread_handler_t handle_slave_io(void *arg);
......
...@@ -625,6 +625,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -625,6 +625,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
transactional_table, transactional_table,
errcode); errcode);
} }
/*
Flushing the IO CACHE while writing the execute load query log event
may result in error (for instance, because the max_binlog_size has been
reached, and rotation of the binary log failed).
*/
error= error || mysql_bin_log.get_log_file()->error;
} }
if (error) if (error)
goto err; goto err;
......
...@@ -1218,7 +1218,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1218,7 +1218,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif #endif
case COM_REFRESH: case COM_REFRESH:
{ {
bool not_used; int not_used;
status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]); status_var_increment(thd->status_var.com_stat[SQLCOM_FLUSH]);
ulong options= (ulong) (uchar) packet[0]; ulong options= (ulong) (uchar) packet[0];
if (trans_commit_implicit(thd)) if (trans_commit_implicit(thd))
...@@ -2780,7 +2780,11 @@ end_with_restore_list: ...@@ -2780,7 +2780,11 @@ end_with_restore_list:
{ {
Incident_log_event ev(thd, incident); Incident_log_event ev(thd, incident);
(void) mysql_bin_log.write(&ev); /* error is ignored */ (void) mysql_bin_log.write(&ev); /* error is ignored */
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE))
{
res= 1;
break;
}
} }
DBUG_PRINT("debug", ("Just after generate_incident()")); DBUG_PRINT("debug", ("Just after generate_incident()"));
} }
...@@ -3516,8 +3520,7 @@ end_with_restore_list: ...@@ -3516,8 +3520,7 @@ end_with_restore_list:
lex->no_write_to_binlog= 1; lex->no_write_to_binlog= 1;
case SQLCOM_FLUSH: case SQLCOM_FLUSH:
{ {
bool write_to_binlog; int write_to_binlog;
if (check_global_access(thd,RELOAD_ACL)) if (check_global_access(thd,RELOAD_ACL))
goto error; goto error;
...@@ -3546,11 +3549,21 @@ end_with_restore_list: ...@@ -3546,11 +3549,21 @@ end_with_restore_list:
/* /*
Presumably, RESET and binlog writing doesn't require synchronization Presumably, RESET and binlog writing doesn't require synchronization
*/ */
if (!lex->no_write_to_binlog && write_to_binlog)
if (write_to_binlog > 0) // we should write
{ {
if ((res= write_bin_log(thd, FALSE, thd->query(), thd->query_length()))) if (!lex->no_write_to_binlog)
break; res= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
} else if (write_to_binlog < 0)
{
/*
We should not write, but rather report error because
reload_acl_and_cache binlog interactions failed
*/
res= 1;
} }
if (!res)
my_ok(thd); my_ok(thd);
} }
......
...@@ -33,7 +33,11 @@ ...@@ -33,7 +33,11 @@
@param thd Thread handler (can be NULL!) @param thd Thread handler (can be NULL!)
@param options What should be reset/reloaded (tables, privileges, slave...) @param options What should be reset/reloaded (tables, privileges, slave...)
@param tables Tables to flush (if any) @param tables Tables to flush (if any)
@param write_to_binlog True if we can write to the binlog. @param write_to_binlog < 0 if there was an error while interacting with the binary log inside
reload_acl_and_cache,
0 if we should not write to the binary log,
> 0 if we can write to the binlog.
@note Depending on 'options', it may be very bad to write the @note Depending on 'options', it may be very bad to write the
query to the binlog (e.g. FLUSH SLAVE); this is a query to the binlog (e.g. FLUSH SLAVE); this is a
...@@ -47,11 +51,11 @@ ...@@ -47,11 +51,11 @@
*/ */
bool reload_acl_and_cache(THD *thd, unsigned long options, bool reload_acl_and_cache(THD *thd, unsigned long options,
TABLE_LIST *tables, bool *write_to_binlog) TABLE_LIST *tables, int *write_to_binlog)
{ {
bool result=0; bool result=0;
select_errors=0; /* Write if more errors */ select_errors=0; /* Write if more errors */
bool tmp_write_to_binlog= 1; int tmp_write_to_binlog= *write_to_binlog= 1;
DBUG_ASSERT(!thd || !thd->in_sub_stmt); DBUG_ASSERT(!thd || !thd->in_sub_stmt);
...@@ -136,13 +140,17 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, ...@@ -136,13 +140,17 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
*/ */
tmp_write_to_binlog= 0; tmp_write_to_binlog= 0;
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE); {
if (mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE))
*write_to_binlog= -1;
}
} }
if (options & REFRESH_RELAY_LOG) if (options & REFRESH_RELAY_LOG)
{ {
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
mysql_mutex_lock(&LOCK_active_mi); mysql_mutex_lock(&LOCK_active_mi);
rotate_relay_log(active_mi); if (rotate_relay_log(active_mi))
*write_to_binlog= -1;
mysql_mutex_unlock(&LOCK_active_mi); mysql_mutex_unlock(&LOCK_active_mi);
#endif #endif
} }
...@@ -274,6 +282,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options, ...@@ -274,6 +282,7 @@ bool reload_acl_and_cache(THD *thd, unsigned long options,
#endif #endif
if (options & REFRESH_USER_RESOURCES) if (options & REFRESH_USER_RESOURCES)
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */ reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
if (*write_to_binlog != -1)
*write_to_binlog= tmp_write_to_binlog; *write_to_binlog= tmp_write_to_binlog;
/* /*
If the query was killed then this function must fail. If the query was killed then this function must fail.
......
...@@ -19,7 +19,7 @@ class THD; ...@@ -19,7 +19,7 @@ class THD;
struct TABLE_LIST; struct TABLE_LIST;
bool reload_acl_and_cache(THD *thd, unsigned long options, bool reload_acl_and_cache(THD *thd, unsigned long options,
TABLE_LIST *tables, bool *write_to_binlog); TABLE_LIST *tables, int *write_to_binlog);
bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables); bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables);
......
...@@ -1925,7 +1925,7 @@ bool show_binlogs(THD* thd) ...@@ -1925,7 +1925,7 @@ bool show_binlogs(THD* thd)
if (!mysql_bin_log.is_open()) if (!mysql_bin_log.is_open())
{ {
my_message(ER_NO_BINARY_LOGGING, ER(ER_NO_BINARY_LOGGING), MYF(0)); my_error(ER_NO_BINARY_LOGGING, MYF(0));
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment