Description:
When I test the ALTER TABLE ADD INDEX operation, I found that server may go crash when concurrent DML is running. In most cases this problem will not happen,but it can be reproduced steadily in a carefully constructed scene. The reason is that there is an assertion failure in function Compression::deserialize. Please to see `how to repeat` to get a detail error stack.
How to repeat:
# Please run the following mtr test case in debug version.
#--------------------------------------------------------
--source include/have_debug.inc
--source include/have_debug_sync.inc
--source include/have_innodb.inc
--source include/not_embedded.inc
--source include/not_windows.inc
--source include/count_sessions.inc
--echo # Reset innodb_sort_buffer_size to a lower value to make ALTER TABLE
--echo # use sort files.
--let $restart_parameters="restart: --innodb_sort_buffer_size=65536"
--source include/restart_mysqld.inc
--disable_warnings
--disable_result_log
--disable_query_log
DROP PROCEDURE IF EXISTS load_data;
DELIMITER //;
CREATE PROCEDURE load_data(table_name VARCHAR(256), start INT, count INT)
BEGIN
DECLARE i INT DEFAULT 0;
SET @insert_stmt := CONCAT("INSERT INTO ",table_name,"(a,b,c,d,e,f,g,h,x,y,z)
VALUES (?, REPEAT('b',100), 3598, REPEAT('d',100), 3598, 3598, 3598, 3598, 3598, 3598, 3598)");
PREPARE insert_stmt FROM @insert_stmt;
WHILE i < count DO
SET @pk = i+start;
EXECUTE insert_stmt USING @pk;
SET i=i+1;
END WHILE;
END//
DELIMITER ;//
--enable_query_log
--enable_result_log
--enable_warnings
CREATE TABLE t_inplace_alter_tmp_file_02(
a INT PRIMARY KEY,
b VARCHAR(100),
c INT DEFAULT NULL,
d VARCHAR(100),
e INT, f INT, g INT, h INT, x INT, y INT, z INT) ENGINE=INNODB;
--echo # con1 used to signal at sync point
connect(con1, localhost, root,,);
--echo # connection DEFAULT
--connection default
--echo # > Case 1: Generate Row Log Files
--echo # -----------------------------------------------------------------------
--echo # connection default
connection default;
--echo # 1. Prepare data.
CALL load_data("t_inplace_alter_tmp_file_02", 0, 20000);
--echo # 2. Alter table inplace.
SET DEBUG_SYNC='RESET';
SET DEBUG_SYNC='innodb_inplace_alter_table_enter SIGNAL do_dml WAIT_FOR go_on_execute EXECUTE 1';
--send ALTER TABLE t_inplace_alter_tmp_file_02 ADD INDEX ci(c);
--echo # 3. Do concurrent DML.
--echo # connnection con1
connection con1;
SET DEBUG_SYNC='now WAIT_FOR do_dml';
CALL load_data("t_inplace_alter_tmp_file_02", 20000, 20000);
SET DEBUG_SYNC='now SIGNAL go_on_execute';
--connection default
--reap
--echo # > Clean Up
--echo # -----------------------------------------------------------------------
disconnect con1;
--source include/wait_until_count_sessions.inc
--source include/force_restart.inc
Suggested fix:
The reason is that:
When the server apply `row log` generated during online ALTER TABLE, row_log_apply_ops() will use function os_file_read_no_error_handling_int_fd() to read the `row log file` and the passed parameter IORequest object is not set disable_compression() to force a raw read.
How to fix:
1. just make the IORequest object passed to os_file_read_no_error_handling_int_fd() in function row_log_apply_ops() to disable compression with IORequest::disable_compression().