Permalink
Browse files

Bug #19779113 INNODB REFUSES STARTUP WITH INNODB_FORCE_RECOVERY>3

Problem:
=======

Server refuses to startup when innodb_force_recovery > 3 and
InnoDB making the server to read-only mode before applying the redo log.

Solution:
========
Introduce a new variable called high_level_read_only and
it will be enabled when server is in read-only mode or
innodb_force_recovery > 3. This variable will be
checked during DML and DDL(expect Drop table). In other words,
Drop table is the only operation allowed when innodb_force_recovery > 3.

Reviewed-by: Marko Mäkelä <marko.makela@oracle.com>
RB: 9320
  • Loading branch information...
Thirunarayanan committed Jul 8, 2015
1 parent 28fcef9 commit e5cb1d5adaa603a88277f03fe37cb729d77e8ff6
@@ -0,0 +1,31 @@
call mtr.add_suppression('InnoDB: Failed to find tablespace for table \'".*".".*"\' in the cache');
call mtr.add_suppression('InnoDB: Allocated tablespace [0-9]+, old maximum was [0-9]+');
create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb;
insert into t1 values(1, 2);
SET GLOBAL innodb_fast_shutdown = 0;
# Stop server
# Restart server.
select * from t1;
f1 f2
1 2
insert into t1 values(2, 3);
ERROR HY000: Table 't1' is read only
alter table t1 add f3 int not null, algorithm=copy;
ERROR HY000: InnoDB is in read only mode.
alter table t1 add f3 int not null, algorithm=inplace;
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Running in read-only mode. Try ALGORITHM=COPY.
drop index idx on t1;
ERROR HY000: InnoDB is in read only mode.
update t1 set f1=3 where f2=2;
ERROR HY000: Table 't1' is read only
create table t3(f1 int not null)engine=innodb;
ERROR HY000: InnoDB is in read only mode.
drop table t3;
ERROR 42S02: Unknown table 'test.t3'
rename table t1 to t3;
ERROR HY000: Error on rename of './test/t1' to './test/t3' (errno: 165 - Table is read only)
truncate table t1;
ERROR HY000: Table 't1' is read only
drop table t1;
show tables;
Tables_in_test
@@ -0,0 +1,73 @@
# Not supported in embedded
--source include/not_embedded.inc
# This test case needs InnoDB.
-- source include/have_innodb.inc
call mtr.add_suppression('InnoDB: Failed to find tablespace for table \'".*".".*"\' in the cache');
call mtr.add_suppression('InnoDB: Allocated tablespace [0-9]+, old maximum was [0-9]+');
create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb;
insert into t1 values(1, 2);
SET GLOBAL innodb_fast_shutdown = 0;
# Restart the server in force recovery mode
--echo # Stop server
# Write file to make mysql-test-run.pl wait for the server to stop
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
# Request shutdown
-- send_shutdown
# Call script that will poll the server waiting for it to disapear
-- source include/wait_until_disconnected.inc
--echo # Restart server.
# Write file to make mysql-test-run.pl start up the server again, ensure
# that no background threads are started, so that we can check that it
# shuts down properly.
--exec echo "restart:--innodb-force-recovery=4" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
# Turn on reconnect
--enable_reconnect
# Call script that will poll the server waiting for it to be back online again
--source include/wait_until_connected_again.inc
# Turn off reconnect again
--disable_reconnect
select * from t1;
--error ER_OPEN_AS_READONLY
insert into t1 values(2, 3);
--error ER_INNODB_READ_ONLY
alter table t1 add f3 int not null, algorithm=copy;
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
alter table t1 add f3 int not null, algorithm=inplace;
--error ER_INNODB_READ_ONLY
drop index idx on t1;
--error ER_OPEN_AS_READONLY
update t1 set f1=3 where f2=2;
--error ER_INNODB_READ_ONLY
create table t3(f1 int not null)engine=innodb;
--error ER_BAD_TABLE_ERROR
drop table t3;
--error ER_ERROR_ON_RENAME
rename table t1 to t3;
--error ER_OPEN_AS_READONLY
truncate table t1;
drop table t1;
show tables;
@@ -6495,7 +6495,7 @@ ha_innobase::write_row(
DBUG_ENTER("ha_innobase::write_row");
if (srv_read_only_mode) {
if (high_level_read_only) {
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (prebuilt->trx != trx) {
@@ -7039,7 +7039,7 @@ ha_innobase::update_row(
ut_a(prebuilt->trx == trx);
if (srv_read_only_mode) {
if (high_level_read_only) {
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) {
@@ -7171,7 +7171,7 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx);
if (srv_read_only_mode) {
if (high_level_read_only) {
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
} else if (!trx_is_started(trx)) {
@@ -9499,7 +9499,7 @@ ha_innobase::create(
if (form->s->fields > REC_MAX_N_USER_FIELDS) {
DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS);
} else if (srv_read_only_mode) {
} else if (high_level_read_only) {
DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
}
@@ -9829,7 +9829,7 @@ ha_innobase::discard_or_import_tablespace(
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
if (srv_read_only_mode) {
if (high_level_read_only) {
DBUG_RETURN(HA_ERR_TABLE_READONLY);
}
@@ -9923,7 +9923,7 @@ ha_innobase::truncate()
DBUG_ENTER("ha_innobase::truncate");
if (srv_read_only_mode) {
if (high_level_read_only) {
DBUG_RETURN(HA_ERR_TABLE_READONLY);
}
@@ -10274,7 +10274,7 @@ ha_innobase::rename_table(
DBUG_ENTER("ha_innobase::rename_table");
if (srv_read_only_mode) {
if (high_level_read_only) {
ib_senderrf(thd, IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ERR_TABLE_READONLY);
}
@@ -234,7 +234,7 @@ ha_innobase::check_if_supported_inplace_alter(
{
DBUG_ENTER("check_if_supported_inplace_alter");
if (srv_read_only_mode) {
if (high_level_read_only) {
ha_alter_info->unsupported_reason =
innobase_get_err_msg(ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1997, 2015, 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
@@ -128,7 +128,8 @@ ibuf_should_try(
&& ibuf->max_size != 0
&& !dict_index_is_clust(index)
&& index->table->quiesce == QUIESCE_NONE
&& (ignore_sec_unique || !dict_index_is_unique(index)));
&& (ignore_sec_unique || !dict_index_is_unique(index))
&& srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE);
}
/******************************************************************//**
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
@@ -187,6 +187,9 @@ extern char* srv_arch_dir;
recovery and open all tables in RO mode instead of RW mode. We don't
sync the max trx id to disk either. */
extern my_bool srv_read_only_mode;
/** Set if InnoDB operates in read-only mode or innodb-force-recovery
is greater than SRV_FORCE_NO_TRX_UNDO. */
extern my_bool high_level_read_only;
/** store to its own file each table created by an user; data
dictionary tables are in the system tablespace 0 */
extern my_bool srv_file_per_table;
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2009, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -3406,11 +3406,7 @@ logs_empty_and_mark_files_at_shutdown(void)
lsn = log_sys->lsn;
ut_ad(srv_force_recovery != SRV_FORCE_NO_LOG_REDO
|| lsn == log_sys->last_checkpoint_lsn + LOG_BLOCK_HDR_SIZE);
if ((srv_force_recovery != SRV_FORCE_NO_LOG_REDO
&& lsn != log_sys->last_checkpoint_lsn)
if (lsn != log_sys->last_checkpoint_lsn
#ifdef UNIV_LOG_ARCHIVE
|| (srv_log_archive_on
&& lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE)
@@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
@@ -126,6 +126,9 @@ UNIV_INTERN ulint srv_file_format = 0;
UNIV_FORMAT_MAX + 1 means no checking ie. FALSE. The default is to
set it to the highest format we support. */
UNIV_INTERN ulint srv_max_file_format_at_startup = UNIV_FORMAT_MAX;
/** Set if InnoDB operates in read-only mode or innodb-force-recovery
is greater than SRV_FORCE_NO_TRX_UNDO. */
UNIV_INTERN my_bool high_level_read_only;
#if UNIV_FORMAT_A
# error "UNIV_FORMAT_A must be 0!"
@@ -1545,9 +1545,8 @@ innobase_start_or_create_for_mysql(void)
char* logfile0 = NULL;
size_t dirnamelen;
if (srv_force_recovery > SRV_FORCE_NO_TRX_UNDO) {
srv_read_only_mode = true;
}
high_level_read_only = srv_read_only_mode
|| srv_force_recovery > SRV_FORCE_NO_TRX_UNDO;
if (srv_read_only_mode) {
ib_logf(IB_LOG_LEVEL_INFO, "Started in read only mode");

0 comments on commit e5cb1d5

Please sign in to comment.