Skip to content

Commit 1983523

Browse files
MDEV-36017 Alter table aborts when temporary directory is full
Problem: ======= - In 10.11, During Copy algorithm, InnoDB does use bulk insert for row by row insert operation. When temporary directory ran out of memory, row_mysql_handle_errors() fails to handle DB_TEMP_FILE_WRITE_FAIL. - During inplace algorithm, concurrent DML fails to write the log operation into the temporary file. InnoDB fail to mark the error for the online log. Fix: === row_mysql_handle_errors(): Rollback the transaction when InnoDB encounters DB_TEMP_FILE_WRITE_FAIL convert_error_code_to_mysql(): Report an aborted transaction when InnoDB encounters DB_TEMP_FILE_WRITE_FAIL during alter table algorithm=copy or innodb bulk insert operation row_log_online_op(): Mark the error in online log when InnoDB ran out of temporary space fil_space_extend_must_retry(): Mark the os_has_said_disk_full as true if os_file_set_size() fails.
1 parent 2a92cf8 commit 1983523

File tree

8 files changed

+84
-1
lines changed

8 files changed

+84
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#
2+
# MDEV-36017 Alter table aborts when temporary
3+
# directory is full
4+
#
5+
CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100),
6+
f3 CHAR(100))ENGINE=InnoDB;
7+
INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_1024;
8+
SET DEBUG_DBUG="+d,write_to_tmp_file_fail";
9+
ALTER TABLE t1 FORCE, ALGORITHM=COPY;
10+
ERROR HY000: Got error 59 'Temp file write failure' from InnoDB
11+
SET DEBUG_DBUG="-d,write_to_tmp_file_fail";
12+
DROP TABLE t1;
13+
CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100),
14+
f3 CHAR(100))ENGINE=InnoDB;
15+
INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_4096;
16+
SET DEBUG_SYNC="inplace_after_index_build SIGNAL dml_start WAIT_FOR dml_commit";
17+
ALTER TABLE t1 ADD KEY(f1), ADD INDEX(f3(10));
18+
connect con1,localhost,root,,,;
19+
SET DEBUG_SYNC="now WAIT_FOR dml_start";
20+
BEGIN;
21+
INSERT INTO t1 SELECT * FROM t1;
22+
SET DEBUG_DBUG="+d,os_file_write_fail";
23+
COMMIT;
24+
SET DEBUG_DBUG="-d,os_file_write_fail";
25+
SET DEBUG_SYNC="now SIGNAL dml_commit";
26+
connection default;
27+
ERROR HY000: Temporary file write failure
28+
disconnect con1;
29+
CHECK TABLE t1;
30+
Table Op Msg_type Msg_text
31+
test.t1 check status OK
32+
DROP TABLE t1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--innodb_sort_buffer_size=64k
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--source include/have_innodb.inc
2+
--source include/have_sequence.inc
3+
--source include/have_debug.inc
4+
--echo #
5+
--echo # MDEV-36017 Alter table aborts when temporary
6+
--echo # directory is full
7+
--echo #
8+
CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100),
9+
f3 CHAR(100))ENGINE=InnoDB;
10+
INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_1024;
11+
SET DEBUG_DBUG="+d,write_to_tmp_file_fail";
12+
--error ER_GET_ERRMSG
13+
ALTER TABLE t1 FORCE, ALGORITHM=COPY;
14+
SET DEBUG_DBUG="-d,write_to_tmp_file_fail";
15+
DROP TABLE t1;
16+
17+
CREATE TABLE t1(f1 INT NOT NULL, f2 CHAR(100),
18+
f3 CHAR(100))ENGINE=InnoDB;
19+
INSERT INTO t1 SELECT seq, 'a', 'b' FROM seq_1_to_4096;
20+
SET DEBUG_SYNC="inplace_after_index_build SIGNAL dml_start WAIT_FOR dml_commit";
21+
SEND ALTER TABLE t1 ADD KEY(f1), ADD INDEX(f3(10));
22+
23+
connect(con1,localhost,root,,,);
24+
SET DEBUG_SYNC="now WAIT_FOR dml_start";
25+
BEGIN;
26+
INSERT INTO t1 SELECT * FROM t1;
27+
SET DEBUG_DBUG="+d,os_file_write_fail";
28+
COMMIT;
29+
SET DEBUG_DBUG="-d,os_file_write_fail";
30+
SET DEBUG_SYNC="now SIGNAL dml_commit";
31+
32+
connection default;
33+
--error ER_TEMP_FILE_WRITE_FAILURE
34+
reap;
35+
disconnect con1;
36+
CHECK TABLE t1;
37+
DROP TABLE t1;

storage/innobase/fil/fil0fil.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@ fil_space_extend_must_retry(
605605
*success = os_file_set_size(node->name, node->handle, new_size,
606606
node->punch_hole == 1);
607607

608-
os_has_said_disk_full = *success;
608+
os_has_said_disk_full = !*success;
609609
if (*success) {
610610
os_file_flush(node->handle);
611611
last_page_no = size;

storage/innobase/handler/ha_innodb.cc

+5
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,11 @@ convert_error_code_to_mysql(
21932193
return(HA_ERR_RECORD_FILE_FULL);
21942194

21952195
case DB_TEMP_FILE_WRITE_FAIL:
2196+
/* This error can happen during
2197+
ALTER TABLE..ALGORITHM=COPY or bulk insert operation */
2198+
innodb_transaction_abort(thd,
2199+
innobase_rollback_on_timeout,
2200+
error);
21962201
my_error(ER_GET_ERRMSG, MYF(0),
21972202
DB_TEMP_FILE_WRITE_FAIL,
21982203
ut_strerr(DB_TEMP_FILE_WRITE_FAIL),

storage/innobase/row/row0log.cc

+5
Original file line numberDiff line numberDiff line change
@@ -398,12 +398,17 @@ bool row_log_online_op(dict_index_t *index, const dtuple_t *tuple,
398398
}
399399

400400
log->tail.blocks++;
401+
DBUG_EXECUTE_IF("os_file_write_fail",
402+
log->error = DB_TEMP_FILE_WRITE_FAIL;
403+
goto write_failed;);
404+
401405
if (os_file_write(
402406
IORequestWrite,
403407
"(modification log)",
404408
log->fd,
405409
buf, byte_offset, srv_sort_buf_size)
406410
!= DB_SUCCESS) {
411+
log->error = DB_TEMP_FILE_WRITE_FAIL;
407412
write_failed:
408413
index->type |= DICT_CORRUPT;
409414
}

storage/innobase/row/row0merge.cc

+2
Original file line numberDiff line numberDiff line change
@@ -5178,6 +5178,8 @@ dberr_t row_merge_bulk_t::write_to_tmp_file(ulint index_no)
51785178
buf->index->table->space->id))
51795179
return DB_TEMP_FILE_WRITE_FAIL;
51805180
MEM_UNDEFINED(&m_block[0], srv_sort_buf_size);
5181+
DBUG_EXECUTE_IF("write_to_tmp_file_fail",
5182+
return DB_TEMP_FILE_WRITE_FAIL;);
51815183
return DB_SUCCESS;
51825184
}
51835185

storage/innobase/row/row0mysql.cc

+1
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,7 @@ row_mysql_handle_errors(
673673
case DB_TABLE_NOT_FOUND:
674674
case DB_DECRYPTION_FAILED:
675675
case DB_COMPUTE_VALUE_FAILED:
676+
case DB_TEMP_FILE_WRITE_FAIL:
676677
rollback_to_savept:
677678
DBUG_EXECUTE_IF("row_mysql_crash_if_error", {
678679
log_buffer_flush_to_disk();

0 commit comments

Comments
 (0)