summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMonty <monty@mariadb.org>2022-06-28 15:57:41 +0300
committerMonty <monty@mariadb.org>2022-06-28 15:57:41 +0300
commit5e40934d24d7704ba8ed4899f4e41b9fc120731a (patch)
tree39565c012a4ae4cb0038d1aa740f6a5899d9b4cb
parent02a313dc5637fae7a5de037ea43df4cd508908fc (diff)
downloadmariadb-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.
-rw-r--r--sql/sql_base.cc49
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);