mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -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;
|
||||
|
Reference in New Issue
Block a user