summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-08-23 10:06:21 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2021-08-23 10:06:21 +0300
commitca89489716890ebab5b207e49f3b157e78e0f8e4 (patch)
tree4c8bbb8ecc6a7fadf40325577222887846c644a9
parent08e5a3d2e3e0ee98a22f58adb9f76c686ba94a8a (diff)
downloadmariadb-git-ca89489716890ebab5b207e49f3b157e78e0f8e4.tar.gz
MDEV-26383 fixup: Consistently protect freed_indexes with autoinc_mutex
To avoid potential race conditions between concurrent access to dict_table_t::freed_indexes, let us consistently use dict_table_t::autoinc_mutex. dict_table_remove_from_cache_low(): To avoid extensive hold time of table->autoinc_mutex, unconditionally free the FTS data structures.
-rw-r--r--storage/innobase/btr/btr0sea.cc15
-rw-r--r--storage/innobase/dict/dict0dict.cc28
-rw-r--r--storage/innobase/include/dict0mem.h5
3 files changed, 25 insertions, 23 deletions
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 2e572fe32a8..0b8036c4fdf 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -253,15 +253,7 @@ ATTRIBUTE_COLD static void btr_search_lazy_free(dict_index_t *index)
{
ut_ad(index->freed());
dict_table_t *table= index->table;
- bool non_exist_table= (table->id == 0);
-
- if (non_exist_table)
- {
- /* autoinc_mutex should be acquired to avoid the race condition
- in case of multiple threads accessing the evicted table
- or dropped table. */
- mysql_mutex_lock(&table->autoinc_mutex);
- }
+ mysql_mutex_lock(&table->autoinc_mutex);
/* Perform the skipped steps of dict_index_remove_from_cache_low(). */
UT_LIST_REMOVE(table->freed_indexes, index);
@@ -271,15 +263,14 @@ ATTRIBUTE_COLD static void btr_search_lazy_free(dict_index_t *index)
if (!UT_LIST_GET_LEN(table->freed_indexes) &&
!UT_LIST_GET_LEN(table->indexes))
{
- ut_ad(non_exist_table);
+ ut_ad(!table->id);
mysql_mutex_unlock(&table->autoinc_mutex);
mysql_mutex_destroy(&table->autoinc_mutex);
dict_mem_table_free(table);
return;
}
- if (non_exist_table)
- mysql_mutex_unlock(&table->autoinc_mutex);
+ mysql_mutex_unlock(&table->autoinc_mutex);
}
/** Clear the adaptive hash index on all pages in the buffer pool. */
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 8243cf51526..d0f8185b927 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2020, MariaDB Corporation.
+Copyright (c) 2013, 2021, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1258,6 +1258,7 @@ dict_index_t *dict_index_t::clone_if_needed()
return this;
dict_index_t *prev= UT_LIST_GET_PREV(indexes, this);
+ mysql_mutex_lock(&table->autoinc_mutex);
UT_LIST_REMOVE(table->indexes, this);
UT_LIST_ADD_LAST(table->freed_indexes, this);
dict_index_t *index= clone();
@@ -1266,6 +1267,7 @@ dict_index_t *dict_index_t::clone_if_needed()
UT_LIST_INSERT_AFTER(table->indexes, prev, index);
else
UT_LIST_ADD_FIRST(table->indexes, index);
+ mysql_mutex_unlock(&table->autoinc_mutex);
return index;
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -1961,15 +1963,21 @@ dict_table_remove_from_cache_low(
}
#ifdef BTR_CUR_HASH_ADAPT
- if (UNIV_UNLIKELY(UT_LIST_GET_LEN(table->freed_indexes) != 0)) {
- if (table->fts) {
- fts_optimize_remove_table(table);
- fts_free(table);
- table->fts = NULL;
- }
+ if (table->fts) {
+ fts_optimize_remove_table(table);
+ fts_free(table);
+ table->fts = NULL;
+ }
+
+ mysql_mutex_lock(&table->autoinc_mutex);
+
+ ulint freed = UT_LIST_GET_LEN(table->freed_indexes);
+
+ table->vc_templ = NULL;
+ table->id = 0;
+ mysql_mutex_unlock(&table->autoinc_mutex);
- table->vc_templ = NULL;
- table->id = 0;
+ if (UNIV_UNLIKELY(freed != 0)) {
return;
}
#endif /* BTR_CUR_HASH_ADAPT */
@@ -2244,8 +2252,10 @@ dict_index_remove_from_cache_low(
zero. See also: dict_table_can_be_evicted() */
if (index->n_ahi_pages()) {
+ mysql_mutex_lock(&table->autoinc_mutex);
index->set_freed();
UT_LIST_ADD_LAST(table->freed_indexes, index);
+ mysql_mutex_unlock(&table->autoinc_mutex);
return;
}
#endif /* BTR_CUR_HASH_ADAPT */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 78244e2f6cb..5fc0e3ebe15 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -1713,7 +1713,8 @@ struct dict_table_t {
UT_LIST_BASE_NODE_T(dict_index_t) indexes;
#ifdef BTR_CUR_HASH_ADAPT
/** List of detached indexes that are waiting to be freed along with
- the last adaptive hash index entry */
+ the last adaptive hash index entry.
+ Protected by autoinc_mutex (sic!) */
UT_LIST_BASE_NODE_T(dict_index_t) freed_indexes;
#endif /* BTR_CUR_HASH_ADAPT */
@@ -1880,7 +1881,7 @@ struct dict_table_t {
from a select. */
lock_t* autoinc_lock;
- /** Mutex protecting the autoincrement counter. */
+ /** Mutex protecting the autoinc counter and freed_indexes. */
mysql_mutex_t autoinc_mutex;
/** Autoinc counter value to give to the next inserted row. */