diff --git a/mysql-test/suite/innodb/r/innodb_force_recovery.result b/mysql-test/suite/innodb/r/innodb_force_recovery.result index e405a79dd53..d71a6c4e8b0 100644 --- a/mysql-test/suite/innodb/r/innodb_force_recovery.result +++ b/mysql-test/suite/innodb/r/innodb_force_recovery.result @@ -1,5 +1,5 @@ create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb; -create table t2(f1 int not null, f2 int not null, index idx(f2))engine=innodb; +create table t2(f1 int primary key, f2 int, index idx(f2))engine=innodb; insert into t1 values(1, 2); insert into t2 values(1, 2); SET GLOBAL innodb_fast_shutdown = 0; @@ -85,6 +85,37 @@ ERROR HY000: Table 't2' is read only show tables; Tables_in_test t2 +# Restart the server with innodb_force_recovery=2 +select * from t2; +f1 f2 +1 2 +begin; +update t2 set f2=3; +connect con1,localhost,root,,; +create table t3(a int)engine=innodb; +# Force a redo log flush of the above uncommitted UPDATE +SET GLOBAL innodb_flush_log_at_trx_commit=1; +drop table t3; +disconnect con1; +connection default; +# Kill the server +# Restart the server with innodb_force_recovery=3 +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +select * from t2; +f1 f2 +1 3 +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +select * from t2; +f1 f2 +1 2 +SET GLOBAL innodb_lock_wait_timeout=1; +insert into t2 values(1,2); +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +insert into t2 values(9,10); +select * from t2; +f1 f2 +1 2 +9 10 drop table t2; show tables; Tables_in_test diff --git a/mysql-test/suite/innodb/t/innodb_force_recovery.test b/mysql-test/suite/innodb/t/innodb_force_recovery.test index 31b9660e872..f9af16f6609 100644 --- a/mysql-test/suite/innodb/t/innodb_force_recovery.test +++ b/mysql-test/suite/innodb/t/innodb_force_recovery.test @@ -10,7 +10,7 @@ call mtr.add_suppression("InnoDB: Allocated tablespace ID \\d+ for test.t[12], o --enable_query_log create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb; -create table t2(f1 int not null, f2 int not null, index idx(f2))engine=innodb; +create table t2(f1 int primary key, f2 int, index idx(f2))engine=innodb; insert into t1 values(1, 2); insert into t2 values(1, 2); @@ -132,8 +132,40 @@ truncate table t2; drop table t2; show tables; +--echo # Restart the server with innodb_force_recovery=2 +--let $restart_parameters= --innodb-force-recovery=2 +--source include/restart_mysqld.inc + +select * from t2; +begin; +update t2 set f2=3; + +connect (con1,localhost,root,,); +create table t3(a int)engine=innodb; +--echo # Force a redo log flush of the above uncommitted UPDATE +SET GLOBAL innodb_flush_log_at_trx_commit=1; +drop table t3; +disconnect con1; + +connection default; +--source include/kill_mysqld.inc + +--echo # Restart the server with innodb_force_recovery=3 +--let $restart_parameters= --innodb-force-recovery=3 +--source include/start_mysqld.inc + +SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; +select * from t2; +SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; +select * from t2; +SET GLOBAL innodb_lock_wait_timeout=1; +--error ER_LOCK_WAIT_TIMEOUT +insert into t2 values(1,2); +insert into t2 values(9,10); + --let $restart_parameters= --source include/restart_mysqld.inc +select * from t2; drop table t2; show tables; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 4751109292f..e74fdc7a5d7 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -70,11 +70,6 @@ Created 9/17/2000 Heikki Tuuri #include #include -static const char* MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY = - "innodb_force_recovery is on. We do not allow database modifications" - " by the user. Shut down mysqld and edit my.cnf to set" - " innodb_force_recovery=0"; - /** Provide optional 4.x backwards compatibility for 5.0 and above */ ibool row_rollback_on_timeout = FALSE; @@ -1432,9 +1427,7 @@ row_insert_for_mysql( } else if (!prebuilt->table->is_readable()) { return(row_mysql_get_table_status(prebuilt->table, trx, true)); - } else if (srv_force_recovery) { - - ib::error() << MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY; + } else if (high_level_read_only) { return(DB_READ_ONLY); } DBUG_EXECUTE_IF("mark_table_corrupted", { @@ -1850,9 +1843,8 @@ row_update_for_mysql_using_upd_graph( return(row_mysql_get_table_status(table, trx, true)); } - if(srv_force_recovery) { - ib::error() << MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY; - DBUG_RETURN(DB_READ_ONLY); + if (high_level_read_only) { + return(DB_READ_ONLY); } DEBUG_SYNC_C("innodb_row_update_for_mysql_begin"); @@ -4472,10 +4464,8 @@ row_rename_table_for_mysql( ut_a(new_name != NULL); ut_ad(trx->state == TRX_STATE_ACTIVE); - if (srv_force_recovery) { - ib::info() << MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY; - err = DB_READ_ONLY; - goto funct_exit; + if (high_level_read_only) { + return(DB_READ_ONLY); } else if (row_mysql_is_system_table(new_name)) { diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index fbe29d5e75f..a6b21e3893f 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1471,10 +1471,6 @@ innobase_start_or_create_for_mysql() srv_read_only_mode = true; } - if (srv_force_recovery == SRV_FORCE_NO_LOG_REDO) { - srv_read_only_mode = 1; - } - high_level_read_only = srv_read_only_mode || srv_force_recovery > SRV_FORCE_NO_TRX_UNDO; diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 5fea72b870c..317087173c5 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -285,8 +285,12 @@ trx_purge_add_update_undo_to_history( purge have been started, recv_recovery_rollback_active() can start transactions in row_merge_drop_temp_indexes() and fts_drop_orphaned_tables(), and roll back recovered transactions. - Also, DROP TABLE may be executed while innodb_force_recovery=2 - prevents the purge from running. + + Arbitrary user transactions may be executed when all the undo log + related background processes (including purge) are disabled due to + innodb_force_recovery=2 or innodb_force_recovery=3. + DROP TABLE may be executed at any innodb_force_recovery level. + After the purge thread has been given permission to exit, in fast shutdown, we may roll back transactions (trx->undo_no==0) in THD::cleanup() invoked from unlink_thd(). */