From fdb3c64e429cdc6f2370b7f4eefc0fbaf72eac6d Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 28 Sep 2020 17:04:02 +0530 Subject: [PATCH 1/6] MDEV-22277 LeakSanitizer: detected memory leaks in mem_heap_create_block_func after attempt to create foreign key - During online DDL, prepare phase error handler fails to remove the memory allocated for newly created foreign keys. --- mysql-test/suite/innodb/r/foreign_key.result | 11 +++++++++++ mysql-test/suite/innodb/t/foreign_key.test | 14 ++++++++++++++ storage/innobase/handler/handler0alter.cc | 6 ++++++ storage/xtradb/handler/handler0alter.cc | 6 ++++++ 4 files changed, 37 insertions(+) diff --git a/mysql-test/suite/innodb/r/foreign_key.result b/mysql-test/suite/innodb/r/foreign_key.result index 378fe74e14b..e9fbc742379 100644 --- a/mysql-test/suite/innodb/r/foreign_key.result +++ b/mysql-test/suite/innodb/r/foreign_key.result @@ -233,3 +233,14 @@ Opened_table_definitions 2 Opened_tables 2 drop function foo; drop table t2, t1; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk)) ENGINE=InnoDB; +XA START 'xid'; +INSERT INTO t1 VALUES (1,2); +CREATE TABLE x AS SELECT * FROM t1; +ERROR XAE07: XAER_RMFAIL: The command cannot be executed when global transaction is in the ACTIVE state +SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1; +ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +XA END 'xid'; +XA ROLLBACK 'xid'; +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/foreign_key.test b/mysql-test/suite/innodb/t/foreign_key.test index b33fbf60675..3269aeed62b 100644 --- a/mysql-test/suite/innodb/t/foreign_key.test +++ b/mysql-test/suite/innodb/t/foreign_key.test @@ -285,6 +285,20 @@ show status like '%opened_tab%'; drop function foo; drop table t2, t1; +CREATE TABLE t1 (pk INT, a INT, PRIMARY KEY (pk)) ENGINE=InnoDB; +XA START 'xid'; +INSERT INTO t1 VALUES (1,2); +--error ER_XAER_RMFAIL +CREATE TABLE x AS SELECT * FROM t1; +--connect (con1,localhost,root,,test) +SET foreign_key_checks= OFF, innodb_lock_wait_timeout= 1; +--error ER_LOCK_WAIT_TIMEOUT +ALTER TABLE t1 ADD FOREIGN KEY f (a) REFERENCES t1 (pk), LOCK=EXCLUSIVE;# Cleanup +--disconnect con1 +--connection default +XA END 'xid'; +XA ROLLBACK 'xid'; +DROP TABLE t1; # # End of 10.1 tests # diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 682f09992a4..e2c7c4421c6 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -3376,6 +3376,12 @@ err_exit: trx_free_for_mysql(ctx->trx); trx_commit_for_mysql(ctx->prebuilt->trx); + for (uint i = 0; i < ctx->num_to_add_fk; i++) { + if (ctx->add_fk[i]) { + dict_foreign_free(ctx->add_fk[i]); + } + } + delete ctx; ha_alter_info->handler_ctx = NULL; diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc index e1b2dcd2441..4126f6b60e0 100644 --- a/storage/xtradb/handler/handler0alter.cc +++ b/storage/xtradb/handler/handler0alter.cc @@ -3388,6 +3388,12 @@ err_exit: trx_free_for_mysql(ctx->trx); trx_commit_for_mysql(ctx->prebuilt->trx); + for (uint i = 0; i < ctx->num_to_add_fk; i++) { + if (ctx->add_fk[i]) { + dict_foreign_free(ctx->add_fk[i]); + } + } + delete ctx; ha_alter_info->handler_ctx = NULL; From 83a520dbbbfb40fdc8bcd34f8a9e9035c458ad08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 09:38:19 +0300 Subject: [PATCH 2/6] Cleanup: Remove unused rw_lock_t::writer_is_wait_ex This was missed in commit 2c252ba96b8f124f81371ec86843a45dc3977d54 (MySQL 5.5.42, MariaDB 5.5.42). --- storage/innobase/include/sync0rw.h | 8 +------- storage/xtradb/include/sync0rw.h | 8 +------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h index 54b6d46c58d..fba53a3f575 100644 --- a/storage/innobase/include/sync0rw.h +++ b/storage/innobase/include/sync0rw.h @@ -2,6 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -620,13 +621,6 @@ struct rw_lock_t { /* last s-lock file/line is not guaranteed to be correct */ const char* last_s_file_name;/*!< File name where last s-locked */ const char* last_x_file_name;/*!< File name where last x-locked */ - ibool writer_is_wait_ex; - /*!< This is TRUE if the writer field is - RW_LOCK_WAIT_EX; this field is located far - from the memory update hotspot fields which - are at the start of this struct, thus we can - peek this field without causing much memory - bus traffic */ unsigned cline:14; /*!< Line where created */ unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */ diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h index 2e25a27192e..19b4793fc7b 100644 --- a/storage/xtradb/include/sync0rw.h +++ b/storage/xtradb/include/sync0rw.h @@ -2,6 +2,7 @@ Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, Google Inc. +Copyright (c) 2020, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -763,13 +764,6 @@ struct rw_lock_t { /* last s-lock file/line is not guaranteed to be correct */ const char* last_s_file_name;/*!< File name where last s-locked */ const char* last_x_file_name;/*!< File name where last x-locked */ - ibool writer_is_wait_ex; - /*!< This is TRUE if the writer field is - RW_LOCK_WAIT_EX; this field is located far - from the memory update hotspot fields which - are at the start of this struct, thus we can - peek this field without causing much memory - bus traffic */ unsigned cline:14; /*!< Line where created */ unsigned last_s_line:14; /*!< Line number where last time s-locked */ unsigned last_x_line:14; /*!< Line number where last time x-locked */ From 74bd3683ca8da4084e664f4f417b95fd74a5b319 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 11:04:12 +0300 Subject: [PATCH 3/6] MDEV-23839 innodb_fast_shutdown=0 hang on change buffer merge ibuf_merge_or_delete_for_page(): Do not attempt to invoke ibuf_delete_recs() on a page of the change buffer itself. The caller could already be holding ibuf->index->lock, and an attempt to acquire it in S mode would hang the release server or cause an assertion failure in rw_lock_s_lock_func() in a debug server. This problem was reproducible on 1 out of 2 runs of the following: ./mtr --no-reorder \ innodb.innodb-page_compression_default \ innodb.innodb-page_compression_snappy \ innodb.innodb-page_compression_zip \ innodb.innodb_wl6326_big innodb.xa_recovery --- storage/innobase/ibuf/ibuf0ibuf.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 7e01c864a50..7068dab77a4 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -4472,7 +4472,10 @@ ibuf_merge_or_delete_for_page( fil_space_release(space); if (UNIV_UNLIKELY(srv_shutdown_state) - && !srv_fast_shutdown) { + && !srv_fast_shutdown + && (!block + || btr_page_get_index_id(block->frame) + != DICT_IBUF_ID_MIN + IBUF_SPACE_ID)) { /* Prevent an infinite loop on slow shutdown, in case the bitmap bits are wrongly clear even though buffered From aa2f263e595624bb64ddd31ce081126381f86a39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 29 Sep 2020 11:07:34 +0300 Subject: [PATCH 4/6] Cleanup: Remove constant parameters async=false, index_name=NULL --- storage/innobase/btr/btr0defragment.cc | 7 +---- storage/innobase/handler/ha_innodb.cc | 35 +++-------------------- storage/innobase/handler/ha_innodb.h | 3 +- storage/innobase/include/btr0defragment.h | 2 -- 4 files changed, 6 insertions(+), 41 deletions(-) diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc index dfaa61a1343..645334cbf4d 100644 --- a/storage/innobase/btr/btr0defragment.cc +++ b/storage/innobase/btr/btr0defragment.cc @@ -157,8 +157,6 @@ synchronized defragmentation. */ os_event_t btr_defragment_add_index( dict_index_t* index, /*!< index to be added */ - bool async, /*!< whether this is an async - defragmentation */ dberr_t* err) /*!< out: error code */ { mtr_t mtr; @@ -191,10 +189,7 @@ btr_defragment_add_index( return NULL; } btr_pcur_t* pcur = btr_pcur_create_for_mysql(); - os_event_t event = NULL; - if (!async) { - event = os_event_create(0); - } + os_event_t event = os_event_create(0); btr_pcur_open_at_index_side(true, index, BTR_SEARCH_LEAF, pcur, true, 0, &mtr); btr_pcur_move_to_next(pcur, &mtr); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 2493a11b554..fb12297d698 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -14705,25 +14705,14 @@ ha_innobase::analyze( /*****************************************************************//** Defragment table. @return error number */ -UNIV_INTERN -int -ha_innobase::defragment_table( -/*==========================*/ - const char* name, /*!< in: table name */ - const char* index_name, /*!< in: index name */ - bool async) /*!< in: whether to wait until finish */ +inline int ha_innobase::defragment_table(const char *name) { char norm_name[FN_REFLEN]; dict_table_t* table = NULL; dict_index_t* index = NULL; - ibool one_index = (index_name != 0); int ret = 0; dberr_t err = DB_SUCCESS; - if (!srv_defragment) { - return ER_FEATURE_DISABLED; - } - normalize_table_name(norm_name, name); table = dict_table_open_on_name(norm_name, FALSE, @@ -14751,10 +14740,6 @@ ha_innobase::defragment_table( continue; } - if (one_index && strcasecmp(index_name, index->name) != 0) { - continue; - } - if (btr_defragment_find_index(index)) { // We borrow this error code. When the same index is // already in the defragmentation queue, issue another @@ -14770,7 +14755,7 @@ ha_innobase::defragment_table( break; } - os_event_t event = btr_defragment_add_index(index, async, &err); + os_event_t event = btr_defragment_add_index(index, &err); if (err != DB_SUCCESS) { push_warning_printf( @@ -14786,7 +14771,7 @@ ha_innobase::defragment_table( break; } - if (!async && event) { + if (event) { while(os_event_wait_time(event, 1000000)) { if (thd_killed(current_thd)) { btr_defragment_remove_index(index); @@ -14800,19 +14785,9 @@ ha_innobase::defragment_table( if (ret) { break; } - - if (one_index) { - one_index = FALSE; - break; - } } dict_table_close(table, FALSE, FALSE); - - if (ret == 0 && one_index) { - ret = ER_NO_SUCH_INDEX; - } - return ret; } @@ -14838,9 +14813,7 @@ ha_innobase::optimize( bool try_alter = true; if (!m_prebuilt->table->is_temporary() && srv_defragment) { - int err; - - err = defragment_table(m_prebuilt->table->name.m_name, NULL, false); + int err = defragment_table(m_prebuilt->table->name.m_name); if (err == 0) { try_alter = false; diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 6d5c108c4a3..a02c897f7ae 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -219,8 +219,7 @@ public: int delete_table(const char *name); int rename_table(const char* from, const char* to); - int defragment_table(const char* name, const char* index_name, - bool async); + inline int defragment_table(const char* name); int check(THD* thd, HA_CHECK_OPT* check_opt); char* update_table_comment(const char* comment); diff --git a/storage/innobase/include/btr0defragment.h b/storage/innobase/include/btr0defragment.h index 57f8c2f3811..d622c3c7c39 100644 --- a/storage/innobase/include/btr0defragment.h +++ b/storage/innobase/include/btr0defragment.h @@ -64,8 +64,6 @@ is a synchronized defragmentation. */ os_event_t btr_defragment_add_index( dict_index_t* index, /*!< index to be added */ - bool async, /*!< whether this is an async - defragmentation */ dberr_t* err); /*!< out: error code */ /******************************************************************//** When table is dropped, this function is called to mark a table as removed in From cd5f4d2a5939aa047734f023b28462c65f3e4569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 30 Sep 2020 13:26:46 +0300 Subject: [PATCH 5/6] Cleanup: Remove unused fts_cache_t::optimize_lock This has been unused from the very beginning (mysql/mysql-server@d5e512ae7e37cd1f70c44a3f12205d70b13118ab). --- storage/innobase/fts/fts0fts.cc | 3 --- storage/innobase/handler/ha_innodb.cc | 1 - storage/innobase/include/fts0types.h | 2 -- storage/innobase/include/sync0sync.h | 1 - storage/innobase/include/sync0types.h | 1 - storage/innobase/sync/sync0debug.cc | 3 --- storage/innobase/sync/sync0sync.cc | 1 - 7 files changed, 12 deletions(-) diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 8a6901bd15b..d56a1cb8bde 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -286,7 +286,6 @@ fts_cache_destroy(fts_cache_t* cache) { rw_lock_free(&cache->lock); rw_lock_free(&cache->init_lock); - mutex_free(&cache->optimize_lock); mutex_free(&cache->deleted_lock); mutex_free(&cache->doc_id_lock); os_event_destroy(cache->sync->event); @@ -623,8 +622,6 @@ fts_cache_create( mutex_create(LATCH_ID_FTS_DELETE, &cache->deleted_lock); - mutex_create(LATCH_ID_FTS_OPTIMIZE, &cache->optimize_lock); - mutex_create(LATCH_ID_FTS_DOC_ID, &cache->doc_id_lock); /* This is the heap used to create the cache itself. */ diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fb12297d698..fd44324afe0 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -588,7 +588,6 @@ static PSI_mutex_info all_innodb_mutexes[] = { PSI_KEY(flush_list_mutex), PSI_KEY(fts_bg_threads_mutex), PSI_KEY(fts_delete_mutex), - PSI_KEY(fts_optimize_mutex), PSI_KEY(fts_doc_id_mutex), PSI_KEY(log_flush_order_mutex), PSI_KEY(hash_table_mutex), diff --git a/storage/innobase/include/fts0types.h b/storage/innobase/include/fts0types.h index 44c3ab77695..f5760a16c0e 100644 --- a/storage/innobase/include/fts0types.h +++ b/storage/innobase/include/fts0types.h @@ -131,8 +131,6 @@ struct fts_cache_t { intialization, it has different SYNC level as above cache lock */ - ib_mutex_t optimize_lock; /*!< Lock for OPTIMIZE */ - ib_mutex_t deleted_lock; /*!< Lock covering deleted_doc_ids */ ib_mutex_t doc_id_lock; /*!< Lock covering Doc ID */ diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h index e250307fa28..1517a93c196 100644 --- a/storage/innobase/include/sync0sync.h +++ b/storage/innobase/include/sync0sync.h @@ -62,7 +62,6 @@ extern mysql_pfs_key_t fil_system_mutex_key; extern mysql_pfs_key_t flush_list_mutex_key; extern mysql_pfs_key_t fts_bg_threads_mutex_key; extern mysql_pfs_key_t fts_delete_mutex_key; -extern mysql_pfs_key_t fts_optimize_mutex_key; extern mysql_pfs_key_t fts_doc_id_mutex_key; extern mysql_pfs_key_t fts_pll_tokenize_mutex_key; extern mysql_pfs_key_t hash_table_mutex_key; diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h index 1820642b004..a52bb4437ea 100644 --- a/storage/innobase/include/sync0types.h +++ b/storage/innobase/include/sync0types.h @@ -307,7 +307,6 @@ enum latch_id_t { LATCH_ID_FLUSH_LIST, LATCH_ID_FTS_BG_THREADS, LATCH_ID_FTS_DELETE, - LATCH_ID_FTS_OPTIMIZE, LATCH_ID_FTS_DOC_ID, LATCH_ID_FTS_PLL_TOKENIZE, LATCH_ID_HASH_TABLE_MUTEX, diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 815e3cee618..b732ad355a0 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1320,9 +1320,6 @@ sync_latch_meta_init() LATCH_ADD_MUTEX(FTS_DELETE, SYNC_FTS_OPTIMIZE, fts_delete_mutex_key); - LATCH_ADD_MUTEX(FTS_OPTIMIZE, SYNC_FTS_OPTIMIZE, - fts_optimize_mutex_key); - LATCH_ADD_MUTEX(FTS_DOC_ID, SYNC_FTS_OPTIMIZE, fts_doc_id_mutex_key); LATCH_ADD_MUTEX(FTS_PLL_TOKENIZE, SYNC_FTS_TOKENIZE, diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc index 22bd9f823ec..a9018f2f5d5 100644 --- a/storage/innobase/sync/sync0sync.cc +++ b/storage/innobase/sync/sync0sync.cc @@ -48,7 +48,6 @@ mysql_pfs_key_t fil_system_mutex_key; mysql_pfs_key_t flush_list_mutex_key; mysql_pfs_key_t fts_bg_threads_mutex_key; mysql_pfs_key_t fts_delete_mutex_key; -mysql_pfs_key_t fts_optimize_mutex_key; mysql_pfs_key_t fts_doc_id_mutex_key; mysql_pfs_key_t fts_pll_tokenize_mutex_key; mysql_pfs_key_t hash_table_mutex_key; From d6b33ea237c620923a7d4458a5907be0738c821d Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 30 Sep 2020 18:02:29 +0530 Subject: [PATCH 6/6] MDEV-23856 fts_optimize_wq accessed after shutdown of FTS Optimize thread In fts_optimize_remove_table(), InnoDB tries to access the fts_optimize_wq after shutting down the fts optimize thread. This issue caused by the commit a41d429765c7ddb528b9b438c68b25ff55d3bd55. Fix should check for fts optimize thread shutdown state before checking fts_optimize_wq. --- storage/innobase/fts/fts0opt.cc | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc index 39720b07bd1..8ad1cf4ebe1 100644 --- a/storage/innobase/fts/fts0opt.cc +++ b/storage/innobase/fts/fts0opt.cc @@ -2603,9 +2603,13 @@ fts_optimize_remove_table( os_event_destroy(event); - ut_d(mutex_enter(&fts_optimize_wq->mutex)); - ut_ad(!table->fts->in_queue); - ut_d(mutex_exit(&fts_optimize_wq->mutex)); +#ifdef UNIV_DEBUG + if (!fts_opt_start_shutdown) { + mutex_enter(&fts_optimize_wq->mutex); + ut_ad(!table->fts->in_queue); + mutex_exit(&fts_optimize_wq->mutex); + } +#endif /* UNIV_DEBUG */ } /** Send sync fts cache for the table.