summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-04-11 14:41:24 +0300
committerMarko Mäkelä <marko.makela@mariadb.com>2022-04-11 14:41:24 +0300
commit840bab858b643ef6c03f1c5a47809e6e5e061499 (patch)
tree21267cc26bb168aa16dcd20dfc6ccab30e76556c
parent7bccf3dd744b6e85b69629c1e18730e77df503a2 (diff)
downloadmariadb-git-840bab858b643ef6c03f1c5a47809e6e5e061499.tar.gz
MDEV-28289 fts_optimize_sync_table() is acquiring dict_sys.latch while holding it
dict_acquire_mdl_shared(): Invoke the correct variant dict_table_t::parse_name<true>() also when trylock=true, that is, we are being called from fts_optimize_sync_table(). Ever since commit 82b7c561b7919fa24e3d24b3f04a16046e24374f (MDEV-24258) this code was prone to a hang. If another thread requested an exclusive dict_sys.latch between the time dict_acquire_mdl_shared<trylock=true>() acquired a shared dict_sys.latch and dict_table_t::parse_name<false>() was trying to acquire another shared dict_sys.latch, InnoDB would get into an infinite livelock of threads, because the futex-based srw-lock implementation prioritizes exclusive latch requests. dict_table_t::parse_name(): Rename the template parameter dict_locked into dict_frozen.
-rw-r--r--storage/innobase/dict/dict0dict.cc18
-rw-r--r--storage/innobase/include/dict0dict.h4
-rw-r--r--storage/innobase/include/dict0mem.h24
3 files changed, 23 insertions, 23 deletions
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index f64fd6f04c9..12b9574ecda 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -602,13 +602,13 @@ dict_index_get_nth_field_pos(
}
/** Parse the table file name into table name and database name.
-@tparam dict_locked whether dict_sys.lock() was called
-@param[in,out] db_name database name buffer
-@param[in,out] tbl_name table name buffer
-@param[out] db_name_len database name length
-@param[out] tbl_name_len table name length
+@tparam dict_frozen whether the caller holds dict_sys.latch
+@param[in,out] db_name database name buffer
+@param[in,out] tbl_name table name buffer
+@param[out] db_name_len database name length
+@param[out] tbl_name_len table name length
@return whether the table name is visible to SQL */
-template<bool dict_locked>
+template<bool dict_frozen>
bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
char (&tbl_name)[NAME_LEN + 1],
size_t *db_name_len, size_t *tbl_name_len) const
@@ -616,7 +616,7 @@ bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
char db_buf[MAX_DATABASE_NAME_LEN + 1];
char tbl_buf[MAX_TABLE_NAME_LEN + 1];
- if (!dict_locked)
+ if (!dict_frozen)
dict_sys.freeze(SRW_LOCK_CALL); /* protect against renaming */
ut_ad(dict_sys.frozen());
const size_t db_len= name.dblen();
@@ -636,7 +636,7 @@ bool dict_table_t::parse_name(char (&db_name)[NAME_LEN + 1],
memcpy(tbl_buf, mdl_name.m_name + db_len + 1, tbl_len);
tbl_buf[tbl_len]= 0;
- if (!dict_locked)
+ if (!dict_frozen)
dict_sys.unfreeze();
*db_name_len= filename_to_tablename(db_buf, db_name,
@@ -782,7 +782,7 @@ return_without_mdl:
size_t db1_len, tbl1_len;
- if (!table->parse_name<!trylock>(db_buf1, tbl_buf1, &db1_len, &tbl1_len))
+ if (!table->parse_name<true>(db_buf1, tbl_buf1, &db1_len, &tbl1_len))
{
/* The table was renamed to #sql prefix.
Release MDL (if any) for the old name and return. */
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index a02f4761964..d84c737b0f5 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2018, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2021, MariaDB Corporation.
+Copyright (c) 2013, 2022, 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
@@ -1570,7 +1570,7 @@ public:
}
else
lock_wait(SRW_LOCK_ARGS(file, line));
- }
+ }
#ifdef UNIV_PFS_RWLOCK
/** Unlock the data dictionary cache. */
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index dac738fbc68..d2f090f0ae4 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -2,7 +2,7 @@
Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2021, MariaDB Corporation.
+Copyright (c) 2013, 2022, 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
@@ -1934,17 +1934,17 @@ struct dict_table_t {
/** For overflow fields returns potential max length stored inline */
inline size_t get_overflow_field_local_len() const;
- /** Parse the table file name into table name and database name.
- @tparam dict_locked whether dict_sys.lock() was called
- @param[in,out] db_name database name buffer
- @param[in,out] tbl_name table name buffer
- @param[out] db_name_len database name length
- @param[out] tbl_name_len table name length
- @return whether the table name is visible to SQL */
- template<bool dict_locked= false>
- bool parse_name(char (&db_name)[NAME_LEN + 1],
- char (&tbl_name)[NAME_LEN + 1],
- size_t *db_name_len, size_t *tbl_name_len) const;
+ /** Parse the table file name into table name and database name.
+ @tparam dict_frozen whether the caller holds dict_sys.latch
+ @param[in,out] db_name database name buffer
+ @param[in,out] tbl_name table name buffer
+ @param[out] db_name_len database name length
+ @param[out] tbl_name_len table name length
+ @return whether the table name is visible to SQL */
+ template<bool dict_frozen= false>
+ bool parse_name(char (&db_name)[NAME_LEN + 1],
+ char (&tbl_name)[NAME_LEN + 1],
+ size_t *db_name_len, size_t *tbl_name_len) const;
/** Clear the table when rolling back TRX_UNDO_EMPTY */
void clear(que_thr_t *thr);