diff --git a/mysql-test/suite/innodb/r/innodb-alter-table-disk-full.result b/mysql-test/suite/innodb/r/innodb-alter-table-disk-full.result index ffeacae7951..8b9cb904886 100644 --- a/mysql-test/suite/innodb/r/innodb-alter-table-disk-full.result +++ b/mysql-test/suite/innodb/r/innodb-alter-table-disk-full.result @@ -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; @@ -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 +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, - PRIMARY KEY (`a`) + `a` int(11) DEFAULT NULL, + `b` int(11) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=latin1 -set DEBUG_DBUG=NULL; +drop table t2; alter table t1 add testcol2 int; -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`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -select count(1) from t1; -count(1) -10000 +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; diff --git a/mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test b/mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test index adeb2ef9fd2..a0aa234776f 100644 --- a/mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test +++ b/mysql-test/suite/innodb/t/innodb-alter-table-disk-full.test @@ -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) @@ -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; +--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; - -set DEBUG_DBUG=NULL; +--error 0,1051 +drop table t2; +--error 1114 alter table t1 add testcol2 int; -show create table t1; +--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 + diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 79b533481b7..00b90120f6c 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -3055,6 +3055,12 @@ func_start: /* 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, diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 4175abdf895..506ba320853 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -4957,6 +4957,9 @@ retry: 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; @@ -4998,6 +5001,11 @@ retry: 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 { diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index e835c1b4e92..c076c6adde6 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -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 @@ -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; } @@ -5443,19 +5439,17 @@ consecutive_loop: 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", - 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) { diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index e9d8bd50d6a..50bad7c9644 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -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, diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 2717d39b4c0..cf7f0cd8037 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -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 */ diff --git a/storage/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc index d240188e772..1da487f1400 100644 --- a/storage/xtradb/btr/btr0btr.cc +++ b/storage/xtradb/btr/btr0btr.cc @@ -3097,6 +3097,12 @@ func_start: /* 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, diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index 5d547edaaf9..da61d29f6f8 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -4982,7 +4982,11 @@ retry: 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; @@ -5023,6 +5027,10 @@ retry: 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 { diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc index 691054a7e47..112581442ab 100644 --- a/storage/xtradb/os/os0file.cc +++ b/storage/xtradb/os/os0file.cc @@ -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; @@ -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"); @@ -5585,17 +5580,15 @@ consecutive_loop: 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) { diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 5d88d750478..1d66707736d 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -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, diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc index 854ebd6f8cc..ec4f865c6b3 100644 --- a/storage/xtradb/row/row0mysql.cc +++ b/storage/xtradb/row/row0mysql.cc @@ -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 */