diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 159613c58a0..74c5af92229 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1047,6 +1047,7 @@ bool compare_record(TABLE *table); bool append_file_to_dir(THD *thd, const char **filename_ptr, const char *table_name); bool table_def_init(void); +void table_def_start_shutdown(void); void table_def_free(void); void assign_new_table_id(TABLE_SHARE *share); uint cached_open_tables(void); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1055d5fed8b..ed1572853bc 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1294,9 +1294,7 @@ void clean_up(bool print_message) grant_free(); #endif query_cache_destroy(); - table_def_free(); hostname_cache_free(); - mdl_destroy(); item_user_lock_free(); lex_free(); /* Free some memory */ item_create_cleanup(); @@ -1308,12 +1306,15 @@ void clean_up(bool print_message) udf_free(); #endif } + table_def_start_shutdown(); plugin_shutdown(); ha_end(); if (tc_log) tc_log->close(); delegates_destroy(); xid_cache_free(); + table_def_free(); + mdl_destroy(); delete_elements(&key_caches, (void (*)(const char*, uchar*)) free_key_cache); multi_keycache_free(); free_status_vars(); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 42fc3ba0566..4f8c6be8e7b 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -114,6 +114,7 @@ TABLE *unused_tables; HASH table_def_cache; static TABLE_SHARE *oldest_unused_share, end_of_unused_share; static bool table_def_inited= 0; +static bool table_def_shutdown_in_progress= 0; static bool check_and_update_table_version(THD *thd, TABLE_LIST *tables, TABLE_SHARE *table_share); @@ -279,13 +280,36 @@ bool table_def_init(void) } +/** + Notify table definition cache that process of shutting down server + has started so it has to keep number of TABLE and TABLE_SHARE objects + minimal in order to reduce number of references to pluggable engines. +*/ + +void table_def_start_shutdown(void) +{ + if (table_def_inited) + { + pthread_mutex_lock(&LOCK_open); + /* Free all cached but unused TABLEs and TABLE_SHAREs first. */ + close_cached_tables(NULL, NULL, TRUE, FALSE); + /* + Ensure that TABLE and TABLE_SHARE objects which are created for + tables that are open during process of plugins' shutdown are + immediately released. This keeps number of references to engine + plugins minimal and allows shutdown to proceed smoothly. + */ + table_def_shutdown_in_progress= TRUE; + pthread_mutex_unlock(&LOCK_open); + } +} + + void table_def_free(void) { DBUG_ENTER("table_def_free"); if (table_def_inited) { - /* Free all open TABLEs first. */ - close_cached_tables(NULL, NULL, FALSE, FALSE); table_def_inited= 0; /* Free table definitions. */ my_hash_free(&table_def_cache); @@ -646,7 +670,8 @@ void release_table_share(TABLE_SHARE *share) DBUG_ASSERT(share->ref_count); if (!--share->ref_count) { - if (share->version != refresh_version) + if (share->version != refresh_version || + table_def_shutdown_in_progress) to_be_deleted=1; else { @@ -1513,7 +1538,8 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) table->mdl_ticket= NULL; if (table->needs_reopen() || - thd->version != refresh_version || !table->db_stat) + thd->version != refresh_version || !table->db_stat || + table_def_shutdown_in_progress) { free_cache_entry(table); found_old_table=1;