Skip to content
Permalink
Browse files
MDEV-25721 Double free of table when inplace alter
		FTS add index fails

Problem:
========
InnoDB double frees the table if auxiliary fts table
creation fails and fails to set the dict operation
for the transaction. It leads to failure while
dropping newly added index.

Solution:
=========
  InnoDB should avoid double freeing and set the
dictionary operation of transaction in
fts_create_common_tables()
  • Loading branch information
Thirunarayanan committed May 23, 2021
1 parent 98f7b2c commit 349d77e
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 11 deletions.
@@ -266,3 +266,15 @@ t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# MDEV-25271 Double free of table when inplace alter
# FTS add index fails
#
call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation.");
call mtr.add_suppression("InnoDB: Error number .* means");
call mtr.add_suppression("InnoDB: Cannot create file");
call mtr.add_suppression("InnoDB: Failed to create");
CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB;
ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE;
ERROR HY000: Got error 11 "Resource temporarily unavailable" from storage engine InnoDB
DROP TABLE t1;
@@ -0,0 +1 @@
--enable-plugin-innodb-sys-tables
@@ -319,3 +319,23 @@ ALTER TABLE t1 ADD FTS_DOC_ID INT UNSIGNED NOT NULL, ALGORITHM=INPLACE;

SHOW CREATE TABLE t1;
DROP TABLE t1;


--echo #
--echo # MDEV-25271 Double free of table when inplace alter
--echo # FTS add index fails
--echo #
call mtr.add_suppression("InnoDB: Operating system error number .* in a file operation.");
call mtr.add_suppression("InnoDB: Error number .* means");
call mtr.add_suppression("InnoDB: Cannot create file");
call mtr.add_suppression("InnoDB: Failed to create");

let MYSQLD_DATADIR=`select @@datadir`;
CREATE TABLE t1(a TEXT, FTS_DOC_ID BIGINT UNSIGNED NOT NULL UNIQUE) ENGINE=InnoDB;
let $fts_aux_file= `select concat('FTS_',right(concat(repeat('0',16), lower(hex(TABLE_ID))),16),'_BEING_DELETED.ibd') FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME='test/t1'`;
write_file $MYSQLD_DATADIR/test/$fts_aux_file;
EOF
--error ER_GET_ERRNO
ALTER TABLE t1 ADD FULLTEXT(a), ALGORITHM=INPLACE;
DROP TABLE t1;
remove_file $MYSQLD_DATADIR/test/$fts_aux_file;
@@ -1787,7 +1787,6 @@ fts_create_one_common_table(

error = row_create_table_for_mysql(new_table, trx,
FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY);

if (error == DB_SUCCESS) {

dict_index_t* index = dict_mem_index_create(
@@ -1808,17 +1807,22 @@ fts_create_one_common_table(
error = row_create_index_for_mysql(index, trx, NULL);

trx->dict_operation = op;
} else {
err_exit:
new_table = NULL;
ib::warn() << "Failed to create FTS common table "
<< fts_table_name;
trx->error_state = error;
return NULL;
}

if (error != DB_SUCCESS) {
dict_mem_table_free(new_table);
new_table = NULL;
ib::warn() << "Failed to create FTS common table "
<< fts_table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(fts_table_name, trx, SQLCOM_DROP_DB);
trx->error_state = error;
goto err_exit;
}

return(new_table);
}

@@ -1866,6 +1870,8 @@ fts_create_common_tables(

FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table);

op = trx_get_dict_operation(trx);

error = fts_drop_common_tables(trx, &fts_table);

if (error != DB_SUCCESS) {
@@ -1882,6 +1888,7 @@ fts_create_common_tables(
trx, table, full_name[i], fts_table.suffix, heap);

if (common_table == NULL) {
trx->error_state = DB_SUCCESS;
error = DB_ERROR;
goto func_exit;
} else {
@@ -1926,8 +1933,6 @@ fts_create_common_tables(

error = row_create_index_for_mysql(index, trx, NULL);

trx->dict_operation = op;

func_exit:
if (error != DB_SUCCESS) {
for (it = common_tables.begin(); it != common_tables.end();
@@ -1937,6 +1942,8 @@ fts_create_common_tables(
}
}

trx->dict_operation = op;

common_tables.clear();
mem_heap_free(heap);

@@ -2019,16 +2026,20 @@ fts_create_one_index_table(
error = row_create_index_for_mysql(index, trx, NULL);

trx->dict_operation = op;
} else {
err_exit:
new_table = NULL;
ib::warn() << "Failed to create FTS index table "
<< table_name;
trx->error_state = error;
return NULL;
}

if (error != DB_SUCCESS) {
dict_mem_table_free(new_table);
new_table = NULL;
ib::warn() << "Failed to create FTS index table "
<< table_name;
trx->error_state = DB_SUCCESS;
row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_DB);
trx->error_state = error;
goto err_exit;
}

return(new_table);

0 comments on commit 349d77e

Please sign in to comment.