diff --git a/mysql-test/suite/innodb/r/alter_temp_fail.result b/mysql-test/suite/innodb/r/alter_temp_fail.result new file mode 100644 index 0000000000000..4c55af459f383 --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_temp_fail.result @@ -0,0 +1,32 @@ +# +# MDEV-36017 Alter table aborts when temporary +# directory is full +# +CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100), +f3 CHAR(100))ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_1024; +SET DEBUG_DBUG="+d,write_to_tmp_file_fail"; +ALTER TABLE t1 FORCE, ALGORITHM=COPY; +ERROR HY000: Got error 59 'Temp file write failure' from InnoDB +SET DEBUG_DBUG="-d,write_to_tmp_file_fail"; +DROP TABLE t1; +CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100), +f3 CHAR(100))ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_4096; +SET DEBUG_SYNC="inplace_after_index_build SIGNAL dml_start WAIT_FOR dml_commit"; +ALTER TABLE t1 ADD KEY(f1), ADD INDEX(f3(10)); +connect con1,localhost,root,,,; +SET DEBUG_SYNC="now WAIT_FOR dml_start"; +BEGIN; +INSERT INTO t1 SELECT * FROM t1; +SET DEBUG_DBUG="+d,os_file_write_fail"; +COMMIT; +SET DEBUG_DBUG="-d,os_file_write_fail"; +SET DEBUG_SYNC="now SIGNAL dml_commit"; +connection default; +ERROR HY000: Temporary file write failure +disconnect con1; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/alter_temp_fail.opt b/mysql-test/suite/innodb/t/alter_temp_fail.opt new file mode 100644 index 0000000000000..c3f4a891ccac5 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_temp_fail.opt @@ -0,0 +1 @@ +--innodb_sort_buffer_size=64k diff --git a/mysql-test/suite/innodb/t/alter_temp_fail.test b/mysql-test/suite/innodb/t/alter_temp_fail.test new file mode 100644 index 0000000000000..c09b5518ba937 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_temp_fail.test @@ -0,0 +1,37 @@ +--source include/have_innodb.inc +--source include/have_sequence.inc +--source include/have_debug.inc +--echo # +--echo # MDEV-36017 Alter table aborts when temporary +--echo # directory is full +--echo # +CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100), + f3 CHAR(100))ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_1024; +SET DEBUG_DBUG="+d,write_to_tmp_file_fail"; +--error ER_GET_ERRMSG +ALTER TABLE t1 FORCE, ALGORITHM=COPY; +SET DEBUG_DBUG="-d,write_to_tmp_file_fail"; +DROP TABLE t1; + +CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100), + f3 CHAR(100))ENGINE=InnoDB; +INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_4096; +SET DEBUG_SYNC="inplace_after_index_build SIGNAL dml_start WAIT_FOR dml_commit"; +SEND ALTER TABLE t1 ADD KEY(f1), ADD INDEX(f3(10)); + +connect(con1,localhost,root,,,); +SET DEBUG_SYNC="now WAIT_FOR dml_start"; +BEGIN; +INSERT INTO t1 SELECT * FROM t1; +SET DEBUG_DBUG="+d,os_file_write_fail"; +COMMIT; +SET DEBUG_DBUG="-d,os_file_write_fail"; +SET DEBUG_SYNC="now SIGNAL dml_commit"; + +connection default; +--error ER_TEMP_FILE_WRITE_FAILURE +reap; +disconnect con1; +CHECK TABLE t1; +DROP TABLE t1; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 4ba3183e3712d..39d6096e9cd53 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -605,7 +605,7 @@ fil_space_extend_must_retry( *success = os_file_set_size(node->name, node->handle, new_size, node->punch_hole == 1); - os_has_said_disk_full = *success; + os_has_said_disk_full = !*success; if (*success) { os_file_flush(node->handle); last_page_no = size; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 17c1bcf637035..22f21f3003343 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -2193,6 +2193,11 @@ convert_error_code_to_mysql( return(HA_ERR_RECORD_FILE_FULL); case DB_TEMP_FILE_WRITE_FAIL: + /* This error can happen during + ALTER TABLE..ALGORITHM=COPY or bulk insert operation */ + innodb_transaction_abort(thd, + innobase_rollback_on_timeout, + error); my_error(ER_GET_ERRMSG, MYF(0), DB_TEMP_FILE_WRITE_FAIL, ut_strerr(DB_TEMP_FILE_WRITE_FAIL), diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 5d0446e455372..19b007f1d931b 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -398,12 +398,17 @@ bool row_log_online_op(dict_index_t *index, const dtuple_t *tuple, } log->tail.blocks++; + DBUG_EXECUTE_IF("os_file_write_fail", + log->error = DB_TEMP_FILE_WRITE_FAIL; + goto write_failed;); + if (os_file_write( IORequestWrite, "(modification log)", log->fd, buf, byte_offset, srv_sort_buf_size) != DB_SUCCESS) { + log->error = DB_TEMP_FILE_WRITE_FAIL; write_failed: index->type |= DICT_CORRUPT; } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index fba8467f095eb..9be0ff1ec0bd0 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -5178,6 +5178,8 @@ dberr_t row_merge_bulk_t::write_to_tmp_file(ulint index_no) buf->index->table->space->id)) return DB_TEMP_FILE_WRITE_FAIL; MEM_UNDEFINED(&m_block[0], srv_sort_buf_size); + DBUG_EXECUTE_IF("write_to_tmp_file_fail", + return DB_TEMP_FILE_WRITE_FAIL;); return DB_SUCCESS; } diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 30b4f5975a144..c5d9b1d178c26 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -673,6 +673,7 @@ row_mysql_handle_errors( case DB_TABLE_NOT_FOUND: case DB_DECRYPTION_FAILED: case DB_COMPUTE_VALUE_FAILED: + case DB_TEMP_FILE_WRITE_FAIL: rollback_to_savept: DBUG_EXECUTE_IF("row_mysql_crash_if_error", { log_buffer_flush_to_disk();