diff options
author | Igor Babaev <igor@askmonty.org> | 2013-01-08 15:04:14 -0800 |
---|---|---|
committer | Igor Babaev <igor@askmonty.org> | 2013-01-08 15:04:14 -0800 |
commit | 7d9df8075e4c9392f4352e6ccd86921994f264bc (patch) | |
tree | 916e10b0a8725f6226c3f9c630516d5c918c8bac /sql | |
parent | 01dca17a9c2255845c050c44e152ece256c9112e (diff) | |
parent | ac45f3b38a2098a0a29fd53f023866d6c0dce78d (diff) | |
download | mariadb-git-7d9df8075e4c9392f4352e6ccd86921994f264bc.tar.gz |
Merge 5.5 -> mwl248
Diffstat (limited to 'sql')
-rw-r--r-- | sql/mysqld.cc | 35 | ||||
-rw-r--r-- | sql/scheduler.cc | 1 | ||||
-rw-r--r-- | sql/sql_base.cc | 102 | ||||
-rw-r--r-- | sql/sql_base.h | 3 | ||||
-rw-r--r-- | sql/sql_class.cc | 1 | ||||
-rw-r--r-- | sql/sql_db.cc | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 9 | ||||
-rw-r--r-- | sql/sql_select.cc | 4 | ||||
-rw-r--r-- | sql/sql_show.cc | 6 | ||||
-rw-r--r-- | sql/sql_table.cc | 21 | ||||
-rw-r--r-- | sql/threadpool_common.cc | 1 |
11 files changed, 139 insertions, 46 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d96e23710ed..64d52014fec 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2443,21 +2443,6 @@ void dec_connection_count(THD *thd) /* - Delete the THD object and decrease number of threads - - SYNOPSIS - delete_thd() - thd Thread handler -*/ - -void delete_thd(THD *thd) -{ - thread_count--; - delete thd; -} - - -/* Unlink thd from global list of available connections and free thd SYNOPSIS @@ -2475,14 +2460,23 @@ void unlink_thd(THD *thd) thd_cleanup(thd); dec_connection_count(thd); + + mysql_mutex_lock(&LOCK_status); + add_to_status(&global_status_var, &thd->status_var); + mysql_mutex_unlock(&LOCK_status); + mysql_mutex_lock(&LOCK_thread_count); + thread_count--; + thd->unlink(); /* Used by binlog_reset_master. It would be cleaner to use DEBUG_SYNC here, but that's not possible because the THD's debug sync feature has been shut down at this point. */ DBUG_EXECUTE_IF("sleep_after_lock_thread_count_before_delete_thd", sleep(5);); - delete_thd(thd); + mysql_mutex_unlock(&LOCK_thread_count); + + delete thd; DBUG_VOID_RETURN; } @@ -2591,10 +2585,13 @@ bool one_thread_per_connection_end(THD *thd, bool put_in_cache) /* Mark that current_thd is not valid anymore */ my_pthread_setspecific_ptr(THR_THD, 0); if (put_in_cache) + { + mysql_mutex_lock(&LOCK_thread_count); put_in_cache= cache_thread(); - mysql_mutex_unlock(&LOCK_thread_count); - if (put_in_cache) - DBUG_RETURN(0); // Thread is reused + mysql_mutex_unlock(&LOCK_thread_count); + if (put_in_cache) + DBUG_RETURN(0); // Thread is reused + } /* It's safe to broadcast outside a lock (COND... is not deleted here) */ DBUG_PRINT("signal", ("Broadcasting COND_thread_count")); diff --git a/sql/scheduler.cc b/sql/scheduler.cc index 0ae4121ef4c..54653557b16 100644 --- a/sql/scheduler.cc +++ b/sql/scheduler.cc @@ -35,7 +35,6 @@ static bool no_threads_end(THD *thd, bool put_in_cache) { unlink_thd(thd); - mysql_mutex_unlock(&LOCK_thread_count); return 1; // Abort handle_one_connection } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0dd1da68a76..b7f321e6290 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2401,10 +2401,11 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, Check that table exists in table definition cache, on disk or in some storage engine. - @param thd Thread context - @param table Table list element - @param[out] exists Out parameter which is set to TRUE if table - exists and to FALSE otherwise. + @param thd Thread context + @param table Table list element + @param fast_check Check only if share or .frm file exists + @param[out] exists Out parameter which is set to TRUE if table + exists and to FALSE otherwise. @note This function acquires LOCK_open internally. @@ -2416,7 +2417,8 @@ void drop_open_table(THD *thd, TABLE *table, const char *db_name, @retval FALSE No error. 'exists' out parameter set accordingly. */ -bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) +bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check, + bool *exists) { char path[FN_REFLEN + 1]; TABLE_SHARE *share; @@ -2424,7 +2426,8 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) *exists= TRUE; - DBUG_ASSERT(thd->mdl_context. + DBUG_ASSERT(fast_check || + thd->mdl_context. is_lock_owner(MDL_key::TABLE, table->db, table->table_name, MDL_SHARED)); @@ -2441,6 +2444,12 @@ bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists) if (!access(path, F_OK)) goto end; + if (fast_check) + { + *exists= FALSE; + goto end; + } + /* .FRM file doesn't exist. Check if some engine can provide it. */ if (ha_check_if_table_exists(thd, table->db, table->table_name, exists)) { @@ -2990,7 +2999,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, { bool exists; - if (check_if_table_exists(thd, table_list, &exists)) + if (check_if_table_exists(thd, table_list, 0, &exists)) DBUG_RETURN(TRUE); if (!exists) @@ -4698,7 +4707,18 @@ extern "C" uchar *schema_set_get_key(const uchar *record, size_t *length, open, see open_table() description for details. @retval FALSE Success. - @retval TRUE Failure (e.g. connection was killed) + @retval TRUE Failure (e.g. connection was killed) or table existed + for a CREATE TABLE. + + @notes + In case of CREATE TABLE we avoid a wait for tables that are in use + by first trying to do a meta data lock with timeout == 0. If we get a + timeout we will check if table exists (it should) and retry with + normal timeout if it didn't exists. + Note that for CREATE TABLE IF EXISTS we only generate a warning + but still return TRUE (to abort the calling open_table() function). + On must check THD->is_error() if one wants to distinguish between warning + and error. */ bool @@ -4710,6 +4730,10 @@ lock_table_names(THD *thd, TABLE_LIST *table; MDL_request global_request; Hash_set<TABLE_LIST, schema_set_get_key> schema_set; + ulong org_lock_wait_timeout= lock_wait_timeout; + /* Check if we are using CREATE TABLE ... IF NOT EXISTS */ + bool create_table; + Dummy_error_handler error_handler; DBUG_ENTER("lock_table_names"); DBUG_ASSERT(!thd->locked_tables_mode); @@ -4731,8 +4755,14 @@ lock_table_names(THD *thd, } } - if (! (flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK) && - ! mdl_requests.is_empty()) + if (mdl_requests.is_empty()) + DBUG_RETURN(FALSE); + + /* Check if CREATE TABLE IF NOT EXISTS was used */ + create_table= (tables_start && tables_start->open_strategy == + TABLE_LIST::OPEN_IF_EXISTS); + + if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) { /* Scoped locks: Take intention exclusive locks on all involved @@ -4760,12 +4790,58 @@ lock_table_names(THD *thd, global_request.init(MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); mdl_requests.push_front(&global_request); + + if (create_table) + lock_wait_timeout= 0; // Don't wait for timeout } - if (thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout)) - DBUG_RETURN(TRUE); + for (;;) + { + bool exists= TRUE; + bool res; - DBUG_RETURN(FALSE); + if (create_table) + thd->push_internal_handler(&error_handler); // Avoid warnings & errors + res= thd->mdl_context.acquire_locks(&mdl_requests, lock_wait_timeout); + if (create_table) + thd->pop_internal_handler(); + if (!res) + DBUG_RETURN(FALSE); // Got locks + + if (!create_table) + DBUG_RETURN(TRUE); // Return original error + + /* + We come here in the case of lock timeout when executing + CREATE TABLE IF NOT EXISTS. + Verify that table really exists (it should as we got a lock conflict) + */ + if (check_if_table_exists(thd, tables_start, 1, &exists)) + DBUG_RETURN(TRUE); // Should never happen + if (exists) + { + if (thd->lex->create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), + tables_start->table_name); + } + else + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tables_start->table_name); + DBUG_RETURN(TRUE); + } + /* purecov: begin inspected */ + /* + We got error from acquire_locks but table didn't exists. + In theory this should never happen, except maybe in + CREATE or DROP DATABASE scenario. + We play safe and restart the original acquire_locks with the + original timeout + */ + create_table= 0; + lock_wait_timeout= org_lock_wait_timeout; + /* purecov: end */ + } } diff --git a/sql/sql_base.h b/sql/sql_base.h index aa2ba9e5680..33cea7ebee0 100644 --- a/sql/sql_base.h +++ b/sql/sql_base.h @@ -302,7 +302,8 @@ TABLE *find_table_for_mdl_upgrade(THD *thd, const char *db, const char *table_name, bool no_error); void mark_tmp_table_for_reuse(TABLE *table); -bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool *exists); +bool check_if_table_exists(THD *thd, TABLE_LIST *table, bool fast_check, + bool *exists); int update_virtual_fields(THD *thd, TABLE *table, enum enum_vcol_update_mode vcol_update_mode= VCOL_UPDATE_FOR_READ); int dynamic_column_error_message(enum_dyncol_func_result rc); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 81f021d9306..42952585e07 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1444,7 +1444,6 @@ THD::~THD() mysql_mutex_lock(&LOCK_thd_data); mysys_var=0; // Safety (shouldn't be needed) mysql_mutex_unlock(&LOCK_thd_data); - add_to_status(&global_status_var, &status_var); /* Close connection */ #ifndef EMBEDDED_LIBRARY diff --git a/sql/sql_db.cc b/sql/sql_db.cc index f4e9ccfc5e6..dc8a2e9f057 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -939,7 +939,7 @@ update_binlog: char quoted_name[FN_REFLEN+3]; // Only write drop table to the binlog for tables that no longer exist. - if (check_if_table_exists(thd, tbl, &exists)) + if (check_if_table_exists(thd, tbl, 0, &exists)) { error= true; goto exit; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5dac052b749..de35d2f3d27 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2512,7 +2512,14 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } - if (!(res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0))) + res= open_and_lock_tables(thd, lex->query_tables, TRUE, 0); + if (res) + { + /* Got error or warning. Set res to 1 if error */ + if (!(res= thd->is_error())) + my_ok(thd); // CREATE ... IF NOT EXISTS + } + else { /* The table already exists */ if (create_table->table) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3550155606e..898fd47dd24 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7335,10 +7335,10 @@ JOIN_TAB *next_breadth_first_tab(JOIN *join, enum enum_exec_or_opt tabs_kind, } -JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables with_const) +JOIN_TAB *first_top_level_tab(JOIN *join, enum enum_with_const_tables const_tbls) { JOIN_TAB *tab= join->join_tab; - if (with_const == WITH_CONST_TABLES) + if (const_tbls == WITHOUT_CONST_TABLES) { if (join->const_tables == join->table_count) return NULL; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 861509b30de..b5bd8efa9da 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3185,13 +3185,13 @@ bool get_lookup_value(THD *thd, Item_func *item_func, Item_field *item_field; CHARSET_INFO *cs= system_charset_info; - if (item_func->arguments()[0]->type() == Item::FIELD_ITEM && + if (item_func->arguments()[0]->real_item()->type() == Item::FIELD_ITEM && item_func->arguments()[1]->const_item()) { idx_field= 0; idx_val= 1; } - else if (item_func->arguments()[1]->type() == Item::FIELD_ITEM && + else if (item_func->arguments()[1]->real_item()->type() == Item::FIELD_ITEM && item_func->arguments()[0]->const_item()) { idx_field= 1; @@ -3200,7 +3200,7 @@ bool get_lookup_value(THD *thd, Item_func *item_func, else return 0; - item_field= (Item_field*) item_func->arguments()[idx_field]; + item_field= (Item_field*) item_func->arguments()[idx_field]->real_item(); if (table->table != item_field->field->table) return 0; tmp_str= item_func->arguments()[idx_val]->val_str(&str_buff); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5bd2b105a92..50d4c72c191 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4137,7 +4137,8 @@ bool mysql_create_table_no_lock(THD *thd, set_table_default_charset(thd, create_info, (char*) db); db_options= create_info->table_options; - if (create_info->row_type != ROW_TYPE_FIXED && + if (!create_info->frm_only && + create_info->row_type != ROW_TYPE_FIXED && create_info->row_type != ROW_TYPE_DEFAULT) db_options|= HA_OPTION_PACK_RECORD; alias= table_case_name(create_info, table_name); @@ -4564,7 +4565,8 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table, */ if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) { - result= TRUE; + /* is_error() may be 0 if table existed and we generated a warning */ + result= thd->is_error(); goto end; } @@ -4759,7 +4761,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, properly isolated from all concurrent operations which matter. */ if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0)) + { + res= thd->is_error(); goto err; + } src_table->table->use_all_columns(); DEBUG_SYNC(thd, "create_table_like_after_open"); @@ -6779,9 +6784,19 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, my_sleep(100000);); /* Create a table with a temporary name. - With create_info->frm_only == 1 this creates a .frm file only. + With create_info->frm_only == 1 this creates a .frm file only and + we keep the original row format. We don't log the statement, it will be logged later. */ + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) + { + DBUG_ASSERT(create_info->frm_only); + /* Ensure we keep the original table format */ + create_info->table_options= ((create_info->table_options & + ~HA_OPTION_PACK_RECORD) | + (table->s->db_create_options & + HA_OPTION_PACK_RECORD)); + } tmp_disable_binlog(thd); error= mysql_create_table_no_lock(thd, new_db, tmp_name, create_info, diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc index 6b956768287..147a59df9b7 100644 --- a/sql/threadpool_common.cc +++ b/sql/threadpool_common.cc @@ -173,7 +173,6 @@ void threadpool_remove_connection(THD *thd) close_connection(thd, 0); unlink_thd(thd); - mysql_mutex_unlock(&LOCK_thread_count); mysql_cond_broadcast(&COND_thread_count); /* |