Skip to content

Commit 454beee

Browse files
author
Jan Lindström
committed
MDEV-6288 :Innodb causes server crash after disk full, then can't ALTER TABLE any more
Fix try to avoid unnecessary crashes when disk full situation is reached on alter table.
1 parent 356ae62 commit 454beee

File tree

12 files changed

+142
-61
lines changed

12 files changed

+142
-61
lines changed
Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
create table t1(a int not null primary key, b int) engine=innodb;
1+
call mtr.add_suppression("InnoDB: Error: row_merge_drop_indexes_dict failed with error code*");
2+
create table t1(a int, b int) engine=innodb;
23
create procedure innodb_insert_proc (repeat_count int)
34
begin
45
declare current_num int;
@@ -10,41 +11,49 @@ end while;
1011
end//
1112
commit;
1213
set autocommit=0;
13-
call innodb_insert_proc(10000);
14+
call innodb_insert_proc(20000);
1415
commit;
1516
set autocommit=1;
17+
create table t2(a int) engine=innodb;
18+
show create table t2;
19+
Table Create Table
20+
t2 CREATE TABLE `t2` (
21+
`a` int(11) DEFAULT NULL
22+
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1623
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
1724
alter table t1 add testcol int;
1825
ERROR HY000: The table 't1' is full
1926
show create table t1;
2027
Table Create Table
2128
t1 CREATE TABLE `t1` (
22-
`a` int(11) NOT NULL,
23-
`b` int(11) DEFAULT NULL,
24-
PRIMARY KEY (`a`)
29+
`a` int(11) DEFAULT NULL,
30+
`b` int(11) DEFAULT NULL
2531
) ENGINE=InnoDB DEFAULT CHARSET=latin1
26-
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2';
32+
alter table t2 add testcol int;
33+
ERROR HY000: The table 't2' is full
34+
alter table t1 add testcol int;
35+
ERROR HY000: The table 't1' is full
2736
alter table t1 add testcol int;
2837
ERROR HY000: The table 't1' is full
29-
show create table t1;
30-
Table Create Table
31-
t1 CREATE TABLE `t1` (
32-
`a` int(11) NOT NULL,
33-
`b` int(11) DEFAULT NULL,
34-
PRIMARY KEY (`a`)
35-
) ENGINE=InnoDB DEFAULT CHARSET=latin1
36-
set DEBUG_DBUG=NULL;
3738
alter table t1 add testcol2 int;
39+
ERROR HY000: The table 't1' is full
40+
alter table t1 add testcol3 int;
41+
ERROR HY000: The table 't1' is full
42+
alter table t1 add testcol int;
43+
ERROR HY000: The table 't1' is full
3844
show create table t1;
3945
Table Create Table
4046
t1 CREATE TABLE `t1` (
41-
`a` int(11) NOT NULL,
42-
`b` int(11) DEFAULT NULL,
43-
`testcol2` int(11) DEFAULT NULL,
44-
PRIMARY KEY (`a`)
47+
`a` int(11) DEFAULT NULL,
48+
`b` int(11) DEFAULT NULL
4549
) ENGINE=InnoDB DEFAULT CHARSET=latin1
46-
select count(1) from t1;
47-
count(1)
48-
10000
50+
drop table t2;
51+
alter table t1 add testcol2 int;
52+
ERROR HY000: The table 't1' is full
53+
alter table t1 add testcol3 int;
54+
ERROR HY000: The table 't1' is full
55+
call innodb_insert_proc(20000);
56+
set DEBUG_DBUG='';
4957
drop procedure innodb_insert_proc;
5058
drop table t1;
59+
drop table if exists t2;

mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
# DEBUG_SYNC must be compiled in.
88
--source include/have_debug_sync.inc
99

10-
create table t1(a int not null primary key, b int) engine=innodb;
10+
call mtr.add_suppression("InnoDB: Error: row_merge_drop_indexes_dict failed with error code*");
11+
12+
create table t1(a int, b int) engine=innodb;
1113

1214
delimiter //;
1315
create procedure innodb_insert_proc (repeat_count int)
@@ -23,28 +25,46 @@ delimiter ;//
2325
commit;
2426

2527
set autocommit=0;
26-
call innodb_insert_proc(10000);
28+
call innodb_insert_proc(20000);
2729
commit;
2830
set autocommit=1;
2931

32+
create table t2(a int) engine=innodb;
33+
show create table t2;
34+
3035
# This caused crash earlier
3136
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
3237
--error 1114
3338
alter table t1 add testcol int;
3439
show create table t1;
35-
36-
# This caused crash earlier
37-
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2';
40+
--error 1114
41+
alter table t2 add testcol int;
3842
--error 1114
3943
alter table t1 add testcol int;
40-
show create table t1;
41-
42-
set DEBUG_DBUG=NULL;
44+
--error 1114
45+
alter table t1 add testcol int;
46+
--error 1114
4347
alter table t1 add testcol2 int;
48+
--error 1114
49+
alter table t1 add testcol3 int;
50+
--error 1114
51+
alter table t1 add testcol int;
4452
show create table t1;
53+
--error 0,1051
54+
drop table t2;
55+
--error 1114
56+
alter table t1 add testcol2 int;
57+
--error 1114
58+
alter table t1 add testcol3 int;
59+
--error 0,1114
60+
call innodb_insert_proc(20000);
4561

46-
select count(1) from t1;
62+
set DEBUG_DBUG='';
4763

4864
drop procedure innodb_insert_proc;
4965
drop table t1;
66+
--disable_warnings
67+
drop table if exists t2;
68+
--enable_warnings
69+
5070

storage/innobase/btr/btr0btr.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3055,6 +3055,12 @@ btr_page_split_and_insert(
30553055
/* 2. Allocate a new page to the index */
30563056
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
30573057
btr_page_get_level(page, mtr), mtr, mtr);
3058+
3059+
/* Play safe, if new page is not allocated */
3060+
if (!new_block) {
3061+
return(rec);
3062+
}
3063+
30583064
new_page = buf_block_get_frame(new_block);
30593065
new_page_zip = buf_block_get_page_zip(new_block);
30603066
btr_page_create(new_block, new_page_zip, cursor->index,

storage/innobase/fil/fil0fil.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4957,6 +4957,9 @@ fil_extend_space_to_desired_size(
49574957
success = TRUE;
49584958
}
49594959

4960+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4961+
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);
4962+
49604963
mutex_enter(&fil_system->mutex);
49614964
if (success) {
49624965
node->size += n_pages;
@@ -4998,6 +5001,11 @@ fil_extend_space_to_desired_size(
49985001
offset, page_size * n_pages,
49995002
NULL, NULL);
50005003
#endif /* UNIV_HOTBACKUP */
5004+
5005+
5006+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
5007+
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);
5008+
50015009
if (success) {
50025010
os_has_said_disk_full = FALSE;
50035011
} else {

storage/innobase/os/os0file.cc

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4585,7 +4585,7 @@ os_aio_func(
45854585
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
45864586

45874587
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4588-
mode = OS_AIO_SYNC;);
4588+
mode = OS_AIO_SYNC; os_has_said_disk_full = TRUE;);
45894589

45904590
if (mode == OS_AIO_SYNC
45914591
#ifdef WIN_ASYNC_IO
@@ -4615,14 +4615,10 @@ os_aio_func(
46154615
ut_a(type == OS_FILE_WRITE);
46164616

46174617
ret = os_file_write_func(name, file, buf, offset, n);
4618-
}
46194618

4620-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4621-
os_has_said_disk_full = FALSE;);
4622-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4623-
ret = 0;);
4624-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4625-
errno = 28;);
4619+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4620+
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
4621+
}
46264622

46274623
return ret;
46284624
}
@@ -5443,17 +5439,15 @@ os_aio_simulated_handle(
54435439
ret = os_file_write(
54445440
aio_slot->name, aio_slot->file, combined_buf,
54455441
aio_slot->offset, total_len);
5446-
} else {
5447-
ret = os_file_read(
5448-
aio_slot->file, combined_buf,
5449-
aio_slot->offset, total_len);
5450-
}
54515442

5452-
if (aio_slot->type == OS_FILE_WRITE) {
54535443
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
5454-
os_has_said_disk_full = FALSE;
5444+
os_has_said_disk_full = TRUE;
54555445
ret = 0;
54565446
errno = 28;);
5447+
} else {
5448+
ret = os_file_read(
5449+
aio_slot->file, combined_buf,
5450+
aio_slot->offset, total_len);
54575451
}
54585452

54595453
srv_set_io_thread_op_info(global_segment, "file i/o done");

storage/innobase/row/row0merge.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2395,6 +2395,24 @@ row_merge_insert_index_tuples(
23952395
#endif /* UNIV_DEBUG */
23962396
ulint* ins_offsets = NULL;
23972397

2398+
/* First reserve enough free space for the file segments
2399+
of the index tree, so that the insert will not fail because
2400+
of lack of space */
2401+
2402+
{
2403+
ulint n_extents = cursor.tree_height / 16 + 3;
2404+
ibool success;
2405+
ulint n_reserved = 0;
2406+
2407+
success = fsp_reserve_free_extents(&n_reserved, index->space,
2408+
n_extents, FSP_NORMAL, &mtr);
2409+
2410+
if (!success) {
2411+
error = DB_OUT_OF_FILE_SPACE;
2412+
goto err_exit;
2413+
}
2414+
}
2415+
23982416
error = btr_cur_optimistic_insert(
23992417
BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
24002418
| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,

storage/innobase/row/row0mysql.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4373,7 +4373,7 @@ row_drop_table_for_mysql(
43734373

43744374
case DB_OUT_OF_FILE_SPACE:
43754375
err = DB_MUST_GET_MORE_FILE_SPACE;
4376-
4376+
trx->error_state = err;
43774377
row_mysql_handle_errors(&err, trx, NULL, NULL);
43784378

43794379
/* raise error */

storage/xtradb/btr/btr0btr.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,6 +3097,12 @@ btr_page_split_and_insert(
30973097
/* 2. Allocate a new page to the index */
30983098
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
30993099
btr_page_get_level(page, mtr), mtr, mtr);
3100+
3101+
/* Play safe, if new page is not allocated */
3102+
if (!new_block) {
3103+
return(rec);
3104+
}
3105+
31003106
new_page = buf_block_get_frame(new_block);
31013107
new_page_zip = buf_block_get_page_zip(new_block);
31023108
btr_page_create(new_block, new_page_zip, cursor->index,

storage/xtradb/fil/fil0fil.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4982,7 +4982,11 @@ fil_extend_space_to_desired_size(
49824982
success = TRUE;
49834983
}
49844984

4985+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4986+
success = FALSE; errno = 28;os_has_said_disk_full = TRUE;);
4987+
49854988
mutex_enter(&fil_system->mutex);
4989+
49864990
if (success) {
49874991
node->size += n_pages;
49884992
space->size += n_pages;
@@ -5023,6 +5027,10 @@ fil_extend_space_to_desired_size(
50235027
offset, page_size * n_pages,
50245028
NULL, NULL, space_id, NULL);
50255029
#endif /* UNIV_HOTBACKUP */
5030+
5031+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
5032+
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);
5033+
50265034
if (success) {
50275035
os_has_said_disk_full = FALSE;
50285036
} else {

storage/xtradb/os/os0file.cc

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4735,7 +4735,7 @@ os_aio_func(
47354735
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
47364736

47374737
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4738-
mode = OS_AIO_SYNC;);
4738+
mode = OS_AIO_SYNC; os_has_said_disk_full = TRUE;);
47394739

47404740
if (mode == OS_AIO_SYNC) {
47414741
ibool ret;
@@ -4744,20 +4744,15 @@ os_aio_func(
47444744

47454745
if (type == OS_FILE_READ) {
47464746
ret = os_file_read_func(file, buf, offset, n, trx);
4747-
}
4748-
else {
4747+
} else {
47494748
ut_ad(!srv_read_only_mode);
47504749
ut_a(type == OS_FILE_WRITE);
47514750

47524751
ret = os_file_write(name, file, buf, offset, n);
4753-
}
47544752

4755-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4756-
os_has_said_disk_full = FALSE;);
4757-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4758-
ret = 0;);
4759-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4760-
errno = 28;);
4753+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
4754+
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
4755+
}
47614756

47624757
if (!ret) {
47634758
fprintf(stderr, "FAIL");
@@ -5585,17 +5580,15 @@ os_aio_simulated_handle(
55855580
ret = os_file_write(
55865581
aio_slot->name, aio_slot->file, combined_buf,
55875582
aio_slot->offset, total_len);
5583+
5584+
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
5585+
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
55885586
} else {
55895587
ret = os_file_read(
55905588
aio_slot->file, combined_buf,
55915589
aio_slot->offset, total_len);
55925590
}
55935591

5594-
if (aio_slot->type == OS_FILE_WRITE) {
5595-
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2",
5596-
os_has_said_disk_full = FALSE; ret = 0; errno = 28;);
5597-
}
5598-
55995592
srv_set_io_thread_op_info(global_segment, "file i/o done");
56005593

56015594
if (aio_slot->type == OS_FILE_READ && n_consecutive > 1) {

storage/xtradb/row/row0merge.cc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,6 +2401,24 @@ row_merge_insert_index_tuples(
24012401
#endif /* UNIV_DEBUG */
24022402
ulint* ins_offsets = NULL;
24032403

2404+
/* First reserve enough free space for the file segments
2405+
of the index tree, so that the insert will not fail because
2406+
of lack of space */
2407+
2408+
{
2409+
ulint n_extents = cursor.tree_height / 16 + 3;
2410+
ibool success;
2411+
ulint n_reserved = 0;
2412+
2413+
success = fsp_reserve_free_extents(&n_reserved, index->space,
2414+
n_extents, FSP_NORMAL, &mtr);
2415+
2416+
if (!success) {
2417+
error = DB_OUT_OF_FILE_SPACE;
2418+
goto err_exit;
2419+
}
2420+
}
2421+
24042422
error = btr_cur_optimistic_insert(
24052423
BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
24062424
| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,

storage/xtradb/row/row0mysql.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,6 +4387,7 @@ row_drop_table_for_mysql(
43874387
case DB_OUT_OF_FILE_SPACE:
43884388
err = DB_MUST_GET_MORE_FILE_SPACE;
43894389

4390+
trx->error_state = err;
43904391
row_mysql_handle_errors(&err, trx, NULL, NULL);
43914392

43924393
/* raise error */

0 commit comments

Comments
 (0)