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.
This commit is contained in:
Marko Mäkelä 2018-05-09 15:06:48 +03:00
parent 34045af03f
commit 4f42f0d1ea
4 changed files with 8 additions and 4 deletions

View File

@ -507,7 +507,8 @@ dict_table_try_drop_aborted(
ut_ad(table->id == table_id); 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(). */ /* Silence a debug assertion in row_merge_drop_indexes(). */
ut_d(table->n_ref_count++); ut_d(table->n_ref_count++);
row_merge_drop_indexes(trx, table, TRUE); row_merge_drop_indexes(trx, table, TRUE);

View File

@ -2907,7 +2907,8 @@ row_merge_drop_indexes(
A concurrent purge will be prevented by dict_operation_lock. */ 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 /* We will have to drop the indexes later, when the
table is guaranteed to be no longer in use. Mark the table is guaranteed to be no longer in use. Mark the
indexes as incomplete and corrupted, so that other indexes as incomplete and corrupted, so that other

View File

@ -507,7 +507,8 @@ dict_table_try_drop_aborted(
ut_ad(table->id == table_id); 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(). */ /* Silence a debug assertion in row_merge_drop_indexes(). */
ut_d(table->n_ref_count++); ut_d(table->n_ref_count++);
row_merge_drop_indexes(trx, table, TRUE); row_merge_drop_indexes(trx, table, TRUE);

View File

@ -2911,7 +2911,8 @@ row_merge_drop_indexes(
A concurrent purge will be prevented by dict_operation_lock. */ 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 /* We will have to drop the indexes later, when the
table is guaranteed to be no longer in use. Mark the table is guaranteed to be no longer in use. Mark the
indexes as incomplete and corrupted, so that other indexes as incomplete and corrupted, so that other