mirror of
https://github.com/MariaDB/server.git
synced 2025-07-08 17:02:21 +03:00
MDEV-35506 commit policy of one-phase-commit even at errored-out binlogging leads to assert
Currently execution of commit in one phase proceeds to commit by engines when binlog_commit() does not succeed. There are two issues with that: 1. absence of binlog_rollback() or lower-level `binlog_cache_data::reset()` along the following execution of the failing statement eventually will raise an assert on non-empty binlog cache, find in the MDEV description # --error assert(sql/log.cc:1712(binlog_close_connection)) # --disconnect default 2. engines, including ones that are rollback capable, commit in this particular error situation. Both effects can be observed with a new mtr test that would fail when run on a BASE of this commit. The BASE has to include MDEV-35207 et all fixes because the test is written with CREATE-TABLE-SELECTs. A new test file verifies the new behaviour to rollback including cases with a side effect of modified non-transactional engine which expose another MDEV-36027 (TODO: fix).
This commit is contained in:
116
mysql-test/suite/binlog/r/binlog_commit_fail.result
Normal file
116
mysql-test/suite/binlog/r/binlog_commit_fail.result
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
set @@session.gtid_domain_id=1;
|
||||||
|
set @save_gtid_stric_mode=@@global.gtid_strict_mode;
|
||||||
|
create table ta (a int) engine=aria;
|
||||||
|
create table ti (a int) engine=innodb;
|
||||||
|
create table ti_pk (a int primary key) engine=innodb;
|
||||||
|
create table t (a int) engine=innodb;
|
||||||
|
create function f_i()
|
||||||
|
returns integer
|
||||||
|
begin
|
||||||
|
insert into ti set a=1;
|
||||||
|
return 1;
|
||||||
|
end |
|
||||||
|
create function f_ia(arg int)
|
||||||
|
returns integer
|
||||||
|
begin
|
||||||
|
insert into ti_pk set a=1;
|
||||||
|
insert into ta set a=1;
|
||||||
|
insert into ti_pk set a=arg;
|
||||||
|
return 1;
|
||||||
|
end |
|
||||||
|
call mtr.add_suppression("Error writing file");
|
||||||
|
select count(*) as zero from t;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
select count(*) as zero from ta;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
# 1. simple Innodb test
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
insert into t set a=1;
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
# observe effective rollback
|
||||||
|
select count(*) as zero from t;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
# 2. simple Aira test
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
insert into ta values (1),(2);
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
# note no rollback
|
||||||
|
select count(*) as '*NON-zero*' from ta;
|
||||||
|
*NON-zero*
|
||||||
|
2
|
||||||
|
delete from ta;
|
||||||
|
# 3. multi-engine test
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
insert into ta set a=f_i();
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
# note no rollback..
|
||||||
|
select count(*) as one from ta;
|
||||||
|
one
|
||||||
|
1
|
||||||
|
# ..except transactional engine
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
delete from ta;
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
insert into t set a=f_ia(0);
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
# note no rollback..
|
||||||
|
select count(*) as one from ta;
|
||||||
|
one
|
||||||
|
1
|
||||||
|
# ..except transactional engine
|
||||||
|
select count(*) as zero from t;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
select count(*) as zero from ti_pk;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
delete from ta;
|
||||||
|
# 4. create-table-select-f()
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
create table f_x (a int) select f_i() as a;
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
# rollback indeed takes place in the pure transactional case
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
set @@global.gtid_strict_mode=0;
|
||||||
|
set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
create table t_x (a int) engine=aria select f_ia(0) as a;
|
||||||
|
ERROR HY000: An attempt was made to binlog GTID VALUE which would create an out-of-order sequence number with existing GTID VALUE, and gtid strict mode is enabled
|
||||||
|
select * from t_x;
|
||||||
|
ERROR 42S02: Table 'test.t_x' doesn't exist
|
||||||
|
# **TODO**: fix MDEV-36027
|
||||||
|
# **TODO**: the empty binlog is buggy ..
|
||||||
|
include/show_binlog_events.inc
|
||||||
|
# .. as non-transactional `ta` (and `t_x` sic!) are modified
|
||||||
|
select count(*) as one from ta;
|
||||||
|
one
|
||||||
|
1
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
zero
|
||||||
|
0
|
||||||
|
delete from ta;
|
||||||
|
#.
|
||||||
|
set @@global.gtid_strict_mode=@save_gtid_stric_mode;
|
||||||
|
drop function f_i;
|
||||||
|
drop function f_ia;
|
||||||
|
drop table t, ta, ti, ti_pk;
|
135
mysql-test/suite/binlog/t/binlog_commit_fail.test
Normal file
135
mysql-test/suite/binlog/t/binlog_commit_fail.test
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
# Tests of commit time failures.
|
||||||
|
# At committing of an auto-commit statement a failure to commit in its
|
||||||
|
# binlog branch should rollback at least the transactional part of the statement.
|
||||||
|
#
|
||||||
|
# References:
|
||||||
|
# MDEV-35506 commit policy of one-phase-commit even at errored-out binlogging leads to assert
|
||||||
|
# MDEV-36027 Errored-out CREATE-SELECT does not binlog results of non-transactional table modification
|
||||||
|
|
||||||
|
source include/have_innodb.inc;
|
||||||
|
source include/have_binlog_format_row.inc;
|
||||||
|
|
||||||
|
set @@session.gtid_domain_id=1;
|
||||||
|
set @save_gtid_stric_mode=@@global.gtid_strict_mode;
|
||||||
|
|
||||||
|
create table ta (a int) engine=aria;
|
||||||
|
create table ti (a int) engine=innodb;
|
||||||
|
create table ti_pk (a int primary key) engine=innodb;
|
||||||
|
create table t (a int) engine=innodb;
|
||||||
|
delimiter |;
|
||||||
|
create function f_i()
|
||||||
|
returns integer
|
||||||
|
begin
|
||||||
|
insert into ti set a=1;
|
||||||
|
return 1;
|
||||||
|
end |
|
||||||
|
create function f_ia(arg int)
|
||||||
|
returns integer
|
||||||
|
begin
|
||||||
|
insert into ti_pk set a=1;
|
||||||
|
insert into ta set a=1;
|
||||||
|
insert into ti_pk set a=arg;
|
||||||
|
return 1;
|
||||||
|
end |
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
call mtr.add_suppression("Error writing file");
|
||||||
|
|
||||||
|
# Naturally all empty now
|
||||||
|
select count(*) as zero from t;
|
||||||
|
select count(*) as zero from ta;
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
|
||||||
|
# Force manual value assignement to gtid::seq_no while in the strict mode
|
||||||
|
# so that the value is rejected. Despite the errorred out statement
|
||||||
|
# being at its commit phase it will eventually be rolled back.
|
||||||
|
# Side effects of non-transactional engines, like Aria, are displayed.
|
||||||
|
--echo # 1. simple Innodb test
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
# mask possible allowed seq_no shift
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
insert into t set a=1;
|
||||||
|
|
||||||
|
--echo # observe effective rollback
|
||||||
|
select count(*) as zero from t;
|
||||||
|
|
||||||
|
--echo # 2. simple Aira test
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
insert into ta values (1),(2);
|
||||||
|
|
||||||
|
--echo # note no rollback
|
||||||
|
select count(*) as '*NON-zero*' from ta;
|
||||||
|
# local cleanup
|
||||||
|
delete from ta;
|
||||||
|
|
||||||
|
--echo # 3. multi-engine test
|
||||||
|
# A. non-transactional top-level
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
insert into ta set a=f_i();
|
||||||
|
--echo # note no rollback..
|
||||||
|
select count(*) as one from ta;
|
||||||
|
--echo # ..except transactional engine
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
delete from ta;
|
||||||
|
|
||||||
|
# B. non-transactional in the leaf
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
insert into t set a=f_ia(0);
|
||||||
|
|
||||||
|
--echo # note no rollback..
|
||||||
|
select count(*) as one from ta;
|
||||||
|
--echo # ..except transactional engine
|
||||||
|
select count(*) as zero from t;
|
||||||
|
select count(*) as zero from ti_pk;
|
||||||
|
delete from ta;
|
||||||
|
|
||||||
|
--echo # 4. create-table-select-f()
|
||||||
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||||
|
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
|
||||||
|
# A. two phase commit branch
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
create table f_x (a int) select f_i() as a;
|
||||||
|
--echo # rollback indeed takes place in the pure transactional case
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
|
||||||
|
# B. one phase commit branch
|
||||||
|
--let $binlog_file= query_get_value(SHOW MASTER STATUS, File, 1)
|
||||||
|
--let $binlog_start = query_get_value(SHOW MASTER STATUS, Position, 1)
|
||||||
|
set @@global.gtid_strict_mode=0; set @@session.gtid_seq_no=1;
|
||||||
|
set @@global.gtid_strict_mode=1;
|
||||||
|
--replace_regex /GTID 1-1-[0-9]+/GTID VALUE/
|
||||||
|
--error ER_GTID_STRICT_OUT_OF_ORDER
|
||||||
|
create table t_x (a int) engine=aria select f_ia(0) as a;
|
||||||
|
--error ER_NO_SUCH_TABLE
|
||||||
|
select * from t_x;
|
||||||
|
|
||||||
|
--echo # **TODO**: fix MDEV-36027
|
||||||
|
--echo # **TODO**: the empty binlog is buggy ..
|
||||||
|
--source include/show_binlog_events.inc
|
||||||
|
--echo # .. as non-transactional `ta` (and `t_x` sic!) are modified
|
||||||
|
select count(*) as one from ta;
|
||||||
|
select count(*) as zero from ti;
|
||||||
|
|
||||||
|
delete from ta;
|
||||||
|
--echo #.
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
|
||||||
|
set @@global.gtid_strict_mode=@save_gtid_stric_mode;
|
||||||
|
drop function f_i;
|
||||||
|
drop function f_ia;
|
||||||
|
drop table t, ta, ti, ti_pk;
|
@ -1901,6 +1901,8 @@ int ha_commit_trans(THD *thd, bool all)
|
|||||||
}
|
}
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
error= ha_commit_one_phase(thd, all);
|
error= ha_commit_one_phase(thd, all);
|
||||||
|
if (error)
|
||||||
|
goto err;
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
// Here in case of error we must return 2 for inconsistency
|
// Here in case of error we must return 2 for inconsistency
|
||||||
if (run_wsrep_hooks && !error)
|
if (run_wsrep_hooks && !error)
|
||||||
@ -2141,7 +2143,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
|||||||
|
|
||||||
if (ha_info)
|
if (ha_info)
|
||||||
{
|
{
|
||||||
int err;
|
int err= 0;
|
||||||
|
|
||||||
if (has_binlog_hton(ha_info) &&
|
if (has_binlog_hton(ha_info) &&
|
||||||
(err= binlog_commit(thd, all,
|
(err= binlog_commit(thd, all,
|
||||||
@ -2149,6 +2151,8 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
|||||||
{
|
{
|
||||||
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
|
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
|
||||||
error= 1;
|
error= 1;
|
||||||
|
|
||||||
|
goto err;
|
||||||
}
|
}
|
||||||
for (; ha_info; ha_info= ha_info_next)
|
for (; ha_info; ha_info= ha_info_next)
|
||||||
{
|
{
|
||||||
@ -2184,7 +2188,7 @@ commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans)
|
|||||||
if (count >= 2)
|
if (count >= 2)
|
||||||
statistic_increment(transactions_multi_engine, LOCK_status);
|
statistic_increment(transactions_multi_engine, LOCK_status);
|
||||||
}
|
}
|
||||||
|
err:
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user