Commit 284f5247 authored by unknown's avatar unknown

Merge MWL#180, binlog checksum backport, into MariaDB 5.3-based tree.

parents 8ac88c88 014b8e7f
......@@ -336,6 +336,7 @@ client/rpl_record_old.h
client/rpl_tblmap.h
client/rpl_tblmap.cc
client/rpl_utility.h
client/rpl_utility.cc
client/select_test
client/sql_string.cpp
client/ssl_test
......@@ -672,6 +673,8 @@ libmysqld/unireg.cc
libmysqld/discover_xt.cc
libmysqld/ha_pbxt.cc
libmysqld/myxt_xt.cc
libmysqld/rpl_reporting.cc
libmysqld/rpl_utility.cc
libmysqltest/*.ds?
libmysqltest/*.vcproj
libmysqltest/mytest.c
......
......@@ -63,7 +63,8 @@ mysqlbinlog_SOURCES = mysqlbinlog.cc \
$(top_srcdir)/mysys/my_bit.c \
$(top_srcdir)/mysys/my_bitmap.c \
$(top_srcdir)/mysys/my_vle.c \
$(top_srcdir)/mysys/base64.c
$(top_srcdir)/mysys/base64.c \
$(top_srcdir)/mysys/checksum.c
mysqlbinlog_LDADD = $(LDADD) $(CXXLDFLAGS)
mysqldump_SOURCES= mysqldump.c \
......@@ -106,6 +107,7 @@ sql_src=log_event.h mysql_priv.h rpl_constants.h \
log_event.cc my_decimal.h my_decimal.cc \
log_event_old.h log_event_old.cc \
rpl_record_old.h rpl_record_old.cc \
rpl_utility.h rpl_utility.cc \
sql_list.h rpl_filter.h sql_list.cc rpl_filter.cc
strings_src=decimal.c strings_def.h
......
......@@ -84,6 +84,7 @@ static const char* database= 0;
static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
static my_bool debug_info_flag, debug_check_flag;
static my_bool force_if_open_opt= 1;
static my_bool opt_verify_binlog_checksum= 1;
static ulonglong offset = 0;
static const char* host = 0;
static int port= 0;
......@@ -164,7 +165,8 @@ Log_event* read_remote_annotate_event(uchar* net_buf, ulong event_len,
event_buf[event_len]= 0;
if (!(event= Log_event::read_log_event((const char*) event_buf, event_len,
error_msg, glob_description_event)))
error_msg, glob_description_event,
opt_verify_binlog_checksum)))
{
my_free(event_buf, MYF(0));
return 0;
......@@ -1311,6 +1313,9 @@ that may lead to an endless loop.",
"Used to reserve file descriptors for use by this program.",
&open_files_limit, &open_files_limit, 0, GET_ULONG,
REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
{"verify-binlog-checksum", 'c', "Verify checksum binlog events.",
(uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"rewrite-db", OPT_REWRITE_DB,
"Updates to a database with a different name than the original. \
Example: rewrite-db='from->to'.",
......@@ -1709,7 +1714,18 @@ static Exit_status check_master_version()
"Master reported NULL for the version.");
goto err;
}
/*
Make a notice to the server that this client
is checksum-aware. It does not need the first fake Rotate
necessary checksummed.
That preference is specified below.
*/
if (mysql_query(mysql, "SET @master_binlog_checksum='NONE'"))
{
error("Could not notify master about checksum awareness."
"Master returned '%s'", mysql_error(mysql));
goto err;
}
delete glob_description_event;
switch (*version) {
case '3':
......@@ -1838,7 +1854,8 @@ static Exit_status dump_remote_log_entries(PRINT_EVENT_INFO *print_event_info,
{
if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
len - 1, &error_msg,
glob_description_event)))
glob_description_event,
opt_verify_binlog_checksum)))
{
error("Could not construct log event object: %s", error_msg);
DBUG_RETURN(ERROR_STOP);
......@@ -2066,7 +2083,8 @@ static Exit_status check_header(IO_CACHE* file,
Format_description_log_event *new_description_event;
my_b_seek(file, tmp_pos); /* seek back to event's start */
if (!(new_description_event= (Format_description_log_event*)
Log_event::read_log_event(file, glob_description_event)))
Log_event::read_log_event(file, glob_description_event,
opt_verify_binlog_checksum)))
/* EOF can't be hit here normally, so it's a real error */
{
error("Could not read a Format_description_log_event event at "
......@@ -2099,7 +2117,8 @@ static Exit_status check_header(IO_CACHE* file,
{
Log_event *ev;
my_b_seek(file, tmp_pos); /* seek back to event's start */
if (!(ev= Log_event::read_log_event(file, glob_description_event)))
if (!(ev= Log_event::read_log_event(file, glob_description_event,
opt_verify_binlog_checksum)))
{
/* EOF can't be hit here normally, so it's a real error */
error("Could not read a Rotate_log_event event at offset %llu;"
......@@ -2212,7 +2231,8 @@ static Exit_status dump_local_log_entries(PRINT_EVENT_INFO *print_event_info,
char llbuff[21];
my_off_t old_off = my_b_tell(file);
Log_event* ev = Log_event::read_log_event(file, glob_description_event);
Log_event* ev = Log_event::read_log_event(file, glob_description_event,
opt_verify_binlog_checksum);
if (!ev)
{
/*
......@@ -2391,4 +2411,4 @@ void *sql_alloc(size_t size)
#include "sql_string.cc"
#include "sql_list.cc"
#include "rpl_filter.cc"
#include "rpl_utility.cc"
......@@ -143,7 +143,8 @@ SET(LIBMYSQLD_SOURCES libmysqld.c emb_qcache.cc lib_sql.cc
../sql/multi_range_read.cc
../sql/opt_index_cond_pushdown.cc
../sql/opt_subselect.cc
../sql/create_options.cc
../sql/create_options.cc ../sql/rpl_utility.cc
../sql/rpl_reporting.cc
../sql/sql_expression_cache.cc
${GEN_SOURCES}
${LIB_SOURCES})
......
......@@ -55,7 +55,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
item_geofunc.cc item_subselect.cc item_row.cc\
item_xmlfunc.cc \
key.cc lock.cc log.cc sql_state.c \
log_event.cc rpl_record.cc \
log_event.cc rpl_record.cc rpl_utility.cc rpl_reporting.cc \
log_event_old.cc rpl_record_old.cc \
protocol.cc net_serv.cc opt_range.cc \
opt_subselect.cc \
......
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_checksum --mysqld=--binlog-checksum=CRC32 --vardir=var-rpl_binlog_checksum --suite=binlog,rpl --skip-test-list=collections/disabled-per-push.list
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema --skip-test-list=collections/disabled-per-push.list
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-test-list=collections/disabled-per-push.list
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=n_mix --vardir=var-n_mix --mysqld=--binlog-format=mixed
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=ps_row --vardir=var-ps_row --ps-protocol --mysqld=--binlog-format=row
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=embedded --vardir=var-emebbed --embedded
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=funcs_1 --vardir=var-funcs_1 --suite=funcs_1
perl mysql-test-run.pl --timer --force --parallel=auto --comment=rpl_ndb_row --vardir=var-rpl_ndb_row --mysqld=--binlog-format=row --suite=rpl_ndb,ndb
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_row --vardir=var-rpl_binlog_row --mysqld=--binlog-format=row --suite=rpl,binlog --skip-ndb
perl mysql-test-run.pl --timer --force --parallel=auto --experimental=collections/default.experimental --comment=rpl_binlog_checksum --mysqld=--binlog-checksum=CRC32 --vardir=var-rpl_binlog_checksum --suite=binlog,rpl
perl mysql-test-run.pl --timer --force --comment=1st --experimental=collections/default.experimental 1st
perl mysql-test-run.pl --timer --force --comment=all_binlog_checksum --experimental=collections/default.experimental --mysqld=--binlog-checksum=CRC32 --vardir=var-all_binlog_checksum --suite=main,binlog,innodb,federated,rpl,sys_vars,perfschema
......@@ -83,17 +83,22 @@ set @bcs = @@binlog_cache_size;
set global binlog_cache_size=4096;
reset master;
create table t1 (a int) engine=innodb;
create table t1 (a int, b char(255)) engine=innodb;
flush status;
show status like "binlog_cache_use";
let $1=400;
let $1=100;
disable_query_log;
begin;
while ($1)
{
eval insert into t1 values( $1 );
eval insert into t1 values( $1, 'just to fill void to make transaction occupying at least two buffers of the trans cache' );
dec $1;
}
commit;
--echo *** the following must show the counter value = 1 ***
show status like "binlog_cache_use";
enable_query_log;
--source include/show_binlog_events.inc
......
......@@ -311,6 +311,7 @@ select get_lock("a",10);
begin;
insert into t1 values(8);
insert into t2 select * from t1;
disconnect con3;
connection con4;
......
......@@ -15,6 +15,7 @@ create table t3 (a int) engine=merge union(t1);
create table t4 (a int);
# We force the slave to open t3 (because we want to try confusing him) with this :
insert into t4 select * from t3;
--let $rename_event_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
rename table t1 to t5, t2 to t1;
# RENAME may have confused the master (this is a known bug): so FLUSH tables,
# first don't write it to the binlog, to test the NO_WRITE_TO_BINLOG keyword.
......
......@@ -10,6 +10,9 @@
-- source include/master-slave.inc
sync_slave_with_master;
--disable_query_log
call mtr.add_suppression('Slave I/O: Get master BINLOG_CHECKSUM failed with error');
--enable_query_log
let $status_items= Master_User, Master_Host;
source include/show_slave_status.inc;
......
......@@ -11,16 +11,18 @@
# Format_description_log_event length =
# 19 /* event common header */ +
# 57 /* misc stuff in the Format description header */ +
# number of events.
# number of events +
# 1 /* Checksum algorithm */ +
# 4 /* CRC32 length */
#
# With current number of events = 160,
#
# binlog_start_pos = 4 + 19 + 57 + 160 = 240.
# binlog_start_pos = 4 + 19 + 57 + 160 + 1 + 4 = 245.
#
##############################################################################
let $binlog_start_pos=240;
let $binlog_start_pos=245;
--disable_query_log
SET @binlog_start_pos=240;
SET @binlog_start_pos=245;
--enable_query_log
if (`select variable_value not like 'NONE' from information_schema.GLOBAL_VARIABLES
where variable_name='binlog_checksum'`){
skip Can not run the test when server activated checksumming;
}
......@@ -209,6 +209,9 @@ INSERT INTO global_suppressions VALUES
("Slave I/O: Get master clock failed with error:.*"),
("Slave I/O: Get master COLLATION_SERVER failed with error:.*"),
("Slave I/O: Get master TIME_ZONE failed with error:.*"),
("Slave I/O: The slave I/O thread stops because a fatal error is encountered when it tried to SET @master_binlog_checksum on master.*"),
("Slave I/O: Get master BINLOG_CHECKSUM failed with error.*"),
("Slave I/O: Notifying master by SET @master_binlog_checksum= @@global.binlog_checksum failed with error.*"),
("THE_LAST_SUPPRESSION")||
......
--let $binlog_start=240
--let $binlog_start=245
--replace_result $binlog_start <binlog_start>
--replace_column 2 # 5 #
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/
......
......@@ -334,10 +334,10 @@ DROP TABLE t1;
DROP TABLE t2;
SHOW BINLOG EVENTS LIMIT 6,3;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 658 Query 1 726 BEGIN
master-bin.000001 726 Query 1 823 use `test`; INSERT INTO t2 VALUES (1,0), (2,0)
master-bin.000001 823 Xid 1 850 COMMIT /* XID */
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=850;
master-bin.000001 663 Query 1 731 BEGIN
master-bin.000001 731 Query 1 828 use `test`; INSERT INTO t2 VALUES (1,0), (2,0)
master-bin.000001 828 Xid 1 855 COMMIT /* XID */
-- CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000001', MASTER_LOG_POS=855;
SELECT * FROM t1 ORDER BY a;
a
1
......
set @save_binlog_checksum = @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 1;
reset master;
must be master-bin.000001
show binary logs;
Log_name File_size
master-bin.000001 #
create table t1 (a int);
flush logs;
drop table t1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; create table t1 (a int)
master-bin.000001 # Rotate # # master-bin.000002;pos=4
show tables;
Tables_in_test
t1
drop table t1;
set @@global.binlog_checksum = @save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
End of the tests
......@@ -6,6 +6,11 @@ get_lock("a", 20)
1
reset master;
insert into t2 values (null, null), (null, get_lock("a", 10));
kill query ID;
select
(@a:=load_file("MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
is not null;
set @result= 2 - 1 - 1;
select @result /* must be zero either way */;
@result
0
......@@ -84,18 +89,19 @@ a b
select @b /* must be 1 at the end of a stmt calling bug27563() */;
@b
1
must have the update query event more to FD
must have the update query event on the 3th line
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # User var # # @`b`=0
master-bin.000001 # Query # # use `test`; update t4 set b=b + bug27563(b)
*** a proof the query is binlogged with an error ***
select
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null;
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null
1
select 0 /* must return 0 to mean the killed query is in */;
select 0 /* must return 0 to mean the killed update is in */;
0
0
select RELEASE_LOCK("a");
......@@ -120,7 +126,7 @@ count(*)
select @b /* must be 1 at the end of a stmt calling bug27563() */;
@b
1
must have the delete query event more to FD
must have the delete query event on the 3th line
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # User var # # @`b`=0
......@@ -131,7 +137,7 @@ is not null;
(@a:=load_file("MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null
1
select 0 /* must return 0 to mean the killed query is in */;
select 0 /* must return 0 to mean the killed delete is in */;
0
0
select RELEASE_LOCK("a");
......
source include/have_innodb.inc;
source include/have_log_bin.inc;
#
# WL#2540 replication event checksum
#
# Objectives of the test are:
# to demo binlog events with CRC32 checksum in them and
# to prove show binlog events and mysqlbinlog are capable to handle
# the checksum.
#
set @save_binlog_checksum = @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 1;
let $MYSQLD_DATADIR= `select @@datadir`;
reset master;
--echo must be master-bin.000001
--source include/show_binary_logs.inc
create table t1 (a int);
flush logs;
drop table t1;
--source include/show_binlog_events.inc
--exec $MYSQL_BINLOG -c $MYSQLD_DATADIR/master-bin.000001 | $MYSQL
show tables;
# clean-up
drop table t1;
set @@global.binlog_checksum = @save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
--echo End of the tests
......@@ -40,10 +40,15 @@ send insert into t2 values (null, null), (null, get_lock("a", 10));
connection con1;
disable_abort_on_error;
disable_query_log;
disable_result_log;
--disable_abort_on_error
--disable_warnings
let $wait_condition=
select count(*) = 1 from information_schema.processlist
where info like "%insert into t2 values%" and state like 'User lock';
--source include/wait_condition.inc
--replace_regex /[0-9]+/ID/
eval kill query $ID;
connection con2;
......@@ -52,20 +57,23 @@ reap;
let $rows= `select count(*) from t2 /* must be 2 or 0 */`;
let $MYSQLD_DATADIR= `select @@datadir`;
let $start_pos= `select @binlog_start_pos + 28`;
--exec $MYSQL_BINLOG --force-if-open --start-position=$start_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
--let $binlog_killed_pos=query_get_value(SHOW BINLOG EVENTS, Pos, 3)
--let $binlog_killed_end_log_pos=query_get_value(SHOW BINLOG EVENTS, End_log_pos, 3)
--exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_killed_pos --stop-position=$binlog_killed_end_log_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
--disable_result_log
eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
is not null;
--enable_result_log
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
let $error_code= `select @a like "%#%error_code=0%" /* must return 1 or 0*/`;
let $insert_binlogged= `select @a like "%insert into%" /* must return 1 or 0 */`;
eval set @result= $rows- $error_code - $insert_binlogged;
eval set @result= $rows - $error_code - $insert_binlogged;
enable_abort_on_error;
enable_query_log;
enable_result_log;
--enable_warnings
--enable_abort_on_error
select @result /* must be zero either way */;
......@@ -259,19 +267,21 @@ connection con2;
reap;
select * from t4 order by b /* must be (1,1), (1,2) */;
select @b /* must be 1 at the end of a stmt calling bug27563() */;
--echo must have the update query event more to FD
--echo must have the update query event on the 3th line
source include/show_binlog_events.inc;
--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 3)
--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 3)
# a proof the query is binlogged with an error
--echo *** a proof the query is binlogged with an error ***
--exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
--exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_killed_pos --stop-position=$binlog_killed_end_log_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`;
eval select $error_code /* must return 0 to mean the killed query is in */;
eval select $error_code /* must return 0 to mean the killed update is in */;
# cleanup for the sub-case
connection con1;
......@@ -305,19 +315,21 @@ connection con2;
reap;
select count(*) from t4 /* must be 1 */;
select @b /* must be 1 at the end of a stmt calling bug27563() */;
--echo must have the delete query event more to FD
--echo must have the delete query event on the 3th line
source include/show_binlog_events.inc;
--let $binlog_killed_pos= query_get_value(SHOW BINLOG EVENTS, Pos, 3)
--let $binlog_killed_end_log_pos= query_get_value(SHOW BINLOG EVENTS, End_log_pos, 3)
# a proof the query is binlogged with an error
--exec $MYSQL_BINLOG --force-if-open --start-position=106 $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
--exec $MYSQL_BINLOG --force-if-open --start-position=$binlog_killed_pos --stop-position=$binlog_killed_end_log_pos $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
eval select
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/binlog_killed_bug27571.binlog"))
is not null;
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
let $error_code= `select @a like "%#%error_code=0%" /* must return 0*/`;
eval select $error_code /* must return 0 to mean the killed query is in */;
eval select $error_code /* must return 0 to mean the killed delete is in */;
# cleanup for the sub-case
connection con1;
......
......@@ -3,11 +3,11 @@ RESET MASTER;
CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb;
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 375
master-bin.000001 380
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
binlog_snapshot_position 375
binlog_snapshot_position 380
BEGIN;
INSERT INTO t1 VALUES (0, "");
# Connection con1
......@@ -38,10 +38,10 @@ a b
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
binlog_snapshot_position 674
binlog_snapshot_position 679
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 861
master-bin.000001 866
SELECT * FROM t2 ORDER BY a;
a
2
......@@ -60,40 +60,40 @@ a b
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000001
binlog_snapshot_position 674
binlog_snapshot_position 679
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000002 240
master-bin.000002 245
COMMIT;
SHOW STATUS LIKE 'binlog_snapshot_%';
Variable_name Value
binlog_snapshot_file master-bin.000002
binlog_snapshot_position 240
binlog_snapshot_position 245
SHOW MASTER STATUS;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000002 240
master-bin.000002 245
SHOW BINLOG EVENTS;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 240 Server ver: #, Binlog ver: #
master-bin.000001 240 Query 1 375 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
master-bin.000001 375 Query 1 487 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
master-bin.000001 487 Query 1 555 BEGIN
master-bin.000001 555 Query 1 647 use `test`; INSERT INTO t1 VALUES (0, "")
master-bin.000001 647 Xid 1 674 COMMIT /* XID */
master-bin.000001 674 Query 1 742 BEGIN
master-bin.000001 742 Query 1 834 use `test`; INSERT INTO t1 VALUES (4, "")
master-bin.000001 834 Xid 1 861 COMMIT /* XID */
master-bin.000001 861 Query 1 929 BEGIN
master-bin.000001 929 Query 1 1021 use `test`; INSERT INTO t1 VALUES (1, "")
master-bin.000001 1021 Xid 1 1048 COMMIT /* XID */
master-bin.000001 1048 Query 1 1116 BEGIN
master-bin.000001 1116 Query 1 1213 use `test`; INSERT INTO t1 VALUES (2, "first")
master-bin.000001 1213 Query 1 1301 use `test`; INSERT INTO t2 VALUES (2)
master-bin.000001 1301 Query 1 1399 use `test`; INSERT INTO t1 VALUES (2, "second")
master-bin.000001 1399 Xid 1 1426 COMMIT /* XID */
master-bin.000001 1426 Query 1 1494 BEGIN
master-bin.000001 1494 Query 1 1586 use `test`; INSERT INTO t1 VALUES (3, "")
master-bin.000001 1586 Query 1 1674 use `test`; INSERT INTO t2 VALUES (3)
master-bin.000001 1674 Xid 1 1701 COMMIT /* XID */
master-bin.000001 1701 Rotate 1 1745 master-bin.000002;pos=4
master-bin.000001 4 Format_desc 1 245 Server ver: #, Binlog ver: #
master-bin.000001 245 Query 1 380 use `test`; CREATE TABLE t1 (a INT, b VARCHAR(100), PRIMARY KEY (a,b)) ENGINE=innodb
master-bin.000001 380 Query 1 492 use `test`; CREATE TABLE t2 (a INT PRIMARY KEY) ENGINE=myisam
master-bin.000001 492 Query 1 560 BEGIN
master-bin.000001 560 Query 1 652 use `test`; INSERT INTO t1 VALUES (0, "")
master-bin.000001 652 Xid 1 679 COMMIT /* XID */
master-bin.000001 679 Query 1 747 BEGIN
master-bin.000001 747 Query 1 839 use `test`; INSERT INTO t1 VALUES (4, "")
master-bin.000001 839 Xid 1 866 COMMIT /* XID */
master-bin.000001 866 Query 1 934 BEGIN
master-bin.000001 934 Query 1 1026 use `test`; INSERT INTO t1 VALUES (1, "")
master-bin.000001 1026 Xid 1 1053 COMMIT /* XID */
master-bin.000001 1053 Query 1 1121 BEGIN
master-bin.000001 1121 Query 1 1218 use `test`; INSERT INTO t1 VALUES (2, "first")
master-bin.000001 1218 Query 1 1306 use `test`; INSERT INTO t2 VALUES (2)
master-bin.000001 1306 Query 1 1404 use `test`; INSERT INTO t1 VALUES (2, "second")
master-bin.000001 1404 Xid 1 1431 COMMIT /* XID */
master-bin.000001 1431 Query 1 1499 BEGIN
master-bin.000001 1499 Query 1 1591 use `test`; INSERT INTO t1 VALUES (3, "")
master-bin.000001 1591 Query 1 1679 use `test`; INSERT INTO t2 VALUES (3)
master-bin.000001 1679 Xid 1 1706 COMMIT /* XID */
master-bin.000001 1706 Rotate 1 1750 master-bin.000002;pos=4
DROP TABLE t1,t2;
......@@ -30,6 +30,6 @@ a
1
2
3
InnoDB: Last MySQL binlog file position 0 901, file name ./master-bin.000001
InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001
SET DEBUG_SYNC= 'RESET';
DROP TABLE t1;
......@@ -31,6 +31,6 @@ a
1
2
3
InnoDB: Last MySQL binlog file position 0 901, file name ./master-bin.000001
InnoDB: Last MySQL binlog file position 0 906, file name ./master-bin.000001
SET DEBUG_SYNC= 'RESET';
DROP TABLE t1;
Binlog checksum testing
=======================
1. How it works.
The script copies a <suite> to directory <suite>_checksum,
collects test case names for t/ directory (except tests from
disabled def), randomly choose 90% of tests and add them
to disabled.def.
It means that mtr will run only 10% of random tests from each
suite.
At end the script run mtr:
./mysql-test-run.pl --suite=aaa_checksum,bbb_checksum \
--mysqld=--binlog-checksum=CRC32 arg1 ... argN
aaa,bbb - suite names from --suite option
arg1,argN - other command-line arguments of checksum.pl
2. The options:
--suite=suite1,suite2. Mandatory option. The list of suites for
binlog checksum testing.
--percent=N, where N is 1..99. Percent of running tests.
#!/usr/bin/perl
# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
use File::Basename;
use File::Copy qw(copy);
use File::Spec qw(catdir);
use File::Path;
use IO::File;
use strict;
# Constants and variables with default values
my $suites;
my $suffix = "_checksum";
my $percent_random_test = 10;
my $mtr_script;
my @mtr_argv;
my @mtr_suites;
# Check some arguments
foreach my $arg ( @ARGV )
{
if ($arg =~ m/\-\-suite\=(.+)/i)
{
$suites = $1;
}
elsif ($arg =~ m/\-\-percent\=(\d{1,2})/i)
{
$percent_random_test= $1;
}
else
{
push(@mtr_argv, $arg);
}
}
if (! defined( $suites ) )
{
die("The script requires --suite argument");
}
print "#################################################################\n";
print "# Binlog checksum testing\n";
print "# Run randomly $percent_random_test\% of tests from following suites: $suites\n";
print "#################################################################\n";
# Set extension directory
my $ext_dir= dirname(File::Spec->rel2abs($0));
# Set mysql-test directory
my $mysql_test_dir= $ext_dir;
$mysql_test_dir =~ s/(\/|\\)suite(\/|\\)rpl(\/|\\)extension$//;
# Main loop
foreach my $src_suite (split(",", $suites))
{
$src_suite=~ s/ //g;
my $dest_suite= $src_suite . $suffix;
push( @mtr_suites, $dest_suite);
print "Creating suite $dest_suite\n";
# *** Set platform-independent pathes ***
# Set source directory of suite
my $src_suite_dir = File::Spec->catdir($mysql_test_dir, "suite", $src_suite);
# Set destination directory of suite
my $dest_suite_dir = File::Spec->catdir($mysql_test_dir, "suite", $dest_suite);
print "Copying files\n\tfrom '$src_suite_dir'\n\tto '$dest_suite_dir'\n";
dircopy($src_suite_dir, $dest_suite_dir);
my $test_case_dir= File::Spec->catdir($dest_suite_dir, "t");
# Read disabled.def
my %disabled = ();
print "Read disabled.def\n";
my $fh = new IO::File File::Spec->catdir($test_case_dir, "disabled.def"), "r";
if ( defined $fh )
{
my @lines = <$fh>;
undef $fh;
foreach my $line ( @lines )
{
if ($line =~ m/^([a-zA-Z0-9_]+).+\:.+/i)
{
$disabled{$1}= 1;
}
}
}
# Read test case list
my %tests = ();
print "Generate test case list\n";
opendir my ($dh), $test_case_dir or die "Could not open dir '$test_case_dir': $!";
for my $entry (readdir $dh)
{
if ( $entry =~ m/^([a-zA-Z0-9_]+)\.test$/i )
{
my $test= $1;
if ( ! defined( $disabled{$test}) )
{
$tests{$test}= 1;
}
}
}
closedir($dh);
#
my @excluded = ();
my $excluded_test= int((((100 - $percent_random_test)/100) * scalar( keys %tests )));
while ( $excluded_test > 0 )
{
my @cases = keys %tests;
my $test = $cases[int(rand(scalar(@cases)))];
push ( @excluded, $test . "\t\t: Excluded for $dest_suite\n" );
delete $tests{$test};
$excluded_test--;
}
my $fh = new IO::File File::Spec->catdir($test_case_dir, "disabled.def"), O_WRONLY|O_APPEND;
if (defined $fh) {
print $fh join ("", sort @excluded);
undef $fh;
}
print "\t" . join("\n\t", sort keys %tests) . "\n";
}
# Set path to mtr with arguments
my $mtr_script = "perl " . File::Spec->catdir($mysql_test_dir, "mysql-test-run.pl") .
" --suite=" . join(",", @mtr_suites) . " " .
" --mysqld=--binlog-checksum=CRC32 " .
join (" ", @mtr_argv);
print "Run $mtr_script\n";
system( $mtr_script );
sub dircopy
{
my ($from_dir, $to_dir)= @_;
mkdir $to_dir if (! -e $to_dir);
opendir my($dh), $from_dir or die "Could not open dir '$from_dir': $!";
for my $entry (readdir $dh)
{
next if $entry =~ /^(\.|\.\.)$/;
my $source = File::Spec->catdir($from_dir, $entry);
my $destination = File::Spec->catdir($to_dir, $entry);
if (-d $source)
{
mkdir $destination or die "mkdir '$destination' failed: $!" if not -e $destination;
dircopy($source, $destination);
}
else
{
copy($source, $destination) or die "copy '$source' to '$destination' failed: $!";
}
}
closedir $dh;
return;
}
include/master-slave.inc
[connection master]
call mtr.add_suppression("Slave I/O: The slave I/O thread stops because a fatal error is encountered when it tried to SET @master_binlog_checksum");
create table t1(n int);
select * from t1;
n
......
include/master-slave.inc
[connection master]
call mtr.add_suppression('Slave can not handle replication events with the checksum that master is configured to log');
call mtr.add_suppression('Replication event checksum verification failed');
call mtr.add_suppression('Relay log write failure: could not queue event from master');
call mtr.add_suppression('Master is configured to log replication events with checksum, but will not send such events to slaves that cannot process them');
set @master_save_binlog_checksum= @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
select @@global.binlog_checksum as 'must be CRC32 because of the command line option';
must be CRC32 because of the command line option
CRC32
select @@session.binlog_checksum as 'no session var';
ERROR HY000: Variable 'binlog_checksum' is a GLOBAL variable
select @@global.master_verify_checksum as 'must be zero because of default';
must be zero because of default
0
select @@session.master_verify_checksum as 'no session var';
ERROR HY000: Variable 'master_verify_checksum' is a GLOBAL variable
set @slave_save_binlog_checksum= @@global.binlog_checksum;
set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
select @@global.slave_sql_verify_checksum as 'must be one because of default';
must be one because of default
1
select @@session.slave_sql_verify_checksum as 'no session var';
ERROR HY000: Variable 'slave_sql_verify_checksum' is a GLOBAL variable
show binary logs;
Log_name File_size
master-bin.000001 #
set @@global.binlog_checksum = NONE;
*** must be rotations seen ***
show binary logs;
Log_name File_size
master-bin.000001 #
master-bin.000002 #
set @@global.binlog_checksum = default;
set @@global.binlog_checksum = CRC32;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
set @@global.binlog_checksum = ADLER32;
ERROR 42000: Variable 'checksum' can't be set to the value of 'ADLER32'
set @@global.master_verify_checksum = 2;
ERROR 42000: Variable 'master_verify_checksum' can't be set to the value of '2'
set @@global.slave_sql_verify_checksum = 0;
set @@global.slave_sql_verify_checksum = default;
set @@global.slave_sql_verify_checksum = 2;
ERROR 42000: Variable 'slave_sql_verify_checksum' can't be set to the value of '2'
set @@global.binlog_checksum = NONE;
create table t1 (a int);
flush logs;
flush logs;
flush logs;
flush logs;
flush logs;
flush logs;
select count(*) as zero from t1;
zero
0
include/stop_slave.inc
set @@global.binlog_checksum = CRC32;
insert into t1 values (1) /* will not be applied on slave due to simulation */;
set @@global.debug='d,simulate_slave_unaware_checksum';
start slave;
include/wait_for_slave_io_to_stop.inc
*** Got IO thread error code: 1236, text: Got fatal error 1236 from master when reading data from binary log: 'Slave can not handle replication events with the checksum that master is configured to log' ***
select count(*) as zero from t1;
zero
0
set @@global.debug='';
include/start_slave.inc
set @@global.master_verify_checksum = 1;
set @@session.debug='d,simulate_checksum_test_failure';
show binlog events;
ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error
set @@session.debug='';
set @@global.master_verify_checksum = default;
include/stop_slave.inc
create table t2 (a int);
set @@global.debug='d,simulate_checksum_test_failure';
start slave io_thread;
include/wait_for_slave_io_to_stop.inc
*** Got IO thread error code: 1595, text: Relay log write failure: could not queue event from master ***
set @@global.debug='';
start slave io_thread;
include/wait_for_slave_param.inc [Read_Master_Log_Pos]
set @@global.slave_sql_verify_checksum = 1;
set @@global.debug='d,simulate_checksum_test_failure';
start slave sql_thread;
include/wait_for_slave_sql_to_stop.inc
*** Got SQL thread error code: 1593, text: Error initializing relay log position: I/O error reading event at position 4 ***
set @@global.debug='';
include/start_slave.inc
select count(*) as 'must be zero' from t2;
must be zero
0
stop slave;
reset slave;
set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE");
flush logs;
set @@global.binlog_checksum= CRC32;
reset master;
flush logs;
create table t3 (a int, b char(5));
include/start_slave.inc
select count(*) as 'must be zero' from t3;
must be zero
0
include/stop_slave.inc
change master to master_host='127.0.0.1',master_port=MASTER_PORT, master_user='root';
flush logs;
reset master;
insert into t3 value (1, @@global.binlog_checksum);
include/start_slave.inc
flush logs;
select count(*) as 'must be one' from t3;
must be one
1
set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE");
insert into t3 value (1, @@global.binlog_checksum);
drop table t1, t2, t3;
set @@global.binlog_checksum = @master_save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
set @@global.binlog_checksum = @slave_save_binlog_checksum;
set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
End of tests
include/rpl_end.inc
include/master-slave.inc
[connection master]
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Statement: insert into t2 set data=repeat.*'a', @act_size.*");
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Statement: insert into t1 values.* NAME_CONST.*'n',.*, @data .*");
set @save_binlog_cache_size = @@global.binlog_cache_size;
set @save_binlog_checksum = @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
set @@global.binlog_cache_size = 4096;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 1;
include/stop_slave.inc
include/start_slave.inc
flush status;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 0
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
drop table if exists t1;
create table t1 (a int PRIMARY KEY, b CHAR(32)) engine=innodb;
create procedure test.p_init (n int, size int)
begin
while n > 0 do
select round(RAND() * size) into @act_size;
set @data = repeat('a', @act_size);
insert into t1 values(n, @data );
set n= n-1;
end while;
end|
begin;
call test.p_init(4000, 32);
commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 1
*** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
include/diff_tables.inc [master:test.t1, slave:test.t1]
begin;
delete from t1;
commit;
flush status;
create table t2(a int auto_increment primary key, data VARCHAR(12288)) ENGINE=Innodb;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 1
*** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
include/diff_tables.inc [master:test.t2, slave:test.t2]
begin;
delete from t2;
commit;
flush status;
create table t3(a int auto_increment primary key, data VARCHAR(8192)) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 1
*** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
include/diff_tables.inc [master:test.t3, slave:test.t3]
begin;
delete from t3;
commit;
flush status;
create procedure test.p1 (n int)
begin
while n > 0 do
case (select (round(rand()*100) % 3) + 1)
when 1 then
select round(RAND() * 32) into @act_size;
set @data = repeat('a', @act_size);
insert into t1 values(n, @data);
when 2 then
begin
select round(8192 + RAND() * 4096) into @act_size;
insert into t2 set data=repeat('a', @act_size);
end;
when 3 then
begin
select round(3686.4000 + RAND() * 819.2000) into @act_size;
insert into t3 set data= repeat('a', @act_size);
end;
end case;
set n= n-1;
end while;
end|
set autocommit= 0;
begin;
call test.p1(1000);
commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 1
*** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
include/diff_tables.inc [master:test.t1, slave:test.t1]
include/diff_tables.inc [master:test.t2, slave:test.t2]
include/diff_tables.inc [master:test.t3, slave:test.t3]
begin;
delete from t1;
delete from t2;
delete from t3;
commit;
drop table t1, t2, t3;
set @@global.binlog_cache_size = @save_binlog_cache_size;
set @@global.binlog_checksum = @save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
drop procedure test.p_init;
drop procedure test.p1;
include/rpl_end.inc
include/master-slave.inc
[connection master]
call mtr.add_suppression('Found invalid event in binary log');
call mtr.add_suppression('Slave I/O: Relay log write failure: could not queue event from master');
call mtr.add_suppression('event read from binlog did not pass crc check');
call mtr.add_suppression('Replication event checksum verification failed');
SET @old_master_verify_checksum = @@master_verify_checksum;
# 1. Creating test table/data and set corruption position for testing
* insert/update/delete rows in table t1 *
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c VARCHAR(100));
include/stop_slave.inc
# 2. Corruption in master binlog and SHOW BINLOG EVENTS
SET GLOBAL debug="+d,corrupt_read_log_event_char";
SHOW BINLOG EVENTS;
ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error
SET GLOBAL debug="-d,corrupt_read_log_event_char";
# 3. Master read a corrupted event from binlog and send the error to slave
SET GLOBAL debug="+d,corrupt_read_log_event2";
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1236]
SET GLOBAL debug="-d,corrupt_read_log_event2";
# 4. Master read a corrupted event from binlog and send it to slave
SET GLOBAL master_verify_checksum=0;
SET GLOBAL debug="+d,corrupt_read_log_event2";
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595]
SET GLOBAL debug="-d,corrupt_read_log_event2";
SET GLOBAL debug= "";
SET GLOBAL master_verify_checksum=1;
# 5. Slave. Corruption in network
SET GLOBAL debug="+d,corrupt_queue_event";
START SLAVE IO_THREAD;
include/wait_for_slave_io_error.inc [errno=1595]
SET GLOBAL debug="-d,corrupt_queue_event";
# 6. Slave. Corruption in relay log
SET GLOBAL debug="+d,corrupt_read_log_event_char";
START SLAVE;
include/wait_for_slave_sql_error.inc [errno=1593]
SET GLOBAL debug="-d,corrupt_read_log_event_char";
SET GLOBAL debug= "";
# 7. Seek diff for tables on master and slave
include/start_slave.inc
include/diff_tables.inc [master:test.t1, slave:test.t1]
# 8. Clean up
SET GLOBAL debug= "";
SET GLOBAL master_verify_checksum = @old_master_verify_checksum;
DROP TABLE t1;
SET GLOBAL debug= "";
include/rpl_end.inc
......@@ -69,7 +69,7 @@ insert into temp_table values ("testing temporary tables part 2");
create table t3 (n int);
select count(*) from t3 where n >= 4;
count(*)
100
90
create table t4 select * from temp_table;
show binary logs;
Log_name File_size
......@@ -88,7 +88,7 @@ include/check_slave_is_running.inc
lock tables t3 read;
select count(*) from t3 where n >= 4;
count(*)
100
90
unlock tables;
drop table if exists t1,t2,t3,t4;
End of 4.1 tests
......
......@@ -22,7 +22,7 @@ a
[on slave]
---- Wait until slave stops with an error ----
include/wait_for_slave_sql_error.inc [errno=1062]
Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log master-bin.000001, end_log_pos 480 (expected "duplicate key" error)
Last_SQL_Error = Could not execute Write_rows event on table test.t1; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log master-bin.000001, end_log_pos 485 (expected "duplicate key" error)
SELECT * FROM t1;
a
1
......
......@@ -3,6 +3,7 @@
# I/O thread left (some old bug fixed in 4.0.17)
source include/master-slave.inc;
call mtr.add_suppression("Slave I/O: The slave I/O thread stops because a fatal error is encountered when it tried to SET @master_binlog_checksum");
connection master;
# Make SQL slave thread advance a bit
......
# WL2540 replication events checksum
# Testing configuration parameters
--source include/master-slave.inc
--source include/have_debug.inc
--source include/have_binlog_format_mixed.inc
call mtr.add_suppression('Slave can not handle replication events with the checksum that master is configured to log');
call mtr.add_suppression('Replication event checksum verification failed');
# due to C failure simulation
call mtr.add_suppression('Relay log write failure: could not queue event from master');
call mtr.add_suppression('Master is configured to log replication events with checksum, but will not send such events to slaves that cannot process them');
# A. read/write access to the global vars:
# binlog_checksum master_verify_checksum slave_sql_verify_checksum
connection master;
set @master_save_binlog_checksum= @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
select @@global.binlog_checksum as 'must be CRC32 because of the command line option';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.binlog_checksum as 'no session var';
select @@global.master_verify_checksum as 'must be zero because of default';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.master_verify_checksum as 'no session var';
connection slave;
set @slave_save_binlog_checksum= @@global.binlog_checksum;
set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
select @@global.slave_sql_verify_checksum as 'must be one because of default';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.slave_sql_verify_checksum as 'no session var';
connection master;
source include/show_binary_logs.inc;
set @@global.binlog_checksum = NONE;
--echo *** must be rotations seen ***
source include/show_binary_logs.inc;
set @@global.binlog_checksum = default;
# testing lack of side-effects in non-effective update of binlog_checksum:
set @@global.binlog_checksum = CRC32;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.binlog_checksum = ADLER32;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.master_verify_checksum = 2; # the var is of bool type
connection slave;
set @@global.slave_sql_verify_checksum = 0;
set @@global.slave_sql_verify_checksum = default;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.slave_sql_verify_checksum = 2; # the var is of bool type
#
# B. Old Slave to New master conditions
#
# while master does not send a checksum-ed binlog the Old Slave can
# work with the New Master
connection master;
set @@global.binlog_checksum = NONE;
create table t1 (a int);
# testing that binlog rotation preserves opt_binlog_checksum value
flush logs;
flush logs;
flush logs;
sync_slave_with_master;
#connection slave;
# checking that rotation on the slave side leaves slave stable
flush logs;
flush logs;
flush logs;
select count(*) as zero from t1;
source include/stop_slave.inc;
connection master;
set @@global.binlog_checksum = CRC32;
insert into t1 values (1) /* will not be applied on slave due to simulation */;
# instruction to the dump thread
### set @@global.debug='d,simulate_slave_unaware_checksum'; # merge todo: +/- d syntax fails in my clone
connection slave;
set @@global.debug='d,simulate_slave_unaware_checksum'; # merge todo: +/- d syntax fails in my clone
start slave;
source include/wait_for_slave_io_to_stop.inc;
let $errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
let $error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
--echo *** Got IO thread error code: $errno, text: $error ***
select count(*) as zero from t1;
###connection master;
set @@global.debug=''; # merge todo: +/- d syntax fails in my clone
connection slave;
source include/start_slave.inc;
#
# C. checksum failure simulations
#
# C1. Failure by a client thread
connection master;
set @@global.master_verify_checksum = 1;
set @@session.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
--error ER_ERROR_WHEN_EXECUTING_COMMAND
show binlog events;
set @@session.debug=''; # merge todo: +/- d syntax fails in my clone
set @@global.master_verify_checksum = default;
#connection master;
sync_slave_with_master;
connection slave;
source include/stop_slave.inc;
connection master;
create table t2 (a int);
let $pos_master= query_get_value(SHOW MASTER STATUS, Position, 1);
connection slave;
# C2. Failure by IO thread
# instruction to io thread
set @@global.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
start slave io_thread;
source include/wait_for_slave_io_to_stop.inc;
let $errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
let $error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
--echo *** Got IO thread error code: $errno, text: $error ***
set @@global.debug=''; # todo: merge
# to make IO thread re-read it again w/o the failure
start slave io_thread;
let $slave_param= Read_Master_Log_Pos;
let $slave_param_value= $pos_master;
source include/wait_for_slave_param.inc;
# C3. Failure by SQL thread
# instruction to sql thread;
set @@global.slave_sql_verify_checksum = 1;
set @@global.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
start slave sql_thread;
source include/wait_for_slave_sql_to_stop.inc;
let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
--echo *** Got SQL thread error code: $errno, text: $error ***
# resuming SQL thread to parse out the event w/o the failure
set @@global.debug='';
source include/start_slave.inc;
connection master;
sync_slave_with_master;
#connection slave;
select count(*) as 'must be zero' from t2;
#
# D. Reset slave, Change-Master, Binlog & Relay-log rotations with
# random value on binlog_checksum on both master and slave
#
connection slave;
stop slave;
reset slave;
# randomize slave server's own checksum policy
set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE");
flush logs;
connection master;
set @@global.binlog_checksum= CRC32;
reset master;
flush logs;
create table t3 (a int, b char(5));
connection slave;
source include/start_slave.inc;
connection master;
sync_slave_with_master;
#connection slave;
select count(*) as 'must be zero' from t3;
source include/stop_slave.inc;
--replace_result $MASTER_MYPORT MASTER_PORT
eval change master to master_host='127.0.0.1',master_port=$MASTER_MYPORT, master_user='root';
connection master;
flush logs;
reset master;
insert into t3 value (1, @@global.binlog_checksum);
connection slave;
source include/start_slave.inc;
flush logs;
connection master;
sync_slave_with_master;
#connection slave;
select count(*) as 'must be one' from t3;
connection master;
set @@global.binlog_checksum= IF(floor((rand()*1000)%2), "CRC32", "NONE");
insert into t3 value (1, @@global.binlog_checksum);
sync_slave_with_master;
#connection slave;
#clean-up
connection master;
drop table t1, t2, t3;
set @@global.binlog_checksum = @master_save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
#connection slave;
sync_slave_with_master;
set @@global.binlog_checksum = @slave_save_binlog_checksum;
set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
--echo End of tests
--source include/rpl_end.inc
-- source include/have_innodb.inc
-- source include/master-slave.inc
--disable_warnings
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Statement: insert into t2 set data=repeat.*'a', @act_size.*");
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave. Statement: insert into t1 values.* NAME_CONST.*'n',.*, @data .*");
--enable_warnings
connection master;
set @save_binlog_cache_size = @@global.binlog_cache_size;
set @save_binlog_checksum = @@global.binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
set @@global.binlog_cache_size = 4096;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 1;
# restart slave to force the dump thread to verify events (on master side)
connection slave;
source include/stop_slave.inc;
source include/start_slave.inc;
connection master;
#
# Testing a critical part of checksum handling dealing with transaction cache.
# The cache's buffer size is set to be less than the transaction's footprint
# in binlog.
#
# To verify combined buffer-by-buffer read out of the file and fixing crc per event
# there are the following parts:
#
# 1. the event size is much less than the cache's buffer
# 2. the event size is bigger than the cache's buffer
# 3. the event size if approximately the same as the cache's buffer
# 4. all in above
#
# 1. the event size is much less than the cache's buffer
#
flush status;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
--disable_warnings
drop table if exists t1;
--enable_warnings
#
# parameter to ensure the test slightly varies binlog content
# between different invocations
#
let $deviation_size=32;
eval create table t1 (a int PRIMARY KEY, b CHAR($deviation_size)) engine=innodb;
# Now we are going to create transaction which is long enough so its
# transaction binlog will be flushed to disk...
delimiter |;
create procedure test.p_init (n int, size int)
begin
while n > 0 do
select round(RAND() * size) into @act_size;
set @data = repeat('a', @act_size);
insert into t1 values(n, @data );
set n= n-1;
end while;
end|
delimiter ;|
let $1 = 4000; # PB2 can run it slow to time out on following sync_slave_with_master:s
begin;
--disable_warnings
# todo: check if it is really so.
#+Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statement uses a system function whose value may differ on slave.
eval call test.p_init($1, $deviation_size);
--enable_warnings
commit;
show status like "binlog_cache_use";
--echo *** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
sync_slave_with_master;
let $diff_tables=master:test.t1, slave:test.t1;
source include/diff_tables.inc;
# undoing changes with verifying the above once again
connection master;
begin;
delete from t1;
commit;
sync_slave_with_master;
#
# 2. the event size is bigger than the cache's buffer
#
connection master;
flush status;
let $t2_data_size= `select 3 * @@global.binlog_cache_size`;
let $t2_aver_size= `select 2 * @@global.binlog_cache_size`;
let $t2_max_rand= `select 1 * @@global.binlog_cache_size`;
eval create table t2(a int auto_increment primary key, data VARCHAR($t2_data_size)) ENGINE=Innodb;
let $1=100;
--disable_query_log
begin;
while ($1)
{
eval select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size;
set @data = repeat('a', @act_size);
insert into t2 set data = @data;
dec $1;
}
commit;
--enable_query_log
show status like "binlog_cache_use";
--echo *** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
sync_slave_with_master;
let $diff_tables=master:test.t2, slave:test.t2;
source include/diff_tables.inc;
# undoing changes with verifying the above once again
connection master;
begin;
delete from t2;
commit;
sync_slave_with_master;
#
# 3. the event size if approximately the same as the cache's buffer
#
connection master;
flush status;
let $t3_data_size= `select 2 * @@global.binlog_cache_size`;
let $t3_aver_size= `select (9 * @@global.binlog_cache_size) / 10`;
let $t3_max_rand= `select (2 * @@global.binlog_cache_size) / 10`;
eval create table t3(a int auto_increment primary key, data VARCHAR($t3_data_size)) engine=innodb;
let $1= 300;
--disable_query_log
begin;
while ($1)
{
eval select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size;
insert into t3 set data= repeat('a', @act_size);
dec $1;
}
commit;
--enable_query_log
show status like "binlog_cache_use";
--echo *** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
sync_slave_with_master;
let $diff_tables=master:test.t3, slave:test.t3;
source include/diff_tables.inc;
# undoing changes with verifying the above once again
connection master;
begin;
delete from t3;
commit;
sync_slave_with_master;
#
# 4. all in above
#
connection master;
flush status;
delimiter |;
eval create procedure test.p1 (n int)
begin
while n > 0 do
case (select (round(rand()*100) % 3) + 1)
when 1 then
select round(RAND() * $deviation_size) into @act_size;
set @data = repeat('a', @act_size);
insert into t1 values(n, @data);
when 2 then
begin
select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size;
insert into t2 set data=repeat('a', @act_size);
end;
when 3 then
begin
select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size;
insert into t3 set data= repeat('a', @act_size);
end;
end case;
set n= n-1;
end while;
end|
delimiter ;|
let $1= 1000;
set autocommit= 0;
begin;
--disable_warnings
eval call test.p1($1);
--enable_warnings
commit;
show status like "binlog_cache_use";
--echo *** binlog_cache_disk_use must be non-zero ***
show status like "binlog_cache_disk_use";
sync_slave_with_master;
let $diff_tables=master:test.t1, slave:test.t1;
source include/diff_tables.inc;
let $diff_tables=master:test.t2, slave:test.t2;
source include/diff_tables.inc;
let $diff_tables=master:test.t3, slave:test.t3;
source include/diff_tables.inc;
connection master;
begin;
delete from t1;
delete from t2;
delete from t3;
commit;
drop table t1, t2, t3;
set @@global.binlog_cache_size = @save_binlog_cache_size;
set @@global.binlog_checksum = @save_binlog_checksum;
set @@global.master_verify_checksum = @save_master_verify_checksum;
drop procedure test.p_init;
drop procedure test.p1;
--source include/rpl_end.inc
--binlog-checksum=CRC32 --master-verify-checksum=1
--binlog-checksum=CRC32 --slave-sql-verify-checksum=1
############################################################
# Author: Serge Kozlov <serge.kozlov@oracle.com>
# Date: 17 Oct 2010
# Purpose: WL#5064 Testing with corrupted events.
# The test emulates the corruption at the vary stages
# of replication:
# - in binlog file
# - in network
# - in relay log
############################################################
--source include/have_debug.inc
--source include/master-slave.inc
# Block legal errors for MTR
call mtr.add_suppression('Found invalid event in binary log');
call mtr.add_suppression('Slave I/O: Relay log write failure: could not queue event from master');
call mtr.add_suppression('event read from binlog did not pass crc check');
call mtr.add_suppression('Replication event checksum verification failed');
SET @old_master_verify_checksum = @@master_verify_checksum;
# Creating test table/data and set corruption position for testing
--echo # 1. Creating test table/data and set corruption position for testing
--connection master
--echo * insert/update/delete rows in table t1 *
# Corruption algorithm modifies only the first event and
# then will be reset. To avoid checking always the first event
# from binlog (usually it is FD) we randomly execute different
# statements and set position for corruption inside events.
CREATE TABLE t1 (a INT NOT NULL PRIMARY KEY, b VARCHAR(10), c VARCHAR(100));
--disable_query_log
let $i=`SELECT 3+CEILING(10*RAND())`;
let $j=1;
let $pos=0;
while ($i) {
eval INSERT INTO t1 VALUES ($j, 'a', NULL);
if (`SELECT RAND() > 0.7`)
{
eval UPDATE t1 SET c = REPEAT('a', 20) WHERE a = $j;
}
if (`SELECT RAND() > 0.8`)
{
eval DELETE FROM t1 WHERE a = $j;
}
if (!$pos) {
let $pos= query_get_value(SHOW MASTER STATUS, Position, 1);
--sync_slave_with_master
--source include/stop_slave.inc
--disable_query_log
--connection master
}
dec $i;
inc $j;
}
--enable_query_log
# Emulate corruption in binlog file when SHOW BINLOG EVENTS is executing
--echo # 2. Corruption in master binlog and SHOW BINLOG EVENTS
SET GLOBAL debug="+d,corrupt_read_log_event_char";
--echo SHOW BINLOG EVENTS;
--disable_query_log
send_eval SHOW BINLOG EVENTS FROM $pos;
--enable_query_log
--error ER_ERROR_WHEN_EXECUTING_COMMAND
reap;
SET GLOBAL debug="-d,corrupt_read_log_event_char";
# Emulate corruption on master with crc checking on master
--echo # 3. Master read a corrupted event from binlog and send the error to slave
SET GLOBAL debug="+d,corrupt_read_log_event2";
--connection slave
START SLAVE IO_THREAD;
let $slave_io_errno= 1236;
--source include/wait_for_slave_io_error.inc
--connection master
SET GLOBAL debug="-d,corrupt_read_log_event2";
# Emulate corruption on master without crc checking on master
--echo # 4. Master read a corrupted event from binlog and send it to slave
--connection master
SET GLOBAL master_verify_checksum=0;
SET GLOBAL debug="+d,corrupt_read_log_event2";
--connection slave
START SLAVE IO_THREAD;
let $slave_io_errno= 1595;
--source include/wait_for_slave_io_error.inc
--connection master
SET GLOBAL debug="-d,corrupt_read_log_event2";
SET GLOBAL debug= "";
SET GLOBAL master_verify_checksum=1;
# Emulate corruption in network
--echo # 5. Slave. Corruption in network
--connection slave
SET GLOBAL debug="+d,corrupt_queue_event";
START SLAVE IO_THREAD;
let $slave_io_errno= 1595;
--source include/wait_for_slave_io_error.inc
SET GLOBAL debug="-d,corrupt_queue_event";
# Emulate corruption in relay log
--echo # 6. Slave. Corruption in relay log
SET GLOBAL debug="+d,corrupt_read_log_event_char";
START SLAVE;
let $slave_sql_errno= 1593;
--source include/wait_for_slave_sql_error.inc
SET GLOBAL debug="-d,corrupt_read_log_event_char";
SET GLOBAL debug= "";
# Start normal replication and compare same table on master
# and slave
--echo # 7. Seek diff for tables on master and slave
--connection slave
--source include/start_slave.inc
--connection master
--sync_slave_with_master
let $diff_tables= master:test.t1, slave:test.t1;
--source include/diff_tables.inc
# Clean up
--echo # 8. Clean up
--connection master
SET GLOBAL debug= "";
SET GLOBAL master_verify_checksum = @old_master_verify_checksum;
DROP TABLE t1;
--sync_slave_with_master
SET GLOBAL debug= "";
--source include/rpl_end.inc
......@@ -4,11 +4,14 @@
# imitate the bug, so it has to stop).
source include/have_debug.inc;
# because of pretend_version_50034_in_binlog the test can't run with checksum
source include/have_binlog_checksum_off.inc;
source include/master-slave.inc;
# Currently only statement-based-specific bugs are here
-- source include/have_binlog_format_mixed_or_statement.inc
#
# This is to test that slave properly detects if
# master may suffer from:
......
......@@ -142,7 +142,10 @@ select * from t2;
connection master;
create temporary table temp_table (a char(80) not null);
insert into temp_table values ("testing temporary tables part 2");
let $1=100;
# the nummber of produced logs is sensitive to whether checksum is NONE or CRC32
# the value of 90 makes it even
let $1=90;
create table t3 (n int);
disable_query_log;
......
......@@ -12,7 +12,7 @@ create table t1(n int);
sync_slave_with_master;
stop slave;
connection master;
let $1=5000;
let $1=2500;
disable_query_log;
while ($1)
{
......
......@@ -37,8 +37,10 @@ stop slave;
# get the master binlog pos from the epoch, from the _other_ "master", server2
connection server2;
--replace_result $the_epoch <the_epoch>
--disable_result_log
eval SELECT @the_pos:=Position,@the_file:=SUBSTRING_INDEX(FILE, '/', -1)
FROM mysql.ndb_binlog_index WHERE epoch = $the_epoch ;
--enable_result_log
let $the_pos= `SELECT @the_pos` ;
let $the_file= `SELECT @the_file` ;
......
set @save_binlog_checksum= @@global.binlog_checksum;
set @@global.binlog_checksum = default;
select @@global.binlog_checksum as 'must be NONE by default';
must be NONE by default
NONE
select @@session.binlog_checksum as 'no session var';
ERROR HY000: Variable 'binlog_checksum' is a GLOBAL variable
set @@global.binlog_checksum = CRC32;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
set @@global.binlog_checksum = ADLER32;
ERROR 42000: Variable 'checksum' can't be set to the value of 'ADLER32'
set @@global.binlog_checksum = @save_binlog_checksum;
set @save_master_verify_checksum = @@global.master_verify_checksum;
select @@global.master_verify_checksum as 'must be zero because of default';
must be zero because of default
0
select @@session.master_verify_checksum as 'no session var';
ERROR HY000: Variable 'master_verify_checksum' is a GLOBAL variable
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
set @@global.master_verify_checksum = 2;
ERROR 42000: Variable 'master_verify_checksum' can't be set to the value of '2'
set @@global.master_verify_checksum = @save_master_verify_checksum;
set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
select @@global.slave_sql_verify_checksum as 'must be one because of default';
must be one because of default
1
select @@session.slave_sql_verify_checksum as 'no session var';
ERROR HY000: Variable 'slave_sql_verify_checksum' is a GLOBAL variable
set @@global.slave_sql_verify_checksum = 0;
set @@global.slave_sql_verify_checksum = default;
set @@global.slave_sql_verify_checksum = 2;
ERROR 42000: Variable 'slave_sql_verify_checksum' can't be set to the value of '2'
set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
--source include/not_embedded.inc
# suite/rpl/t/rpl_checksum.test contains similar testing of
# all checksum related system variables.
set @save_binlog_checksum= @@global.binlog_checksum;
set @@global.binlog_checksum = default;
select @@global.binlog_checksum as 'must be NONE by default';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.binlog_checksum as 'no session var';
# testing lack of side-effects in non-effective update of binlog_checksum:
set @@global.binlog_checksum = CRC32;
set @@global.binlog_checksum = CRC32;
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.binlog_checksum = ADLER32;
# cleanup
set @@global.binlog_checksum = @save_binlog_checksum;
--source include/not_embedded.inc
# suite/rpl/t/rpl_checksum.test contains similar testing of
# all checksum related system variables.
set @save_master_verify_checksum = @@global.master_verify_checksum;
select @@global.master_verify_checksum as 'must be zero because of default';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.master_verify_checksum as 'no session var';
set @@global.master_verify_checksum = 0;
set @@global.master_verify_checksum = default;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.master_verify_checksum = 2; # the var is of bool type
# cleanup
set @@global.master_verify_checksum = @save_master_verify_checksum;
--source include/not_embedded.inc
# suite/rpl/t/rpl_checksum.test contains similar testing of
# all checksum related system variables.
set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
select @@global.slave_sql_verify_checksum as 'must be one because of default';
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@session.slave_sql_verify_checksum as 'no session var';
set @@global.slave_sql_verify_checksum = 0;
set @@global.slave_sql_verify_checksum = default;
--error ER_WRONG_VALUE_FOR_VAR
set @@global.slave_sql_verify_checksum = 2; # the var is of bool type
# cleanup
set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
This diff is collapsed.
......@@ -403,7 +403,41 @@ public:
/* This is relay log */
bool is_relay_log;
uint8 checksum_alg_reset; // to contain a new value when binlog is rotated
/*
Holds the last seen in Relay-Log FD's checksum alg value.
The initial value comes from the slave's local FD that heads
the very first Relay-Log file. In the following the value may change
with each received master's FD_m.
Besides to be used in verification events that IO thread receives
(except the 1st fake Rotate, see @c Master_info:: checksum_alg_before_fd),
the value specifies if/how to compute checksum for slave's local events
and the first fake Rotate (R_f^1) coming from the master.
R_f^1 needs logging checksum-compatibly with the RL's heading FD_s.
Legends for the checksum related comments:
FD - Format-Description event,
R - Rotate event
R_f - the fake Rotate event
E - an arbirary event
The underscore indexes for any event
`_s' indicates the event is generated by Slave
`_m' - by Master
Two special underscore indexes of FD:
FD_q - Format Description event for queuing (relay-logging)
FD_e - Format Description event for executing (relay-logging)
Upper indexes:
E^n - n:th event is a sequence
RL - Relay Log
(A) - checksum algorithm descriptor value
FD.(A) - the value of (A) in FD
*/
uint8 relay_log_checksum_alg;
/*
These describe the log's format. This is used only for relay logs.
_for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
......
This diff is collapsed.
......@@ -72,6 +72,7 @@
#define LOG_READ_MEM -5
#define LOG_READ_TRUNC -6
#define LOG_READ_TOO_LARGE -7
#define LOG_READ_CHECKSUM_FAILURE -8
#define LOG_EVENT_OFFSET 4
......@@ -525,6 +526,22 @@ struct sql_ex_info
#endif
#undef EXPECTED_OPTIONS /* You shouldn't use this one */
enum enum_binlog_checksum_alg {
BINLOG_CHECKSUM_ALG_OFF= 0, // Events are without checksum though its generator
// is checksum-capable New Master (NM).
BINLOG_CHECKSUM_ALG_CRC32= 1, // CRC32 of zlib algorithm.
BINLOG_CHECKSUM_ALG_ENUM_END, // the cut line: valid alg range is [1, 0x7f].
BINLOG_CHECKSUM_ALG_UNDEF= 255 // special value to tag undetermined yet checksum
// or events from checksum-unaware servers
};
#define CHECKSUM_CRC32_SIGNATURE_LEN 4
/**
defined statically while there is just one alg implemented
*/
#define BINLOG_CHECKSUM_LEN CHECKSUM_CRC32_SIGNATURE_LEN
#define BINLOG_CHECKSUM_ALG_DESC_LEN 1 /* 1 byte checksum alg descriptor */
/**
@enum Log_event_type
......@@ -923,6 +940,27 @@ public:
uint16 flags;
bool cache_stmt;
/*
The revid:alfranio.correia@sun.com-20091103190256-637o8qxlveikrt3i commit
("WL#2687 WL#5072 BUG#40278 BUG#47175") in MySQL 5.5 changes the bool
cache_stmt into an enum cache_type. For the backport of WL#2540 binlog
event checksum, we need this event_type member to know if we are writing
directly to the log, or into a transaction cache.
Until the cache_type stuff is merged, we temporarily partially backport
the cache_type member, only enough to be able to check if we are writing
directly to log or not. Once MySQL 5.5 is merged, this can be removed, and
replaced with the MySQL 5.5 code.
Similarly, in MySQL 5.5 the decision on whether to write directly to log
or indirectly through cache is decided differently, and the
pre_55_writing_direct() (and all calls to it) are not needed and can be
removed once 5.5 is merged.
*/
enum enum_event_cache_type { EVENT_INVALID_CACHE, EVENT_STMT_CACHE,
EVENT_TRANSACTIONAL_CACHE, EVENT_NO_CACHE };
uint16 cache_type;
void pre_55_writing_direct() { cache_type= EVENT_NO_CACHE; }
/**
A storage to cache the global system variable's value.
......@@ -930,6 +968,10 @@ public:
*/
ulong slave_exec_mode;
/**
Placeholder for event checksum while writing to binlog.
*/
ha_checksum crc;
#ifndef MYSQL_CLIENT
THD* thd;
......@@ -949,9 +991,10 @@ public:
static Log_event* read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
const Format_description_log_event
*description_event);
*description_event,
my_bool crc_check);
static int read_log_event(IO_CACHE* file, String* packet,
pthread_mutex_t* log_lock);
pthread_mutex_t* log_lock, uint8 checksum_alg_arg);
/*
init_show_field_list() prepares the column names and types for the
output of SHOW BINLOG EVENTS; it is used only by SHOW BINLOG
......@@ -978,7 +1021,7 @@ public:
/* avoid having to link mysqlbinlog against libpthread */
static Log_event* read_log_event(IO_CACHE* file,
const Format_description_log_event
*description_event);
*description_event, my_bool crc_check);
/* print*() functions are used by mysqlbinlog */
virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
void print_timestamp(IO_CACHE* file, time_t *ts = 0);
......@@ -987,6 +1030,15 @@ public:
void print_base64(IO_CACHE* file, PRINT_EVENT_INFO* print_event_info,
bool is_more);
#endif
/*
The value is set by caller of FD constructor and
Log_event::write_header() for the rest.
In the FD case it's propagated into the last byte
of post_header_len[] at FD::write().
On the slave side the value is assigned from post_header_len[last]
of the last seen FD event.
*/
uint8 checksum_alg;
static void *operator new(size_t size)
{
......@@ -1001,14 +1053,19 @@ public:
/* Placement version of the above operators */
static void *operator new(size_t, void* ptr) { return ptr; }
static void operator delete(void*, void*) { }
bool wrapper_my_b_safe_write(IO_CACHE* file, const uchar* buf, ulong data_length);
#ifndef MYSQL_CLIENT
bool write_header(IO_CACHE* file, ulong data_length);
bool write_footer(IO_CACHE* file);
my_bool need_checksum();
virtual bool write(IO_CACHE* file)
{
return (write_header(file, get_data_size()) ||
write_data_header(file) ||
write_data_body(file));
return(write_header(file, get_data_size()) ||
write_data_header(file) ||
write_data_body(file) ||
write_footer(file));
}
virtual bool write_data_header(IO_CACHE* file)
{ return 0; }
......@@ -1058,7 +1115,7 @@ public:
static Log_event* read_log_event(const char* buf, uint event_len,
const char **error,
const Format_description_log_event
*description_event);
*description_event, my_bool crc_check);
/**
Returns the human readable name of the given event type.
*/
......@@ -2237,9 +2294,17 @@ public:
*/
uint8 common_header_len;
uint8 number_of_event_types;
/* The list of post-headers' lengthes */
/*
The list of post-headers' lengths followed
by the checksum alg decription byte
*/
uint8 *post_header_len;
uchar server_version_split[3];
struct master_version_split {
enum {KIND_MYSQL, KIND_MARIADB};
int kind;
uchar ver[3];
};
master_version_split server_version_split;
const uint8 *event_type_permutation;
Format_description_log_event(uint8 binlog_ver, const char* server_ver=0);
......@@ -2271,7 +2336,7 @@ public:
}
void calc_server_version_split();
static bool is_version_before_checksum(master_version_split *version_split);
protected:
#if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
virtual int do_apply_event(Relay_log_info const *rli);
......@@ -2326,9 +2391,10 @@ public:
uchar type;
#ifndef MYSQL_CLIENT
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg)
:Log_event(thd_arg,0,0),val(val_arg),type(type_arg)
{}
Intvar_log_event(THD* thd_arg,uchar type_arg, ulonglong val_arg,
uint16 cache_type_arg)
:Log_event(thd_arg,0,0), val(val_arg), type(type_arg)
{ cache_type= cache_type_arg; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
......@@ -2402,9 +2468,10 @@ class Rand_log_event: public Log_event
ulonglong seed2;
#ifndef MYSQL_CLIENT
Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg)
:Log_event(thd_arg,0,0),seed1(seed1_arg),seed2(seed2_arg)
{}
Rand_log_event(THD* thd_arg, ulonglong seed1_arg, ulonglong seed2_arg,
uint16 cache_type_arg)
:Log_event(thd_arg, 0, 0), seed1(seed1_arg), seed2(seed2_arg)
{ cache_type= cache_type_arg; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
......@@ -2448,7 +2515,8 @@ class Xid_log_event: public Log_event
my_xid xid;
#ifndef MYSQL_CLIENT
Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg, 0, 0), xid(x)
{ cache_type= EVENT_NO_CACHE; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
......@@ -2495,10 +2563,11 @@ public:
#ifndef MYSQL_CLIENT
User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
char *val_arg, ulong val_len_arg, Item_result type_arg,
uint charset_number_arg)
:Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
{ is_null= !val; }
uint charset_number_arg,
uint16 cache_type_arg)
:Log_event(thd_arg, 0, 0), name(name_arg), name_len(name_len_arg), val(val_arg),
val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
{ is_null= !val; cache_type= cache_type_arg; }
void pack_info(Protocol* protocol);
#else
void print(FILE* file, PRINT_EVENT_INFO* print_event_info);
......@@ -3010,7 +3079,7 @@ class Annotate_rows_log_event: public Log_event
{
public:
#ifndef MYSQL_CLIENT
Annotate_rows_log_event(THD*);
Annotate_rows_log_event(THD*, uint16 cache_type_arg);
#endif
Annotate_rows_log_event(const char *buf, uint event_len,
const Format_description_log_event*);
......@@ -4040,6 +4109,10 @@ bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
const char **group_relay_log_name,
ulonglong *relay_log_pos);
bool event_checksum_test(uchar *buf, ulong event_len, uint8 alg);
uint8 get_checksum_alg(const char* buf, ulong len);
extern TYPELIB binlog_checksum_typelib;
/**
@} (end of group Replication)
*/
......
......@@ -2056,6 +2056,8 @@ extern ulong binlog_cache_size, open_files_limit;
extern ulonglong max_binlog_cache_size;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong opt_binlog_rows_event_max_size;
extern my_bool opt_master_verify_checksum;
extern my_bool opt_slave_sql_verify_checksum;
extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
extern ulong back_log;
#endif /* MYSQL_SERVER */
......
......@@ -602,6 +602,8 @@ my_bool opt_noacl;
my_bool sp_automatic_privileges= 1;
ulong opt_binlog_rows_event_max_size;
my_bool opt_master_verify_checksum= 0;
my_bool opt_slave_sql_verify_checksum= 1;
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
TYPELIB binlog_format_typelib=
{ array_elements(binlog_format_names) - 1, "",
......@@ -4659,6 +4661,7 @@ int main(int argc, char **argv)
#ifndef DBUG_OFF
test_lc_time_sz();
srand(time(NULL));
#endif
/*
......@@ -6077,7 +6080,9 @@ enum options_mysqld
OPT_SLOW_QUERY_LOG_FILE,
OPT_IGNORE_BUILTIN_INNODB,
OPT_BINLOG_DIRECT_NON_TRANS_UPDATE,
OPT_DEFAULT_CHARACTER_SET_OLD
OPT_DEFAULT_CHARACTER_SET_OLD,
OPT_MASTER_VERIFY_CHECKSUM,
OPT_SLAVE_SQL_VERIFY_CHECKSUM
};
......@@ -6940,6 +6945,19 @@ each time the SQL thread starts.",
"not stop for operations that are idempotent. In STRICT mode, replication "
"will stop on any unexpected difference between the master and the slave.",
&slave_exec_mode_str, &slave_exec_mode_str, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"master-verify-checksum", OPT_MASTER_VERIFY_CHECKSUM,
"Force checksum verification of logged events in binary log before "
"sending them to slaves or printing them in output of SHOW BINLOG EVENTS. "
"Disabled by default.",
&opt_master_verify_checksum, &opt_master_verify_checksum,
0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"slave-sql-verify-checksum", OPT_SLAVE_SQL_VERIFY_CHECKSUM,
"Force checksum verification of replication events after reading them "
"from relay log. Note: Events are always checksum-verified by slave on "
"receiving them from the network before writing them to the relay "
"log. Enabled by default.",
&opt_slave_sql_verify_checksum, &opt_slave_sql_verify_checksum,
0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
#endif
{"slow-query-log", OPT_SLOW_LOG,
"Enable/disable slow query log. See also '--log-slow-queries'",
......
......@@ -244,7 +244,8 @@ static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
for (;;)
{
Log_event* ev;
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0)))
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0,
opt_slave_sql_verify_checksum)))
{
if (log->error > 0)
strmov(errmsg, "Binary log truncated in the middle of event");
......@@ -418,7 +419,8 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
for (i = 0; i < 2; i++)
{
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0,
opt_slave_sql_verify_checksum)))
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Error reading event in log '%s'",
......
......@@ -24,7 +24,8 @@
Master_info::Master_info()
:Slave_reporting_capability("I/O"),
ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0),
ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0),
checksum_alg_before_fd(BINLOG_CHECKSUM_ALG_UNDEF), inited(0),
abort_slave(0),slave_running(0),
slave_run_id(0)
{
......
......@@ -83,6 +83,12 @@ class Master_info : public Slave_reporting_capability
Relay_log_info rli;
uint port;
uint connect_retry;
/*
to hold checksum alg in use until IO thread has received FD.
Initialized to novalue, then set to the queried from master
@@global.binlog_checksum and deactivated once FD has been received.
*/
uint8 checksum_alg_before_fd;
#ifndef DBUG_OFF
int events_till_disconnect;
#endif
......
......@@ -176,6 +176,9 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
"this problem.", ln);
name_warning_sent= 1;
}
rli->relay_log.is_relay_log= TRUE;
/*
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
......@@ -189,7 +192,6 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
sql_print_error("Failed in open_log() called from init_relay_log_info()");
DBUG_RETURN(1);
}
rli->relay_log.is_relay_log= TRUE;
}
/* if file does not exist */
......@@ -535,8 +537,9 @@ int init_relay_log_pos(Relay_log_info* rli,const char* log,
Because of we have rli->data_lock and log_lock, we can safely read an
event
*/
if (!(ev=Log_event::read_log_event(rli->cur_log,0,
rli->relay_log.description_event_for_exec)))
if (!(ev= Log_event::read_log_event(rli->cur_log, 0,
rli->relay_log.description_event_for_exec,
opt_slave_sql_verify_checksum)))
{
DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
rli->cur_log->error));
......
......@@ -14,6 +14,8 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
#include "rpl_utility.h"
#ifndef MYSQL_CLIENT
#include "rpl_rli.h"
/*********************************************************************
......@@ -224,3 +226,62 @@ table_def::compatible_with(Relay_log_info const *rli_arg, TABLE *table)
return error;
}
#endif /* MYSQL_CLIENT */
/**
@param even_buf point to the buffer containing serialized event
@param event_len length of the event accounting possible checksum alg
@return TRUE if test fails
FALSE as success
*/
bool event_checksum_test(uchar *event_buf, ulong event_len, uint8 alg)
{
bool res= FALSE;
uint16 flags= 0; // to store in FD's buffer flags orig value
if (alg != BINLOG_CHECKSUM_ALG_OFF && alg != BINLOG_CHECKSUM_ALG_UNDEF)
{
ha_checksum incoming;
ha_checksum computed;
if (event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
{
#ifndef DBUG_OFF
int8 fd_alg= event_buf[event_len - BINLOG_CHECKSUM_LEN -
BINLOG_CHECKSUM_ALG_DESC_LEN];
#endif
/*
FD event is checksummed and therefore verified w/o the binlog-in-use flag
*/
flags= uint2korr(event_buf + FLAGS_OFFSET);
if (flags & LOG_EVENT_BINLOG_IN_USE_F)
event_buf[FLAGS_OFFSET] &= ~LOG_EVENT_BINLOG_IN_USE_F;
/*
The only algorithm currently is CRC32. Zero indicates
the binlog file is checksum-free *except* the FD-event.
*/
DBUG_ASSERT(fd_alg == BINLOG_CHECKSUM_ALG_CRC32 || fd_alg == 0);
DBUG_ASSERT(alg == BINLOG_CHECKSUM_ALG_CRC32);
/*
Complile time guard to watch over the max number of alg
*/
compile_time_assert(BINLOG_CHECKSUM_ALG_ENUM_END <= 0x80);
}
incoming= uint4korr(event_buf + event_len - BINLOG_CHECKSUM_LEN);
computed= my_checksum(0L, NULL, 0);
/* checksum the event content but the checksum part itself */
computed= my_checksum(computed, (const uchar*) event_buf,
event_len - BINLOG_CHECKSUM_LEN);
if (flags != 0)
{
/* restoring the orig value of flags of FD */
DBUG_ASSERT(event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT);
event_buf[FLAGS_OFFSET]= flags;
}
res= !(computed == incoming);
}
return DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, res);
}
......@@ -6249,6 +6249,10 @@ ER_UNKNOWN_OPTION
eng "Unknown option '%-.64s'"
ER_BAD_OPTION_VALUE
eng "Incorrect value '%-.64s' for option '%-.64s'"
ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from network."
ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE
eng "Replication event checksum verification failed while reading from a log file."
ER_CANT_DO_ONLINE
eng "Can't execute the given '%s' command as online"
This diff is collapsed.
......@@ -186,7 +186,8 @@ void mysql_client_binlog_statement(THD* thd)
}
ev= Log_event::read_log_event(bufptr, event_len, &error,
rli->relay_log.description_event_for_exec);
rli->relay_log.description_event_for_exec,
0);
DBUG_PRINT("info",("binlog base64 err=%s", error));
if (!ev)
......
......@@ -188,7 +188,7 @@ typedef struct st_user_var_events
#define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
#define RP_FORCE_ROTATE 2
#define RP_BINLOG_CHECKSUM_ALG_CHANGE 4
/*
The COPY_INFO structure is used by INSERT/REPLACE code.
The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY
......
This diff is collapsed.
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