diff options
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r-- | sql/sql_class.cc | 210 |
1 files changed, 89 insertions, 121 deletions
diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f06c7885c85..15fbc6a1480 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -57,6 +57,7 @@ #include "transaction.h" #include "debug_sync.h" #include "sql_parse.h" // is_update_query +#include "sql_callback.h" /* The following is used to initialise Table_ident with a internal @@ -306,6 +307,11 @@ void **thd_ha_data(const THD *thd, const struct handlerton *hton) return (void **) &thd->ha_data[hton->slot].ha_ptr; } +extern "C" +void thd_storage_lock_wait(THD *thd, long long value) +{ + thd->utime_after_lock+= value; +} /** Provide a handler data getter to simplify coding @@ -1071,6 +1077,7 @@ THD::~THD() DBUG_ENTER("~THD()"); /* Ensure that no one is using 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); @@ -1096,7 +1103,6 @@ THD::~THD() my_free(db); db= NULL; free_root(&transaction.mem_root,MYF(0)); - mysys_var=0; // Safety (shouldn't be needed) mysql_mutex_destroy(&LOCK_thd_data); #ifndef DBUG_OFF dbug_sentry= THD_SENTRY_GONE; @@ -1185,7 +1191,7 @@ void THD::awake(THD::killed_state state_to_set) { thr_alarm_kill(thread_id); if (!slave_thread) - thread_scheduler.post_kill_notification(this); + MYSQL_CALLBACK(thread_scheduler, post_kill_notification, (this)); #ifdef SIGNAL_WITH_VIO_CLOSE if (this != current_thd) { @@ -1254,6 +1260,15 @@ bool THD::store_globals() if (my_pthread_setspecific_ptr(THR_THD, this) || my_pthread_setspecific_ptr(THR_MALLOC, &mem_root)) return 1; + /* + mysys_var is concurrently readable by a killer thread. + It is protected by LOCK_thd_data, it is not needed to lock while the + pointer is changing from NULL not non-NULL. If the kill thread reads + NULL it doesn't refer to anything, but if it is non-NULL we need to + ensure that the thread doesn't proceed to assign another thread to + have the mysys_var reference (which in fact refers to the worker + threads local storage with key THR_KEY_mysys. + */ mysys_var=my_thread_var; /* Let mysqld define the thread id (not mysys) @@ -3190,6 +3205,60 @@ extern "C" bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd) { return sqlcom_can_generate_row_events(thd); } + +#ifndef EMBEDDED_LIBRARY +extern "C" void thd_pool_wait_begin(MYSQL_THD thd, int wait_type); +extern "C" void thd_pool_wait_end(MYSQL_THD thd); + +/* + Interface for MySQL Server, plugins and storage engines to report + when they are going to sleep/stall. + + SYNOPSIS + thd_wait_begin() + thd Thread object + wait_type Type of wait + 1 -- short wait (e.g. for mutex) + 2 -- medium wait (e.g. for disk io) + 3 -- large wait (e.g. for locked row/table) + NOTES + This is used by the threadpool to have better knowledge of which + threads that currently are actively running on CPUs. When a thread + reports that it's going to sleep/stall, the threadpool scheduler is + free to start another thread in the pool most likely. The expected wait + time is simply an indication of how long the wait is expected to + become, the real wait time could be very different. + + thd_wait_end MUST be called immediately after waking up again. +*/ +extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type) +{ + MYSQL_CALLBACK(thread_scheduler, thd_wait_begin, (thd, wait_type)); +} + +/** + Interface for MySQL Server, plugins and storage engines to report + when they waking up from a sleep/stall. + + @param thd Thread handle +*/ +extern "C" void thd_wait_end(MYSQL_THD thd) +{ + MYSQL_CALLBACK(thread_scheduler, thd_wait_end, (thd)); +} +#else +extern "C" void thd_wait_begin(MYSQL_THD thd, thd_wait_type wait_type) +{ + /* do NOTHING for the embedded library */ + return; +} + +extern "C" void thd_wait_end(MYSQL_THD thd) +{ + /* do NOTHING for the embedded library */ + return; +} +#endif #endif // INNODB_COMPATIBILITY_HOOKS */ /**************************************************************************** @@ -3373,6 +3442,13 @@ void THD::set_query_id(query_id_t new_query_id) mysql_mutex_unlock(&LOCK_thd_data); } +/** Assign a new value to thd->mysys_var. */ +void THD::set_mysys_var(struct st_my_thread_var *new_mysys_var) +{ + mysql_mutex_lock(&LOCK_thd_data); + mysys_var= new_mysys_var; + mysql_mutex_unlock(&LOCK_thd_data); +} /** Leave explicit LOCK TABLES or prelocked mode and restore value of @@ -3651,7 +3727,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) { DBUG_ENTER("THD::decide_logging_format"); DBUG_PRINT("info", ("query: %s", query())); - DBUG_PRINT("info", ("variables.binlog_format: %u", + DBUG_PRINT("info", ("variables.binlog_format: %lu", variables.binlog_format)); DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x", lex->get_stmt_unsafe_flags())); @@ -3782,124 +3858,16 @@ int THD::decide_logging_format(TABLE_LIST *tables) int error= 0; int unsafe_flags; - /* - Classify a statement as unsafe when there is a mixed statement and an - on-going transaction at any point of the execution if: - - 1. The mixed statement is about to update a transactional table and - a non-transactional table. - - 2. The mixed statement is about to update a temporary transactional - table and a non-transactional table. - - 3. The mixed statement is about to update a transactional table and - read from a non-transactional table. - - 4. The mixed statement is about to update a temporary transactional - table and read from a non-transactional table. + bool multi_stmt_trans= in_multi_stmt_transaction_mode(); + bool trans_table= trans_has_updated_trans_table(this); + bool binlog_direct= variables.binlog_direct_non_trans_update; - 5. The mixed statement is about to update a non-transactional table - and read from a transactional table when the isolation level is - lower than repeatable read. - - After updating a transactional table if: - - 6. The mixed statement is about to update a non-transactional table - and read from a temporary transactional table. - - 7. The mixed statement is about to update a non-transactional table - and read from a temporary transactional table. - - 8. The mixed statement is about to update a non-transactionala table - and read from a temporary non-transactional table. - - 9. The mixed statement is about to update a temporary non-transactional - table and update a non-transactional table. - - 10. The mixed statement is about to update a temporary non-transactional - table and read from a non-transactional table. - - 11. A statement is about to update a non-transactional table and the - option variables.binlog_direct_non_trans_update is OFF. - - The reason for this is that locks acquired may not protected a concurrent - transaction of interfering in the current execution and by consequence in - the result. In particular, if there is an on-going transaction and a - transactional table was already updated, a temporary table must be written - to the binary log in the boundaries of the on-going transaction and as - such we artificially classify them as transactional. - */ - if (in_multi_stmt_transaction_mode()) - { - my_bool mixed_unsafe= FALSE; - my_bool non_trans_unsafe= FALSE; - - /* Case 1. */ - if (lex->stmt_accessed_table(LEX::STMT_WRITES_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 2. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_TEMP_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 3. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 4. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_TEMP_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 5. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_TRANS_TABLE) && - tx_isolation < ISO_REPEATABLE_READ) - /* - By default, InnoDB operates in REPEATABLE READ and with the option - --innodb-locks-unsafe-for-binlog disabled. In this case, InnoDB uses - next-key locks for searches and index scans, which prevents phantom - rows. - - This is scenario is safe for Innodb. However, there are no means to - transparently get this information. Therefore, we need to improve this - and change the storage engines to report somehow when an execution is - safe under an isolation level & binary logging format. - */ - mixed_unsafe= TRUE; - - if (trans_has_updated_trans_table(this)) - { - /* Case 6. */ - if (lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 7. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_TEMP_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 8. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_TEMP_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 9. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 10. */ - else if (lex->stmt_accessed_table(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE) && - lex->stmt_accessed_table(LEX::STMT_READS_NON_TRANS_TABLE)) - mixed_unsafe= TRUE; - /* Case 11. */ - else if (!variables.binlog_direct_non_trans_update && - lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE)) - non_trans_unsafe= TRUE; - } - - if (mixed_unsafe) - lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT); - else if (non_trans_unsafe) - lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS); - } + if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct, + trans_table, tx_isolation)) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT); + else if (multi_stmt_trans && trans_table && !binlog_direct && + lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE)) + lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS); /* If more than one engine is involved in the statement and at @@ -4024,7 +3992,7 @@ int THD::decide_logging_format(TABLE_LIST *tables) DBUG_PRINT("info", ("decision: no logging since " "mysql_bin_log.is_open() = %d " "and (options & OPTION_BIN_LOG) = 0x%llx " - "and binlog_format = %u " + "and binlog_format = %lu " "and binlog_filter->db_ok(db) = %d", mysql_bin_log.is_open(), (variables.option_bits & OPTION_BIN_LOG), |