summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h14
-rw-r--r--sql/event_scheduler.cc40
-rw-r--r--sql/ha_partition.cc1
-rw-r--r--sql/handler.cc6
-rw-r--r--sql/item_cmpfunc.cc27
-rw-r--r--sql/item_cmpfunc.h12
-rw-r--r--sql/item_func.cc15
-rw-r--r--sql/item_func.h1
-rw-r--r--sql/item_subselect.cc2
-rw-r--r--sql/log.cc47
-rw-r--r--sql/log_event.cc18
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/mysql_install_db.cc4
-rw-r--r--sql/mysqld.cc106
-rw-r--r--sql/mysqld.h6
-rw-r--r--sql/nt_servc.cc2
-rw-r--r--sql/nt_servc.h2
-rw-r--r--sql/opt_range.cc25
-rw-r--r--sql/opt_subselect.cc2
-rw-r--r--sql/partition_info.cc2
-rw-r--r--sql/rpl_mi.cc411
-rw-r--r--sql/rpl_mi.h20
-rw-r--r--sql/rpl_parallel.cc126
-rw-r--r--sql/rpl_parallel.h1
-rw-r--r--sql/rpl_rli.cc15
-rw-r--r--sql/rpl_rli.h2
-rw-r--r--sql/slave.cc137
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sql_acl.cc6
-rw-r--r--sql/sql_alter.h35
-rw-r--r--sql/sql_base.cc18
-rw-r--r--sql/sql_class.cc7
-rw-r--r--sql/sql_class.h19
-rw-r--r--sql/sql_db.cc9
-rw-r--r--sql/sql_delete.cc5
-rw-r--r--sql/sql_derived.cc3
-rw-r--r--sql/sql_join_cache.cc5
-rw-r--r--sql/sql_parse.cc132
-rw-r--r--sql/sql_parse.h3
-rw-r--r--sql/sql_reload.cc56
-rw-r--r--sql/sql_repl.cc79
-rw-r--r--sql/sql_select.cc77
-rw-r--r--sql/sql_table.cc5
-rw-r--r--sql/sql_trigger.cc3
-rw-r--r--sql/sql_update.cc11
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--sql/sys_vars.cc130
-rw-r--r--sql/table.cc21
-rw-r--r--sql/table.h3
49 files changed, 953 insertions, 727 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index 0359ec54022..3a771e2b493 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -37,16 +37,18 @@ struct show_table_contributors_st {
struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
- {"Booking.com", "http://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
+ {"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
+ {"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"},
- {"Visma", "http://visma.com", "Gold Sponsor of the MariaDB Foundation"},
- {"DBS", "http://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
{"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
{"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
{"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Verkkokauppa.com", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Virtuozzo", "https://virtuozzo.com/", "Bronze Sponsor of the MariaDB Foundation"},
- {"Tencent Game DBA", "http://tencentdba.com/about/", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Verkkokauppa.com", "https://www.verkkokauppa.com", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Virtuozzo", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Tencent Game DBA", "http://tencentdba.com/about", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Tencent TDSQL", "http://tdsql.org", "Bronze Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 5c4926c830c..2423fac4ca6 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -133,12 +133,6 @@ post_init_event_thread(THD *thd)
thd->cleanup();
return TRUE;
}
-
- thread_safe_increment32(&thread_count, &thread_count_lock);
- mysql_mutex_lock(&LOCK_thread_count);
- threads.append(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
- inc_thread_running();
return FALSE;
}
@@ -157,7 +151,13 @@ deinit_event_thread(THD *thd)
thd->proc_info= "Clearing";
DBUG_PRINT("exit", ("Event thread finishing"));
- delete_running_thd(thd);
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->unlink();
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ delete thd;
+ thread_safe_decrement32(&thread_count, &thread_count_lock);
+ signal_thd_deleted();
}
@@ -191,8 +191,10 @@ pre_init_event_thread(THD* thd)
thd->net.read_timeout= slave_net_timeout;
thd->variables.option_bits|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
+ thread_safe_increment32(&thread_count, &thread_count_lock);
mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
+ threads.append(thd);
mysql_mutex_unlock(&LOCK_thread_count);
/*
@@ -240,13 +242,8 @@ event_scheduler_thread(void *arg)
my_free(arg);
if (!res)
scheduler->run(thd);
- else
- {
- thd->proc_info= "Clearing";
- net_end(&thd->net);
- delete thd;
- }
+ deinit_event_thread(thd);
DBUG_LEAVE; // Against gcc warnings
my_thread_end();
return 0;
@@ -310,6 +307,7 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
DBUG_ENTER("Event_worker_thread::run");
DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx", (long) my_time(0), (long) thd));
+ inc_thread_running();
if (res)
goto end;
@@ -338,6 +336,7 @@ end:
event->name.str));
delete event;
+ dec_thread_running();
deinit_event_thread(thd);
DBUG_VOID_RETURN;
@@ -442,13 +441,9 @@ Event_scheduler::start(int *err_no)
" Can not create thread for event scheduler (errno=%d)",
*err_no);
- new_thd->proc_info= "Clearing";
- DBUG_ASSERT(new_thd->net.buff != 0);
- net_end(&new_thd->net);
-
state= INITIALIZED;
scheduler_thd= NULL;
- delete new_thd;
+ deinit_event_thread(new_thd);
delete scheduler_param_value;
ret= true;
@@ -515,7 +510,6 @@ Event_scheduler::run(THD *thd)
}
LOCK_DATA();
- deinit_event_thread(thd);
scheduler_thd= NULL;
state= INITIALIZED;
DBUG_PRINT("info", ("Broadcasting COND_state back to the stoppers"));
@@ -575,10 +569,7 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
sql_print_error("Event_scheduler::execute_top: Can not create event worker"
" thread (errno=%d). Stopping event scheduler", res);
- new_thd->proc_info= "Clearing";
- DBUG_ASSERT(new_thd->net.buff != 0);
- net_end(&new_thd->net);
-
+ deinit_event_thread(new_thd);
goto error;
}
@@ -590,9 +581,6 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
error:
DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res));
- if (new_thd)
- delete new_thd;
-
delete event_name;
DBUG_RETURN(TRUE);
}
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index af81962904f..e854045661b 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -7279,6 +7279,7 @@ int ha_partition::reset(void)
result= tmp;
}
bitmap_clear_all(&m_partitions_to_reset);
+ m_extra_prepare_for_update= FALSE;
DBUG_RETURN(result);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 79649316e73..47c5889431d 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -3441,6 +3441,7 @@ void handler::print_error(int error, myf errflag)
textno=ER_FILE_USED;
break;
case ENOENT:
+ case ENOTDIR:
textno=ER_FILE_NOT_FOUND;
break;
case ENOSPC:
@@ -3919,8 +3920,7 @@ int handler::delete_table(const char *name)
for (const char **ext=bas_ext(); *ext ; ext++)
{
- fn_format(buff, name, "", *ext, MY_UNPACK_FILENAME|MY_APPEND_EXT);
- if (mysql_file_delete_with_symlink(key_file_misc, buff, MYF(0)))
+ if (my_handler_delete_with_symlink(key_file_misc, name, *ext, 0))
{
if (my_errno != ENOENT)
{
@@ -4279,7 +4279,7 @@ enum_alter_inplace_result
handler::check_if_supported_inplace_alter(TABLE *altered_table,
Alter_inplace_info *ha_alter_info)
{
- DBUG_ENTER("check_if_supported_alter");
+ DBUG_ENTER("handler::check_if_supported_inplace_alter");
HA_CREATE_INFO *create_info= ha_alter_info->create_info;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e0dbf2c5a73..192e06566ff 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -798,7 +798,7 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
Item_result type)
{
- thd= current_thd;
+ THD *thd= current_thd;
owner= owner_arg;
set_null= set_null && owner_arg;
a= a1;
@@ -868,7 +868,6 @@ Item** Arg_comparator::cache_converted_constant(THD *thd_arg, Item **value,
void Arg_comparator::set_datetime_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **b1)
{
- thd= current_thd;
owner= owner_arg;
a= a1;
b= b1;
@@ -943,12 +942,10 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg,
if (cache_arg && item->const_item() &&
!(item->type() == Item::CACHE_ITEM && item->cmp_type() == TIME_RESULT))
{
- Query_arena backup;
- Query_arena *save_arena= thd->switch_to_arena_for_cached_items(&backup);
- Item_cache_temporal *cache= new Item_cache_temporal(f_type);
- if (save_arena)
- thd->set_query_arena(save_arena);
+ if (!thd)
+ thd= current_thd;
+ Item_cache_temporal *cache= new Item_cache_temporal(f_type);
cache->store_packed(value, item);
*cache_arg= cache;
*item_arg= cache_arg;
@@ -983,12 +980,12 @@ int Arg_comparator::compare_datetime()
owner->null_value= 1;
/* Get DATE/DATETIME/TIME value of the 'a' item. */
- a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null);
+ a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null);
if (a_is_null)
return -1;
/* Get DATE/DATETIME/TIME value of the 'b' item. */
- b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null);
+ b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null);
if (b_is_null)
return -1;
@@ -1006,10 +1003,10 @@ int Arg_comparator::compare_e_datetime()
longlong a_value, b_value;
/* Get DATE/DATETIME/TIME value of the 'a' item. */
- a_value= get_datetime_value(thd, &a, &a_cache, *b, &a_is_null);
+ a_value= get_datetime_value(0, &a, &a_cache, *b, &a_is_null);
/* Get DATE/DATETIME/TIME value of the 'b' item. */
- b_value= get_datetime_value(thd, &b, &b_cache, *a, &b_is_null);
+ b_value= get_datetime_value(0, &b, &b_cache, *a, &b_is_null);
return a_is_null || b_is_null ? a_is_null == b_is_null
: a_value == b_value;
}
@@ -3663,7 +3660,7 @@ void in_datetime::set(uint pos,Item *item)
bool is_null;
struct packed_longlong *buff= &((packed_longlong*) base)[pos];
- buff->val= get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null);
+ buff->val= get_datetime_value(0, &tmp_item, 0, warn_item, &is_null);
buff->unsigned_flag= 1L;
}
@@ -3671,7 +3668,7 @@ uchar *in_datetime::get_value(Item *item)
{
bool is_null;
Item **tmp_item= lval_cache ? &lval_cache : &item;
- tmp.val= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
+ tmp.val= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null);
if (item->null_value)
return 0;
tmp.unsigned_flag= 1L;
@@ -3915,7 +3912,7 @@ void cmp_item_datetime::store_value(Item *item)
{
bool is_null;
Item **tmp_item= lval_cache ? &lval_cache : &item;
- value= get_datetime_value(thd, &tmp_item, &lval_cache, warn_item, &is_null);
+ value= get_datetime_value(0, &tmp_item, &lval_cache, warn_item, &is_null);
}
@@ -3924,7 +3921,7 @@ int cmp_item_datetime::cmp(Item *arg)
bool is_null;
Item **tmp_item= &arg;
return value !=
- get_datetime_value(thd, &tmp_item, 0, warn_item, &is_null);
+ get_datetime_value(0, &tmp_item, 0, warn_item, &is_null);
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 9e83b732dc7..b84cb26fb9c 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -45,7 +45,6 @@ class Arg_comparator: public Sql_alloc
Arg_comparator *comparators; // used only for compare_row()
double precision;
/* Fields used in DATE/DATETIME comparison. */
- THD *thd;
Item *a_cache, *b_cache; // Cached values of a and b items
// when one of arguments is NULL.
int set_compare_func(Item_result_field *owner, Item_result type);
@@ -61,10 +60,10 @@ public:
/* Allow owner function to use string buffers. */
String value1, value2;
- Arg_comparator(): set_null(TRUE), comparators(0), thd(0),
+ Arg_comparator(): set_null(TRUE), comparators(0),
a_cache(0), b_cache(0) {};
Arg_comparator(Item **a1, Item **a2): a(a1), b(a2), set_null(TRUE),
- comparators(0), thd(0), a_cache(0), b_cache(0) {};
+ comparators(0), a_cache(0), b_cache(0) {};
int set_cmp_func(Item_result_field *owner_arg,
Item **a1, Item **a2,
@@ -963,15 +962,13 @@ public:
class in_datetime :public in_longlong
{
public:
- THD *thd;
/* An item used to issue warnings. */
Item *warn_item;
/* Cache for the left item. */
Item *lval_cache;
in_datetime(Item *warn_item_arg, uint elements)
- :in_longlong(elements), thd(current_thd), warn_item(warn_item_arg),
- lval_cache(0) {};
+ :in_longlong(elements), warn_item(warn_item_arg), lval_cache(0) {};
void set(uint pos,Item *item);
uchar *get_value(Item *item);
Item* create_item()
@@ -1131,14 +1128,13 @@ class cmp_item_datetime :public cmp_item
{
longlong value;
public:
- THD *thd;
/* Item used for issuing warnings. */
Item *warn_item;
/* Cache for the left item. */
Item *lval_cache;
cmp_item_datetime(Item *warn_item_arg)
- :thd(current_thd), warn_item(warn_item_arg), lval_cache(0) {}
+ : warn_item(warn_item_arg), lval_cache(0) {}
void store_value(Item *item);
int cmp(Item *arg);
int compare(cmp_item *ci);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 07acaacc862..ef164d060d2 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2865,7 +2865,6 @@ void Item_func_min_max::fix_length_and_dec()
decimals=0;
max_length=0;
maybe_null=0;
- thd= current_thd;
cmp_type=args[0]->result_type();
for (uint i=0 ; i < arg_count ; i++)
@@ -2938,13 +2937,11 @@ bool Item_func_min_max::get_date(MYSQL_TIME *ltime, ulonglong fuzzy_date)
{
Item **arg= args + i;
bool is_null;
- longlong res= get_datetime_value(thd, &arg, 0, compare_as_dates, &is_null);
+ longlong res= get_datetime_value(0, &arg, 0, compare_as_dates, &is_null);
/* Check if we need to stop (because of error or KILL) and stop the loop */
- if (thd->is_error() || args[i]->null_value)
- {
+ if (args[i]->null_value)
return (null_value= 1);
- }
if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0)
min_max= res;
@@ -3973,12 +3970,7 @@ longlong Item_master_pos_wait::val_int()
else
connection_name= thd->variables.default_master_connection;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index) // master_info_index is set to NULL on shutdown.
- mi= master_info_index->get_master_info(&connection_name,
- Sql_condition::WARN_LEVEL_WARN);
- mysql_mutex_unlock(&LOCK_active_mi);
- if (!mi)
+ if (!(mi= get_master_info(&connection_name, Sql_condition::WARN_LEVEL_WARN)))
goto err;
if ((event_count = mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
@@ -3986,6 +3978,7 @@ longlong Item_master_pos_wait::val_int()
null_value = 1;
event_count=0;
}
+ mi->release();
#endif
return event_count;
diff --git a/sql/item_func.h b/sql/item_func.h
index 3d0cdca4472..0141619dced 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1077,7 +1077,6 @@ class Item_func_min_max :public Item_func
int cmp_sign;
/* An item used for issuing warnings while string to DATETIME conversion. */
Item *compare_as_dates;
- THD *thd;
protected:
enum_field_types cached_field_type;
public:
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f3a98785a0b..8cff6a1e6c8 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -894,7 +894,7 @@ void Item_subselect::update_used_tables()
if (!forced_const)
{
recalc_used_tables(parent_select, FALSE);
- if (!engine->uncacheable())
+ if (!(engine->uncacheable() & ~UNCACHEABLE_EXPLAIN))
{
// did all used tables become static?
if (!(used_tables_cache & ~engine->upper_select_const_tables()))
diff --git a/sql/log.cc b/sql/log.cc
index 02e6ef98a65..3f3e0201c0c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2835,16 +2835,16 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
void MYSQL_QUERY_LOG::reopen_file()
{
char *save_name;
-
DBUG_ENTER("MYSQL_LOG::reopen_file");
+
+ mysql_mutex_lock(&LOCK_log);
if (!is_open())
{
DBUG_PRINT("info",("log is closed"));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
}
- mysql_mutex_lock(&LOCK_log);
-
save_name= name;
name= 0; // Don't free name
close(LOG_CLOSE_TO_BE_OPENED);
@@ -3003,13 +3003,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
DBUG_ENTER("MYSQL_QUERY_LOG::write");
mysql_mutex_lock(&LOCK_log);
-
- if (!is_open())
- {
- mysql_mutex_unlock(&LOCK_log);
- DBUG_RETURN(0);
- }
-
if (is_open())
{ // Safety agains reopen
int tmp_errno= 0;
@@ -3233,7 +3226,9 @@ void MYSQL_BIN_LOG::cleanup()
}
inited= 0;
+ mysql_mutex_lock(&LOCK_log);
close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(&LOCK_log);
delete description_event_for_queue;
delete description_event_for_exec;
@@ -3390,10 +3385,11 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
{
File file= -1;
xid_count_per_binlog *new_xid_list_entry= NULL, *b;
-
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (!is_relay_log)
{
if (!binlog_state_recover_done)
@@ -4286,7 +4282,7 @@ void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
{
- int error;
+ int error, errcode;
char *to_purge_if_included= NULL;
inuse_relaylog *ir;
ulonglong log_space_reclaimed= 0;
@@ -4357,7 +4353,8 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
}
/* Store where we are in the new file for the execution thread */
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ error= LOG_INFO_IO;
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
@@ -4373,11 +4370,13 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
* Need to update the log pos because purge logs has been called
* after fetching initially the log pos at the begining of the method.
*/
- if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
+ if ((errcode= find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
{
char buff[22];
+ if (!error)
+ error= errcode;
sql_print_error("next log error: %d offset: %s log: %s included: %d",
- error,
+ errcode,
llstr(rli->linfo.index_file_offset,buff),
rli->group_relay_log_name,
included);
@@ -4996,21 +4995,21 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
bool delay_close= false;
File old_file;
LINT_INIT(old_file);
-
DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
+
+ if (need_lock)
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (!is_open())
{
DBUG_PRINT("info",("log is closed"));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}
- if (need_lock)
- mysql_mutex_lock(&LOCK_log);
mysql_mutex_lock(&LOCK_index);
- mysql_mutex_assert_owner(&LOCK_log);
- mysql_mutex_assert_owner(&LOCK_index);
-
/* Reuse old name if not binlog and not update log */
new_name_ptr= name;
@@ -5143,9 +5142,9 @@ end:
new_name_ptr, errno);
}
+ mysql_mutex_unlock(&LOCK_index);
if (need_lock)
mysql_mutex_unlock(&LOCK_log);
- mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -7974,9 +7973,11 @@ int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
void MYSQL_BIN_LOG::close(uint exiting)
{ // One can't set log_type here!
bool failed_to_save_state= false;
-
DBUG_ENTER("MYSQL_BIN_LOG::close");
DBUG_PRINT("enter",("exiting: %d", (int) exiting));
+
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (log_state == LOG_OPENED)
{
#ifdef HAVE_REPLICATION
diff --git a/sql/log_event.cc b/sql/log_event.cc
index d2f3b2c60f6..1ae65a02f15 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6273,9 +6273,11 @@ bool Rotate_log_event::write(IO_CACHE* file)
@retval
0 ok
+ 1 error
*/
int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
{
+ int error= 0;
Relay_log_info *rli= rgi->rli;
DBUG_ENTER("Rotate_log_event::do_update_pos");
#ifndef DBUG_OFF
@@ -6327,7 +6329,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
(ulong) rli->group_master_log_pos));
mysql_mutex_unlock(&rli->data_lock);
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- flush_relay_log_info(rli);
+ error= flush_relay_log_info(rli);
/*
Reset thd->variables.option_bits and sql_mode etc, because this could
@@ -6345,8 +6347,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
else
rgi->inc_event_relay_log_pos();
-
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -6944,6 +6945,7 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
rli->abort_slave= true;
rli->stop_for_until= true;
}
+ free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
return ret;
}
@@ -8220,6 +8222,7 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
int Stop_log_event::do_update_pos(rpl_group_info *rgi)
{
+ int error= 0;
Relay_log_info *rli= rgi->rli;
DBUG_ENTER("Stop_log_event::do_update_pos");
/*
@@ -8235,9 +8238,10 @@ int Stop_log_event::do_update_pos(rpl_group_info *rgi)
{
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
rli->inc_group_relay_log_pos(0, rgi);
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ error= 1;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
#endif /* !MYSQL_CLIENT */
@@ -10273,8 +10277,8 @@ int
Rows_log_event::do_update_pos(rpl_group_info *rgi)
{
Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Rows_log_event::do_update_pos");
int error= 0;
+ DBUG_ENTER("Rows_log_event::do_update_pos");
DBUG_PRINT("info", ("flags: %s",
get_flags(STMT_END_F) ? "STMT_END_F " : ""));
@@ -10286,7 +10290,7 @@ Rows_log_event::do_update_pos(rpl_group_info *rgi)
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
- rli->stmt_done(log_pos, thd, rgi);
+ error= rli->stmt_done(log_pos, thd, rgi);
/*
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 22ef970dab9..8bdb81f5283 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1843,8 +1843,8 @@ int
Old_rows_log_event::do_update_pos(rpl_group_info *rgi)
{
Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Old_rows_log_event::do_update_pos");
int error= 0;
+ DBUG_ENTER("Old_rows_log_event::do_update_pos");
DBUG_PRINT("info", ("flags: %s",
get_flags(STMT_END_F) ? "STMT_END_F " : ""));
@@ -1856,7 +1856,7 @@ Old_rows_log_event::do_update_pos(rpl_group_info *rgi)
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
- rli->stmt_done(log_pos, thd, rgi);
+ error= rli->stmt_done(log_pos, thd, rgi);
/*
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index c23a20ebac9..de799874a8f 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -386,8 +386,8 @@ static int register_service()
CloseServiceHandle(sc_manager);
die("CreateService failed (%u)", GetLastError());
}
-
- SERVICE_DESCRIPTION sd= { "MariaDB database server" };
+ char description[] = "MariaDB database server";
+ SERVICE_DESCRIPTION sd= { description };
ChangeServiceConfig2(sc_service, SERVICE_CONFIG_DESCRIPTION, &sd);
CloseServiceHandle(sc_service);
CloseServiceHandle(sc_manager);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f252d19f50b..349971e86fa 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -21,7 +21,7 @@
#ifndef __WIN__
#include <netdb.h> // getservbyname, servent
#endif
-#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_parse.h" // path_starts_from_data_home_dir
#include "sql_cache.h" // query_cache, query_cache_*
#include "sql_locale.h" // MY_LOCALES, my_locales, my_locale_by_name
#include "sql_show.h" // free_status_vars, add_status_vars,
@@ -721,12 +721,15 @@ mysql_mutex_t
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt,
LOCK_global_system_variables,
- LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
+ LOCK_user_conn, LOCK_slave_list,
LOCK_connection_count, LOCK_error_messages, LOCK_slave_init;
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
+/* This protects against changes in master_info_index */
+mysql_mutex_t LOCK_active_mi;
+
/**
The below lock protects access to two global server variables:
max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -896,7 +899,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_system_variables_hash, key_LOCK_thd_data,
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
- key_master_info_sleep_lock,
+ key_master_info_sleep_lock, key_master_info_start_stop_lock,
key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
key_rpl_group_info_sleep_lock,
key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
@@ -972,6 +975,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
{ &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
{ &key_master_info_data_lock, "Master_info::data_lock", 0},
+ { &key_master_info_start_stop_lock, "Master_info::start_stop_lock", 0},
{ &key_master_info_run_lock, "Master_info::run_lock", 0},
{ &key_master_info_sleep_lock, "Master_info::sleep_lock", 0},
{ &key_mutex_slave_reporting_capability_err_lock, "Slave_reporting_capability::err_lock", 0},
@@ -1483,7 +1487,7 @@ ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
#ifdef HAVE_SMEM
-char *shared_memory_base_name= default_shared_memory_base_name;
+const char *shared_memory_base_name= default_shared_memory_base_name;
my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
@@ -1725,7 +1729,7 @@ static void close_connections(void)
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::deinit();
- end_slave();
+ slave_prepare_for_shutdown();
/*
Give threads time to die.
@@ -1801,6 +1805,7 @@ static void close_connections(void)
DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
mysql_mutex_unlock(&LOCK_thread_count);
}
+ end_slave();
/* All threads has now been aborted */
DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
mysql_mutex_lock(&LOCK_thread_count);
@@ -2802,23 +2807,6 @@ void dec_connection_count(THD *thd)
/*
- Delete THD and decrement thread counters, including thread_running
-*/
-
-void delete_running_thd(THD *thd)
-{
- mysql_mutex_lock(&LOCK_thread_count);
- thd->unlink();
- mysql_mutex_unlock(&LOCK_thread_count);
-
- delete thd;
- dec_thread_running();
- thread_safe_decrement32(&thread_count, &thread_count_lock);
- signal_thd_deleted();
-}
-
-
-/*
Send a signal to unblock close_conneciton() if there is no more
threads running with a THD attached
@@ -5252,9 +5240,17 @@ static int init_server_components()
unireg_abort(1);
}
- if (opt_bin_log && mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
- WRITE_CACHE, max_binlog_size, 0, TRUE))
- unireg_abort(1);
+ if (opt_bin_log)
+ {
+ int error;
+ mysql_mutex_t *log_lock= mysql_bin_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
+ error= mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0,
+ WRITE_CACHE, max_binlog_size, 0, TRUE);
+ mysql_mutex_unlock(log_lock);
+ if (error)
+ unireg_abort(1);
+ }
#ifdef HAVE_REPLICATION
if (opt_bin_log && expire_logs_days)
@@ -8025,17 +8021,14 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff)
var->type= SHOW_MY_BOOL;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_READING &&
- mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN);
+ tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_READING &&
+ mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
if (mi)
*((my_bool *)buff)= tmp;
else
@@ -8067,38 +8060,26 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONGLONG;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
- *((longlong *)buff)= master_info_index->any_slave_sql_running();
- else
- *((longlong *)buff)= 0;
+ *((longlong *)buff)= any_slave_sql_running();
- mysql_mutex_unlock(&LOCK_active_mi);
return 0;
}
static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff)
{
- Master_info *mi= NULL;
- longlong tmp;
- LINT_INIT(tmp);
+ Master_info *mi;
var->type= SHOW_LONGLONG;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= mi->received_heartbeats;
+ *((longlong *)buff)= mi->received_heartbeats;
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
- if (mi)
- *((longlong *)buff)= tmp;
else
var->type= SHOW_UNDEF;
return 0;
@@ -8108,23 +8089,16 @@ static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff)
static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff)
{
Master_info *mi= NULL;
- float tmp;
- LINT_INIT(tmp);
var->type= SHOW_CHAR;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= mi->heartbeat_period;
+ sprintf(buff, "%.3f", mi->heartbeat_period);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
- if (mi)
- sprintf(buff, "%.3f", tmp);
else
var->type= SHOW_UNDEF;
return 0;
@@ -8965,7 +8939,7 @@ static int mysql_init_variables(void)
mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0;
#if defined(HAVE_REALPATH) && !defined(HAVE_valgrind) && !defined(HAVE_BROKEN_REALPATH)
/* We can only test for sub paths if my_symlink.c is using realpath */
- myisam_test_invalid_symlink= test_if_data_home_dir;
+ mysys_test_invalid_symlink= path_starts_from_data_home_dir;
#endif
opt_log= opt_slow_log= 0;
opt_bin_log= opt_bin_log_used= 0;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index c68cab26374..731391490e0 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -59,7 +59,6 @@ void kill_mysql(void);
void close_connection(THD *thd, uint sql_errno= 0);
void handle_connection_in_main_thread(THD *thd);
void create_thread_to_handle_connection(THD *thd);
-void delete_running_thd(THD *thd);
void signal_thd_deleted();
void unlink_thd(THD *thd);
bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
@@ -118,7 +117,8 @@ extern my_bool sp_automatic_privileges, opt_noacl;
extern ulong use_stat_tables;
extern my_bool opt_old_style_user_limits, trust_function_creators;
extern uint opt_crash_binlog_innodb;
-extern char *shared_memory_base_name, *mysqld_unix_port;
+extern const char *shared_memory_base_name;
+extern char *mysqld_unix_port;
extern my_bool opt_enable_shared_memory;
extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name;
@@ -269,7 +269,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_thd_data,
key_LOCK_user_conn, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
- key_master_info_sleep_lock,
+ key_master_info_sleep_lock, key_master_info_start_stop_lock,
key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
key_rpl_group_info_sleep_lock,
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index d6a8eac7ed5..e05e43a0a59 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -508,7 +508,7 @@ BOOL NTService::IsService(LPCSTR ServiceName)
}
/* ------------------------------------------------------------------------
-------------------------------------------------------------------------- */
-BOOL NTService::got_service_option(char **argv, char *service_option)
+BOOL NTService::got_service_option(char **argv, const char *service_option)
{
char *option;
for (option= argv[1]; *option; option++)
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
index 949499d8d7f..6781fe0ddfa 100644
--- a/sql/nt_servc.h
+++ b/sql/nt_servc.h
@@ -61,7 +61,7 @@ class NTService
BOOL SeekStatus(LPCSTR szInternName, int OperationType);
BOOL Remove(LPCSTR szInternName);
BOOL IsService(LPCSTR ServiceName);
- BOOL got_service_option(char **argv, char *service_option);
+ BOOL got_service_option(char **argv, const char *service_option);
BOOL is_super_user();
/*
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 5d6891a1edf..8f9d5abfa4d 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -8067,8 +8067,15 @@ static SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param,COND *cond)
if (cond_func->functype() == Item_func::BETWEEN ||
cond_func->functype() == Item_func::IN_FUNC)
inv= ((Item_func_opt_neg *) cond_func)->negated;
- else if (cond_func->select_optimize() == Item_func::OPTIMIZE_NONE)
- DBUG_RETURN(0);
+ else
+ {
+ MEM_ROOT *tmp_root= param->mem_root;
+ param->thd->mem_root= param->old_root;
+ Item_func::optimize_type opt_res= cond_func->select_optimize();
+ param->thd->mem_root= tmp_root;
+ if (opt_res == Item_func::OPTIMIZE_NONE)
+ DBUG_RETURN(0);
+ }
param->cond= cond;
@@ -9923,6 +9930,13 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
if (!tmp->next_key_part)
{
+ if (key2->use_count)
+ {
+ SEL_ARG *key2_cpy= new SEL_ARG(*key2);
+ if (key2_cpy)
+ return 0;
+ key2= key2_cpy;
+ }
/*
tmp->next_key_part is empty: cut the range that is covered
by tmp from key2.
@@ -9954,13 +9968,6 @@ key_or(RANGE_OPT_PARAM *param, SEL_ARG *key1,SEL_ARG *key2)
key2: [---]
tmp: [---------]
*/
- if (key2->use_count)
- {
- SEL_ARG *key2_cpy= new SEL_ARG(*key2);
- if (key2_cpy)
- return 0;
- key2= key2_cpy;
- }
key2->copy_max_to_min(tmp);
continue;
}
diff --git a/sql/opt_subselect.cc b/sql/opt_subselect.cc
index a81b091461f..564a108c766 100644
--- a/sql/opt_subselect.cc
+++ b/sql/opt_subselect.cc
@@ -4044,13 +4044,13 @@ SJ_TMP_TABLE::create_sj_weedout_tmp_table(THD *thd)
share->db_plugin= ha_lock_engine(0, TMP_ENGINE_HTON);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
- DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length());
}
else
{
share->db_plugin= ha_lock_engine(0, heap_hton);
table->file= get_new_handler(share, &table->mem_root,
share->db_type());
+ DBUG_ASSERT(uniq_tuple_length_arg <= table->file->max_key_length());
}
if (!table->file)
goto err;
diff --git a/sql/partition_info.cc b/sql/partition_info.cc
index 1607b1937df..1eee5df2bc5 100644
--- a/sql/partition_info.cc
+++ b/sql/partition_info.cc
@@ -27,7 +27,7 @@
#include "sql_partition.h" // partition_info.h: LIST_PART_ENTRY
// NOT_A_PARTITION_ID
#include "partition_info.h"
-#include "sql_parse.h" // test_if_data_home_dir
+#include "sql_parse.h"
#include "sql_acl.h" // *_ACL
#include "sql_base.h" // fill_record
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index c9a9ba3fc6d..f1508024c22 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -40,7 +40,9 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
sync_counter(0), heartbeat_period(0), received_heartbeats(0),
master_id(0), prev_master_id(0),
using_gtid(USE_GTID_NO), events_queued_since_last_gtid(0),
- gtid_reconnect_event_skip_count(0), gtid_event_seen(false)
+ gtid_reconnect_event_skip_count(0), gtid_event_seen(false),
+ in_start_all_slaves(0), in_stop_all_slaves(0),
+ users(0), killed(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
@@ -78,6 +80,8 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
bzero((char*) &file, sizeof(file));
mysql_mutex_init(key_master_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_master_info_data_lock, &data_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_master_info_start_stop_lock, &start_stop_lock,
+ MY_MUTEX_INIT_SLOW);
mysql_mutex_setflags(&run_lock, MYF_NO_DEADLOCK_DETECTION);
mysql_mutex_setflags(&data_lock, MYF_NO_DEADLOCK_DETECTION);
mysql_mutex_init(key_master_info_sleep_lock, &sleep_lock, MY_MUTEX_INIT_FAST);
@@ -87,6 +91,24 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
mysql_cond_init(key_master_info_sleep_cond, &sleep_cond, NULL);
}
+
+/**
+ Wait until no one is using Master_info
+*/
+
+void Master_info::wait_until_free()
+{
+ mysql_mutex_lock(&sleep_lock);
+ killed= 1;
+ while (users)
+ mysql_cond_wait(&sleep_cond, &sleep_lock);
+ mysql_mutex_unlock(&sleep_lock);
+}
+
+/**
+ Delete master_info
+*/
+
Master_info::~Master_info()
{
#ifdef WITH_WSREP
@@ -103,6 +125,7 @@ Master_info::~Master_info()
mysql_mutex_destroy(&run_lock);
mysql_mutex_destroy(&data_lock);
mysql_mutex_destroy(&sleep_lock);
+ mysql_mutex_destroy(&start_stop_lock);
mysql_cond_destroy(&data_cond);
mysql_cond_destroy(&start_cond);
mysql_cond_destroy(&stop_cond);
@@ -713,12 +736,28 @@ uchar *get_key_master_info(Master_info *mi, size_t *length,
return (uchar*) mi->cmp_connection_name.str;
}
+/*
+ Delete a master info
+
+ Called from my_hash_delete(&master_info_hash)
+ Stops associated slave threads and frees master_info
+*/
+
void free_key_master_info(Master_info *mi)
{
DBUG_ENTER("free_key_master_info");
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ /* Ensure that we are not in reset_slave while this is done */
+ mi->lock_slave_threads();
terminate_slave_threads(mi,SLAVE_FORCE_ALL);
+ /* We use 2 here instead of 1 just to make it easier when debugging */
+ mi->killed= 2;
end_master_info(mi);
+ mi->unlock_slave_threads();
delete mi;
+
+ mysql_mutex_lock(&LOCK_active_mi);
DBUG_VOID_RETURN;
}
@@ -874,9 +913,28 @@ Master_info_index::Master_info_index()
index_file.file= -1;
}
+
+/**
+ Free all connection threads
+
+ This is done during early stages of shutdown
+ to give connection threads and slave threads time
+ to die before ~Master_info_index is called
+*/
+
+void Master_info_index::free_connections()
+{
+ mysql_mutex_assert_owner(&LOCK_active_mi);
+ my_hash_reset(&master_info_hash);
+}
+
+
+/**
+ Free all connection threads and free structures
+*/
+
Master_info_index::~Master_info_index()
{
- /* This will close connection for all objects in the cache */
my_hash_free(&master_info_hash);
end_io_cache(&index_file);
if (index_file.file >= 0)
@@ -899,7 +957,6 @@ bool Master_info_index::init_all_master_info()
File index_file_nr;
DBUG_ENTER("init_all_master_info");
- mysql_mutex_assert_owner(&LOCK_active_mi);
DBUG_ASSERT(master_info_index);
if ((index_file_nr= my_open(index_file_name,
@@ -947,7 +1004,6 @@ bool Master_info_index::init_all_master_info()
DBUG_RETURN(1);
}
- lock_slave_threads(mi);
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
create_logfile_name_with_suffix(buf_master_info_file,
@@ -962,6 +1018,7 @@ bool Master_info_index::init_all_master_info()
sql_print_information("Reading Master_info: '%s' Relay_info:'%s'",
buf_master_info_file, buf_relay_log_info_file);
+ mi->lock_slave_threads();
if (init_master_info(mi, buf_master_info_file, buf_relay_log_info_file,
0, thread_mask))
{
@@ -975,14 +1032,15 @@ bool Master_info_index::init_all_master_info()
if (master_info_index->add_master_info(mi, FALSE))
DBUG_RETURN(1);
succ_num++;
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
}
else
{
/* Master_info already in HASH */
sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS),
+ (int) connection_name.length, connection_name.str,
(int) connection_name.length, connection_name.str);
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
delete mi;
}
continue;
@@ -998,8 +1056,9 @@ bool Master_info_index::init_all_master_info()
{
/* Master_info was already registered */
sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS),
+ (int) connection_name.length, connection_name.str,
(int) connection_name.length, connection_name.str);
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
delete mi;
continue;
}
@@ -1008,7 +1067,6 @@ bool Master_info_index::init_all_master_info()
if (master_info_index->add_master_info(mi, FALSE))
DBUG_RETURN(1);
succ_num++;
- unlock_slave_threads(mi);
if (!opt_skip_slave_start)
{
@@ -1029,6 +1087,7 @@ bool Master_info_index::init_all_master_info()
(int) connection_name.length,
connection_name.str);
}
+ mi->unlock_slave_threads();
}
}
@@ -1080,6 +1139,71 @@ bool Master_info_index::write_master_name_to_index_file(LEX_STRING *name,
/**
+ Get Master_info for a connection and lock the object from deletion
+
+ @param
+ connection_name Connection name
+ warning WARN_LEVEL_NOTE -> Don't print anything
+ WARN_LEVEL_WARN -> Issue warning if not exists
+ WARN_LEVEL_ERROR-> Issue error if not exists
+*/
+
+Master_info *get_master_info(LEX_STRING *connection_name,
+ Sql_condition::enum_warning_level warning)
+{
+ Master_info *mi;
+ DBUG_ENTER("get_master_info");
+
+ /* Protect against inserts into hash */
+ mysql_mutex_lock(&LOCK_active_mi);
+ /*
+ The following can only be true during shutdown when slave has been killed
+ but some other threads are still trying to access slave statistics.
+ */
+ if (unlikely(!master_info_index))
+ {
+ if (warning != Sql_condition::WARN_LEVEL_NOTE)
+ my_error(WARN_NO_MASTER_INFO,
+ MYF(warning == Sql_condition::WARN_LEVEL_WARN ?
+ ME_JUST_WARNING : 0),
+ (int) connection_name->length, connection_name->str);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(0);
+ }
+ if ((mi= master_info_index->get_master_info(connection_name, warning)))
+ {
+ /*
+ We have to use sleep_lock here. If we would use LOCK_active_mi
+ then we would take locks in wrong order in Master_info::release()
+ */
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++;
+ DBUG_PRINT("info",("users: %d", mi->users));
+ mysql_mutex_unlock(&mi->sleep_lock);
+ }
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(mi);
+}
+
+
+/**
+ Release master info.
+ Signals ~Master_info that it's now safe to delete it
+*/
+
+void Master_info::release()
+{
+ mysql_mutex_lock(&sleep_lock);
+ if (!--users && killed)
+ {
+ /* Signal ~Master_info that it's ok to now free it */
+ mysql_cond_signal(&sleep_cond);
+ }
+ mysql_mutex_unlock(&sleep_lock);
+}
+
+
+/**
Get Master_info for a connection
@param
@@ -1101,8 +1225,6 @@ Master_info_index::get_master_info(LEX_STRING *connection_name,
("connection_name: '%.*s'", (int) connection_name->length,
connection_name->str));
- mysql_mutex_assert_owner(&LOCK_active_mi);
-
/* Make name lower case for comparison */
res= strmake(buff, connection_name->str, connection_name->length);
my_casedn_str(system_charset_info, buff);
@@ -1168,7 +1290,12 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg,
/* Add a Master_info class to Hash Table */
bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file)
{
- if (!my_hash_insert(&master_info_hash, (uchar*) mi))
+ /*
+ We have to protect against shutdown to ensure we are not calling
+ my_hash_insert() while my_hash_free() is in progress
+ */
+ if (unlikely(shutdown_in_progress) ||
+ !my_hash_insert(&master_info_hash, (uchar*) mi))
{
if (global_system_variables.log_warnings > 1)
sql_print_information("Added new Master_info '%.*s' to hash table",
@@ -1194,105 +1321,131 @@ bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file)
atomic
*/
-bool Master_info_index::remove_master_info(LEX_STRING *name)
+bool Master_info_index::remove_master_info(Master_info *mi)
{
- Master_info* mi;
DBUG_ENTER("remove_master_info");
+ mysql_mutex_assert_owner(&LOCK_active_mi);
- if ((mi= get_master_info(name, Sql_condition::WARN_LEVEL_WARN)))
+ // Delete Master_info and rewrite others to file
+ if (!my_hash_delete(&master_info_hash, (uchar*) mi))
{
- // Delete Master_info and rewrite others to file
- if (!my_hash_delete(&master_info_hash, (uchar*) mi))
+ File index_file_nr;
+
+ // Close IO_CACHE and FILE handler fisrt
+ end_io_cache(&index_file);
+ my_close(index_file.file, MYF(MY_WME));
+
+ // Reopen File and truncate it
+ if ((index_file_nr= my_open(index_file_name,
+ O_RDWR | O_CREAT | O_TRUNC | O_BINARY ,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&index_file, index_file_nr,
+ IO_SIZE, WRITE_CACHE,
+ my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
{
- File index_file_nr;
-
- // Close IO_CACHE and FILE handler fisrt
- end_io_cache(&index_file);
- my_close(index_file.file, MYF(MY_WME));
-
- // Reopen File and truncate it
- if ((index_file_nr= my_open(index_file_name,
- O_RDWR | O_CREAT | O_TRUNC | O_BINARY ,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&index_file, index_file_nr,
- IO_SIZE, WRITE_CACHE,
- my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
- {
- int error= my_errno;
- if (index_file_nr >= 0)
- my_close(index_file_nr,MYF(0));
-
- sql_print_error("Create of Master Info Index file '%s' failed with "
- "error: %M",
- index_file_name, error);
- DBUG_RETURN(TRUE);
- }
+ int error= my_errno;
+ if (index_file_nr >= 0)
+ my_close(index_file_nr,MYF(0));
- // Rewrite Master_info.index
- for (uint i= 0; i< master_info_hash.records; ++i)
- {
- Master_info *tmp_mi;
- tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i);
- write_master_name_to_index_file(&tmp_mi->connection_name, 0);
- }
- my_sync(index_file_nr, MYF(MY_WME));
+ sql_print_error("Create of Master Info Index file '%s' failed with "
+ "error: %M",
+ index_file_name, error);
+ DBUG_RETURN(TRUE);
+ }
+
+ // Rewrite Master_info.index
+ for (uint i= 0; i< master_info_hash.records; ++i)
+ {
+ Master_info *tmp_mi;
+ tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ write_master_name_to_index_file(&tmp_mi->connection_name, 0);
}
+ if (my_sync(index_file_nr, MYF(MY_WME)))
+ DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
/**
- Master_info_index::give_error_if_slave_running()
+ give_error_if_slave_running()
+
+ @param
+ already_locked 0 if we need to lock, 1 if we have LOCK_active_mi_locked
@return
TRUE If some slave is running. An error is printed
FALSE No slave is running
*/
-bool Master_info_index::give_error_if_slave_running()
+bool give_error_if_slave_running(bool already_locked)
{
+ bool ret= 0;
DBUG_ENTER("give_error_if_slave_running");
- mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ if (!already_locked)
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (!master_info_index)
{
- Master_info *mi;
- mi= (Master_info *) my_hash_element(&master_info_hash, i);
- if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
+ my_error(ER_SERVER_SHUTDOWN, MYF(0));
+ ret= 1;
+ }
+ else
+ {
+ HASH *hash= &master_info_index->master_info_hash;
+ for (uint i= 0; i< hash->records; ++i)
{
- my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
- mi->connection_name.str);
- DBUG_RETURN(TRUE);
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(hash, i);
+ if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
+ {
+ my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
+ mi->connection_name.str);
+ ret= 1;
+ break;
+ }
}
}
- DBUG_RETURN(FALSE);
+ if (!already_locked)
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(ret);
}
/**
- Master_info_index::any_slave_sql_running()
-
- The LOCK_active_mi must be held while calling this function.
+ any_slave_sql_running()
@return
0 No Slave SQL thread is running
# Number of slave SQL thread running
+
+ Note that during shutdown we return 1. This is needed to ensure we
+ don't try to resize thread pool during shutdown as during shutdown
+ master_info_hash may be freeing the hash and during that time
+ hash entries can't be accessed.
*/
-uint Master_info_index::any_slave_sql_running()
+uint any_slave_sql_running()
{
uint count= 0;
+ HASH *hash;
DBUG_ENTER("any_slave_sql_running");
- mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (unlikely(shutdown_in_progress || !master_info_index))
+ {
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(1);
+ }
+ hash= &master_info_index->master_info_hash;
+ for (uint i= 0; i< hash->records; ++i)
{
- Master_info *mi= (Master_info *)my_hash_element(&master_info_hash, i);
+ Master_info *mi= (Master_info *)my_hash_element(hash, i);
if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
count++;
}
+ mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(count);
}
@@ -1305,15 +1458,25 @@ uint Master_info_index::any_slave_sql_running()
@return
TRUE Error
FALSE Everything ok.
+
+ This code is written so that we don't keep LOCK_active_mi active
+ while we are starting a slave.
*/
bool Master_info_index::start_all_slaves(THD *thd)
{
bool result= FALSE;
- DBUG_ENTER("warn_if_slave_running");
+ DBUG_ENTER("start_all_slaves");
mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ for (uint i= 0; i< master_info_hash.records; i++)
+ {
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ mi->in_start_all_slaves= 0;
+ }
+
+ for (uint i= 0; i< master_info_hash.records; )
{
int error;
Master_info *mi;
@@ -1323,25 +1486,40 @@ bool Master_info_index::start_all_slaves(THD *thd)
Try to start all slaves that are configured (host is defined)
and are not already running
*/
- if ((mi->slave_running == MYSQL_SLAVE_NOT_RUN ||
- !mi->rli.slave_running) && *mi->host)
+ if (!((mi->slave_running == MYSQL_SLAVE_NOT_RUN ||
+ !mi->rli.slave_running) && *mi->host) ||
+ mi->in_start_all_slaves)
{
- if ((error= start_slave(thd, mi, 1)))
- {
- my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
- "START",
- (int) mi->connection_name.length,
- mi->connection_name.str);
- result= 1;
- if (error < 0) // fatal error
- break;
- }
- else
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SLAVE_STARTED, ER(ER_SLAVE_STARTED),
- (int) mi->connection_name.length,
- mi->connection_name.str);
+ i++;
+ continue;
}
+ mi->in_start_all_slaves= 1;
+
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++; // Mark used
+ mysql_mutex_unlock(&mi->sleep_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ error= start_slave(thd, mi, 1);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (error)
+ {
+ my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
+ "START",
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ result= 1;
+ if (error < 0) // fatal error
+ break;
+ }
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SLAVE_STARTED, ER(ER_SLAVE_STARTED),
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ /* Restart from first element as master_info_hash may have changed */
+ i= 0;
+ continue;
}
DBUG_RETURN(result);
}
@@ -1355,38 +1533,63 @@ bool Master_info_index::start_all_slaves(THD *thd)
@return
TRUE Error
FALSE Everything ok.
+
+ This code is written so that we don't keep LOCK_active_mi active
+ while we are stopping a slave.
*/
bool Master_info_index::stop_all_slaves(THD *thd)
{
bool result= FALSE;
- DBUG_ENTER("warn_if_slave_running");
+ DBUG_ENTER("stop_all_slaves");
mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ for (uint i= 0; i< master_info_hash.records; i++)
+ {
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ mi->in_stop_all_slaves= 0;
+ }
+
+ for (uint i= 0; i< master_info_hash.records ;)
{
int error;
Master_info *mi;
mi= (Master_info *) my_hash_element(&master_info_hash, i);
- if ((mi->slave_running != MYSQL_SLAVE_NOT_RUN ||
- mi->rli.slave_running))
+ if (!(mi->slave_running != MYSQL_SLAVE_NOT_RUN ||
+ mi->rli.slave_running) ||
+ mi->in_stop_all_slaves)
{
- if ((error= stop_slave(thd, mi, 1)))
- {
- my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
- "STOP",
- (int) mi->connection_name.length,
- mi->connection_name.str);
- result= 1;
- if (error < 0) // Fatal error
- break;
- }
- else
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SLAVE_STOPPED, ER(ER_SLAVE_STOPPED),
- (int) mi->connection_name.length,
- mi->connection_name.str);
+ i++;
+ continue;
}
+ mi->in_stop_all_slaves= 1; // Protection for loops
+
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++; // Mark used
+ mysql_mutex_unlock(&mi->sleep_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ error= stop_slave(thd, mi, 1);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (error)
+ {
+ my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
+ "STOP",
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ result= 1;
+ if (error < 0) // Fatal error
+ break;
+ }
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SLAVE_STOPPED, ER(ER_SLAVE_STOPPED),
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ /* Restart from first element as master_info_hash may have changed */
+ i= 0;
+ continue;
}
DBUG_RETURN(result);
}
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index e58df0150f5..5c42378ca2c 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -79,6 +79,10 @@ class Master_info : public Slave_reporting_capability
{
return opt_slave_parallel_threads > 0;
}
+ void release();
+ void wait_until_free();
+ void lock_slave_threads();
+ void unlock_slave_threads();
/* the variables below are needed because we can change masters on the fly */
char master_log_name[FN_REFLEN+6]; /* Room for multi-*/
@@ -97,7 +101,7 @@ class Master_info : public Slave_reporting_capability
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
- mysql_mutex_t data_lock, run_lock, sleep_lock;
+ mysql_mutex_t data_lock, run_lock, sleep_lock, start_stop_lock;
mysql_cond_t data_cond, start_cond, stop_cond, sleep_cond;
THD *io_thd;
MYSQL* mysql;
@@ -182,7 +186,11 @@ class Master_info : public Slave_reporting_capability
uint64 gtid_reconnect_event_skip_count;
/* gtid_event_seen is false until we receive first GTID event from master. */
bool gtid_event_seen;
+ bool in_start_all_slaves, in_stop_all_slaves;
+ uint users; /* Active user for object */
+ uint killed;
};
+
int init_master_info(Master_info* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file,
@@ -218,13 +226,12 @@ public:
bool check_duplicate_master_info(LEX_STRING *connection_name,
const char *host, uint port);
bool add_master_info(Master_info *mi, bool write_to_file);
- bool remove_master_info(LEX_STRING *connection_name);
+ bool remove_master_info(Master_info *mi);
Master_info *get_master_info(LEX_STRING *connection_name,
Sql_condition::enum_warning_level warning);
- bool give_error_if_slave_running();
- uint any_slave_sql_running();
bool start_all_slaves(THD *thd);
bool stop_all_slaves(THD *thd);
+ void free_connections();
};
@@ -237,6 +244,8 @@ public:
};
+Master_info *get_master_info(LEX_STRING *connection_name,
+ Sql_condition::enum_warning_level warning);
bool check_master_connection_name(LEX_STRING *name);
void create_logfile_name_with_suffix(char *res_file_name, size_t length,
const char *info_file,
@@ -246,7 +255,8 @@ void create_logfile_name_with_suffix(char *res_file_name, size_t length,
uchar *get_key_master_info(Master_info *mi, size_t *length,
my_bool not_used __attribute__((unused)));
void free_key_master_info(Master_info *mi);
-
+uint any_slave_sql_running();
+bool give_error_if_slave_running(bool already_lock);
#endif /* HAVE_REPLICATION */
#endif /* RPL_MI_H */
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 23f61a82a90..44f60e4482b 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1253,39 +1253,16 @@ handle_rpl_parallel_thread(void *arg)
*/
rpt->batch_free();
- for (;;)
+ if ((events= rpt->event_queue) != NULL)
{
- if ((events= rpt->event_queue) != NULL)
- {
- /*
- Take next group of events from the replication pool.
- This is faster than having to wakeup the pool manager thread to give
- us a new event.
- */
- rpt->dequeue1(events);
- mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
- goto more_events;
- }
- if (!rpt->pause_for_ftwrl ||
- (in_event_group && !group_rgi->parallel_entry->force_abort))
- break;
/*
- We are currently in the delicate process of pausing parallel
- replication while FLUSH TABLES WITH READ LOCK is starting. We must
- not de-allocate the thread (setting rpt->current_owner= NULL) until
- rpl_unpause_after_ftwrl() has woken us up.
+ Take next group of events from the replication pool.
+ This is faster than having to wakeup the pool manager thread to give
+ us a new event.
*/
- mysql_mutex_lock(&rpt->current_entry->LOCK_parallel_entry);
+ rpt->dequeue1(events);
mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
- if (rpt->pause_for_ftwrl)
- mysql_cond_wait(&rpt->current_entry->COND_parallel_entry,
- &rpt->current_entry->LOCK_parallel_entry);
- mysql_mutex_unlock(&rpt->current_entry->LOCK_parallel_entry);
- mysql_mutex_lock(&rpt->LOCK_rpl_thread);
- /*
- Now loop to check again for more events available, since we released
- and re-aquired the LOCK_rpl_thread mutex.
- */
+ goto more_events;
}
rpt->inuse_relaylog_refcount_update();
@@ -1312,11 +1289,36 @@ handle_rpl_parallel_thread(void *arg)
}
if (!in_event_group)
{
+ /* If we are in a FLUSH TABLES FOR READ LOCK, wait for it */
+ while (rpt->current_entry && rpt->pause_for_ftwrl)
+ {
+ /*
+ We are currently in the delicate process of pausing parallel
+ replication while FLUSH TABLES WITH READ LOCK is starting. We must
+ not de-allocate the thread (setting rpt->current_owner= NULL) until
+ rpl_unpause_after_ftwrl() has woken us up.
+ */
+ rpl_parallel_entry *e= rpt->current_entry;
+ /*
+ Ensure that we will unblock rpl_pause_for_ftrwl()
+ e->pause_sub_id may be LONGLONG_MAX if rpt->current_entry has changed
+ */
+ DBUG_ASSERT(e->pause_sub_id == (uint64)ULONGLONG_MAX ||
+ e->last_committed_sub_id >= e->pause_sub_id);
+ mysql_mutex_lock(&e->LOCK_parallel_entry);
+ mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
+ if (rpt->pause_for_ftwrl)
+ mysql_cond_wait(&e->COND_parallel_entry, &e->LOCK_parallel_entry);
+ mysql_mutex_unlock(&e->LOCK_parallel_entry);
+ mysql_mutex_lock(&rpt->LOCK_rpl_thread);
+ }
+
rpt->current_owner= NULL;
/* Tell wait_for_done() that we are done, if it is waiting. */
if (likely(rpt->current_entry) &&
unlikely(rpt->current_entry->force_abort))
mysql_cond_broadcast(&rpt->COND_rpl_thread_stop);
+
rpt->current_entry= NULL;
if (!rpt->stop)
rpt->pool->release_thread(rpt);
@@ -1355,10 +1357,24 @@ dealloc_gco(group_commit_orderer *gco)
my_free(gco);
}
+/**
+ Change thread count for global parallel worker threads
+
+ @param pool parallel thread pool
+ @param new_count Number of threads to be in pool. 0 in shutdown
+ @param force Force thread count to new_count even if slave
+ threads are running
+
+ By default we don't resize pool of there are running threads.
+ However during shutdown we will always do it.
+ This is needed as any_slave_sql_running() returns 1 during shutdown
+ as we don't want to access master_info while
+ Master_info_index::free_connections are running.
+*/
static int
rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
- uint32 new_count)
+ uint32 new_count, bool force)
{
uint32 i;
rpl_parallel_thread **new_list= NULL;
@@ -1369,6 +1385,28 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
if ((res= pool_mark_busy(pool, current_thd)))
return res;
+ /* Protect against parallel pool resizes */
+ if (pool->count == new_count)
+ {
+ pool_mark_not_busy(pool);
+ return 0;
+ }
+
+ /*
+ If we are about to delete pool, do an extra check that there are no new
+ slave threads running since we marked pool busy
+ */
+ if (!new_count && !force)
+ {
+ if (any_slave_sql_running())
+ {
+ DBUG_PRINT("warning",
+ ("SQL threads running while trying to reset parallel pool"));
+ pool_mark_not_busy(pool);
+ return 0; // Ok to not resize pool
+ }
+ }
+
/*
Allocate the new list of threads up-front.
That way, if we fail half-way, we only need to free whatever we managed
@@ -1382,7 +1420,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
{
my_error(ER_OUTOFMEMORY, MYF(0), (int(new_count*sizeof(*new_list) +
new_count*sizeof(*rpt_array))));
- goto err;;
+ goto err;
}
for (i= 0; i < new_count; ++i)
@@ -1503,12 +1541,26 @@ err:
return 1;
}
+/*
+ Deactivate the parallel replication thread pool, if there are now no more
+ SQL threads running.
+*/
+
+int rpl_parallel_resize_pool_if_no_slaves(void)
+{
+ /* master_info_index is set to NULL on shutdown */
+ if (opt_slave_parallel_threads > 0 && !any_slave_sql_running())
+ return rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
+ return 0;
+}
+
int
rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
{
if (!pool->count)
- return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads);
+ return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads,
+ 0);
return 0;
}
@@ -1516,7 +1568,7 @@ rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
int
rpl_parallel_inactivate_pool(rpl_parallel_thread_pool *pool)
{
- return rpl_parallel_change_thread_count(pool, 0);
+ return rpl_parallel_change_thread_count(pool, 0, 0);
}
@@ -1795,7 +1847,7 @@ rpl_parallel_thread_pool::destroy()
{
if (!inited)
return;
- rpl_parallel_change_thread_count(this, 0);
+ rpl_parallel_change_thread_count(this, 0, 1);
mysql_mutex_destroy(&LOCK_rpl_thread_pool);
mysql_cond_destroy(&COND_rpl_thread_pool);
inited= false;
@@ -1814,6 +1866,7 @@ rpl_parallel_thread_pool::get_thread(rpl_parallel_thread **owner,
{
rpl_parallel_thread *rpt;
+ DBUG_ASSERT(count > 0);
mysql_mutex_lock(&LOCK_rpl_thread_pool);
while (unlikely(busy) || !(rpt= free_list))
mysql_cond_wait(&COND_rpl_thread_pool, &LOCK_rpl_thread_pool);
@@ -2042,6 +2095,11 @@ rpl_parallel::find(uint32 domain_id)
return e;
}
+/**
+ Wait until all sql worker threads has stopped processing
+
+ This is called when sql thread has been killed/stopped
+*/
void
rpl_parallel::wait_for_done(THD *thd, Relay_log_info *rli)
diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h
index a02c1af3b3e..0d7cd4f2e9b 100644
--- a/sql/rpl_parallel.h
+++ b/sql/rpl_parallel.h
@@ -342,6 +342,7 @@ struct rpl_parallel {
extern struct rpl_parallel_thread_pool global_rpl_thread_pool;
+extern int rpl_parallel_resize_pool_if_no_slaves(void);
extern int rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool);
extern int rpl_parallel_inactivate_pool(rpl_parallel_thread_pool *pool);
extern bool process_gtid_for_restart_pos(Relay_log_info *rli, rpl_gtid *gtid);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index c570105cdf6..928fbd3d7c1 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -208,6 +208,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
Master_info* mi= rli->mi;
char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN];
char *buf_relaylog_index_name= opt_relaylog_index_name;
+ mysql_mutex_t *log_lock;
create_logfile_name_with_suffix(buf_relay_logname,
sizeof(buf_relay_logname),
@@ -227,14 +228,18 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
+ log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
if (rli->relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
rli->relay_log.open(ln, LOG_BIN, 0, SEQ_READ_APPEND,
mi->rli.max_relay_log_size, 1, TRUE))
{
+ mysql_mutex_unlock(log_lock);
mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Failed when trying to open logs for '%s' in init_relay_log_info(). Error: %M", ln, my_errno);
DBUG_RETURN(1);
}
+ mysql_mutex_unlock(log_lock);
}
/* if file does not exist */
@@ -432,7 +437,7 @@ Failed to open the existing relay log info file '%s' (errno %d)",
}
rli->inited= 1;
mysql_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
err:
sql_print_error("%s", msg);
@@ -1304,9 +1309,10 @@ bool Relay_log_info::is_until_satisfied(THD *thd, Log_event *ev)
}
-void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
+bool Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
rpl_group_info *rgi)
{
+ int error= 0;
DBUG_ENTER("Relay_log_info::stmt_done");
DBUG_ASSERT(rgi->rli == this);
@@ -1358,10 +1364,11 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
}
DBUG_EXECUTE_IF("inject_crash_before_flush_rli", DBUG_SUICIDE(););
if (mi->using_gtid == Master_info::USE_GTID_NO)
- flush_relay_log_info(this);
+ if (flush_relay_log_info(this))
+ error= 1;
DBUG_EXECUTE_IF("inject_crash_after_flush_rli", DBUG_SUICIDE(););
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index efcec83b880..7fc41786957 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -416,7 +416,7 @@ public:
relay log info and used to produce information for <code>SHOW
SLAVE STATUS</code>.
*/
- void stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi);
+ bool stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi);
int alloc_inuse_relaylog(const char *name);
void free_inuse_relaylog(inuse_relaylog *ir);
void reset_inuse_relaylog();
diff --git a/sql/slave.cc b/sql/slave.cc
index ae335a24811..694e9a2e673 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -231,16 +231,14 @@ void init_thread_mask(int* mask,Master_info* mi,bool inverse)
/*
- lock_slave_threads()
+ lock_slave_threads() against other threads doing STOP, START or RESET SLAVE
+
*/
-void lock_slave_threads(Master_info* mi)
+void Master_info::lock_slave_threads()
{
DBUG_ENTER("lock_slave_threads");
-
- //TODO: see if we can do this without dual mutex
- mysql_mutex_lock(&mi->run_lock);
- mysql_mutex_lock(&mi->rli.run_lock);
+ mysql_mutex_lock(&start_stop_lock);
DBUG_VOID_RETURN;
}
@@ -249,13 +247,10 @@ void lock_slave_threads(Master_info* mi)
unlock_slave_threads()
*/
-void unlock_slave_threads(Master_info* mi)
+void Master_info::unlock_slave_threads()
{
DBUG_ENTER("unlock_slave_threads");
-
- //TODO: see if we can do this without dual mutex
- mysql_mutex_unlock(&mi->rli.run_lock);
- mysql_mutex_unlock(&mi->run_lock);
+ mysql_mutex_unlock(&start_stop_lock);
DBUG_VOID_RETURN;
}
@@ -377,7 +372,6 @@ int init_slave()
accepted. However bootstrap may conflict with us if it does START SLAVE.
So it's safer to take the lock.
*/
- mysql_mutex_lock(&LOCK_active_mi);
if (pthread_key_create(&RPL_MASTER_INFO, NULL))
goto err;
@@ -386,7 +380,6 @@ int init_slave()
if (!master_info_index || master_info_index->init_all_master_info())
{
sql_print_error("Failed to initialize multi master structures");
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(1);
}
if (!(active_mi= new Master_info(&default_master_connection_name,
@@ -444,7 +437,6 @@ int init_slave()
}
end:
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(error);
err:
@@ -617,6 +609,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
if (!mi->inited)
DBUG_RETURN(0); /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
+ int retval= 0;
mysql_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
mysql_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
@@ -636,24 +629,19 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+ retval= error;
mysql_mutex_lock(log_lock);
DBUG_PRINT("info",("Flushing relay-log info file."));
if (current_thd)
THD_STAGE_INFO(current_thd, stage_flushing_relay_log_info_file);
- if (flush_relay_log_info(&mi->rli))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
- if (my_sync(mi->rli.info_fd, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+ if (flush_relay_log_info(&mi->rli) ||
+ my_sync(mi->rli.info_fd, MYF(MY_WME)))
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
mysql_mutex_unlock(log_lock);
}
- if (opt_slave_parallel_threads > 0 &&
- master_info_index &&// master_info_index is set to NULL on server shutdown
- !master_info_index->any_slave_sql_running())
- rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL))
{
DBUG_PRINT("info",("Terminating IO thread"));
@@ -664,25 +652,26 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+ if (!retval)
+ retval= error;
mysql_mutex_lock(log_lock);
DBUG_PRINT("info",("Flushing relay log and master info file."));
if (current_thd)
THD_STAGE_INFO(current_thd, stage_flushing_relay_log_and_master_info_repository);
- if (flush_master_info(mi, TRUE, FALSE))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
+ if (likely(mi->fd >= 0))
+ {
+ if (flush_master_info(mi, TRUE, FALSE) || my_sync(mi->fd, MYF(MY_WME)))
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
+ }
if (mi->rli.relay_log.is_open() &&
my_sync(mi->rli.relay_log.get_log_file()->file, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
- if (my_sync(mi->fd, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
mysql_mutex_unlock(log_lock);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(retval);
}
@@ -845,6 +834,15 @@ int start_slave_thread(
mysql_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_THREAD);
}
+
+ /*
+ In the following loop we can't check for thd->killed as we have to
+ wait until THD structures for the slave thread are created
+ before we can return.
+ This should be ok as there is no major work done in the slave
+ threads before they signal that we can stop waiting.
+ */
+
if (start_cond && cond_lock) // caller has cond_lock
{
THD* thd = current_thd;
@@ -862,16 +860,9 @@ int start_slave_thread(
registered, we could otherwise go waiting though thd->killed is
set.
*/
- if (!thd->killed)
- mysql_cond_wait(start_cond, cond_lock);
+ mysql_cond_wait(start_cond, cond_lock);
thd->EXIT_COND(& saved_stage);
mysql_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
- if (thd->killed)
- {
- if (start_lock)
- mysql_mutex_unlock(start_lock);
- DBUG_RETURN(thd->killed_errno());
- }
}
}
if (start_lock)
@@ -959,10 +950,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
mi);
if (!error && (thread_mask & SLAVE_SQL))
{
- if (opt_slave_parallel_threads > 0)
- error= rpl_parallel_activate_pool(&global_rpl_thread_pool);
- if (!error)
- error= start_slave_thread(
+ error= start_slave_thread(
#ifdef HAVE_PSI_INTERFACE
key_thread_slave_sql,
#endif
@@ -978,10 +966,18 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
/*
- Release slave threads at time of executing shutdown.
+ Kill slaves preparing for shutdown
+*/
- SYNOPSIS
- end_slave()
+void slave_prepare_for_shutdown()
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ master_info_index->free_connections();
+ mysql_mutex_unlock(&LOCK_active_mi);
+}
+
+/*
+ Release slave threads at time of executing shutdown.
*/
void end_slave()
@@ -999,7 +995,10 @@ void end_slave()
startup parameter to the server was wrong.
*/
mysql_mutex_lock(&LOCK_active_mi);
- /* This will call terminate_slave_threads() on all connections */
+ /*
+ master_info_index should not have any threads anymore as they where
+ killed as part of slave_prepare_for_shutdown()
+ */
delete master_info_index;
master_info_index= 0;
active_mi= 0;
@@ -2663,7 +2662,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
mysql_mutex_lock(&mi->data_lock);
mysql_mutex_lock(&mi->rli.data_lock);
+ /* err_lock is to protect mi->last_error() */
mysql_mutex_lock(&mi->err_lock);
+ /* err_lock is to protect mi->rli.last_error() */
mysql_mutex_lock(&mi->rli.err_lock);
protocol->store(mi->host, &my_charset_bin);
protocol->store(mi->user, &my_charset_bin);
@@ -4532,6 +4533,16 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
pthread_detach_this_thread();
+
+ if (opt_slave_parallel_threads > 0 &&
+ rpl_parallel_activate_pool(&global_rpl_thread_pool))
+ {
+ mysql_cond_broadcast(&rli->start_cond);
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
+ "Failed during parallel slave pool activation");
+ goto err_during_init;
+ }
+
if (init_slave_thread(thd, mi, SLAVE_THD_SQL))
{
/*
@@ -4840,8 +4851,15 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME,
if (rli->mi->using_gtid != Master_info::USE_GTID_NO)
{
ulong domain_count;
+ my_bool save_log_all_errors= thd->log_all_errors;
+ /*
+ We don't need to check return value for flush_relay_log_info()
+ as any errors should be logged to stderr
+ */
+ thd->log_all_errors= 1;
flush_relay_log_info(rli);
+ thd->log_all_errors= save_log_all_errors;
if (mi->using_parallel())
{
/*
@@ -4950,17 +4968,7 @@ err_during_init:
DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
mysql_mutex_unlock(&rli->run_lock); // tell the world we are done
- /*
- Deactivate the parallel replication thread pool, if there are now no more
- SQL threads running. Do this here, when we have released all locks, but
- while our THD (and current_thd) is still valid.
- */
- mysql_mutex_lock(&LOCK_active_mi);
- if (opt_slave_parallel_threads > 0 &&
- master_info_index &&// master_info_index is set to NULL on server shutdown
- !master_info_index->any_slave_sql_running())
- rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
- mysql_mutex_unlock(&LOCK_active_mi);
+ rpl_parallel_resize_pool_if_no_slaves();
mysql_mutex_lock(&LOCK_thread_count);
delete thd;
@@ -6070,6 +6078,7 @@ err:
void end_relay_log_info(Relay_log_info* rli)
{
+ mysql_mutex_t *log_lock;
DBUG_ENTER("end_relay_log_info");
if (!rli->inited)
@@ -6087,8 +6096,11 @@ void end_relay_log_info(Relay_log_info* rli)
rli->cur_log_fd = -1;
}
rli->inited = 0;
+ log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
+ mysql_mutex_unlock(log_lock);
/*
Delete the slave's temporary tables from memory.
In the future there will be other actions than this, to ensure persistance
@@ -6240,7 +6252,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,
suppress_warnings= 0;
mi->report(ERROR_LEVEL, last_errno, NULL,
"error %s to master '%s@%s:%d'"
- " - retry-time: %d retries: %lu message: %s",
+ " - retry-time: %d maximum-retries: %lu message: %s",
(reconnect ? "reconnecting" : "connecting"),
mi->user, mi->host, mi->port,
mi->connect_retry, master_retry_count,
@@ -6804,9 +6816,12 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
}
rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake_buf(rli->event_relay_log_name,rli->linfo.log_file_name);
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ {
+ errmsg= "error flushing relay log";
+ goto err;
+ }
}
-
/*
Now we want to open this next log. To know if it's a hot log (the one
being written by the I/O thread now) or a cold log, we can use
diff --git a/sql/slave.h b/sql/slave.h
index c6b78b96aca..abcb4df984b 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -213,13 +213,12 @@ bool rpl_master_erroneous_autoinc(THD* thd);
const char *print_slave_db_safe(const char *db);
void skip_load_data_infile(NET* net);
+void slave_prepare_for_shutdown();
void end_slave(); /* release slave threads */
void close_active_mi(); /* clean up slave threads data */
void clear_until_condition(Relay_log_info* rli);
void clear_slave_error(Relay_log_info* rli);
void end_relay_log_info(Relay_log_info* rli);
-void lock_slave_threads(Master_info* mi);
-void unlock_slave_threads(Master_info* mi);
void init_thread_mask(int* mask,Master_info* mi,bool inverse);
Format_description_log_event *
read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos,
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index be8b0c5a022..d4b23a9fbc2 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8975,13 +8975,13 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
case USER_ACL:
acl_user->user.str= strdup_root(&acl_memroot, user_to->user.str);
acl_user->user.length= user_to->user.length;
- acl_user->host.hostname= strdup_root(&acl_memroot, user_to->host.str);
- acl_user->hostname_length= user_to->host.length;
+ update_hostname(&acl_user->host, strdup_root(&acl_memroot, user_to->host.str));
+ acl_user->hostname_length= strlen(acl_user->host.hostname);
break;
case DB_ACL:
acl_db->user= strdup_root(&acl_memroot, user_to->user.str);
- acl_db->host.hostname= strdup_root(&acl_memroot, user_to->host.str);
+ update_hostname(&acl_db->host, strdup_root(&acl_memroot, user_to->host.str));
break;
case COLUMN_PRIVILEGES_HASH:
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 526442e83e2..7114694124b 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -70,59 +70,56 @@ public:
// Set for DISABLE KEYS | ENABLE KEYS
static const uint ALTER_KEYS_ONOFF = 1L << 9;
- // Set for CONVERT TO CHARACTER SET
- static const uint ALTER_CONVERT = 1L << 10;
-
// Set for FORCE
// Set for ENGINE(same engine)
// Set by mysql_recreate_table()
- static const uint ALTER_RECREATE = 1L << 11;
+ static const uint ALTER_RECREATE = 1L << 10;
// Set for ADD PARTITION
- static const uint ALTER_ADD_PARTITION = 1L << 12;
+ static const uint ALTER_ADD_PARTITION = 1L << 11;
// Set for DROP PARTITION
- static const uint ALTER_DROP_PARTITION = 1L << 13;
+ static const uint ALTER_DROP_PARTITION = 1L << 12;
// Set for COALESCE PARTITION
- static const uint ALTER_COALESCE_PARTITION = 1L << 14;
+ static const uint ALTER_COALESCE_PARTITION = 1L << 13;
// Set for REORGANIZE PARTITION ... INTO
- static const uint ALTER_REORGANIZE_PARTITION = 1L << 15;
+ static const uint ALTER_REORGANIZE_PARTITION = 1L << 14;
// Set for partition_options
- static const uint ALTER_PARTITION = 1L << 16;
+ static const uint ALTER_PARTITION = 1L << 15;
// Set for LOAD INDEX INTO CACHE ... PARTITION
// Set for CACHE INDEX ... PARTITION
- static const uint ALTER_ADMIN_PARTITION = 1L << 17;
+ static const uint ALTER_ADMIN_PARTITION = 1L << 16;
// Set for REORGANIZE PARTITION
- static const uint ALTER_TABLE_REORG = 1L << 18;
+ static const uint ALTER_TABLE_REORG = 1L << 17;
// Set for REBUILD PARTITION
- static const uint ALTER_REBUILD_PARTITION = 1L << 19;
+ static const uint ALTER_REBUILD_PARTITION = 1L << 18;
// Set for partitioning operations specifying ALL keyword
- static const uint ALTER_ALL_PARTITION = 1L << 20;
+ static const uint ALTER_ALL_PARTITION = 1L << 19;
// Set for REMOVE PARTITIONING
- static const uint ALTER_REMOVE_PARTITIONING = 1L << 21;
+ static const uint ALTER_REMOVE_PARTITIONING = 1L << 20;
// Set for ADD FOREIGN KEY
- static const uint ADD_FOREIGN_KEY = 1L << 22;
+ static const uint ADD_FOREIGN_KEY = 1L << 21;
// Set for DROP FOREIGN KEY
- static const uint DROP_FOREIGN_KEY = 1L << 23;
+ static const uint DROP_FOREIGN_KEY = 1L << 22;
// Set for EXCHANGE PARITION
- static const uint ALTER_EXCHANGE_PARTITION = 1L << 24;
+ static const uint ALTER_EXCHANGE_PARTITION = 1L << 23;
// Set by Sql_cmd_alter_table_truncate_partition::execute()
- static const uint ALTER_TRUNCATE_PARTITION = 1L << 25;
+ static const uint ALTER_TRUNCATE_PARTITION = 1L << 24;
// Set for ADD [COLUMN] FIRST | AFTER
- static const uint ALTER_COLUMN_ORDER = 1L << 26;
+ static const uint ALTER_COLUMN_ORDER = 1L << 25;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index efe9ac6f7f4..2c7f3147901 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -6672,7 +6672,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
if (!table_ref->belong_to_view &&
!table_ref->belong_to_derived)
{
- SELECT_LEX *current_sel= thd->lex->current_select;
+ SELECT_LEX *current_sel= item->context->select_lex;
SELECT_LEX *last_select= table_ref->select_lex;
bool all_merged= TRUE;
for (SELECT_LEX *sl= current_sel; sl && sl!=last_select;
@@ -8758,9 +8758,7 @@ fill_record(THD * thd, TABLE *table_arg, List<Item> &fields, List<Item> &values,
/* Update virtual fields*/
thd->abort_on_warning= FALSE;
if (vcol_table && vcol_table->vfield &&
- update_virtual_fields(thd, vcol_table,
- vcol_table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_WRITE))
+ update_virtual_fields(thd, vcol_table, VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= save_abort_on_warning;
thd->no_errors= save_no_errors;
@@ -8821,9 +8819,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, List<Item> &fields,
if (item_field && item_field->field && table && table->vfield)
{
DBUG_ASSERT(table == item_field->field->table);
- result= update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_WRITE);
+ result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE);
}
}
}
@@ -8908,9 +8904,7 @@ fill_record(THD *thd, TABLE *table, Field **ptr, List<Item> &values,
/* Update virtual fields*/
thd->abort_on_warning= FALSE;
if (table->vfield &&
- update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_WRITE))
+ update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE))
goto err;
thd->abort_on_warning= abort_on_warning_saved;
DBUG_RETURN(thd->is_error());
@@ -8961,9 +8955,7 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, Field **ptr,
{
DBUG_ASSERT(table == (*ptr)->table);
if (table->vfield)
- result= update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_WRITE);
+ result= update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE);
}
return result;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index b210a4d32dc..57c228900fe 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -1272,7 +1272,6 @@ THD::THD()
m_internal_handler= NULL;
m_binlog_invoker= INVOKER_NONE;
- arena_for_cached_items= 0;
memset(&invoker_user, 0, sizeof(invoker_user));
memset(&invoker_host, 0, sizeof(invoker_host));
prepare_derived_at_open= FALSE;
@@ -6849,7 +6848,13 @@ wait_for_commit::reinit()
So in this case, do a re-init of the mutex. In release builds, we want to
avoid the overhead of a re-init though.
+
+ To ensure that no one is locking the mutex, we take a lock of it first.
+ For full explanation, see wait_for_commit::~wait_for_commit()
*/
+ mysql_mutex_lock(&LOCK_wait_commit);
+ mysql_mutex_unlock(&LOCK_wait_commit);
+
mysql_mutex_destroy(&LOCK_wait_commit);
mysql_mutex_init(key_LOCK_wait_commit, &LOCK_wait_commit, MY_MUTEX_INIT_FAST);
#endif
diff --git a/sql/sql_class.h b/sql/sql_class.h
index aed75d94972..beef22a8140 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3702,26 +3702,7 @@ public:
}
}
-private:
- /*
- This reference points to the table arena when the expression
- for a virtual column is being evaluated
- */
- Query_arena *arena_for_cached_items;
-
public:
- void reset_arena_for_cached_items(Query_arena *new_arena)
- {
- arena_for_cached_items= new_arena;
- }
- Query_arena *switch_to_arena_for_cached_items(Query_arena *backup)
- {
- if (!arena_for_cached_items)
- return 0;
- set_n_backup_active_arena(arena_for_cached_items, backup);
- return backup;
- }
-
void clear_wakeup_ready() { wakeup_ready= false; }
/*
Sleep waiting for others to wake us up with signal_wakeup_ready().
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 0a3ff64113f..3f43a33ab7c 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -815,7 +815,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if there exists a table with the name 'db', so let's just do it
separately. We know this file exists and needs to be deleted anyway.
*/
- if (my_delete_with_symlink(path, MYF(0)) && my_errno != ENOENT)
+ if (my_handler_delete_with_symlink(key_file_misc, path, "", MYF(0)) &&
+ my_errno != ENOENT)
{
my_error(EE_DELETE, MYF(0), path, my_errno);
DBUG_RETURN(true);
@@ -1116,9 +1117,9 @@ static bool find_db_tables_and_rm_known_files(THD *thd, MY_DIR *dirp,
strxmov(filePath, path, "/", file->name, NullS);
/*
We ignore ENOENT error in order to skip files that was deleted
- by concurrently running statement like REAPIR TABLE ...
+ by concurrently running statement like REPAIR TABLE ...
*/
- if (my_delete_with_symlink(filePath, MYF(0)) &&
+ if (my_handler_delete_with_symlink(key_file_misc, filePath, "", MYF(0)) &&
my_errno != ENOENT)
{
my_error(EE_DELETE, MYF(0), filePath, my_errno);
@@ -1234,7 +1235,7 @@ long mysql_rm_arc_files(THD *thd, MY_DIR *dirp, const char *org_path)
continue;
}
strxmov(filePath, org_path, "/", file->name, NullS);
- if (mysql_file_delete_with_symlink(key_file_misc, filePath, MYF(MY_WME)))
+ if (my_handler_delete_with_symlink(key_file_misc, filePath, "", MYF(MY_WME)))
{
goto err;
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 9ac7e64ec23..ad5bc23a31b 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -548,9 +548,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
! thd->is_error())
{
if (table->vfield)
- update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_READ);
+ update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
// thd->is_error() is tested to disallow delete row on error
if (!select || select->skip_record(thd) > 0)
@@ -1309,4 +1307,3 @@ bool multi_delete::send_eof()
}
return 0;
}
-
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index f2674cb8dab..af5b016df9d 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -447,6 +447,9 @@ bool mysql_derived_merge(THD *thd, LEX *lex, TABLE_LIST *derived)
{
Item *expr= derived->on_expr;
expr= and_conds(expr, dt_select->join ? dt_select->join->conds : 0);
+ if (expr)
+ expr->top_level_item();
+
if (expr && (derived->prep_on_expr || expr != derived->on_expr))
{
derived->on_expr= expr;
diff --git a/sql/sql_join_cache.cc b/sql/sql_join_cache.cc
index f701c424f63..7584b42c904 100644
--- a/sql/sql_join_cache.cc
+++ b/sql/sql_join_cache.cc
@@ -589,6 +589,11 @@ void JOIN_CACHE::create_remaining_fields()
{
MY_BITMAP *rem_field_set;
TABLE *table= tab->table;
+#if MYSQL_VERSION_ID < 100204
+ empty_record(table);
+#else
+#error remove
+#endif
if (all_read_fields)
rem_field_set= table->read_set;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index c906a941867..3db0f37974a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2119,12 +2119,12 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
#endif
case SCH_COLUMNS:
case SCH_STATISTICS:
- {
#ifdef DONT_ALLOW_SHOW_COMMANDS
my_message(ER_NOT_ALLOWED_COMMAND,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
+ {
DBUG_ASSERT(table_ident);
TABLE_LIST **query_tables_last= lex->query_tables_last;
schema_select_lex= new SELECT_LEX();
@@ -2424,7 +2424,7 @@ static bool wsrep_is_show_query(enum enum_sql_command command)
int
mysql_execute_command(THD *thd)
{
- int res= FALSE;
+ int res= 0;
int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
@@ -2983,10 +2983,17 @@ case SQLCOM_PREPARE:
if (check_global_access(thd, SUPER_ACL))
goto error;
+ /*
+ In this code it's ok to use LOCK_active_mi as we are adding new things
+ into master_info_index
+ */
mysql_mutex_lock(&LOCK_active_mi);
-
if (!master_info_index)
+ {
+ mysql_mutex_unlock(&LOCK_active_mi);
+ my_error(ER_SERVER_SHUTDOWN, MYF(0));
goto error;
+ }
mi= master_info_index->get_master_info(&lex_mi->connection_name,
Sql_condition::WARN_LEVEL_NOTE);
@@ -3015,7 +3022,7 @@ case SQLCOM_PREPARE:
If new master was not added, we still need to free mi.
*/
if (master_info_added)
- master_info_index->remove_master_info(&lex_mi->connection_name);
+ master_info_index->remove_master_info(mi);
else
delete mi;
}
@@ -3033,22 +3040,24 @@ case SQLCOM_PREPARE:
/* Accept one of two privileges */
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
- mysql_mutex_lock(&LOCK_active_mi);
if (lex->verbose)
+ {
+ mysql_mutex_lock(&LOCK_active_mi);
res= show_all_master_info(thd);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
else
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
Master_info *mi;
- mi= master_info_index->get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR);
- if (mi != NULL)
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
res= show_master_info(thd, mi, 0);
+ mi->release();
}
}
- mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SHOW_MASTER_STAT:
@@ -3383,22 +3392,23 @@ end_with_restore_list:
load_error= rpl_load_gtid_slave_state(thd);
- mysql_mutex_lock(&LOCK_active_mi);
-
- if ((mi= (master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
+ /*
+ We don't need to ensure that only one user is using master_info
+ as start_slave is protected against simultaneous usage
+ */
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
if (load_error)
{
/*
- We cannot start a slave using GTID if we cannot load the GTID position
- from the mysql.gtid_slave_pos table. But we can allow non-GTID
- replication (useful eg. during upgrade).
+ We cannot start a slave using GTID if we cannot load the
+ GTID position from the mysql.gtid_slave_pos table. But we
+ can allow non-GTID replication (useful eg. during upgrade).
*/
if (mi->using_gtid != Master_info::USE_GTID_NO)
{
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
break;
}
else
@@ -3406,8 +3416,8 @@ end_with_restore_list:
}
if (!start_slave(thd, mi, 1 /* net report*/))
my_ok(thd);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SLAVE_STOP:
@@ -3437,13 +3447,17 @@ end_with_restore_list:
}
lex_mi= &thd->lex->mi;
- mysql_mutex_lock(&LOCK_active_mi);
- if ((mi= (master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
- if (!stop_slave(thd, mi, 1/* net report*/))
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
+ {
+ if (stop_slave(thd, mi, 1/* net report*/))
+ res= 1;
+ mi->release();
+ if (rpl_parallel_resize_pool_if_no_slaves())
+ res= 1;
+ if (!res)
my_ok(thd);
- mysql_mutex_unlock(&LOCK_active_mi);
+ }
break;
}
case SQLCOM_SLAVE_ALL_START:
@@ -4744,11 +4758,13 @@ end_with_restore_list:
reload_acl_and_cache binlog interactions failed
*/
res= 1;
- }
+ }
if (!res)
my_ok(thd);
}
+ else
+ res= 1; // reload_acl_and_cache failed
#ifdef HAVE_REPLICATION
if (lex->type & REFRESH_READ_LOCK)
rpl_unpause_after_ftwrl(thd);
@@ -7123,7 +7139,7 @@ static void wsrep_mysql_parse(THD *thd, char *rawbuf, uint length,
#endif /* WITH_WSREP */
/*
- When you modify mysql_parse(), you may need to mofify
+ When you modify mysql_parse(), you may need to modify
mysql_test_parse_for_slave() in this same file.
*/
@@ -9113,48 +9129,24 @@ bool check_ident_length(LEX_STRING *ident)
}
-C_MODE_START
-
/*
Check if path does not contain mysql data home directory
SYNOPSIS
- test_if_data_home_dir()
- dir directory
+ path_starts_from_data_home_dir()
+ dir directory, with all symlinks resolved
RETURN VALUES
0 ok
1 error ; Given path contains data directory
*/
+extern "C" {
-int test_if_data_home_dir(const char *dir)
+int path_starts_from_data_home_dir(const char *path)
{
- char path[FN_REFLEN];
- int dir_len;
- DBUG_ENTER("test_if_data_home_dir");
-
- if (!dir)
- DBUG_RETURN(0);
+ int dir_len= strlen(path);
+ DBUG_ENTER("path_starts_from_data_home_dir");
- /*
- data_file_name and index_file_name include the table name without
- extension. Mostly this does not refer to an existing file. When
- comparing data_file_name or index_file_name against the data
- directory, we try to resolve all symbolic links. On some systems,
- we use realpath(3) for the resolution. This returns ENOENT if the
- resolved path does not refer to an existing file. my_realpath()
- does then copy the requested path verbatim, without symlink
- resolution. Thereafter the comparison can fail even if the
- requested path is within the data directory. E.g. if symlinks to
- another file system are used. To make realpath(3) return the
- resolved path, we strip the table name and compare the directory
- path only. If the directory doesn't exist either, table creation
- will fail anyway.
- */
-
- (void) fn_format(path, dir, "", "",
- (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS));
- dir_len= strlen(path);
if (mysql_unpacked_real_data_home_len<= dir_len)
{
if (dir_len > mysql_unpacked_real_data_home_len &&
@@ -9182,7 +9174,31 @@ int test_if_data_home_dir(const char *dir)
DBUG_RETURN(0);
}
-C_MODE_END
+}
+
+/*
+ Check if path does not contain mysql data home directory
+
+ SYNOPSIS
+ test_if_data_home_dir()
+ dir directory
+
+ RETURN VALUES
+ 0 ok
+ 1 error ; Given path contains data directory
+*/
+
+int test_if_data_home_dir(const char *dir)
+{
+ char path[FN_REFLEN];
+ DBUG_ENTER("test_if_data_home_dir");
+
+ if (!dir)
+ DBUG_RETURN(0);
+
+ (void) fn_format(path, dir, "", "", MY_RETURN_REAL_PATH);
+ DBUG_RETURN(path_starts_from_data_home_dir(path));
+}
int error_if_data_home_dir(const char *path, const char *what)
diff --git a/sql/sql_parse.h b/sql/sql_parse.h
index 0e60a5cc884..368bba91c20 100644
--- a/sql/sql_parse.h
+++ b/sql/sql_parse.h
@@ -33,7 +33,8 @@ enum enum_mysql_completiontype {
COMMIT_RELEASE=-1, COMMIT=0, COMMIT_AND_CHAIN=6
};
-extern "C" int test_if_data_home_dir(const char *dir);
+extern "C" int path_starts_from_data_home_dir(const char *dir);
+int test_if_data_home_dir(const char *dir);
int error_if_data_home_dir(const char *path, const char *what);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index a83e91680da..704e2f84437 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -181,24 +181,20 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
slave is not likely to have the same connection names.
*/
tmp_write_to_binlog= 0;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if (!(mi= (get_master_info(&connection_name,
+ Sql_condition::WARN_LEVEL_ERROR))))
{
- if (!(mi= (master_info_index->
- get_master_info(&connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
- {
- result= 1;
- }
- else
- {
- mysql_mutex_lock(&mi->data_lock);
- if (rotate_relay_log(mi))
- *write_to_binlog= -1;
- mysql_mutex_unlock(&mi->data_lock);
- }
+ result= 1;
+ }
+ else
+ {
+ mysql_mutex_lock(&mi->data_lock);
+ if (rotate_relay_log(mi))
+ *write_to_binlog= -1;
+ mysql_mutex_unlock(&mi->data_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
#endif
}
#ifdef HAVE_QUERY_CACHE
@@ -377,27 +373,33 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
Master_info *mi;
tmp_write_to_binlog= 0;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if (!(mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
- if (!(mi= (master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
- {
- result= 1;
- }
- else if (reset_slave(thd, mi))
+ result= 1;
+ }
+ else
+ {
+ /* The following will fail if slave is running */
+ if (reset_slave(thd, mi))
{
+ mi->release();
/* NOTE: my_error() has been already called by reset_slave(). */
result= 1;
}
else if (mi->connection_name.length && thd->lex->reset_slave_info.all)
{
/* If not default connection and 'all' is used */
- master_info_index->remove_master_info(&mi->connection_name);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (master_info_index->remove_master_info(mi))
+ result= 1;
+ mysql_mutex_unlock(&LOCK_active_mi);
}
+ else
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
}
#endif
if (options & REFRESH_USER_RESOURCES)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 4ee55b59c11..ece137aa380 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -2833,7 +2833,16 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
relay_log_info_file, 0,
&mi->cmp_connection_name);
- lock_slave_threads(mi); // this allows us to cleanly read slave_running
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(-1);
+ }
+
// Get a mask of _stopped_ threads
init_thread_mask(&thread_mask,mi,1 /* inverse */);
@@ -2968,7 +2977,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
ER(ER_UNTIL_COND_IGNORED));
if (!slave_errno)
- slave_errno = start_slave_threads(0 /*no mutex */,
+ slave_errno = start_slave_threads(1,
1 /* wait for start */,
mi,
master_info_file_tmp,
@@ -2984,7 +2993,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
}
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
#ifdef WITH_WSREP
if (WSREP(thd))
@@ -3033,8 +3042,12 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
DBUG_RETURN(-1);
THD_STAGE_INFO(thd, stage_killing_slave);
int thread_mask;
- lock_slave_threads(mi);
- // Get a mask of _running_ threads
+ mi->lock_slave_threads();
+ /*
+ Get a mask of _running_ threads.
+ We don't have to test for mi->killed as the thread_mask will take care
+ of checking if threads exists
+ */
init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
/*
Below we will stop all running threads.
@@ -3047,8 +3060,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
if (thread_mask)
{
- slave_errno= terminate_slave_threads(mi,thread_mask,
- 1 /*skip lock */);
+ slave_errno= terminate_slave_threads(mi,thread_mask, 0 /* get lock */);
}
else
{
@@ -3057,7 +3069,8 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_SLAVE_WAS_NOT_RUNNING,
ER(ER_SLAVE_WAS_NOT_RUNNING));
}
- unlock_slave_threads(mi);
+
+ mi->unlock_slave_threads();
if (slave_errno)
{
@@ -3092,11 +3105,20 @@ int reset_slave(THD *thd, Master_info* mi)
char relay_log_info_file_tmp[FN_REFLEN];
DBUG_ENTER("reset_slave");
- lock_slave_threads(mi);
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(-1);
+ }
+
init_thread_mask(&thread_mask,mi,0 /* not inverse */);
if (thread_mask) // We refuse if any slave thread is running
{
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
mi->connection_name.str);
DBUG_RETURN(ER_SLAVE_MUST_STOP);
@@ -3161,7 +3183,7 @@ int reset_slave(THD *thd, Master_info* mi)
RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi));
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
if (error)
my_error(sql_errno, MYF(0), errmsg);
DBUG_RETURN(error);
@@ -3274,8 +3296,8 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
DBUG_ENTER("change_master");
- mysql_mutex_assert_owner(&LOCK_active_mi);
DBUG_ASSERT(master_info_index);
+ mysql_mutex_assert_owner(&LOCK_active_mi);
*master_info_added= false;
/*
@@ -3295,7 +3317,16 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
lex_mi->port))
DBUG_RETURN(TRUE);
- lock_slave_threads(mi);
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(TRUE);
+ }
+
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
if (thread_mask) // We refuse if any slave thread is running
{
@@ -3597,12 +3628,13 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
in-memory value at restart (thus causing errors, as the old relay log does
not exist anymore).
*/
- flush_relay_log_info(&mi->rli);
+ if (flush_relay_log_info(&mi->rli))
+ ret= 1;
mysql_cond_broadcast(&mi->data_cond);
mysql_mutex_unlock(&mi->rli.data_lock);
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
if (ret == FALSE)
my_ok(thd);
DBUG_RETURN(ret);
@@ -3655,7 +3687,6 @@ bool mysql_show_binlog_events(THD* thd)
int old_max_allowed_packet= thd->variables.max_allowed_packet;
Master_info *mi= 0;
LOG_INFO linfo;
-
DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
@@ -3683,13 +3714,9 @@ bool mysql_show_binlog_events(THD* thd)
}
else /* showing relay log contents */
{
- mysql_mutex_lock(&LOCK_active_mi);
- if (!master_info_index ||
- !(mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_ERROR)))
+ if (!(mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(TRUE);
}
binary_log= &(mi->rli.relay_log);
@@ -3709,7 +3736,7 @@ bool mysql_show_binlog_events(THD* thd)
if (mi)
{
/* We can unlock the mutex as we have a lock on the file */
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
mi= 0;
}
@@ -3731,6 +3758,7 @@ bool mysql_show_binlog_events(THD* thd)
goto err;
}
+ /* These locks is here to enable syncronization with log_in_use() */
mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = &linfo;
mysql_mutex_unlock(&LOCK_thread_count);
@@ -3808,7 +3836,7 @@ bool mysql_show_binlog_events(THD* thd)
mysql_mutex_unlock(log_lock);
}
else if (mi)
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
// Check that linfo is still on the function scope.
DEBUG_SYNC(thd, "after_show_binlog_events");
@@ -3829,8 +3857,9 @@ err:
else
my_eof(thd);
+ /* These locks is here to enable syncronization with log_in_use() */
mysql_mutex_lock(&LOCK_thread_count);
- thd->current_linfo = 0;
+ thd->current_linfo= 0;
mysql_mutex_unlock(&LOCK_thread_count);
thd->variables.max_allowed_packet= old_max_allowed_packet;
DBUG_RETURN(ret);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 7850c7a0dcf..d459d0b88bf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -8510,8 +8510,6 @@ get_best_combination(JOIN *join)
form=join->table[tablenr]=j->table;
used_tables|= form->map;
form->reginfo.join_tab=j;
- if (!*j->on_expr_ref)
- form->reginfo.not_exists_optimize=0; // Only with LEFT JOIN
DBUG_PRINT("info",("type: %d", j->type));
if (j->type == JT_CONST)
goto loop_end; // Handled in make_join_stat..
@@ -9355,7 +9353,10 @@ make_outerjoin_info(JOIN *join)
tab->cond_equal= tbl->cond_equal;
if (embedding && !embedding->is_active_sjm())
tab->first_upper= embedding->nested_join->first_nested;
- }
+ }
+ else if (!embedding)
+ tab->table->reginfo.not_exists_optimize= 0;
+
for ( ; embedding ; embedding= embedding->embedding)
{
if (embedding->is_active_sjm())
@@ -9365,7 +9366,10 @@ make_outerjoin_info(JOIN *join)
}
/* Ignore sj-nests: */
if (!(embedding->on_expr && embedding->outer_join))
+ {
+ tab->table->reginfo.not_exists_optimize= 0;
continue;
+ }
NESTED_JOIN *nested_join= embedding->nested_join;
if (!nested_join->counter)
{
@@ -9381,17 +9385,10 @@ make_outerjoin_info(JOIN *join)
}
if (!tab->first_inner)
tab->first_inner= nested_join->first_nested;
- if (tab->table->reginfo.not_exists_optimize)
- tab->first_inner->table->reginfo.not_exists_optimize= 1;
if (++nested_join->counter < nested_join->n_tables)
break;
/* Table tab is the last inner table for nested join. */
nested_join->first_nested->last_inner= tab;
- if (tab->first_inner->table->reginfo.not_exists_optimize)
- {
- for (JOIN_TAB *join_tab= tab->first_inner; join_tab <= tab; join_tab++)
- join_tab->table->reginfo.not_exists_optimize= 1;
- }
}
}
DBUG_RETURN(FALSE);
@@ -15510,7 +15507,9 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table,
if (new_field)
new_field->init(table);
- if (copy_func && item->real_item()->is_result_field())
+ if (copy_func &&
+ (item->is_result_field() ||
+ (item->real_item()->is_result_field())))
*((*copy_func)++) = item; // Save for copy_funcs
if (modify_item)
item->set_result_field(new_field);
@@ -17982,32 +17981,41 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
first_unmatched->found= 1;
for (JOIN_TAB *tab= first_unmatched; tab <= join_tab; tab++)
{
+ /*
+ Check whether 'not exists' optimization can be used here.
+ If tab->table->reginfo.not_exists_optimize is set to true
+ then WHERE contains a conjunctive predicate IS NULL over
+ a non-nullable field of tab. When activated this predicate
+ will filter out all records with matches for the left part
+ of the outer join whose inner tables start from the
+ first_unmatched table and include table tab. To safely use
+ 'not exists' optimization we have to check that the
+ IS NULL predicate is really activated, i.e. all guards
+ that wrap it are in the 'open' state.
+ */
+ bool not_exists_opt_is_applicable=
+ tab->table->reginfo.not_exists_optimize;
+ for (JOIN_TAB *first_upper= first_unmatched->first_upper;
+ not_exists_opt_is_applicable && first_upper;
+ first_upper= first_upper->first_upper)
+ {
+ if (!first_upper->found)
+ not_exists_opt_is_applicable= false;
+ }
/* Check all predicates that has just been activated. */
/*
Actually all predicates non-guarded by first_unmatched->found
will be re-evaluated again. It could be fixed, but, probably,
it's not worth doing now.
*/
- /*
- not_exists_optimize has been created from a
- select_cond containing 'is_null'. This 'is_null'
- predicate is still present on any 'tab' with
- 'not_exists_optimize'. Furthermore, the usual rules
- for condition guards also applies for
- 'not_exists_optimize' -> When 'is_null==false' we
- know all cond. guards are open and we can apply
- the 'not_exists_optimize'.
- */
- DBUG_ASSERT(!(tab->table->reginfo.not_exists_optimize &&
- !tab->select_cond));
-
if (tab->select_cond && !tab->select_cond->val_int())
{
/* The condition attached to table tab is false */
-
if (tab == join_tab)
{
found= 0;
+ if (not_exists_opt_is_applicable)
+ DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
}
else
{
@@ -18016,21 +18024,10 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab,
not to the last table of the current nest level.
*/
join->return_tab= tab;
- }
-
- if (tab->table->reginfo.not_exists_optimize)
- {
- /*
- When not_exists_optimize is set: No need to further
- explore more rows of 'tab' for this partial result.
- Any found 'tab' matches are known to evaluate to 'false'.
- Returning .._NO_MORE_ROWS will skip rem. 'tab' rows.
- */
- DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
- }
- else if (tab != join_tab)
- {
- DBUG_RETURN(NESTED_LOOP_OK);
+ if (not_exists_opt_is_applicable)
+ DBUG_RETURN(NESTED_LOOP_NO_MORE_ROWS);
+ else
+ DBUG_RETURN(NESTED_LOOP_OK);
}
}
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index aec81e17bd3..0732d6b74f0 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -4149,7 +4149,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
- !sql_field->def &&
+ !sql_field->def && !sql_field->vcol_info &&
is_timestamp_type(sql_field->sql_type) &&
(sql_field->flags & NOT_NULL_FLAG) &&
(type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
@@ -6492,6 +6492,9 @@ static bool fill_alter_inplace_info(THD *thd,
new_key->user_defined_key_parts))
goto index_changed;
+ if (table_key->block_size != new_key->block_size)
+ goto index_changed;
+
if (engine_options_differ(table_key->option_struct, new_key->option_struct,
table->file->ht->index_options))
goto index_changed;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index fec90d7ddf3..327b5bb0260 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -2230,6 +2230,9 @@ void Table_triggers_list::mark_fields_used(trg_event_type event)
bitmap_set_bit(trigger_table->read_set, trg_field->field_idx);
if (trg_field->get_settable_routine_parameter())
bitmap_set_bit(trigger_table->write_set, trg_field->field_idx);
+ if (trigger_table->field[trg_field->field_idx]->vcol_info)
+ trigger_table->mark_virtual_col(trigger_table->
+ field[trg_field->field_idx]);
}
}
}
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 65a94d1da60..1a136e5158b 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -629,9 +629,7 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (table->vfield)
- update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_READ);
+ update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
if (!select || (error= select->skip_record(thd)) > 0)
{
@@ -744,9 +742,7 @@ int mysql_update(THD *thd,
while (!(error=info.read_record(&info)) && !thd->killed)
{
if (table->vfield)
- update_virtual_fields(thd, table,
- table->triggers ? VCOL_UPDATE_ALL :
- VCOL_UPDATE_FOR_READ);
+ update_virtual_fields(thd, table, VCOL_UPDATE_FOR_READ);
thd->inc_examined_row_count(1);
if (!select || select->skip_record(thd) > 0)
{
@@ -2407,8 +2403,7 @@ int multi_update::do_updates()
if (table->default_field && (error= table->update_default_fields()))
goto err2;
if (table->vfield &&
- update_virtual_fields(thd, table,
- (table->triggers ? VCOL_UPDATE_ALL : VCOL_UPDATE_FOR_WRITE)))
+ update_virtual_fields(thd, table, VCOL_UPDATE_FOR_WRITE))
goto err2;
if ((error= cur_table->view_check_option(thd, ignore)) !=
VIEW_CHECK_OK)
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index a7408f7bf50..b5d9604fd41 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -7649,7 +7649,7 @@ alter_list_item:
LEX *lex= Lex;
if (lex->create_info.add_alter_list_item_convert_to_charset($5))
MYSQL_YYABORT;
- lex->alter_info.flags|= Alter_info::ALTER_CONVERT;
+ lex->alter_info.flags|= Alter_info::ALTER_OPTIONS;
}
| create_table_options_space_separated
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 379294fa7b2..6457a8597bd 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1548,7 +1548,6 @@ bool
Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
{
String str, *res;
- bool running;
DBUG_ASSERT(var->type == OPT_GLOBAL);
@@ -1559,11 +1558,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
return true;
}
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
+ if (give_error_if_slave_running(0))
return true;
if (!(res= var->value->val_str(&str)))
return true;
@@ -1601,7 +1596,7 @@ Sys_var_gtid_slave_pos::global_update(THD *thd, set_var *var)
mysql_mutex_unlock(&LOCK_global_system_variables);
mysql_mutex_lock(&LOCK_active_mi);
- if (!master_info_index || master_info_index->give_error_if_slave_running())
+ if (give_error_if_slave_running(1))
err= true;
else
err= rpl_gtid_pos_update(thd, var->save_result.string_value.str,
@@ -1787,16 +1782,7 @@ Sys_var_last_gtid::session_value_ptr(THD *thd, LEX_STRING *base)
static bool
check_slave_parallel_threads(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -1805,10 +1791,7 @@ fix_slave_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
bool err;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- err= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ err= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
return err;
@@ -1831,16 +1814,7 @@ static Sys_var_ulong Sys_slave_parallel_threads(
static bool
check_slave_domain_parallel_threads(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -1849,13 +1823,10 @@ fix_slave_domain_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
bool running;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ running= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
- return running ? true : false;
+ return running;
}
@@ -1886,16 +1857,7 @@ static Sys_var_ulong Sys_slave_parallel_max_queued(
static bool
check_gtid_ignore_duplicates(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -1904,13 +1866,10 @@ fix_gtid_ignore_duplicates(sys_var *self, THD *thd, enum_var_type type)
bool running;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ running= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
- return running ? true : false;
+ return running;
}
@@ -2858,10 +2817,8 @@ Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var)
DBUG_ENTER("Sys_var_replicate_events_marked_for_skip::global_update");
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index && !master_info_index->give_error_if_slave_running())
+ if (!give_error_if_slave_running(0))
result= Sys_var_enum::global_update(thd, var);
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
DBUG_RETURN(result);
}
@@ -4137,19 +4094,16 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
Master_info *mi;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
if (!var->base.length) // no base name
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_ERROR);
+ mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_ERROR);
}
else // has base name
{
- mi= master_info_index->
- get_master_info(&var->base,
- Sql_condition::WARN_LEVEL_WARN);
+ mi= get_master_info(&var->base,
+ Sql_condition::WARN_LEVEL_WARN);
}
if (mi)
@@ -4157,17 +4111,17 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
if (mi->rli.slave_running)
{
my_error(ER_SLAVE_MUST_STOP, MYF(0),
- mi->connection_name.length,
- mi->connection_name.str);
+ mi->connection_name.length,
+ mi->connection_name.str);
result= true;
}
else
{
result= set_filter_value(var->save_result.string_value.str, mi);
}
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
return result;
}
@@ -4175,8 +4129,10 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
bool Sys_var_rpl_filter::set_filter_value(const char *value, Master_info *mi)
{
bool status= true;
- Rpl_filter* rpl_filter= mi ? mi->rpl_filter : global_rpl_filter;
+ Rpl_filter* rpl_filter= mi->rpl_filter;
+ /* Proctect against other threads */
+ mysql_mutex_lock(&LOCK_active_mi);
switch (opt_id) {
case OPT_REPLICATE_DO_DB:
status= rpl_filter->set_do_db(value);
@@ -4197,7 +4153,7 @@ bool Sys_var_rpl_filter::set_filter_value(const char *value, Master_info *mi)
status= rpl_filter->set_wild_ignore_table(value);
break;
}
-
+ mysql_mutex_unlock(&LOCK_active_mi);
return status;
}
@@ -4210,29 +4166,24 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
Rpl_filter *rpl_filter;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
if (!base->length) // no base name
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_ERROR);
+ mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_ERROR);
}
else // has base name
- {
- mi= master_info_index->
- get_master_info(base,
- Sql_condition::WARN_LEVEL_WARN);
- }
- mysql_mutex_lock(&LOCK_global_system_variables);
+ mi= get_master_info(base, Sql_condition::WARN_LEVEL_WARN);
if (!mi)
{
- mysql_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_global_system_variables);
return 0;
}
+
rpl_filter= mi->rpl_filter;
tmp.length(0);
+ mysql_mutex_lock(&LOCK_active_mi);
switch (opt_id) {
case OPT_REPLICATE_DO_DB:
rpl_filter->get_do_db(&tmp);
@@ -4253,9 +4204,12 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
rpl_filter->get_wild_ignore_table(&tmp);
break;
}
+ mysql_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+
+ mi->release();
ret= (uchar *) thd->strmake(tmp.ptr(), tmp.length());
- mysql_mutex_unlock(&LOCK_active_mi);
return ret;
}
@@ -4326,17 +4280,12 @@ get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset)
Master_info *mi;
ulonglong res= 0; // Default value
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_WARN);
- if (mi)
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_WARN)))
{
- mysql_mutex_lock(&mi->rli.data_lock);
res= *((ulonglong*) (((uchar*) mi) + master_info_offset));
- mysql_mutex_unlock(&mi->rli.data_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
return res;
}
@@ -4351,19 +4300,16 @@ bool update_multi_source_variable(sys_var *self_var, THD *thd,
if (type == OPT_GLOBAL)
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_ERROR);
- if (mi)
+ if ((mi= (get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_ERROR))))
{
mysql_mutex_lock(&mi->rli.run_lock);
mysql_mutex_lock(&mi->rli.data_lock);
result= self->update_variable(thd, mi);
mysql_mutex_unlock(&mi->rli.data_lock);
mysql_mutex_unlock(&mi->rli.run_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
if (type == OPT_GLOBAL)
mysql_mutex_lock(&LOCK_global_system_variables);
return result;
diff --git a/sql/table.cc b/sql/table.cc
index 57effed81ff..60334740790 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -572,7 +572,7 @@ enum open_frm_error open_table_def(THD *thd, TABLE_SHARE *share, uint flags)
{
DBUG_ASSERT(flags & GTS_TABLE);
DBUG_ASSERT(flags & GTS_USE_DISCOVERY);
- mysql_file_delete_with_symlink(key_file_frm, path, MYF(0));
+ my_handler_delete_with_symlink(key_file_frm, path, "", MYF(0));
file= -1;
}
else
@@ -6689,11 +6689,9 @@ bool is_simple_order(ORDER *order)
@details
The function computes the values of the virtual columns of the table and
stores them in the table record buffer.
- If vcol_update_mode is set to VCOL_UPDATE_ALL then all virtual column are
- computed. Otherwise, only fields from vcol_set are computed: all of them,
- if vcol_update_mode is set to VCOL_UPDATE_FOR_WRITE, and, only those with
- the stored_in_db flag set to false, if vcol_update_mode is equal to
- VCOL_UPDATE_FOR_READ.
+ Only fields from vcol_set are computed: all of them, if vcol_update_mode is
+ set to VCOL_UPDATE_FOR_WRITE, and, only those with the stored_in_db flag
+ set to false, if vcol_update_mode is equal to VCOL_UPDATE_FOR_READ.
@retval
0 Success
@@ -6709,15 +6707,16 @@ int update_virtual_fields(THD *thd, TABLE *table,
int error __attribute__ ((unused))= 0;
DBUG_ASSERT(table && table->vfield);
- thd->reset_arena_for_cached_items(table->expr_arena);
+ Query_arena backup_arena;
+ thd->set_n_backup_active_arena(table->expr_arena, &backup_arena);
+
/* Iterate over virtual fields in the table */
for (vfield_ptr= table->vfield; *vfield_ptr; vfield_ptr++)
{
vfield= (*vfield_ptr);
DBUG_ASSERT(vfield->vcol_info && vfield->vcol_info->expr_item);
- if ((bitmap_is_set(table->vcol_set, vfield->field_index) &&
- (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db)) ||
- vcol_update_mode == VCOL_UPDATE_ALL)
+ if (bitmap_is_set(table->vcol_set, vfield->field_index) &&
+ (vcol_update_mode == VCOL_UPDATE_FOR_WRITE || !vfield->stored_in_db))
{
/* Compute the actual value of the virtual fields */
error= vfield->vcol_info->expr_item->save_in_field(vfield, 0);
@@ -6728,7 +6727,7 @@ int update_virtual_fields(THD *thd, TABLE *table,
DBUG_PRINT("info", ("field '%s' - skipped", vfield->field_name));
}
}
- thd->reset_arena_for_cached_items(0);
+ thd->restore_active_arena(table->expr_arena, &backup_arena);
DBUG_RETURN(0);
}
diff --git a/sql/table.h b/sql/table.h
index 39faa8b9765..bf98f08842a 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -315,8 +315,7 @@ enum release_type { RELEASE_NORMAL, RELEASE_WAIT_FOR_DROP };
enum enum_vcol_update_mode
{
VCOL_UPDATE_FOR_READ= 0,
- VCOL_UPDATE_FOR_WRITE,
- VCOL_UPDATE_ALL
+ VCOL_UPDATE_FOR_WRITE
};
class Filesort_info