summaryrefslogtreecommitdiff
path: root/sql/sql_class.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_class.cc')
-rw-r--r--sql/sql_class.cc210
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),