Commit 46ee272a authored by Nikita Malyavin's avatar Nikita Malyavin

MDEV-32100 Online ALTER TABLE ends with 1032 under some isolation levels

1032 (Can't find record) could be emitted when ALTER TABLE is execued vs
concurrent DELETE/UPDATE/other DML that would require search on the online
ALTER's side.

Innodb's INPLACE, in comparison, creates a new trx_t and uses it in scope
of the alter table context.

ALTER TABLE class of statements (i.g. CREATE INDEX, OPTIMIZE, etc.) is
expected to be unaffected by the value of current session's transaction
isolation.

This patch save-and-restores thd->tx_isolation and sets in to
ISO_REPEATABLE_READ for almost a whole mysql_alter_table duration, to avoid
any possible side-effect of it. This should be primarily done before the
lock_tables call, to initialize the storage engine's local value correctly
during the store_lock() call.

sql_table.cc: set thd->tx_isolation to ISO_REPEATABLE_READ in
mysql_alter_table and then restore it to the original value in the end of
the call.
parent 5c5123df
......@@ -1456,6 +1456,68 @@ connection default;
set old_mode= @old_old_mode;
drop table t1;
set debug_sync= reset;
#
# MDEV-32100 Online ALTER TABLE ends with 1032 under some isolation levels
#
create table iso_levels(id int, level text);
INSERT iso_levels VALUES (0, "READ UNCOMMITTED"),
(1, "READ COMMITTED"),
(2, "REPEATABLE READ"),
(3, "SERIALIZABLE");
create table t1 (a int, b int, key(b)) engine=innodb;
connection con2;
insert into t1 values (1,1),(null,null),(3,3),(4,null),(null,5);
connection default;
set session transaction isolation level SERIALIZABLE;
set debug_sync= "alter_table_online_downgraded signal downgraded wait_for goalters";
alter table t1 force, algorithm=copy;
connection con2;
set debug_sync= "now wait_for downgraded";
delete from t1 where b is null;
set debug_sync= "now signal goalters";
connection default;
drop table t1;
create table t1 (a int, b int, key(b)) engine=innodb;
connection con2;
insert into t1 values (1,1),(null,null),(3,3),(4,null),(null,5);
connection default;
set session transaction isolation level REPEATABLE READ;
set debug_sync= "alter_table_online_downgraded signal downgraded wait_for goalters";
alter table t1 force, algorithm=copy;
connection con2;
set debug_sync= "now wait_for downgraded";
delete from t1 where b is null;
set debug_sync= "now signal goalters";
connection default;
drop table t1;
create table t1 (a int, b int, key(b)) engine=innodb;
connection con2;
insert into t1 values (1,1),(null,null),(3,3),(4,null),(null,5);
connection default;
set session transaction isolation level READ COMMITTED;
set debug_sync= "alter_table_online_downgraded signal downgraded wait_for goalters";
alter table t1 force, algorithm=copy;
connection con2;
set debug_sync= "now wait_for downgraded";
delete from t1 where b is null;
set debug_sync= "now signal goalters";
connection default;
drop table t1;
create table t1 (a int, b int, key(b)) engine=innodb;
connection con2;
insert into t1 values (1,1),(null,null),(3,3),(4,null),(null,5);
connection default;
set session transaction isolation level READ UNCOMMITTED;
set debug_sync= "alter_table_online_downgraded signal downgraded wait_for goalters";
alter table t1 force, algorithm=copy;
connection con2;
set debug_sync= "now wait_for downgraded";
delete from t1 where b is null;
set debug_sync= "now signal goalters";
connection default;
drop table t1;
set debug_sync= reset;
drop table iso_levels;
disconnect con1;
disconnect con2;
#
......
......@@ -1695,6 +1695,47 @@ set old_mode= @old_old_mode;
drop table t1;
set debug_sync= reset;
--echo #
--echo # MDEV-32100 Online ALTER TABLE ends with 1032 under some isolation levels
--echo #
let $tx_iso_id=4;
create table iso_levels(id int, level text);
INSERT iso_levels VALUES (0, "READ UNCOMMITTED"),
(1, "READ COMMITTED"),
(2, "REPEATABLE READ"),
(3, "SERIALIZABLE");
while($tx_iso_id) {
dec $tx_iso_id;
let tx_iso= `select level from iso_levels where id = $tx_iso_id`;
create table t1 (a int, b int, key(b)) engine=innodb;
--connection con2
insert into t1 values (1,1),(null,null),(3,3),(4,null),(null,5);
--connection default
eval set session transaction isolation level $tx_iso;
set debug_sync= "alter_table_online_downgraded signal downgraded wait_for goalters";
send alter table t1 force, algorithm=copy;
--connection con2
set debug_sync= "now wait_for downgraded";
delete from t1 where b is null;
set debug_sync= "now signal goalters";
--connection default
--reap
drop table t1;
}
set debug_sync= reset;
drop table iso_levels;
--disconnect con1
--disconnect con2
......
......@@ -65,6 +65,7 @@
#include "rpl_rli.h"
#include "log.h"
#include "sql_debug.h"
#include "scope.h"
#ifdef _WIN32
#include <io.h>
......@@ -10236,6 +10237,12 @@ bool mysql_alter_table(THD *thd, const LEX_CSTRING *new_db,
table_list->lock_type= TL_READ;
}
enum_tx_isolation iso_level_initial= thd->tx_isolation;
SCOPE_EXIT([thd, iso_level_initial](){
thd->tx_isolation= iso_level_initial;
});
thd->tx_isolation= ISO_REPEATABLE_READ;
DEBUG_SYNC(thd, "alter_table_before_open_tables");
thd->open_options|= HA_OPEN_FOR_ALTER;
......
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