diff options
author | Monty <monty@mariadb.org> | 2022-06-28 15:57:41 +0300 |
---|---|---|
committer | Monty <monty@mariadb.org> | 2022-06-28 15:57:41 +0300 |
commit | 5e40934d24d7704ba8ed4899f4e41b9fc120731a (patch) | |
tree | 39565c012a4ae4cb0038d1aa740f6a5899d9b4cb /sql/sql_base.cc | |
parent | 02a313dc5637fae7a5de037ea43df4cd508908fc (diff) | |
download | mariadb-git-5e40934d24d7704ba8ed4899f4e41b9fc120731a.tar.gz |
MDEV-28897 Wrong table.get_ref_count() upon concurrent truncate and backup stage operation
The issue was that flush_tables() didn't take a MDL lock on cached
TABLE_SHARE before calling open_table() to do a HA_EXTRA_FLUSH call.
Most engines seams to have no issue with it, but apparantly this conflicts
with InnoDB in 10.6 when using TRUNCATE
Fixed by taking a MDL lock before trying to open the table in
flush_tables().
There is no test case as it hard to repeat the scheduling that causes
the error. I did run the test case in MDEV-28897 to verify
that the bug is fixed.
Diffstat (limited to 'sql/sql_base.cc')
-rw-r--r-- | sql/sql_base.cc | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/sql/sql_base.cc b/sql/sql_base.cc index ed21f5ab3e2..1dd57cc319a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -515,7 +515,7 @@ public: Sql_condition ** cond_hdl) { *cond_hdl= NULL; - if (sql_errno == ER_OPEN_AS_READONLY) + if (sql_errno == ER_OPEN_AS_READONLY || sql_errno == ER_LOCK_WAIT_TIMEOUT) { handled_errors++; return TRUE; @@ -600,24 +600,43 @@ bool flush_tables(THD *thd, flush_tables_type flag) else { /* - HA_OPEN_FOR_FLUSH is used to allow us to open the table even if - TABLE_SHARE::incompatible_version is set. It also will tell - SEQUENCE engine that we don't have to read the sequence information - (which may cause deadlocks with concurrently running ALTER TABLE or - ALTER SEQUENCE) as we will close the table at once. + No free TABLE instances available. We have to open a new one. + + Try to take a MDL lock to ensure we can open a new table instance. + If the lock fails, it means that some DDL operation or flush tables + with read lock is ongoing. + In this case we cannot sending the HA_EXTRA_FLUSH signal. */ - if (!open_table_from_share(thd, share, &empty_clex_str, - HA_OPEN_KEYFILE, 0, - HA_OPEN_FOR_ALTER | HA_OPEN_FOR_FLUSH, - tmp_table, FALSE, - NULL)) + + MDL_request mdl_request; + MDL_REQUEST_INIT(&mdl_request, MDL_key::TABLE, + share->db.str, + share->table_name.str, + MDL_SHARED, MDL_EXPLICIT); + + if (!thd->mdl_context.acquire_lock(&mdl_request, 0)) { - (void) tmp_table->file->extra(HA_EXTRA_FLUSH); /* - We don't put the table into the TDC as the table was not fully - opened (we didn't open triggers) + HA_OPEN_FOR_FLUSH is used to allow us to open the table even if + TABLE_SHARE::incompatible_version is set. It also will tell + SEQUENCE engine that we don't have to read the sequence information + (which may cause deadlocks with concurrently running ALTER TABLE or + ALTER SEQUENCE) as we will close the table at once. */ - closefrm(tmp_table); + if (!open_table_from_share(thd, share, &empty_clex_str, + HA_OPEN_KEYFILE, 0, + HA_OPEN_FOR_ALTER | HA_OPEN_FOR_FLUSH, + tmp_table, FALSE, + NULL)) + { + (void) tmp_table->file->extra(HA_EXTRA_FLUSH); + /* + We don't put the table into the TDC as the table was not fully + opened (we didn't open triggers) + */ + closefrm(tmp_table); + } + thd->mdl_context.release_lock(mdl_request.ticket); } } tdc_release_share(share); |