From 4f42f0d1eafd82adef513a1064ff44b50063db7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 9 May 2018 15:06:48 +0300 Subject: MDEV-16119 InnoDB lock->index refers to a freed object after failed ADD INDEX The problem is hard to repeat, and I failed to create a deterministic test case. Online index creation creates stubs for to-be-created indexes. If index creation fails, we could remove these stubs while locks exist in the indexes. (This would require that the index creation was completed, and a concurrent DML operation acquired a lock on a record in the uncommitted index. If a duplicate key error occurs in an uncommitted index, the error will be reported for the CREATE UNIQUE INDEX, not for the DML operation that tried to insert the duplicate.) dict_table_try_drop_aborted(), row_merge_drop_indexes(): If transactional locks exist on the table, keep the table->indexes intact. --- storage/innobase/dict/dict0dict.cc | 3 ++- storage/innobase/row/row0merge.cc | 3 ++- storage/xtradb/dict/dict0dict.cc | 3 ++- storage/xtradb/row/row0merge.cc | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 0c8a278586d..7575a4aed62 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -507,7 +507,8 @@ dict_table_try_drop_aborted( ut_ad(table->id == table_id); } - if (table && table->n_ref_count == ref_count && table->drop_aborted) { + if (table && table->n_ref_count == ref_count && table->drop_aborted + && !UT_LIST_GET_FIRST(table->locks)) { /* Silence a debug assertion in row_merge_drop_indexes(). */ ut_d(table->n_ref_count++); row_merge_drop_indexes(trx, table, TRUE); diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 49c9aa4b51f..4090e388610 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -2907,7 +2907,8 @@ row_merge_drop_indexes( A concurrent purge will be prevented by dict_operation_lock. */ - if (!locked && table->n_ref_count > 1) { + if (!locked && (table->n_ref_count > 1 + || UT_LIST_GET_FIRST(table->locks))) { /* We will have to drop the indexes later, when the table is guaranteed to be no longer in use. Mark the indexes as incomplete and corrupted, so that other diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index e2aefc909f8..b76414eeea4 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -507,7 +507,8 @@ dict_table_try_drop_aborted( ut_ad(table->id == table_id); } - if (table && table->n_ref_count == ref_count && table->drop_aborted) { + if (table && table->n_ref_count == ref_count && table->drop_aborted + && !UT_LIST_GET_FIRST(table->locks)) { /* Silence a debug assertion in row_merge_drop_indexes(). */ ut_d(table->n_ref_count++); row_merge_drop_indexes(trx, table, TRUE); diff --git a/storage/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc index 00da85a19dd..e15b87b8ed5 100644 --- a/storage/xtradb/row/row0merge.cc +++ b/storage/xtradb/row/row0merge.cc @@ -2911,7 +2911,8 @@ row_merge_drop_indexes( A concurrent purge will be prevented by dict_operation_lock. */ - if (!locked && table->n_ref_count > 1) { + if (!locked && (table->n_ref_count > 1 + || UT_LIST_GET_FIRST(table->locks))) { /* We will have to drop the indexes later, when the table is guaranteed to be no longer in use. Mark the indexes as incomplete and corrupted, so that other -- cgit v1.2.1