From 588e95bb128c94d976d560a4c10a53b781854ab9 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 13 Feb 2026 20:25:09 +0530 Subject: [PATCH] MDEV-38832 Assertion `!commit_lsn' failed in void trx_t::free() Problem: ======== When creating tables with vector indexes, if the secondary table creation fails after the main table is successfully created, the server was not properly cleaning up the main table's .ibd file. When we try to do DROP DATABASE, the server sees an orphaned file and attempts to clean up a "stale" handle. If innodb_flush_log_later trx_commit=0 is set then the log buffer is written to the file and flushed to disk only once per second. Due to this reason, InnoDB doesn't reset trx->commit_lsn to 0. This lead to assertion failure in trx_t::free() Reason: ======= This occurred because create_table_impl() always called ddl_log_complete() on any error, which disables DDL log entries instead of executing them for cleanup. The main table would be left behind even though the overall CREATE TABLE operation failed. Solution: ========= ha_create_table(): Return error code 2 specifically when secondary table creation for high-level indexes fails create_table_impl(): Call ddl_log_revert() when error code is 2 to properly clean up the main table files. innodb_drop_database(): Add debug assertion reset to clear commit_lsn before freeing the transaction. --- mysql-test/suite/atomic/vector_innodb.result | 11 +++++++++++ mysql-test/suite/atomic/vector_innodb.test | 13 +++++++++++++ sql/handler.cc | 10 +++++++++- sql/sql_table.cc | 16 ++++++++++++---- storage/innobase/handler/ha_innodb.cc | 2 ++ 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/atomic/vector_innodb.result b/mysql-test/suite/atomic/vector_innodb.result index fff1a6c755be3..87d869d3fb4e5 100644 --- a/mysql-test/suite/atomic/vector_innodb.result +++ b/mysql-test/suite/atomic/vector_innodb.result @@ -1816,3 +1816,14 @@ count(*) 2 master-bin.000002 # Query # # use `test`; ALTER TABLE t1 DROP INDEX a ALTER DATABASE test CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci; +# +# MDEV-38832 Assertion `!commit_lsn' failed in void trx_t::free() +# +CREATE DATABASE test_1; +SET STATEMENT max_session_mem_used=8192 FOR +CREATE TABLE test_1.t (a INT,b VECTOR (5) NOT NULL, +VECTOR INDEX (b)) ENGINE=INNODB; +ERROR HY000: Engine InnoDB failed to discover table `test_1`.`t` with 'CREATE TABLE i ( layer tinyint not null, tref varbinary(6), vec blob not null, neighbors blob not null, unique (tref), key (layer)) ' +SET GLOBAL innodb_flush_log_at_trx_commit=0; +DROP DATABASE test_1; +SET GLOBAL innodb_flush_log_at_trx_commit=1; diff --git a/mysql-test/suite/atomic/vector_innodb.test b/mysql-test/suite/atomic/vector_innodb.test index 929f845cba50d..33ad23a565e74 100644 --- a/mysql-test/suite/atomic/vector_innodb.test +++ b/mysql-test/suite/atomic/vector_innodb.test @@ -1,3 +1,16 @@ let $skip_vector=1; let $extra_fields=, v vector(5) not null default x'e360d63ebe554f3fcdbc523f4522193f5236083d', vector index(v); --source alter_table_innodb.test + +--echo # +--echo # MDEV-38832 Assertion `!commit_lsn' failed in void trx_t::free() +--echo # +CREATE DATABASE test_1; +--error ER_SQL_DISCOVER_ERROR +SET STATEMENT max_session_mem_used=8192 FOR +CREATE TABLE test_1.t (a INT,b VECTOR (5) NOT NULL, + VECTOR INDEX (b)) ENGINE=INNODB; +let $flush_log_at_commit=`select @@global.innodb_flush_log_at_trx_commit`; +SET GLOBAL innodb_flush_log_at_trx_commit=0; +DROP DATABASE test_1; +eval SET GLOBAL innodb_flush_log_at_trx_commit=$flush_log_at_commit; diff --git a/sql/handler.cc b/sql/handler.cc index 22de4590067be..2d3b9ceea001f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6484,6 +6484,7 @@ static int ha_create_table_from_share(THD *thd, TABLE_SHARE *share, 0 ok @retval 1 error + 2 error while creating high level index failure */ int ha_create_table(THD *thd, const char *path, const char *db, const char *table_name, HA_CREATE_INFO *create_info, @@ -6552,7 +6553,10 @@ int ha_create_table(THD *thd, const char *path, const char *db, } if ((error= share.path.length > sizeof(file_name) - HLINDEX_BUF_LEN)) + { + error= 2; goto err; + } enum_sql_command old_sql_command= thd->lex->sql_command; for (uint i= share.keys; i < share.total_keys; i++) @@ -6569,13 +6573,17 @@ int ha_create_table(THD *thd, const char *path, const char *db, if (error) { index_share.db_plugin= NULL; + error= 2; break; } uint unused; if ((error= ha_create_table_from_share(thd, &index_share, &index_cinfo, &unused))) + { + error= 2; break; + } } thd->lex->sql_command= old_sql_command; free_table_share(&index_share); @@ -6583,7 +6591,7 @@ int ha_create_table(THD *thd, const char *path, const char *db, err: free_table_share(&share); - DBUG_RETURN(error != 0); + DBUG_RETURN(error); } void st_ha_check_opt::init() diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4c660c3924c05..fe27b91f98f94 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4932,8 +4932,8 @@ int create_table_impl(THD *thd, if (!frm_only) { debug_crash_here("ddl_log_create_before_create_table"); - if (ha_create_table(thd, path.str, db.str, table_name.str, create_info, - frm, 0)) + if ((error= ha_create_table(thd, path.str, db.str, table_name.str, create_info, + frm, 0))) { file->ha_create_partitioning_metadata(path.str, NULL, CHF_DELETE_FLAG); deletefrm(path.str); @@ -4969,8 +4969,16 @@ int create_table_impl(THD *thd, err: if (unlikely(error) && ddl_log_state_create) { - /* Table was never created, so we can ignore the ddl log entry */ - ddl_log_complete(ddl_log_state_create); + if (error == 2) + { + /* hlindex creation failed, need to revert to clean up main table */ + ddl_log_revert(thd, ddl_log_state_create); + } + else + { + /* Table was never created, so we can ignore the ddl log entry */ + ddl_log_complete(ddl_log_state_create); + } } THD_STAGE_INFO(thd, stage_after_create); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 21dbe9ce1910d..99759907f99c4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1531,6 +1531,8 @@ static void innodb_drop_database(handlerton*, char *path) log_write_up_to(mtr.commit_lsn(), true); } + /* Reset the commit_lsn when innodb_flush_log_at_trx_commit = 0 */ + ut_d(trx->commit_lsn= 0); trx->free(); my_free(namebuf); }