1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00

Merge branch '10.4' into bb-10.4-mdev16188

This commit is contained in:
Igor Babaev
2019-02-03 18:41:18 -08:00
2383 changed files with 85155 additions and 37192 deletions

View File

@@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2015, Oracle and/or its affiliates.
Copyright (c) 2008, 2017, MariaDB Corporation.
Copyright (c) 2008, 2018, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -66,9 +66,11 @@
#include "sql_callback.h"
#include "lock.h"
#include "wsrep_mysqld.h"
#include "wsrep_thd.h"
#include "sql_connect.h"
#include "my_atomic.h"
#ifdef WITH_WSREP
#include "wsrep_thd.h"
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
#ifdef HAVE_SYS_SYSCALL_H
#include <sys/syscall.h>
@@ -640,16 +642,42 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
xid_hash_pins(0),
m_tmp_tables_locked(false)
#ifdef WITH_WSREP
,
,
wsrep_applier(is_wsrep_applier),
wsrep_applier_closing(false),
wsrep_client_thread(false),
wsrep_apply_toi(false),
wsrep_retry_counter(0),
wsrep_PA_safe(true),
wsrep_retry_query(NULL),
wsrep_retry_query_len(0),
wsrep_retry_command(COM_CONNECT),
wsrep_consistency_check(NO_CONSISTENCY_CHECK),
wsrep_mysql_replicated(0),
wsrep_TOI_pre_query(NULL),
wsrep_TOI_pre_query_len(0),
wsrep_po_handle(WSREP_PO_INITIALIZER),
wsrep_po_cnt(0),
wsrep_apply_format(0),
wsrep_ignore_table(false)
#endif
wsrep_apply_toi(false),
wsrep_rbr_buf(NULL),
wsrep_sync_wait_gtid(WSREP_GTID_UNDEFINED),
wsrep_affected_rows(0),
wsrep_has_ignored_error(false),
wsrep_replicate_GTID(false),
wsrep_ignore_table(false),
/* wsrep-lib */
m_wsrep_next_trx_id(WSREP_UNDEFINED_TRX_ID),
m_wsrep_mutex(LOCK_thd_data),
m_wsrep_cond(COND_wsrep_thd),
m_wsrep_client_service(this, m_wsrep_client_state),
m_wsrep_client_state(this,
m_wsrep_mutex,
m_wsrep_cond,
Wsrep_server_state::instance(),
m_wsrep_client_service,
wsrep::client_id(thread_id))
#endif /*WITH_WSREP */
{
ulong tmp;
bzero(&variables, sizeof(variables));
@@ -668,6 +696,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
main_da.init();
mdl_context.init(this);
mdl_backup_lock= 0;
/*
Pass nominal parameters to init_alloc_root only to ensure that
@@ -757,11 +786,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
mysql_mutex_init(key_LOCK_wakeup_ready, &LOCK_wakeup_ready, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_thd_kill, &LOCK_thd_kill, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_wakeup_ready, &COND_wakeup_ready, 0);
/*
LOCK_thread_count goes before LOCK_thd_data - the former is called around
'delete thd', the latter - in THD::~THD
*/
mysql_mutex_record_order(&LOCK_thread_count, &LOCK_thd_data);
/* Variables with default values */
proc_info="login";
@@ -771,22 +795,8 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
*scramble= '\0';
#ifdef WITH_WSREP
wsrep_ws_handle.trx_id = WSREP_UNDEFINED_TRX_ID;
wsrep_ws_handle.opaque = NULL;
wsrep_retry_counter = 0;
wsrep_PA_safe = true;
wsrep_retry_query = NULL;
wsrep_retry_query_len = 0;
wsrep_retry_command = COM_CONNECT;
wsrep_consistency_check = NO_CONSISTENCY_CHECK;
wsrep_mysql_replicated = 0;
wsrep_TOI_pre_query = NULL;
wsrep_TOI_pre_query_len = 0;
mysql_cond_init(key_COND_wsrep_thd, &COND_wsrep_thd, NULL);
wsrep_info[sizeof(wsrep_info) - 1] = '\0'; /* make sure it is 0-terminated */
wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
wsrep_affected_rows = 0;
wsrep_replicate_GTID = false;
wsrep_skip_wsrep_GTID = false;
#endif
/* Call to init() below requires fully initialized Open_tables_state. */
reset_open_tables_state(this);
@@ -849,7 +859,6 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock)
save_prep_leaf_list= FALSE;
/* Restore THR_THD */
set_current_thd(old_THR_THD);
inc_thread_count();
}
@@ -1049,10 +1058,25 @@ Sql_condition* THD::raise_condition(uint sql_errno,
is_slave_error= 1; // needed to catch query errors during replication
if (!da->is_error())
#ifdef WITH_WSREP
/*
With wsrep we allow converting BF abort error to warning if
errors are ignored.
*/
if (!is_fatal_error &&
no_errors &&
(wsrep_trx().bf_aborted() || wsrep_retry_counter))
{
set_row_count_func(-1);
da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
WSREP_DEBUG("BF abort error converted to warning");
}
else
#endif /* WITH_WSREP */
{
if (!da->is_error())
{
set_row_count_func(-1);
da->set_error_status(sql_errno, msg, sqlstate, ucid, cond);
}
}
}
@@ -1113,6 +1137,13 @@ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size)
extern "C"
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
#ifdef WITH_WSREP
if (!thd->wsrep_xid.is_null())
{
*xid = *(MYSQL_XID *) &thd->wsrep_xid;
}
else
#endif /* WITH_WSREP */
*xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
}
@@ -1219,13 +1250,11 @@ void THD::init(bool skip_lock)
first_successful_insert_id_in_prev_stmt= 0;
first_successful_insert_id_in_prev_stmt_for_binlog= 0;
first_successful_insert_id_in_cur_stmt= 0;
current_backup_stage= BACKUP_FINISHED;
#ifdef WITH_WSREP
wsrep_exec_mode= wsrep_applier ? REPL_RECV : LOCAL_STATE;
wsrep_conflict_state= NO_CONFLICT;
wsrep_query_state= QUERY_IDLE;
wsrep_last_query_id= 0;
wsrep_trx_meta.gtid= WSREP_GTID_UNDEFINED;
wsrep_trx_meta.depends_on= WSREP_SEQNO_UNDEFINED;
wsrep_xid.null();
wsrep_skip_locking= FALSE;
wsrep_converted_lock_session= false;
wsrep_retry_counter= 0;
wsrep_rgi= NULL;
@@ -1234,10 +1263,10 @@ void THD::init(bool skip_lock)
wsrep_mysql_replicated = 0;
wsrep_TOI_pre_query = NULL;
wsrep_TOI_pre_query_len = 0;
wsrep_sync_wait_gtid = WSREP_GTID_UNDEFINED;
wsrep_rbr_buf = NULL;
wsrep_affected_rows = 0;
m_wsrep_next_trx_id = WSREP_UNDEFINED_TRX_ID;
wsrep_replicate_GTID = false;
wsrep_skip_wsrep_GTID = false;
#endif /* WITH_WSREP */
if (variables.sql_log_bin)
@@ -1466,6 +1495,13 @@ void THD::cleanup(void)
#error xid_state in the cache should be replaced by the allocated value
}
#endif
#ifdef WITH_WSREP
if (wsrep_cs().state() != wsrep::client_state::s_none)
{
wsrep_cs().cleanup();
}
wsrep_client_thread= false;
#endif /* WITH_WSREP */
mysql_ha_cleanup(this);
locked_tables_list.unlock_locked_tables(this);
@@ -1487,6 +1523,9 @@ void THD::cleanup(void)
*/
mdl_context.release_transactional_locks();
backup_end(this);
backup_unlock(this);
/* Release the global read lock, if acquired. */
if (global_read_lock.is_acquired())
global_read_lock.unlock_global_read_lock(this);
@@ -1513,6 +1552,7 @@ void THD::cleanup(void)
auto_inc_intervals_in_cur_stmt_for_binlog.empty();
mysql_ull_cleanup(this);
stmt_map.reset();
/* All metadata locks must have been released by now. */
DBUG_ASSERT(!mdl_context.has_locks());
@@ -1582,6 +1622,9 @@ void THD::reset_for_reuse()
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
#ifdef WITH_WSREP
wsrep_free_status(this);
#endif /* WITH_WSREP */
}
@@ -1590,10 +1633,8 @@ THD::~THD()
THD *orig_thd= current_thd;
THD_CHECK_SENTRY(this);
DBUG_ENTER("~THD()");
/* Check that we have already called thd->unlink() */
DBUG_ASSERT(prev == 0 && next == 0);
/* This takes a long time so we should not do this under LOCK_thread_count */
mysql_mutex_assert_not_owner(&LOCK_thread_count);
/* Make sure threads are not available via server_threads. */
assert_not_linked();
/*
In error cases, thd may not be current thd. We have to fix this so
@@ -1608,15 +1649,21 @@ THD::~THD()
THD is not deleted while they access it. The following mutex_lock
ensures that no one else is using this THD and it's now safe to delete
*/
if (WSREP(this)) mysql_mutex_lock(&LOCK_thd_data);
mysql_mutex_lock(&LOCK_thd_kill);
mysql_mutex_unlock(&LOCK_thd_kill);
if (WSREP(this)) mysql_mutex_unlock(&LOCK_thd_data);
#ifdef WITH_WSREP
delete wsrep_rgi;
#endif
if (!free_connection_done)
free_connection();
#ifdef WITH_WSREP
if (wsrep_rgi != NULL) {
delete wsrep_rgi;
wsrep_rgi = NULL;
}
mysql_cond_destroy(&COND_wsrep_thd);
#endif
mdl_context.destroy();
free_root(&transaction.mem_root,MYF(0));
@@ -1668,7 +1715,6 @@ THD::~THD()
}
update_global_memory_status(status_var.global_memory_used);
set_current_thd(orig_thd == this ? 0 : orig_thd);
dec_thread_count();
DBUG_VOID_RETURN;
}
@@ -1798,6 +1844,7 @@ void THD::awake_no_mutex(killed_state state_to_set)
DBUG_PRINT("enter", ("this: %p current_thd: %p state: %d",
this, current_thd, (int) state_to_set));
THD_CHECK_SENTRY(this);
if (WSREP(this)) mysql_mutex_assert_owner(&LOCK_thd_data);
mysql_mutex_assert_owner(&LOCK_thd_kill);
print_aborted_warning(3, "KILLED");
@@ -1830,7 +1877,8 @@ void THD::awake_no_mutex(killed_state state_to_set)
}
/* Interrupt target waiting inside a storage engine. */
if (state_to_set != NOT_KILLED)
if (IF_WSREP(state_to_set != NOT_KILLED && !wsrep_is_bf_aborted(this),
state_to_set != NOT_KILLED))
ha_kill_query(this, thd_kill_level(this));
/* Broadcast a condition to kick the target if it is waiting on it. */
@@ -1983,12 +2031,6 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
if (!thd_table->needs_reopen())
{
signalled|= mysql_lock_abort_for_thread(this, thd_table);
if (WSREP(this) && wsrep_thd_is_BF(this, FALSE))
{
WSREP_DEBUG("remove_table_from_cache: %llu",
(unsigned long long) this->real_id);
wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
}
}
}
}
@@ -2220,12 +2262,6 @@ void THD::cleanup_after_query()
/* reset table map for multi-table update */
table_map_for_update= 0;
m_binlog_invoker= INVOKER_NONE;
#ifdef WITH_WSREP
if (TOTAL_ORDER == wsrep_exec_mode)
{
wsrep_exec_mode = LOCAL_STATE;
}
#endif /* WITH_WSREP */
#ifndef EMBEDDED_LIBRARY
if (rgi_slave)
@@ -2233,7 +2269,6 @@ void THD::cleanup_after_query()
#endif
#ifdef WITH_WSREP
wsrep_sync_wait_gtid= WSREP_GTID_UNDEFINED;
if (!in_active_multi_stmt_transaction())
wsrep_affected_rows= 0;
#endif /* WITH_WSREP */
@@ -2494,6 +2529,16 @@ void THD::update_charset()
&not_used);
}
void THD::give_protection_error()
{
if (current_backup_stage != BACKUP_FINISHED)
my_error(ER_BACKUP_LOCK_IS_ACTIVE, MYF(0));
else
{
DBUG_ASSERT(global_read_lock.is_acquired());
my_error(ER_CANT_UPDATE_WITH_READLOCK, MYF(0));
}
}
/* routings to adding tables to list of changed in transaction tables */
@@ -3238,6 +3283,10 @@ int select_export::send_data(List<Item> &items)
error_pos= copier.most_important_error_pos();
if (unlikely(error_pos))
{
/*
TODO:
add new error message that will show user this printable_buff
char printable_buff[32];
convert_to_printable(printable_buff, sizeof(printable_buff),
error_pos, res->ptr() + res->length() - error_pos,
@@ -3247,6 +3296,11 @@ int select_export::send_data(List<Item> &items)
ER_THD(thd, ER_TRUNCATED_WRONG_VALUE_FOR_FIELD),
"string", printable_buff,
item->name.str, static_cast<long>(row_count));
*/
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_TRUNCATED_WRONG_VALUE_FOR_FIELD,
ER_THD(thd, WARN_DATA_TRUNCATED),
item->name.str, static_cast<long>(row_count));
}
else if (copier.source_end_pos() < res->ptr() + res->length())
{
@@ -3971,11 +4025,13 @@ void Statement_map::erase(Statement *statement)
void Statement_map::reset()
{
/* Must be first, hash_free will reset st_hash.records */
mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
prepared_stmt_count-= st_hash.records;
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
if (st_hash.records)
{
mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
prepared_stmt_count-= st_hash.records;
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
}
my_hash_reset(&names_hash);
my_hash_reset(&st_hash);
last_found_statement= 0;
@@ -3984,12 +4040,8 @@ void Statement_map::reset()
Statement_map::~Statement_map()
{
/* Must go first, hash_free will reset st_hash.records */
mysql_mutex_lock(&LOCK_prepared_stmt_count);
DBUG_ASSERT(prepared_stmt_count >= st_hash.records);
prepared_stmt_count-= st_hash.records;
mysql_mutex_unlock(&LOCK_prepared_stmt_count);
/* Statement_map::reset() should be called prior to destructor. */
DBUG_ASSERT(!st_hash.records);
my_hash_free(&names_hash);
my_hash_free(&st_hash);
}
@@ -4711,14 +4763,14 @@ MYSQL_THD create_thd()
thd->set_command(COM_DAEMON);
thd->system_thread= SYSTEM_THREAD_GENERIC;
thd->security_ctx->host_or_ip="";
add_to_active_threads(thd);
server_threads.insert(thd);
return thd;
}
void destroy_thd(MYSQL_THD thd)
{
thd->add_status_to_global();
unlink_not_visible_thd(thd);
server_threads.erase(thd);
delete thd;
}
@@ -4789,7 +4841,8 @@ extern "C" int thd_slave_thread(const MYSQL_THD thd)
extern "C" int thd_rpl_stmt_based(const MYSQL_THD thd)
{
return !thd->is_current_stmt_binlog_format_row() &&
return thd &&
!thd->is_current_stmt_binlog_format_row() &&
!thd->is_current_stmt_binlog_disabled();
}
@@ -4984,8 +5037,9 @@ extern "C" int thd_binlog_format(const MYSQL_THD thd)
if (WSREP(thd))
{
/* for wsrep binlog format is meaningful also when binlogging is off */
return (int) thd->wsrep_binlog_format();
return (int) WSREP_BINLOG_FORMAT(thd->variables.binlog_format);
}
if (mysql_bin_log.is_open() && (thd->variables.option_bits & OPTION_BIN_LOG))
return (int) thd->variables.binlog_format;
return BINLOG_FORMAT_UNSPEC;
@@ -5468,6 +5522,10 @@ void THD::set_query_and_id(char *query_arg, uint32 query_length_arg,
set_query_inner(query_arg, query_length_arg, cs);
mysql_mutex_unlock(&LOCK_thd_data);
query_id= new_query_id;
#ifdef WITH_WSREP
set_wsrep_next_trx_id(query_id);
WSREP_DEBUG("assigned new next query and trx id: %lu", wsrep_next_trx_id());
#endif /* WITH_WSREP */
}
/** Assign a new value to thd->mysys_var. */
@@ -5578,34 +5636,34 @@ class XID_cache_element
ACQUIRED and RECOVERED flags are cleared before element is deleted from
hash in a spin loop, after last reference is released.
*/
int32 m_state;
std::atomic<int32_t> m_state;
public:
static const int32 ACQUIRED= 1 << 30;
static const int32 RECOVERED= 1 << 29;
XID_STATE *m_xid_state;
bool is_set(int32 flag)
{ return my_atomic_load32_explicit(&m_state, MY_MEMORY_ORDER_RELAXED) & flag; }
void set(int32 flag)
bool is_set(int32_t flag)
{ return m_state.load(std::memory_order_relaxed) & flag; }
void set(int32_t flag)
{
DBUG_ASSERT(!is_set(ACQUIRED | RECOVERED));
my_atomic_add32_explicit(&m_state, flag, MY_MEMORY_ORDER_RELAXED);
m_state.fetch_add(flag, std::memory_order_relaxed);
}
bool lock()
{
int32 old= my_atomic_add32_explicit(&m_state, 1, MY_MEMORY_ORDER_ACQUIRE);
int32_t old= m_state.fetch_add(1, std::memory_order_acquire);
if (old & (ACQUIRED | RECOVERED))
return true;
unlock();
return false;
}
void unlock()
{ my_atomic_add32_explicit(&m_state, -1, MY_MEMORY_ORDER_RELEASE); }
{ m_state.fetch_sub(1, std::memory_order_release); }
void mark_uninitialized()
{
int32 old= ACQUIRED;
while (!my_atomic_cas32_weak_explicit(&m_state, &old, 0,
MY_MEMORY_ORDER_RELAXED,
MY_MEMORY_ORDER_RELAXED))
int32_t old= ACQUIRED;
while (!m_state.compare_exchange_weak(old, 0,
std::memory_order_relaxed,
std::memory_order_relaxed))
{
old&= ACQUIRED | RECOVERED;
(void) LF_BACKOFF();
@@ -5613,10 +5671,10 @@ public:
}
bool acquire_recovered()
{
int32 old= RECOVERED;
while (!my_atomic_cas32_weak_explicit(&m_state, &old, ACQUIRED | RECOVERED,
MY_MEMORY_ORDER_RELAXED,
MY_MEMORY_ORDER_RELAXED))
int32_t old= RECOVERED;
while (!m_state.compare_exchange_weak(old, ACQUIRED | RECOVERED,
std::memory_order_relaxed,
std::memory_order_relaxed))
{
if (!(old & RECOVERED) || (old & ACQUIRED))
return false;
@@ -5913,9 +5971,27 @@ int THD::decide_logging_format(TABLE_LIST *tables)
binlogging is off, or if the statement is filtered out from the
binlog by filtering rules.
*/
#ifdef WITH_WSREP
if (WSREP_CLIENT_NNULL(this) && variables.wsrep_trx_fragment_size > 0)
{
if (!is_current_stmt_binlog_format_row())
{
my_message(ER_NOT_SUPPORTED_YET,
"Streaming replication not supported with "
"binlog_format=STATEMENT", MYF(0));
DBUG_RETURN(-1);
}
}
if ((WSREP_EMULATE_BINLOG_NNULL(this) ||
(mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG))) &&
!(wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db.str)))
#else
if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
!(wsrep_binlog_format() == BINLOG_FORMAT_STMT &&
!binlog_filter->db_ok(db.str)))
#endif /* WITH_WSREP */
{
if (is_bulk_op())
@@ -6237,7 +6313,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
5. Error: Cannot modify table that uses a storage engine
limited to row-logging when binlog_format = STATEMENT
*/
if (IF_WSREP((!WSREP(this) || wsrep_exec_mode == LOCAL_STATE),1))
if (IF_WSREP((!WSREP(this) ||
wsrep_cs().mode() == wsrep::client_state::m_local),1))
{
my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
}