Bug #116035 with parallel instant ddl and select INFORMATION_SCHEMA will show Duplicate row
Submitted: 9 Sep 2024 1:55 Modified: 11 Sep 2024 12:55
Reporter: zongyi chen (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S3 (Non-critical)
Version: OS:Any
Assigned to: CPU Architecture:Any
Tags: instant ddl

[9 Sep 2024 1:55] zongyi chen
Description:
as topics say

How to repeat:
1.sql in mysql:
drop table t1;
CREATE TABLE IF NOT EXISTS `t1` (`a` int);

2.write sql in bash file(vim instant_simple.sh):
/home/czy/open_8037/mysql/bin/mysql -u root -h 127.0.0.1 -P 8037 -f -Dtest -e"
                alter table t1 add column b int,algorithm=instant;
                SELECT TABLE_ID,NAME,N_COLS,ROW_FORMAT,INSTANT_COLS,TOTAL_ROW_VERSIONS,64-TOTAL_ROW_VERSIONS AS \"REMAINING_copy_DDLs\" FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE name like \"%t1%\" ORDER BY TOTAL_ROW_VERSIONS DESC;" >>tmp5.log 2>&1 &

/home/czy/open_8037/mysql/bin/mysql -u root -h 127.0.0.1 -P 8037 -f -Dtest -e"
                alter table t1 drop column b,algorithm=instant;          
                SELECT TABLE_ID,NAME,N_COLS,ROW_FORMAT,INSTANT_COLS,TOTAL_ROW_VERSIONS,64-TOTAL_ROW_VERSIONS AS \"REMAINING_copy_DDLs\" FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE name like \"%t1%\" ORDER BY TOTAL_ROW_VERSIONS DESC;" >>tmp5.log 2>&1 &

3.sh instant_simple.sh

4.cat tmp5.log will show
TABLE_ID        NAME    N_COLS  ROW_FORMAT      INSTANT_COLS    TOTAL_ROW_VERSIONS      REMAINING_copy_DDLs
2707    test/t1 4       Dynamic 0       2       62
2707    test/t1 4       Dynamic 0       2       62
TABLE_ID        NAME    N_COLS  ROW_FORMAT      INSTANT_COLS    TOTAL_ROW_VERSIONS      REMAINING_copy_DDLs
2707    test/t1 4       Dynamic 0       2       62

in first select i_s.innodb_tables show duplicate row.
[9 Sep 2024 17:21] MySQL Verification Team
Hi,

Not sure why is this a bug, the entries have same table_id so the values are not wrong.. the fact that in some edge case i_s table with do this I would not consider a bug. I_S tables are made to be as fast as possible and as light on the system as possible. How would this behavior affect you badly?
[10 Sep 2024 2:54] zongyi chen
Stable reproduction:
change two files:
1.
diff --git a/sql/dd/impl/raw/raw_record.cc b/sql/dd/impl/raw/raw_record.cc
index a773e18..c66543f 100644
--- a/sql/dd/impl/raw/raw_record.cc
+++ b/sql/dd/impl/raw/raw_record.cc
@@ -40,6 +40,8 @@
 #include "sql/tztime.h"  // Time_zone_offset
 #include "sql_string.h"
 #include "template_utils.h"
+#include "sql/debug_sync.h"
+#include "sql/current_thd.h"
 
 namespace dd {
 
@@ -98,6 +100,7 @@ bool Raw_record::update() {
 bool Raw_record::drop() {
   DBUG_TRACE;
 
+  DEBUG_SYNC(current_thd, "before_delete_dd");
   int rc = m_table->file->ha_delete_row(m_table->record[1]);
 
   if (rc) {

2.
diff --git a/storage/innobase/dict/dict0dd.cc b/storage/innobase/dict/dict0dd.cc
index ca5312a..a7a95e1 100644
--- a/storage/innobase/dict/dict0dd.cc
+++ b/storage/innobase/dict/dict0dd.cc
@@ -5551,6 +5551,17 @@ const char *dd_process_dd_tables_rec_and_mtr_commit(
   mtr_commit(mtr);
   THD *thd = current_thd;
 
+  dict_table_t *ib_table;
+  const auto hash_value = ut::hash_uint64(table_id);
+
+  HASH_SEARCH(id_hash, dict_sys->table_id_hash, hash_value, dict_table_t *,
+              ib_table, ut_ad(ib_table->cached), ib_table->id == table_id);
+
+  if (ib_table != nullptr && ib_table->name.m_name[0] == 't' && ib_table->name.m_name[5] == 't') {
+    DEBUG_SYNC(thd, "before_first_open");
+    sleep(5);
+  }
+
   *table = dd_table_open_on_id(table_id, thd, mdl, true, false);
 
   if (!(*table)) {

two conn
1.
use test;
drop table t1;
CREATE TABLE t1 (a int); 
set debug_sync = 'before_delete_dd wait_for go';
alter table t1 add column b int;

2.
set debug_sync = 'before_first_open SIGNAL go';
SELECT TABLE_ID,NAME,N_COLS,ROW_FORMAT,INSTANT_COLS,TOTAL_ROW_VERSIONS,64-TOTAL_ROW_VERSIONS AS "REMAINING_copy_DDLs" FROM INFORMATION_SCHEMA.INNODB_TABLES WHERE name like "%t1%";
[10 Sep 2024 3:02] zongyi chen
it is not affect me yet,but maybe someone who use select count(*) from i_s will be affect. maybe we can use a set to deal this issue.