Skip to content

Commit e5cb1d5

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ä <[email protected]> RB: 9320
1 parent 28fcef9 commit e5cb1d5

File tree

9 files changed

+127
-21
lines changed

9 files changed

+127
-21
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
call mtr.add_suppression('InnoDB: Failed to find tablespace for table \'".*".".*"\' in the cache');
2+
call mtr.add_suppression('InnoDB: Allocated tablespace [0-9]+, old maximum was [0-9]+');
3+
create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb;
4+
insert into t1 values(1, 2);
5+
SET GLOBAL innodb_fast_shutdown = 0;
6+
# Stop server
7+
# Restart server.
8+
select * from t1;
9+
f1 f2
10+
1 2
11+
insert into t1 values(2, 3);
12+
ERROR HY000: Table 't1' is read only
13+
alter table t1 add f3 int not null, algorithm=copy;
14+
ERROR HY000: InnoDB is in read only mode.
15+
alter table t1 add f3 int not null, algorithm=inplace;
16+
ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Running in read-only mode. Try ALGORITHM=COPY.
17+
drop index idx on t1;
18+
ERROR HY000: InnoDB is in read only mode.
19+
update t1 set f1=3 where f2=2;
20+
ERROR HY000: Table 't1' is read only
21+
create table t3(f1 int not null)engine=innodb;
22+
ERROR HY000: InnoDB is in read only mode.
23+
drop table t3;
24+
ERROR 42S02: Unknown table 'test.t3'
25+
rename table t1 to t3;
26+
ERROR HY000: Error on rename of './test/t1' to './test/t3' (errno: 165 - Table is read only)
27+
truncate table t1;
28+
ERROR HY000: Table 't1' is read only
29+
drop table t1;
30+
show tables;
31+
Tables_in_test
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Not supported in embedded
2+
--source include/not_embedded.inc
3+
4+
# This test case needs InnoDB.
5+
-- source include/have_innodb.inc
6+
7+
call mtr.add_suppression('InnoDB: Failed to find tablespace for table \'".*".".*"\' in the cache');
8+
call mtr.add_suppression('InnoDB: Allocated tablespace [0-9]+, old maximum was [0-9]+');
9+
10+
create table t1(f1 int not null, f2 int not null, index idx(f2))engine=innodb;
11+
insert into t1 values(1, 2);
12+
13+
SET GLOBAL innodb_fast_shutdown = 0;
14+
15+
# Restart the server in force recovery mode
16+
--echo # Stop server
17+
18+
# Write file to make mysql-test-run.pl wait for the server to stop
19+
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
20+
21+
# Request shutdown
22+
-- send_shutdown
23+
24+
# Call script that will poll the server waiting for it to disapear
25+
-- source include/wait_until_disconnected.inc
26+
27+
--echo # Restart server.
28+
29+
# Write file to make mysql-test-run.pl start up the server again, ensure
30+
# that no background threads are started, so that we can check that it
31+
# shuts down properly.
32+
--exec echo "restart:--innodb-force-recovery=4" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
33+
34+
# Turn on reconnect
35+
--enable_reconnect
36+
37+
# Call script that will poll the server waiting for it to be back online again
38+
--source include/wait_until_connected_again.inc
39+
40+
# Turn off reconnect again
41+
--disable_reconnect
42+
43+
select * from t1;
44+
45+
--error ER_OPEN_AS_READONLY
46+
insert into t1 values(2, 3);
47+
48+
--error ER_INNODB_READ_ONLY
49+
alter table t1 add f3 int not null, algorithm=copy;
50+
51+
--error ER_ALTER_OPERATION_NOT_SUPPORTED_REASON
52+
alter table t1 add f3 int not null, algorithm=inplace;
53+
54+
--error ER_INNODB_READ_ONLY
55+
drop index idx on t1;
56+
57+
--error ER_OPEN_AS_READONLY
58+
update t1 set f1=3 where f2=2;
59+
60+
--error ER_INNODB_READ_ONLY
61+
create table t3(f1 int not null)engine=innodb;
62+
63+
--error ER_BAD_TABLE_ERROR
64+
drop table t3;
65+
66+
--error ER_ERROR_ON_RENAME
67+
rename table t1 to t3;
68+
69+
--error ER_OPEN_AS_READONLY
70+
truncate table t1;
71+
72+
drop table t1;
73+
show tables;

storage/innobase/handler/ha_innodb.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6495,7 +6495,7 @@ ha_innobase::write_row(
64956495

64966496
DBUG_ENTER("ha_innobase::write_row");
64976497

6498-
if (srv_read_only_mode) {
6498+
if (high_level_read_only) {
64996499
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
65006500
DBUG_RETURN(HA_ERR_TABLE_READONLY);
65016501
} else if (prebuilt->trx != trx) {
@@ -7039,7 +7039,7 @@ ha_innobase::update_row(
70397039

70407040
ut_a(prebuilt->trx == trx);
70417041

7042-
if (srv_read_only_mode) {
7042+
if (high_level_read_only) {
70437043
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
70447044
DBUG_RETURN(HA_ERR_TABLE_READONLY);
70457045
} else if (!trx_is_started(trx)) {
@@ -7171,7 +7171,7 @@ ha_innobase::delete_row(
71717171

71727172
ut_a(prebuilt->trx == trx);
71737173

7174-
if (srv_read_only_mode) {
7174+
if (high_level_read_only) {
71757175
ib_senderrf(ha_thd(), IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
71767176
DBUG_RETURN(HA_ERR_TABLE_READONLY);
71777177
} else if (!trx_is_started(trx)) {
@@ -9499,7 +9499,7 @@ ha_innobase::create(
94999499

95009500
if (form->s->fields > REC_MAX_N_USER_FIELDS) {
95019501
DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS);
9502-
} else if (srv_read_only_mode) {
9502+
} else if (high_level_read_only) {
95039503
DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
95049504
}
95059505

@@ -9829,7 +9829,7 @@ ha_innobase::discard_or_import_tablespace(
98299829
ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
98309830
ut_a(prebuilt->trx == thd_to_trx(ha_thd()));
98319831

9832-
if (srv_read_only_mode) {
9832+
if (high_level_read_only) {
98339833
DBUG_RETURN(HA_ERR_TABLE_READONLY);
98349834
}
98359835

@@ -9923,7 +9923,7 @@ ha_innobase::truncate()
99239923

99249924
DBUG_ENTER("ha_innobase::truncate");
99259925

9926-
if (srv_read_only_mode) {
9926+
if (high_level_read_only) {
99279927
DBUG_RETURN(HA_ERR_TABLE_READONLY);
99289928
}
99299929

@@ -10274,7 +10274,7 @@ ha_innobase::rename_table(
1027410274

1027510275
DBUG_ENTER("ha_innobase::rename_table");
1027610276

10277-
if (srv_read_only_mode) {
10277+
if (high_level_read_only) {
1027810278
ib_senderrf(thd, IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
1027910279
DBUG_RETURN(HA_ERR_TABLE_READONLY);
1028010280
}

storage/innobase/handler/handler0alter.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ ha_innobase::check_if_supported_inplace_alter(
234234
{
235235
DBUG_ENTER("check_if_supported_inplace_alter");
236236

237-
if (srv_read_only_mode) {
237+
if (high_level_read_only) {
238238
ha_alter_info->unsupported_reason =
239239
innobase_get_err_msg(ER_READ_ONLY_MODE);
240240
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);

storage/innobase/include/ibuf0ibuf.ic

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22

3-
Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
44

55
This program is free software; you can redistribute it and/or modify it under
66
the terms of the GNU General Public License as published by the Free Software
@@ -128,7 +128,8 @@ ibuf_should_try(
128128
&& ibuf->max_size != 0
129129
&& !dict_index_is_clust(index)
130130
&& index->table->quiesce == QUIESCE_NONE
131-
&& (ignore_sec_unique || !dict_index_is_unique(index)));
131+
&& (ignore_sec_unique || !dict_index_is_unique(index))
132+
&& srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE);
132133
}
133134

134135
/******************************************************************//**

storage/innobase/include/srv0srv.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
3+
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
44
Copyright (c) 2008, 2009, Google Inc.
55
Copyright (c) 2009, Percona Inc.
66
@@ -187,6 +187,9 @@ extern char* srv_arch_dir;
187187
recovery and open all tables in RO mode instead of RW mode. We don't
188188
sync the max trx id to disk either. */
189189
extern my_bool srv_read_only_mode;
190+
/** Set if InnoDB operates in read-only mode or innodb-force-recovery
191+
is greater than SRV_FORCE_NO_TRX_UNDO. */
192+
extern my_bool high_level_read_only;
190193
/** store to its own file each table created by an user; data
191194
dictionary tables are in the system tablespace 0 */
192195
extern my_bool srv_file_per_table;

storage/innobase/log/log0log.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2009, Google Inc.
55
66
Portions of this file contain modifications contributed and copyrighted by
@@ -3406,11 +3406,7 @@ logs_empty_and_mark_files_at_shutdown(void)
34063406

34073407
lsn = log_sys->lsn;
34083408

3409-
ut_ad(srv_force_recovery != SRV_FORCE_NO_LOG_REDO
3410-
|| lsn == log_sys->last_checkpoint_lsn + LOG_BLOCK_HDR_SIZE);
3411-
3412-
if ((srv_force_recovery != SRV_FORCE_NO_LOG_REDO
3413-
&& lsn != log_sys->last_checkpoint_lsn)
3409+
if (lsn != log_sys->last_checkpoint_lsn
34143410
#ifdef UNIV_LOG_ARCHIVE
34153411
|| (srv_log_archive_on
34163412
&& lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE)

storage/innobase/srv/srv0srv.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*****************************************************************************
22
3-
Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
3+
Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
44
Copyright (c) 2008, 2009 Google Inc.
55
Copyright (c) 2009, Percona Inc.
66
@@ -126,6 +126,9 @@ UNIV_INTERN ulint srv_file_format = 0;
126126
UNIV_FORMAT_MAX + 1 means no checking ie. FALSE. The default is to
127127
set it to the highest format we support. */
128128
UNIV_INTERN ulint srv_max_file_format_at_startup = UNIV_FORMAT_MAX;
129+
/** Set if InnoDB operates in read-only mode or innodb-force-recovery
130+
is greater than SRV_FORCE_NO_TRX_UNDO. */
131+
UNIV_INTERN my_bool high_level_read_only;
129132

130133
#if UNIV_FORMAT_A
131134
# error "UNIV_FORMAT_A must be 0!"

storage/innobase/srv/srv0start.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,9 +1545,8 @@ innobase_start_or_create_for_mysql(void)
15451545
char* logfile0 = NULL;
15461546
size_t dirnamelen;
15471547

1548-
if (srv_force_recovery > SRV_FORCE_NO_TRX_UNDO) {
1549-
srv_read_only_mode = true;
1550-
}
1548+
high_level_read_only = srv_read_only_mode
1549+
|| srv_force_recovery > SRV_FORCE_NO_TRX_UNDO;
15511550

15521551
if (srv_read_only_mode) {
15531552
ib_logf(IB_LOG_LEVEL_INFO, "Started in read only mode");

0 commit comments

Comments
 (0)