Skip to content

Commit

Permalink
MDEV-6288 :Innodb causes server crash after disk full, then can't ALT…
Browse files Browse the repository at this point in the history
…ER TABLE any more

Fix try to avoid unnecessary crashes when disk full situation is reached
on alter table.
  • Loading branch information
Jan Lindström committed Feb 13, 2015
1 parent 356ae62 commit 454beee
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 61 deletions.
51 changes: 30 additions & 21 deletions mysql-test/suite/innodb/r/innodb-alter-table-disk-full.result
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
create table t1(a int not null primary key, b int) engine=innodb;
call mtr.add_suppression("InnoDB: Error: row_merge_drop_indexes_dict failed with error code*");
create table t1(a int, b int) engine=innodb;
create procedure innodb_insert_proc (repeat_count int)
begin
declare current_num int;
Expand All @@ -10,41 +11,49 @@ end while;
end//
commit;
set autocommit=0;
call innodb_insert_proc(10000);
call innodb_insert_proc(20000);
commit;
set autocommit=1;
create table t2(a int) engine=innodb;
show create table t2;
Table Create Table
t2 CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2';
alter table t2 add testcol int;
ERROR HY000: The table 't2' is full
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
set DEBUG_DBUG=NULL;
alter table t1 add testcol2 int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol3 int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol int;
ERROR HY000: The table 't1' is full
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
`testcol2` int(11) DEFAULT NULL,
PRIMARY KEY (`a`)
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
select count(1) from t1;
count(1)
10000
drop table t2;
alter table t1 add testcol2 int;
ERROR HY000: The table 't1' is full
alter table t1 add testcol3 int;
ERROR HY000: The table 't1' is full
call innodb_insert_proc(20000);
set DEBUG_DBUG='';
drop procedure innodb_insert_proc;
drop table t1;
drop table if exists t2;
38 changes: 29 additions & 9 deletions mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
# DEBUG_SYNC must be compiled in.
--source include/have_debug_sync.inc

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

create table t1(a int, b int) engine=innodb;

delimiter //;
create procedure innodb_insert_proc (repeat_count int)
Expand All @@ -23,28 +25,46 @@ delimiter ;//
commit;

set autocommit=0;
call innodb_insert_proc(10000);
call innodb_insert_proc(20000);
commit;
set autocommit=1;

create table t2(a int) engine=innodb;
show create table t2;

# This caused crash earlier
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28';
--error 1114
alter table t1 add testcol int;
show create table t1;

# This caused crash earlier
set DEBUG_DBUG='+d,ib_os_aio_func_io_failure_28_2';
--error 1114
alter table t2 add testcol int;
--error 1114
alter table t1 add testcol int;
show create table t1;

set DEBUG_DBUG=NULL;
--error 1114
alter table t1 add testcol int;
--error 1114
alter table t1 add testcol2 int;
--error 1114
alter table t1 add testcol3 int;
--error 1114
alter table t1 add testcol int;
show create table t1;
--error 0,1051
drop table t2;
--error 1114
alter table t1 add testcol2 int;
--error 1114
alter table t1 add testcol3 int;
--error 0,1114
call innodb_insert_proc(20000);

select count(1) from t1;
set DEBUG_DBUG='';

drop procedure innodb_insert_proc;
drop table t1;
--disable_warnings
drop table if exists t2;
--enable_warnings


6 changes: 6 additions & 0 deletions storage/innobase/btr/btr0btr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,12 @@ btr_page_split_and_insert(
/* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
btr_page_get_level(page, mtr), mtr, mtr);

/* Play safe, if new page is not allocated */
if (!new_block) {
return(rec);
}

new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, cursor->index,
Expand Down
8 changes: 8 additions & 0 deletions storage/innobase/fil/fil0fil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4957,6 +4957,9 @@ fil_extend_space_to_desired_size(
success = TRUE;
}

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);

mutex_enter(&fil_system->mutex);
if (success) {
node->size += n_pages;
Expand Down Expand Up @@ -4998,6 +5001,11 @@ fil_extend_space_to_desired_size(
offset, page_size * n_pages,
NULL, NULL);
#endif /* UNIV_HOTBACKUP */


DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);

if (success) {
os_has_said_disk_full = FALSE;
} else {
Expand Down
24 changes: 9 additions & 15 deletions storage/innobase/os/os0file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4585,7 +4585,7 @@ os_aio_func(
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
mode = OS_AIO_SYNC;);
mode = OS_AIO_SYNC; os_has_said_disk_full = TRUE;);

if (mode == OS_AIO_SYNC
#ifdef WIN_ASYNC_IO
Expand Down Expand Up @@ -4615,14 +4615,10 @@ os_aio_func(
ut_a(type == OS_FILE_WRITE);

ret = os_file_write_func(name, file, buf, offset, n);
}

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = FALSE;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
ret = 0;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
errno = 28;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
}

return ret;
}
Expand Down Expand Up @@ -5443,17 +5439,15 @@ os_aio_simulated_handle(
ret = os_file_write(
aio_slot->name, aio_slot->file, combined_buf,
aio_slot->offset, total_len);
} else {
ret = os_file_read(
aio_slot->file, combined_buf,
aio_slot->offset, total_len);
}

if (aio_slot->type == OS_FILE_WRITE) {
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = FALSE;
os_has_said_disk_full = TRUE;
ret = 0;
errno = 28;);
} else {
ret = os_file_read(
aio_slot->file, combined_buf,
aio_slot->offset, total_len);
}

srv_set_io_thread_op_info(global_segment, "file i/o done");
Expand Down
18 changes: 18 additions & 0 deletions storage/innobase/row/row0merge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2395,6 +2395,24 @@ row_merge_insert_index_tuples(
#endif /* UNIV_DEBUG */
ulint* ins_offsets = NULL;

/* First reserve enough free space for the file segments
of the index tree, so that the insert will not fail because
of lack of space */

{
ulint n_extents = cursor.tree_height / 16 + 3;
ibool success;
ulint n_reserved = 0;

success = fsp_reserve_free_extents(&n_reserved, index->space,
n_extents, FSP_NORMAL, &mtr);

if (!success) {
error = DB_OUT_OF_FILE_SPACE;
goto err_exit;
}
}

error = btr_cur_optimistic_insert(
BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,
Expand Down
2 changes: 1 addition & 1 deletion storage/innobase/row/row0mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4373,7 +4373,7 @@ row_drop_table_for_mysql(

case DB_OUT_OF_FILE_SPACE:
err = DB_MUST_GET_MORE_FILE_SPACE;

trx->error_state = err;
row_mysql_handle_errors(&err, trx, NULL, NULL);

/* raise error */
Expand Down
6 changes: 6 additions & 0 deletions storage/xtradb/btr/btr0btr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3097,6 +3097,12 @@ btr_page_split_and_insert(
/* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
btr_page_get_level(page, mtr), mtr, mtr);

/* Play safe, if new page is not allocated */
if (!new_block) {
return(rec);
}

new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, cursor->index,
Expand Down
8 changes: 8 additions & 0 deletions storage/xtradb/fil/fil0fil.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4982,7 +4982,11 @@ fil_extend_space_to_desired_size(
success = TRUE;
}

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
success = FALSE; errno = 28;os_has_said_disk_full = TRUE;);

mutex_enter(&fil_system->mutex);

if (success) {
node->size += n_pages;
space->size += n_pages;
Expand Down Expand Up @@ -5023,6 +5027,10 @@ fil_extend_space_to_desired_size(
offset, page_size * n_pages,
NULL, NULL, space_id, NULL);
#endif /* UNIV_HOTBACKUP */

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
success = FALSE; errno = 28; os_has_said_disk_full = TRUE;);

if (success) {
os_has_said_disk_full = FALSE;
} else {
Expand Down
23 changes: 8 additions & 15 deletions storage/xtradb/os/os0file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4735,7 +4735,7 @@ os_aio_func(
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
mode = OS_AIO_SYNC;);
mode = OS_AIO_SYNC; os_has_said_disk_full = TRUE;);

if (mode == OS_AIO_SYNC) {
ibool ret;
Expand All @@ -4744,20 +4744,15 @@ os_aio_func(

if (type == OS_FILE_READ) {
ret = os_file_read_func(file, buf, offset, n, trx);
}
else {
} else {
ut_ad(!srv_read_only_mode);
ut_a(type == OS_FILE_WRITE);

ret = os_file_write(name, file, buf, offset, n);
}

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = FALSE;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
ret = 0;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
errno = 28;);
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
}

if (!ret) {
fprintf(stderr, "FAIL");
Expand Down Expand Up @@ -5585,17 +5580,15 @@ os_aio_simulated_handle(
ret = os_file_write(
aio_slot->name, aio_slot->file, combined_buf,
aio_slot->offset, total_len);

DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
os_has_said_disk_full = TRUE; ret = 0; errno = 28;);
} else {
ret = os_file_read(
aio_slot->file, combined_buf,
aio_slot->offset, total_len);
}

if (aio_slot->type == OS_FILE_WRITE) {
DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2",
os_has_said_disk_full = FALSE; ret = 0; errno = 28;);
}

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

if (aio_slot->type == OS_FILE_READ && n_consecutive > 1) {
Expand Down
18 changes: 18 additions & 0 deletions storage/xtradb/row/row0merge.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2401,6 +2401,24 @@ row_merge_insert_index_tuples(
#endif /* UNIV_DEBUG */
ulint* ins_offsets = NULL;

/* First reserve enough free space for the file segments
of the index tree, so that the insert will not fail because
of lack of space */

{
ulint n_extents = cursor.tree_height / 16 + 3;
ibool success;
ulint n_reserved = 0;

success = fsp_reserve_free_extents(&n_reserved, index->space,
n_extents, FSP_NORMAL, &mtr);

if (!success) {
error = DB_OUT_OF_FILE_SPACE;
goto err_exit;
}
}

error = btr_cur_optimistic_insert(
BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG
| BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG,
Expand Down
1 change: 1 addition & 0 deletions storage/xtradb/row/row0mysql.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4387,6 +4387,7 @@ row_drop_table_for_mysql(
case DB_OUT_OF_FILE_SPACE:
err = DB_MUST_GET_MORE_FILE_SPACE;

trx->error_state = err;
row_mysql_handle_errors(&err, trx, NULL, NULL);

/* raise error */
Expand Down

0 comments on commit 454beee

Please sign in to comment.