diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2020-04-25 21:57:52 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2020-04-25 21:57:52 +0300 |
commit | fbe2712705d464bf8488df249c36115e2c1f63f7 (patch) | |
tree | 274e728c719611769288afcb10f79549f6e11f8c /sql | |
parent | 62903434eb009cb0bcd5003b0a45914bd4c09886 (diff) | |
parent | a19782522b1eac52d72f5e787b5d96f1fd1a2cb7 (diff) | |
download | mariadb-git-fbe2712705d464bf8488df249c36115e2c1f63f7.tar.gz |
Merge 10.4 into 10.5
The functional changes of commit 5836191c8f0658d5d75484766fdcc3d838b0a5c1
(MDEV-21168) are omitted due to MDEV-742 having addressed the issue.
Diffstat (limited to 'sql')
38 files changed, 285 insertions, 165 deletions
diff --git a/sql/field_comp.cc b/sql/field_comp.cc index eb4ae42aa4d..ab97c8ccf08 100644 --- a/sql/field_comp.cc +++ b/sql/field_comp.cc @@ -67,10 +67,12 @@ static uint compress_zlib(THD *thd, char *to, const char *from, uint length) stream.zfree= 0; stream.opaque= 0; - if (deflateInit2(&stream, level, Z_DEFLATED, wbits, 8, strategy) == Z_OK && - deflate(&stream, Z_FINISH) == Z_STREAM_END && - deflateEnd(&stream) == Z_OK) - return (uint) (stream.next_out - (Bytef*) to); + if (deflateInit2(&stream, level, Z_DEFLATED, wbits, 8, strategy) == Z_OK) + { + int res= deflate(&stream, Z_FINISH); + if (deflateEnd(&stream) == Z_OK && res == Z_STREAM_END) + return (uint) (stream.next_out - (Bytef*) to); + } } return 0; } @@ -117,12 +119,14 @@ static int uncompress_zlib(String *to, const uchar *from, uint from_length, stream.zfree= 0; stream.opaque= 0; - if (inflateInit2(&stream, wbits) == Z_OK && - inflate(&stream, Z_FINISH) == Z_STREAM_END && - inflateEnd(&stream) == Z_OK) + if (inflateInit2(&stream, wbits) == Z_OK) { - to->length(stream.total_out); - return 0; + int res= inflate(&stream, Z_FINISH); + if (inflateEnd(&stream) == Z_OK && res == Z_STREAM_END) + { + to->length(stream.total_out); + return 0; + } } my_error(ER_ZLIB_Z_DATA_ERROR, MYF(0)); return 1; diff --git a/sql/handler.cc b/sql/handler.cc index 893453ba1c2..4f99b6e675f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1808,7 +1808,8 @@ end: thd->mdl_context.release_lock(mdl_request.ticket); } #ifdef WITH_WSREP - if (wsrep_is_active(thd) && is_real_trans && !error && (rw_ha_count == 0) && + if (wsrep_is_active(thd) && is_real_trans && !error && + (rw_ha_count == 0 || all) && wsrep_not_committed(thd)) { wsrep_commit_empty(thd, all); @@ -2105,29 +2106,33 @@ int ha_commit_or_rollback_by_xid(XID *xid, bool commit) #ifndef DBUG_OFF -/** - @note - This does not need to be multi-byte safe or anything -*/ -static char* xid_to_str(char *buf, XID *xid) +/** Converts XID to string. + +@param[out] buf output buffer +@param[in] xid XID to convert + +@return pointer to converted string + +@note This does not need to be multi-byte safe or anything */ +static char *xid_to_str(char *buf, const XID &xid) { int i; char *s=buf; *s++='\''; - for (i=0; i < xid->gtrid_length+xid->bqual_length; i++) + for (i= 0; i < xid.gtrid_length + xid.bqual_length; i++) { - uchar c=(uchar)xid->data[i]; + uchar c= (uchar) xid.data[i]; /* is_next_dig is set if next character is a number */ bool is_next_dig= FALSE; if (i < XIDDATASIZE) { - char ch= xid->data[i+1]; + char ch= xid.data[i + 1]; is_next_dig= (ch >= '0' && ch <='9'); } - if (i == xid->gtrid_length) + if (i == xid.gtrid_length) { *s++='\''; - if (xid->bqual_length) + if (xid.bqual_length) { *s++='.'; *s++='\''; @@ -2237,6 +2242,11 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, the prepare. */ my_xid wsrep_limit __attribute__((unused))= 0; + + /* Note that we could call this for binlog also that + will not have WSREP(thd) but global wsrep on might + be true. + */ if (WSREP_ON) wsrep_limit= wsrep_order_and_check_continuity(info->list, got); @@ -2250,7 +2260,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, { DBUG_EXECUTE("info",{ char buf[XIDDATASIZE*4+6]; - _db_doprnt_("ignore xid %s", xid_to_str(buf, info->list+i)); + _db_doprnt_("ignore xid %s", xid_to_str(buf, info->list[i])); }); xid_cache_insert(info->list + i); info->found_foreign_xids++; @@ -2277,7 +2287,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, { DBUG_EXECUTE("info",{ char buf[XIDDATASIZE*4+6]; - _db_doprnt_("commit xid %s", xid_to_str(buf, info->list+i)); + _db_doprnt_("commit xid %s", xid_to_str(buf, info->list[i])); }); } } @@ -2288,7 +2298,7 @@ static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, { DBUG_EXECUTE("info",{ char buf[XIDDATASIZE*4+6]; - _db_doprnt_("rollback xid %s", xid_to_str(buf, info->list+i)); + _db_doprnt_("rollback xid %s", xid_to_str(buf, info->list[i])); }); } } diff --git a/sql/item.cc b/sql/item.cc index 4c1fe99e222..0c08169db2b 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9257,8 +9257,10 @@ bool Item_default_value::fix_fields(THD *thd, Item **items) } if (!(def_field= (Field*) thd->alloc(field_arg->field->size_of()))) goto error; + cached_field= def_field; memcpy((void *)def_field, (void *)field_arg->field, field_arg->field->size_of()); + def_field->reset_fields(); // If non-constant default value expression if (def_field->default_value && def_field->default_value->flags) { @@ -9286,6 +9288,12 @@ error: return TRUE; } +void Item_default_value::cleanup() +{ + delete cached_field; // Free cached blob data + cached_field= 0; + Item_field::cleanup(); +} void Item_default_value::print(String *str, enum_query_type query_type) { diff --git a/sql/item.h b/sql/item.h index 5eab1d049f0..3073a4d240d 100644 --- a/sql/item.h +++ b/sql/item.h @@ -2,7 +2,7 @@ #define SQL_ITEM_INCLUDED /* Copyright (c) 2000, 2017, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB Corporation. + Copyright (c) 2009, 2020, 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 @@ -6241,19 +6241,18 @@ class Item_default_value : public Item_field { void calculate(); public: - Item *arg; - Item_default_value(THD *thd, Name_resolution_context *context_arg) - :Item_field(thd, context_arg), - arg(NULL) {} - Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) - :Item_field(thd, context_arg), - arg(a) {} + Item *arg= nullptr; + Field *cached_field= nullptr; + Item_default_value(THD *thd, Name_resolution_context *context_arg) : + Item_field(thd, context_arg) {} + Item_default_value(THD *thd, Name_resolution_context *context_arg, Item *a) : + Item_field(thd, context_arg), arg(a) {} Item_default_value(THD *thd, Name_resolution_context *context_arg, Field *a) - :Item_field(thd, context_arg), - arg(NULL) {} + :Item_field(thd, context_arg) {} enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, Item **); + void cleanup(); void print(String *str, enum_query_type query_type); String *val_str(String *str); double val_real(); diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index e494e9d84e1..4bbb33d4eb7 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -729,7 +729,7 @@ bool Item_subselect::exec() push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, ER_UNKNOWN_ERROR, "DBUG: Item_subselect::exec %.*s", - print.length(),print.ptr()); + print.length(),print.c_ptr()); ); /* Do not execute subselect in case of a fatal error diff --git a/sql/lock.cc b/sql/lock.cc index 487f2c3115f..f427ee0e115 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -1,5 +1,6 @@ /* Copyright (c) 2000, 2011, Oracle and/or its affiliates. + Copyright (c) 2020, MariaDB 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 @@ -1124,13 +1125,15 @@ void Global_read_lock::unlock_global_read_lock(THD *thd) { Wsrep_server_state& server_state= Wsrep_server_state::instance(); if (server_state.state() == Wsrep_server_state::s_donor || - (wsrep_on(thd) && server_state.state() != Wsrep_server_state::s_synced)) + (WSREP_NNULL(thd) && + server_state.state() != Wsrep_server_state::s_synced)) { /* TODO: maybe redundant here?: */ wsrep_locked_seqno= WSREP_SEQNO_UNDEFINED; server_state.resume(); } - else if (wsrep_on(thd) && server_state.state() == Wsrep_server_state::s_synced) + else if (WSREP_NNULL(thd) && + server_state.state() == Wsrep_server_state::s_synced) { server_state.resume_and_resync(); } @@ -1186,11 +1189,13 @@ bool Global_read_lock::make_global_read_lock_block_commit(THD *thd) Wsrep_server_state& server_state= Wsrep_server_state::instance(); wsrep::seqno paused_seqno; if (server_state.state() == Wsrep_server_state::s_donor || - (wsrep_on(thd) && server_state.state() != Wsrep_server_state::s_synced)) + (WSREP_NNULL(thd) && + server_state.state() != Wsrep_server_state::s_synced)) { paused_seqno= server_state.pause(); } - else if (wsrep_on(thd) && server_state.state() == Wsrep_server_state::s_synced) + else if (WSREP_NNULL(thd) && + server_state.state() == Wsrep_server_state::s_synced) { paused_seqno= server_state.desync_and_pause(); } diff --git a/sql/log.cc b/sql/log.cc index fce768b2e4c..731bb3e98f0 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -1834,7 +1834,7 @@ binlog_commit_flush_stmt_cache(THD *thd, bool all, #ifdef WITH_WSREP if (thd->wsrep_mysql_replicated > 0) { - DBUG_ASSERT(WSREP_ON); + DBUG_ASSERT(WSREP(thd)); WSREP_DEBUG("avoiding binlog_commit_flush_trx_cache: %d", thd->wsrep_mysql_replicated); return 0; @@ -6924,14 +6924,15 @@ int MYSQL_BIN_LOG::rotate(bool force_rotate, bool* check_purge) int error= 0; DBUG_ENTER("MYSQL_BIN_LOG::rotate"); - if (wsrep_to_isolation) +#ifdef WITH_WSREP + if (WSREP_ON && wsrep_to_isolation) { - DBUG_ASSERT(WSREP_ON); *check_purge= false; - WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", + WSREP_DEBUG("avoiding binlog rotate due to TO isolation: %d", wsrep_to_isolation); DBUG_RETURN(0); } +#endif /* WITH_WSREP */ //todo: fix the macro def and restore safe_mutex_assert_owner(&LOCK_log); *check_purge= false; diff --git a/sql/log_event_server.cc b/sql/log_event_server.cc index feb8fd643b7..9c69b67bce1 100644 --- a/sql/log_event_server.cc +++ b/sql/log_event_server.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB + Copyright (c) 2009, 2020, MariaDB 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 @@ -1396,9 +1396,14 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, /* If Query_log_event will contain non trans keyword (not BEGIN, COMMIT, SAVEPOINT or ROLLBACK) we disable PA for this transaction. + Note that here WSREP(thd) might not be true e.g. when wsrep_shcema + is created we create tables with thd->variables.wsrep_on=false + to avoid replicating wsrep_schema tables to other nodes. */ if (WSREP_ON && !is_trans_keyword()) + { thd->wsrep_PA_safe= false; + } #endif /* WITH_WSREP */ memset(&user, 0, sizeof(user)); @@ -2115,7 +2120,7 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) } } #ifdef WITH_WSREP - else if (WSREP_ON && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 && + else if (WSREP(thd) && wsrep_mysql_replication_bundle && opt_slave_domain_parallel_threads == 0 && thd->wsrep_mysql_replicated > 0 && (is_begin() || is_commit())) { @@ -2129,7 +2134,7 @@ Query_log_event::do_shall_skip(rpl_group_info *rgi) thd->wsrep_mysql_replicated = 0; } } -#endif +#endif /* WITH_WSREP */ DBUG_RETURN(Log_event::do_shall_skip(rgi)); } @@ -3976,7 +3981,7 @@ Xid_apply_log_event::do_shall_skip(rpl_group_info *rgi) DBUG_RETURN(Log_event::EVENT_SKIP_COUNT); } #ifdef WITH_WSREP - else if (wsrep_mysql_replication_bundle && WSREP_ON && + else if (wsrep_mysql_replication_bundle && WSREP(thd) && opt_slave_domain_parallel_threads == 0) { if (++thd->wsrep_mysql_replicated < (int)wsrep_mysql_replication_bundle) diff --git a/sql/mdl.cc b/sql/mdl.cc index 98a9d8f0d01..287e0cb5f65 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -1242,12 +1242,12 @@ void MDL_lock::Ticket_list::add_ticket(MDL_ticket *ticket) wsrep_thd_is_BF(ticket->get_ctx()->get_thd(), false)) { Ticket_iterator itw(ticket->get_lock()->m_waiting); - - DBUG_ASSERT(WSREP_ON); MDL_ticket *waiting; MDL_ticket *prev=NULL; bool added= false; + DBUG_ASSERT(WSREP(ticket->get_ctx()->get_thd())); + while ((waiting= itw++) && !added) { if (!wsrep_thd_is_BF(waiting->get_ctx()->get_thd(), true)) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 97dfca47beb..f6aac3adfd8 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -54,6 +54,7 @@ #include <m_ctype.h> #include <my_dir.h> #include <my_bit.h> +#include "my_cpu.h" #include "slave.h" #include "rpl_mi.h" #include "sql_repl.h" @@ -446,7 +447,7 @@ uint lower_case_table_names; ulong tc_heuristic_recover= 0; Atomic_counter<uint32_t> thread_count; bool shutdown_wait_for_slaves; -int32 slave_open_temp_tables; +Atomic_counter<uint32_t> slave_open_temp_tables; ulong thread_created; ulong back_log, connect_timeout, server_id; ulong what_to_log; @@ -1135,6 +1136,14 @@ PSI_file_key key_file_map; PSI_statement_info stmt_info_new_packet; #endif +#ifdef WITH_WSREP +/** Whether the Galera write-set replication is enabled. A cached copy of +global_system_variables.wsrep_on && wsrep_provider && + strcmp(wsrep_provider, WSREP_NONE) +*/ +bool WSREP_ON_; +#endif /* WITH_WSREP */ + #ifndef EMBEDDED_LIBRARY void net_before_header_psi(struct st_net *net, void *thd, size_t /* unused: count */) { @@ -1873,6 +1882,9 @@ extern "C" void unireg_abort(int exit_code) disable_log_notes= 1; #ifdef WITH_WSREP + // Note that we do not have thd here, thus can't use + // WSREP(thd) + if (WSREP_ON && Wsrep_server_state::is_inited() && Wsrep_server_state::instance().state() != wsrep::server_state::s_disconnected) @@ -1888,6 +1900,7 @@ extern "C" void unireg_abort(int exit_code) sleep(1); /* so give some time to exit for those which can */ WSREP_INFO("Some threads may fail to exit."); } + if (WSREP_ON) { /* In bootstrap mode we deinitialize wsrep here. */ @@ -1932,11 +1945,7 @@ static void mysqld_exit(int exit_code) shutdown_performance_schema(); // we do it as late as possible #endif set_malloc_size_cb(NULL); - if (opt_endinfo && global_status_var.global_memory_used) - fprintf(stderr, "Warning: Memory not freed: %ld\n", - (long) global_status_var.global_memory_used); - if (!opt_debugging && !my_disable_leak_check && exit_code == 0 && - debug_assert_on_not_freed_memory) + if (global_status_var.global_memory_used) { #ifdef SAFEMALLOC sf_report_leaked_memory(0); @@ -4645,7 +4654,6 @@ static int init_default_storage_engine_impl(const char *opt_name, return 0; } - static int init_gtid_pos_auto_engines(void) { @@ -4672,7 +4680,6 @@ init_gtid_pos_auto_engines(void) return 0; } - static int init_server_components() { DBUG_ENTER("init_server_components"); @@ -5531,7 +5538,13 @@ int mysqld_main(int argc, char **argv) set_user(mysqld_user, user_info); } +#ifdef WITH_WSREP + WSREP_ON_= (global_system_variables.wsrep_on && + wsrep_provider && + strcmp(wsrep_provider, WSREP_NONE)); + if (WSREP_ON && wsrep_check_opts()) unireg_abort(1); +#endif /* The subsequent calls may take a long time : e.g. innodb log read. @@ -6954,18 +6967,6 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff, } -/* How many slaves are connected to this master */ - -static int show_slaves_connected(THD *thd, SHOW_VAR *var, char *buff) -{ - - var->type= SHOW_LONGLONG; - var->value= buff; - *((longlong*) buff)= uint32_t(binlog_dump_thread_count); - return 0; -} - - /* How many masters this slave is connected to */ @@ -7531,9 +7532,9 @@ SHOW_VAR status_vars[]= { {"Select_range", (char*) offsetof(STATUS_VAR, select_range_count_), SHOW_LONG_STATUS}, {"Select_range_check", (char*) offsetof(STATUS_VAR, select_range_check_count_), SHOW_LONG_STATUS}, {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count_), SHOW_LONG_STATUS}, - {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_INT}, + {"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_ATOMIC_COUNTER_UINT32_T}, #ifdef HAVE_REPLICATION - {"Slaves_connected", (char*) &show_slaves_connected, SHOW_SIMPLE_FUNC }, + {"Slaves_connected", (char*) &binlog_dump_thread_count, SHOW_ATOMIC_COUNTER_UINT32_T}, {"Slaves_running", (char*) &show_slaves_running, SHOW_SIMPLE_FUNC }, {"Slave_connections", (char*) offsetof(STATUS_VAR, com_register_slave), SHOW_LONG_STATUS}, {"Slave_heartbeat_period", (char*) &show_heartbeat_period, SHOW_SIMPLE_FUNC}, diff --git a/sql/mysqld.h b/sql/mysqld.h index 2649a3ac61b..8adfda0dfec 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -221,7 +221,7 @@ extern ulong delayed_insert_timeout; extern ulong delayed_insert_limit, delayed_queue_size; extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; -extern int32 slave_open_temp_tables; +extern Atomic_counter<uint32_t> slave_open_temp_tables; extern ulonglong query_cache_size; extern ulong query_cache_limit; extern ulong query_cache_min_res_unit; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 7390345ed29..384b2d5ced2 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -356,7 +356,8 @@ QUICK_RANGE_SELECT *get_quick_select(PARAM *param,uint index, static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, bool index_read_must_be_used, bool update_tbl_stats, - double read_time); + double read_time, + bool ror_scans_required); static TRP_INDEX_INTERSECT *get_best_index_intersect(PARAM *param, SEL_TREE *tree, double read_time); @@ -2632,7 +2633,7 @@ static int fill_used_fields_bitmap(PARAM *param) force_quick_range is really needed. RETURN - -1 if impossible select (i.e. certainly no rows will be selected) + -1 if error or impossible select (i.e. certainly no rows will be selected) 0 if can't use quick_select 1 if found usable ranges and quick select has been successfully created. */ @@ -2745,7 +2746,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, { thd->no_errors=0; free_root(&alloc,MYF(0)); // Return memory & allocator - DBUG_RETURN(0); // Can't use range + DBUG_RETURN(-1); // Error } key_parts= param.key_parts; @@ -2813,7 +2814,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, { thd->no_errors=0; free_root(&alloc,MYF(0)); // Return memory & allocator - DBUG_RETURN(0); // Can't use range + DBUG_RETURN(-1); // Error } thd->mem_root= &alloc; @@ -2873,6 +2874,13 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, tree= NULL; } } + else if (thd->is_error()) + { + thd->no_errors=0; + thd->mem_root= param.old_root; + free_root(&alloc, MYF(0)); + DBUG_RETURN(-1); + } } if (tree) @@ -2896,7 +2904,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use, /* Get best 'range' plan and prepare data for making other plans */ if ((range_trp= get_key_scans_params(¶m, tree, only_single_index_range_scan, TRUE, - best_read_time))) + best_read_time, FALSE))) { best_trp= range_trp; best_read_time= best_trp->read_cost; @@ -5050,8 +5058,8 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, double roru_index_costs; ha_rows roru_total_records; double roru_intersect_part= 1.0; - double limit_read_time= read_time; size_t n_child_scans; + double limit_read_time= read_time; THD *thd= param->thd; DBUG_ENTER("get_best_disjunct_quick"); DBUG_PRINT("info", ("Full table scan cost: %g", read_time)); @@ -5078,6 +5086,10 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, sizeof(TRP_RANGE*)* n_child_scans))) DBUG_RETURN(NULL); + + const bool only_ror_scans_required= !optimizer_flag(param->thd, + OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION); + Json_writer_object trace_best_disjunct(thd); Json_writer_array to_merge(thd, "indexes_to_merge"); /* @@ -5092,7 +5104,9 @@ TABLE_READ_PLAN *get_best_disjunct_quick(PARAM *param, SEL_IMERGE *imerge, DBUG_EXECUTE("info", print_sel_tree(param, *ptree, &(*ptree)->keys_map, "tree in SEL_IMERGE");); Json_writer_object trace_idx(thd); - if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, FALSE, read_time))) + if (!(*cur_child= get_key_scans_params(param, *ptree, TRUE, FALSE, + read_time, + only_ror_scans_required))) { /* One of index scans in this index_merge is more expensive than entire @@ -5452,7 +5466,7 @@ TABLE_READ_PLAN *merge_same_index_scans(PARAM *param, SEL_IMERGE *imerge, index merge retrievals are not well calibrated */ trp= get_key_scans_params(param, *imerge->trees, FALSE, TRUE, - read_time); + read_time, FALSE); } DBUG_RETURN(trp); @@ -7338,6 +7352,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, index_read_must_be_used if TRUE, assume 'index only' option will be set (except for clustered PK indexes) read_time don't create read plans with cost > read_time. + only_ror_scans_required set to TRUE when we are only interested + in ROR scan RETURN Best range read plan NULL if no plan found or error occurred @@ -7346,7 +7362,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, bool index_read_must_be_used, bool update_tbl_stats, - double read_time) + double read_time, + bool only_ror_scans_required) { uint idx, UNINIT_VAR(best_idx); SEL_ARG *key_to_read= NULL; @@ -7400,8 +7417,7 @@ static TRP_RANGE *get_key_scans_params(PARAM *param, SEL_TREE *tree, found_records= check_quick_select(param, idx, read_index_only, key, update_tbl_stats, &mrr_flags, &buf_size, &cost, &is_ror_scan); - if (!is_ror_scan && - !optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION)) + if (only_ror_scans_required && !is_ror_scan) continue; if (found_records != HA_POS_ERROR && tree->index_scans && @@ -9789,7 +9805,7 @@ key_and(RANGE_OPT_PARAM *param, SEL_ARG *key1, SEL_ARG *key2, uint clone_flag) if (key2->next_key_part) { key1->use_count--; // Incremented in and_all_keys - return and_all_keys(param, key1, key2, clone_flag); + return and_all_keys(param, key1, key2->next_key_part, clone_flag); } key2->use_count--; // Key2 doesn't have a tree } diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc index 4a15dd709db..d33e26d2ecc 100644 --- a/sql/rpl_parallel.cc +++ b/sql/rpl_parallel.cc @@ -60,7 +60,7 @@ rpt_handle_event(rpl_parallel_thread::queued_event *qev, rgi->last_master_timestamp= ev->when + (time_t)ev->exec_time; err= apply_event_and_update_pos_for_parallel(ev, thd, rgi); - thread_safe_increment64(&rli->executed_entries); + rli->executed_entries++; #ifdef WITH_WSREP if (wsrep_after_statement(thd)) { diff --git a/sql/rpl_record.cc b/sql/rpl_record.cc index 29ca0931fb8..7da296b47d9 100644 --- a/sql/rpl_record.cc +++ b/sql/rpl_record.cc @@ -329,22 +329,6 @@ unpack_row(rpl_group_info *rgi, (int) (pack_ptr - old_pack_ptr))); if (!pack_ptr) { -#ifdef WITH_WSREP - if (WSREP_ON) - { - /* - Debug message to troubleshoot bug: - https://mariadb.atlassian.net/browse/MDEV-4404 - Galera Node throws "Could not read field" error and drops out of cluster - */ - WSREP_WARN("ROW event unpack field: %s metadata: 0x%x;" - " conv_table %p conv_field %p table %s" - " row_end: %p", - f->field_name.str, metadata, conv_table, conv_field, - (table_found) ? "found" : "not found", row_end - ); - } -#endif /* WITH_WSREP */ rgi->rli->report(ERROR_LEVEL, ER_SLAVE_CORRUPT_EVENT, rgi->gtid_info(), "Could not read field '%s' of table '%s.%s'", diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h index 5d2d33c397f..fafe8ead63d 100644 --- a/sql/rpl_rli.h +++ b/sql/rpl_rli.h @@ -347,7 +347,7 @@ public: Number of executed events for SLAVE STATUS. Protected by slave_executed_entries_lock */ - int64 executed_entries; + Atomic_counter<uint32_t> executed_entries; /* If the end of the hot relay log is made of master's events ignored by the diff --git a/sql/slave.cc b/sql/slave.cc index 754c8df3638..381417c353b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -3476,7 +3476,7 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full, { protocol->store((uint32) mi->rli.retried_trans); protocol->store((ulonglong) mi->rli.max_relay_log_size); - protocol->store((uint32) mi->rli.executed_entries); + protocol->store(mi->rli.executed_entries); protocol->store((uint32) mi->received_heartbeats); protocol->store((double) mi->heartbeat_period, 3, &tmp); protocol->store(gtid_pos->ptr(), gtid_pos->length(), &my_charset_bin); @@ -3996,7 +3996,8 @@ apply_event_and_update_pos_apply(Log_event* ev, THD* thd, rpl_group_info *rgi, exec_res= ev->apply_event(rgi); #ifdef WITH_WSREP - if (WSREP_ON) { + if (WSREP(thd)) { + if (exec_res) { mysql_mutex_lock(&thd->LOCK_thd_data); switch(thd->wsrep_trx().state()) { @@ -4574,7 +4575,7 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli, } } - thread_safe_increment64(&rli->executed_entries); + rli->executed_entries++; #ifdef WITH_WSREP wsrep_after_statement(thd); #endif /* WITH_WSREP */ @@ -5650,7 +5651,7 @@ pthread_handler_t handle_slave_sql(void *arg) if (exec_relay_log_event(thd, rli, serial_rgi)) { #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { mysql_mutex_lock(&thd->LOCK_thd_data); @@ -5668,8 +5669,10 @@ pthread_handler_t handle_slave_sql(void *arg) if (!sql_slave_killed(serial_rgi)) { slave_output_error_info(serial_rgi, thd); - if (WSREP_ON && rli->last_error().number == ER_UNKNOWN_COM_ERROR) + if (WSREP(thd) && rli->last_error().number == ER_UNKNOWN_COM_ERROR) + { wsrep_node_dropped= TRUE; + } } goto err; } @@ -5806,7 +5809,7 @@ err_during_init: If slave stopped due to node going non primary, we set global flag to trigger automatic restart of slave when node joins back to cluster. */ - if (WSREP_ON && wsrep_node_dropped && wsrep_restart_slave) + if (WSREP(thd) && wsrep_node_dropped && wsrep_restart_slave) { if (wsrep_ready_get()) { diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1606e8cb7eb..e22a23d197e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4366,7 +4366,7 @@ restart: } #ifdef WITH_WSREP - if (WSREP_ON && + if (WSREP(thd) && wsrep_replicate_myisam && (*start) && (*start)->table && diff --git a/sql/sql_class.h b/sql/sql_class.h index 07136c10e1d..96ebfca3723 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3414,7 +3414,7 @@ public: void awake_no_mutex(killed_state state_to_set); void awake(killed_state state_to_set) { - bool wsrep_on_local= WSREP_ON; + bool wsrep_on_local= WSREP_NNULL(this); /* mutex locking order (LOCK_thd_data - LOCK_thd_kill)) requires to grab LOCK_thd_data here diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 70cefa8e977..59990e11e71 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -8083,7 +8083,8 @@ Item *LEX::create_item_limit(THD *thd, const Lex_ident_cli_st *ca) if (unlikely(!(item= new (thd->mem_root) Item_splocal(thd, rh, &sa, spv->offset, spv->type_handler(), - pos.pos(), pos.length())))) + clone_spec_offset ? 0 : pos.pos(), + clone_spec_offset ? 0 : pos.length())))) return NULL; #ifdef DBUG_ASSERT_EXISTS item->m_sp= sphead; @@ -8183,14 +8184,15 @@ Item *LEX::create_item_ident_sp(THD *thd, Lex_ident_sys_st *name, } Query_fragment pos(thd, sphead, start, end); + uint f_pos= clone_spec_offset ? 0 : pos.pos(); + uint f_length= clone_spec_offset ? 0 : pos.length(); Item_splocal *splocal= spv->field_def.is_column_type_ref() ? new (thd->mem_root) Item_splocal_with_delayed_data_type(thd, rh, name, spv->offset, - pos.pos(), - pos.length()) : + f_pos, f_length) : new (thd->mem_root) Item_splocal(thd, rh, name, spv->offset, spv->type_handler(), - pos.pos(), pos.length()); + f_pos, f_length); if (unlikely(splocal == NULL)) return NULL; #ifdef DBUG_ASSERT_EXISTS diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b1756b83056..273e5b79233 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1751,7 +1751,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { mysqld_stmt_bulk_execute(thd, packet, packet_length); #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { (void)wsrep_after_statement(thd); } @@ -1762,7 +1762,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, { mysqld_stmt_execute(thd, packet, packet_length); #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { (void)wsrep_after_statement(thd); } @@ -1820,7 +1820,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { if (wsrep_mysql_parse(thd, thd->query(), thd->query_length(), &parser_state, @@ -1922,7 +1922,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, parser_state.reset(beginning_of_next_stmt, length); #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { if (wsrep_mysql_parse(thd, beginning_of_next_stmt, length, &parser_state, @@ -3530,7 +3530,7 @@ mysql_execute_command(THD *thd) * and dirty reads (if configured) */ if (!(thd->wsrep_applier) && - !(wsrep_ready_get() && wsrep_reject_queries == WSREP_REJECT_NONE) && + !(wsrep_ready_get() && wsrep_reject_queries == WSREP_REJECT_NONE) && !(thd->variables.wsrep_dirty_reads && (sql_command_flags[lex->sql_command] & CF_CHANGES_DATA) == 0) && !wsrep_tables_accessible_when_detached(all_tables) && diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index de2d5c2f253..d6c7066e655 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5915,6 +5915,24 @@ the generated partition syntax in a correct manner. *partition_changed= true; } } + + // In case of PARTITION BY KEY(), check if primary key has changed + // System versioning also implicitly adds/removes primary key parts + if (alter_info->partition_flags == 0 && part_info->list_of_part_fields + && part_info->part_field_list.elements == 0) + { + if (alter_info->flags & (ALTER_DROP_SYSTEM_VERSIONING | + ALTER_ADD_SYSTEM_VERSIONING)) + *partition_changed= true; + + List_iterator<Key> it(alter_info->key_list); + Key *key; + while((key= it++) && !*partition_changed) + { + if (key->type == Key::PRIMARY) + *partition_changed= true; + } + } /* Set up partition default_engine_type either from the create_info or from the previus table diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 8b200cfc6fd..e1360794a3b 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -25,7 +25,7 @@ SHOW_LONG_STATUS, SHOW_DOUBLE_STATUS, \ SHOW_HAVE, SHOW_MY_BOOL, SHOW_HA_ROWS, SHOW_SYS, \ SHOW_LONG_NOFLUSH, SHOW_LONGLONG_STATUS, SHOW_UINT32_STATUS, \ - SHOW_LEX_STRING + SHOW_LEX_STRING, SHOW_ATOMIC_COUNTER_UINT32_T #include "mariadb.h" #undef SHOW_always_last diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index ce49378204d..e7988d2c423 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -153,6 +153,8 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, if (mysql_bin_log.rotate_and_purge(true, drop_gtid_domain)) *write_to_binlog= -1; + /* Note that WSREP(thd) might not be true here e.g. during + SST. */ if (WSREP_ON) { /* Wait for last binlog checkpoint event to be logged. */ diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index b8de0d411e0..55e5e940b19 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3941,7 +3941,7 @@ int reset_master(THD* thd, rpl_gtid *init_state, uint32 init_state_len, } #ifdef WITH_WSREP - if (WSREP_ON) + if (WSREP(thd)) { /* RESET MASTER will initialize GTID sequence, and that would happen locally in this node, so better reject it diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 755ae547db3..2528134f4ee 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -64,6 +64,7 @@ #endif #include "transaction.h" #include "opt_trace.h" +#include "my_cpu.h" enum enum_i_s_events_fields { @@ -3630,6 +3631,11 @@ const char* get_one_variable(THD *thd, end= pos + ls->length; break; } + case SHOW_ATOMIC_COUNTER_UINT32_T: + end= int10_to_str( + static_cast<long>(*static_cast<Atomic_counter<uint32_t>*>(value)), + buff, 10); + break; case SHOW_UNDEF: break; // Return empty string case SHOW_SYS: // Cannot happen diff --git a/sql/sql_string.h b/sql/sql_string.h index 37225e17c1e..2d38f6d5d13 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -86,7 +86,7 @@ public: Well_formed_prefix(CHARSET_INFO *cs, const char *str, size_t length) :Well_formed_prefix_status(cs, str, str + length, length), m_str(str) { } - Well_formed_prefix(CHARSET_INFO *cs, LEX_STRING str, size_t nchars) + Well_formed_prefix(CHARSET_INFO *cs, LEX_CSTRING str, size_t nchars) :Well_formed_prefix_status(cs, str.str, str.str + str.length, nchars), m_str(str.str) { } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 86eba4a521b..e7fbae9e0f7 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -4470,9 +4470,9 @@ bool validate_comment_length(THD *thd, LEX_CSTRING *comment, size_t max_len, DBUG_ENTER("validate_comment_length"); if (comment->length == 0) DBUG_RETURN(false); - size_t tmp_len= system_charset_info->charpos(comment->str, - comment->str + comment->length, - max_len); + + size_t tmp_len= + Well_formed_prefix(system_charset_info, *comment, max_len).length(); if (tmp_len < comment->length) { if (thd->is_strict_mode()) @@ -5728,9 +5728,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, DBUG_ENTER("mysql_create_like_table"); #ifdef WITH_WSREP - if (WSREP_ON && !thd->wsrep_applier && + if (WSREP(thd) && !thd->wsrep_applier && wsrep_create_like_table(thd, table, src_table, create_info)) + { DBUG_RETURN(res); + } #endif /* @@ -10980,7 +10982,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, bool make_versioned= !from->versioned() && to->versioned(); bool make_unversioned= from->versioned() && !to->versioned(); bool keep_versioned= from->versioned() && to->versioned(); - bool drop_history= false; // XXX Field *to_row_start= NULL, *to_row_end= NULL, *from_row_end= NULL; MYSQL_TIME query_start; DBUG_ENTER("copy_data_between_tables"); @@ -11111,10 +11112,6 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, { from_row_end= from->vers_end_field(); } - else if (keep_versioned && drop_history) - { - from_row_end= from->vers_end_field(); - } if (from_row_end) bitmap_set_bit(from->read_set, from_row_end->field_index); @@ -11153,6 +11150,13 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, error= 1; break; } + + if (make_unversioned) + { + if (!from_row_end->is_max()) + continue; // Drop history rows. + } + if (unlikely(++thd->progress.counter >= time_to_report_progress)) { time_to_report_progress+= MY_HOW_OFTEN_TO_WRITE/10; @@ -11172,20 +11176,12 @@ copy_data_between_tables(THD *thd, TABLE *from, TABLE *to, copy_ptr->do_copy(copy_ptr); } - if (drop_history && from_row_end && !from_row_end->is_max()) - continue; - if (make_versioned) { to_row_start->set_notnull(); to_row_start->store_time(&query_start); to_row_end->set_max(); } - else if (make_unversioned) - { - if (!from_row_end->is_max()) - continue; // Drop history rows. - } prev_insert_id= to->file->next_insert_id; if (to->default_field) diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc index 047f56d220b..d6fb06f34a5 100644 --- a/sql/sql_type_geom.cc +++ b/sql/sql_type_geom.cc @@ -872,7 +872,7 @@ int Field_geom::store(const char *from, size_t length, CHARSET_INFO *cs) my_error(ER_TRUNCATED_WRONG_VALUE_FOR_FIELD, MYF(0), Geometry::ci_collection[m_type_handler->geometry_type()]->m_name.str, - wkt.c_ptr(), + wkt.c_ptr_safe(), db, tab_name, field_name.str, (ulong) table->in_use->get_stmt_da()-> current_row_for_warning()); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 75824d3fbcf..8e6eb4c815a 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2011, 2016, MariaDB + Copyright (c) 2011, 2020, MariaDB 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 @@ -2592,6 +2592,9 @@ int multi_update::send_data(List<Item> ¬_used_values) TABLE *tmp_table= tmp_tables[offset]; if (copy_funcs(tmp_table_param[offset].items_to_copy, thd)) DBUG_RETURN(1); + /* rowid field is NULL if join tmp table has null row from outer join */ + if (tmp_table->field[0]->is_null()) + continue; /* Store regular updated fields in the row. */ DBUG_ASSERT(1 + unupdated_check_opt_tables.elements == tmp_table_param[offset].func_count); @@ -2789,6 +2792,7 @@ int multi_update::do_updates() uint field_num= 0; do { + DBUG_ASSERT(!tmp_table->field[field_num]->is_null()); String rowid; tmp_table->field[field_num]->val_str(&rowid); if (unlikely((local_error= tbl->file->ha_rnd_pos(tbl->record[0], diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 09a617cece1..df6f9933e36 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6080,7 +6080,7 @@ vio_keepalive_opts opt_vio_keepalive; static Sys_var_int Sys_keepalive_time( "tcp_keepalive_time", - "Timeout, in milliseconds, with no activity until the first TCP keep-alive packet is sent." + "Timeout, in seconds, with no activity until the first TCP keep-alive packet is sent." "If set to 0, system dependent default is used.", AUTO_SET GLOBAL_VAR(opt_vio_keepalive.idle), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, INT_MAX32/1000), DEFAULT(0), diff --git a/sql/temporary_tables.cc b/sql/temporary_tables.cc index 9491a23793b..ef6f1c42434 100644 --- a/sql/temporary_tables.cc +++ b/sql/temporary_tables.cc @@ -1139,9 +1139,7 @@ TABLE *THD::open_temporary_table(TMP_TABLE_SHARE *share, /* Increment Slave_open_temp_table_definitions status variable count. */ if (rgi_slave) - { - thread_safe_increment32(&slave_open_temp_tables); - } + slave_open_temp_tables++; DBUG_PRINT("tmptable", ("Opened table: '%s'.'%s table: %p", table->s->db.str, @@ -1247,7 +1245,7 @@ void THD::close_temporary_table(TABLE *table) /* Natural invariant of temporary_tables */ DBUG_ASSERT(slave_open_temp_tables || !temporary_tables); /* Decrement Slave_open_temp_table_definitions status variable count. */ - thread_safe_decrement32(&slave_open_temp_tables); + slave_open_temp_tables--; } DBUG_VOID_RETURN; diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc index 6c2f20081a7..49880b2e827 100644 --- a/sql/wsrep_mysqld.cc +++ b/sql/wsrep_mysqld.cc @@ -269,6 +269,45 @@ char* wsrep_cluster_capabilities = NULL; wsp::Config_state *wsrep_config_state; +void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...) +{ + /* Allocate short buffer from stack. If the vsnprintf() return value + indicates that the message was truncated, a new buffer will be allocated + dynamically and the message will be reprinted. */ + char msg[128] = {'\0'}; + va_list arglist; + va_start(arglist, fmt); + int n= vsnprintf(msg, sizeof(msg) - 1, fmt, arglist); + va_end(arglist); + if (n < 0) + { + sql_print_warning("WSREP: Printing message failed"); + } + else if (n < (int)sizeof(msg)) + { + fun("WSREP: %s", msg); + } + else + { + size_t dynbuf_size= std::max(n, 4096); + char* dynbuf= (char*) my_malloc(PSI_NOT_INSTRUMENTED, dynbuf_size, MYF(0)); + if (dynbuf) + { + va_start(arglist, fmt); + (void)vsnprintf(&dynbuf[0], dynbuf_size - 1, fmt, arglist); + va_end(arglist); + dynbuf[dynbuf_size - 1] = '\0'; + fun("WSREP: %s", &dynbuf[0]); + my_free(dynbuf); + } + else + { + /* Memory allocation for vector failed, print truncated message. */ + fun("WSREP: %s", msg); + } + } +} + wsrep_uuid_t local_uuid = WSREP_UUID_UNDEFINED; wsrep_seqno_t local_seqno = WSREP_SEQNO_UNDEFINED; @@ -756,6 +795,7 @@ void wsrep_init_globals() wsrep_gtid_server.seqno(gtid.seqno); } wsrep_init_schema(); + if (WSREP_ON) { Wsrep_server_state::instance().initialized(); @@ -793,6 +833,8 @@ int wsrep_init() global_system_variables.wsrep_on= 1; + WSREP_ON_= wsrep_provider && strcmp(wsrep_provider, WSREP_NONE); + if (wsrep_gtid_mode && opt_bin_log && !opt_log_slave_updates) { WSREP_ERROR("Option --log-slave-updates is required if " @@ -2217,8 +2259,10 @@ int wsrep_to_isolation_begin(THD *thd, const char *db_, const char *table_, DBUG_ASSERT(wsrep_thd_is_local(thd)); DBUG_ASSERT(thd->wsrep_trx().ws_meta().seqno().is_undefined()); - if (thd->global_read_lock.is_acquired()) + if (Wsrep_server_state::instance().desynced_on_pause()) { + my_message(ER_UNKNOWN_COM_ERROR, + "Aborting TOI: Global Read-Lock (FTWRL) in place.", MYF(0)); WSREP_DEBUG("Aborting TOI: Global Read-Lock (FTWRL) in place: %s %llu", wsrep_thd_query(thd), thd->thread_id); return -1; diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 46ca4959741..cf2404e329e 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -19,6 +19,7 @@ #include <wsrep.h> #ifdef WITH_WSREP +extern bool WSREP_ON_; #include <mysql/plugin.h> #include "mysql/service_wsrep.h" @@ -214,15 +215,12 @@ extern void wsrep_prepend_PATH (const char* path); /* Other global variables */ extern wsrep_seqno_t wsrep_locked_seqno; -#define WSREP_ON \ - ((global_system_variables.wsrep_on) && \ - wsrep_provider && \ - strcmp(wsrep_provider, WSREP_NONE)) +#define WSREP_ON unlikely(WSREP_ON_) /* use xxxxxx_NNULL macros when thd pointer is guaranteed to be non-null to * avoid compiler warnings (GCC 6 and later) */ -#define WSREP_NNULL(thd) \ - (thd->variables.wsrep_on && WSREP_ON) + +#define WSREP_NNULL(thd) (WSREP_ON && thd->variables.wsrep_on) #define WSREP(thd) \ (thd && WSREP_NNULL(thd)) @@ -243,13 +241,9 @@ extern wsrep_seqno_t wsrep_locked_seqno; ((wsrep_forced_binlog_format != BINLOG_FORMAT_UNSPEC) ? \ wsrep_forced_binlog_format : my_format) -// prefix all messages with "WSREP" -#define WSREP_LOG(fun, ...) \ - do { \ - char msg[1024]= {'\0'}; \ - snprintf(msg, sizeof(msg) - 1, ## __VA_ARGS__); \ - fun("WSREP: %s", msg); \ - } while(0) +/* A wrapper function for MySQL log functions. The call will prefix + the log message with WSREP and forward the result buffer to fun. */ +void WSREP_LOG(void (*fun)(const char* fmt, ...), const char* fmt, ...); #define WSREP_DEBUG(...) \ if (wsrep_debug) sql_print_information( "WSREP: " __VA_ARGS__) @@ -615,9 +609,9 @@ enum wsrep::streaming_context::fragment_unit wsrep_fragment_unit(ulong unit); /* These macros are needed to compile MariaDB without WSREP support * (e.g. embedded) */ +#define WSREP_ON false #define WSREP(T) (0) #define WSREP_NNULL(T) (0) -#define WSREP_ON (0) #define WSREP_EMULATE_BINLOG(thd) (0) #define WSREP_EMULATE_BINLOG_NNULL(thd) (0) #define WSREP_BINLOG_FORMAT(my_format) ((ulong)my_format) diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc index 0bb8a9eb675..8ffcb32e10a 100644 --- a/sql/wsrep_sst.cc +++ b/sql/wsrep_sst.cc @@ -367,6 +367,7 @@ void wsrep_sst_received (THD* thd, my_pthread_setspecific_ptr(THR_THD, NULL); } + /* During sst WSREP(thd) is not yet set for joiner. */ if (WSREP_ON) { int const rcode(seqno < 0 ? seqno : 0); diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index 94d01b273c5..0f72c132d84 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -320,10 +320,15 @@ int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal) DBUG_ENTER("wsrep_abort_thd"); THD *victim_thd= (THD *) victim_thd_ptr; THD *bf_thd= (THD *) bf_thd_ptr; + mysql_mutex_lock(&victim_thd->LOCK_thd_data); - if ( (WSREP(bf_thd) || - ( (WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) && - wsrep_thd_is_toi(bf_thd)) ) && + + /* Note that when you use RSU node is desynced from cluster, thus WSREP(thd) + might not be true. + */ + if ((WSREP(bf_thd) || + ((WSREP_ON || bf_thd->variables.wsrep_OSU_method == WSREP_OSU_RSU) && + wsrep_thd_is_toi(bf_thd))) && victim_thd && !wsrep_thd_is_aborting(victim_thd)) { @@ -337,6 +342,7 @@ int wsrep_abort_thd(THD *bf_thd_ptr, THD *victim_thd_ptr, my_bool signal) { WSREP_DEBUG("wsrep_abort_thd not effective: %p %p", bf_thd, victim_thd); } + mysql_mutex_unlock(&victim_thd->LOCK_thd_data); DBUG_RETURN(1); } diff --git a/sql/wsrep_trans_observer.h b/sql/wsrep_trans_observer.h index cb58026207b..55bb7462d99 100644 --- a/sql/wsrep_trans_observer.h +++ b/sql/wsrep_trans_observer.h @@ -431,7 +431,7 @@ static inline void wsrep_after_apply(THD* thd) static inline void wsrep_open(THD* thd) { DBUG_ENTER("wsrep_open"); - if (wsrep_on(thd)) + if (WSREP(thd)) { thd->wsrep_cs().open(wsrep::client_id(thd->thread_id)); thd->wsrep_cs().debug_log_level(wsrep_debug); diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 28dbe4096f7..4fffc3ddc8a 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -91,6 +91,12 @@ static bool refresh_provider_options() } } +static void wsrep_set_wsrep_on() +{ + WSREP_ON_= global_system_variables.wsrep_on && wsrep_provider && + strcmp(wsrep_provider, WSREP_NONE); +} + /* This is intentionally declared as a weak global symbol, so that linking will succeed even if the server is built with a dynamically linked InnoDB. */ @@ -125,6 +131,8 @@ bool wsrep_on_update (sys_var *self, THD* thd, enum_var_type var_type) thd->variables.wsrep_on= global_system_variables.wsrep_on= saved_wsrep_on; } + wsrep_set_wsrep_on(); + return false; } @@ -418,6 +426,7 @@ bool wsrep_provider_update (sys_var *self, THD* thd, enum_var_type type) if (!rcode) refresh_provider_options(); + wsrep_set_wsrep_on(); mysql_mutex_lock(&LOCK_global_system_variables); return rcode; @@ -437,6 +446,7 @@ void wsrep_provider_init (const char* value) if (wsrep_provider) my_free((void *)wsrep_provider); wsrep_provider= my_strdup(PSI_INSTRUMENT_MEM, value, MYF(0)); + wsrep_set_wsrep_on(); } bool wsrep_provider_options_check(sys_var *self, THD* thd, set_var* var) @@ -924,6 +934,8 @@ static void export_wsrep_status_to_mysql(THD* thd) int wsrep_show_status (THD *thd, SHOW_VAR *var, char *buff) { + /* Note that we should allow show status like 'wsrep%' even + when WSREP(thd) is false. */ if (WSREP_ON) { export_wsrep_status_to_mysql(thd); diff --git a/sql/xa.cc b/sql/xa.cc index cde6350f38d..69e9fd70af6 100644 --- a/sql/xa.cc +++ b/sql/xa.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2000, 2016, Oracle and/or its affiliates. - Copyright (c) 2009, 2019, MariaDB Corporation. + Copyright (c) 2009, 2020, 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 @@ -19,6 +19,7 @@ #include "mariadb.h" #include "sql_class.h" #include "transaction.h" +#include "my_cpu.h" #include <pfs_transaction_provider.h> #include <mysql/psi/mysql_transaction.h> |