Commit 4ba2a332 authored by andrey@lmy004's avatar andrey@lmy004

- fix for bug #16414 (Events: Crash or hang if event drops itself)

WL#1034 (Internal CRON)
(with post-review fix)
parent 0a0304b5
......@@ -15,20 +15,11 @@ create event event2 on schedule every 2 second starts now() ends date_add(now(),
drop event event2;
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
select sleep(2);
sleep(2)
0
alter event e_43 do alter event e_43 do set @a = 4;
select sleep(3);
sleep(3)
0
select db, name, body, status, interval_field, interval_value from mysql.event;
db name body status interval_field interval_value
events_test e_43 set @a = 4 ENABLED SECOND 1
drop event e_43;
select sleep(1);
sleep(1)
0
set global event_scheduler = 0;
create table t_event3 (a int, b float);
drop event if exists event3;
......@@ -121,6 +112,7 @@ drop event two_event;
drop event three_event;
drop user ev_test@localhost;
drop event one_event;
"Sleep a bit so the server closes the second connection"
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
......@@ -137,4 +129,70 @@ set event_scheduler=0;
ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL
set global event_scheduler=2;
ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2'
"DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=0;
select definer, name, db from mysql.event;
definer name db
select get_lock("test_lock1", 20);
get_lock("test_lock1", 20)
1
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
"Should return 1 row"
select definer, name, db from mysql.event;
definer name db
root@localhost закачка events_test
"Should be only 1 process"
show processlist;
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
select release_lock("test_lock1");
release_lock("test_lock1")
1
drop event закачка;
"Should have 0 events"
select count(*) from mysql.event;
count(*)
0
"ENABLE the scheduler and get a lock"
set global event_scheduler=1;
select get_lock("test_lock2", 20);
get_lock("test_lock2", 20)
1
"Create an event which tries to acquire a mutex. The event locks on the mutex"
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
"Let some time pass to the event starts"
"Should have only 3 processes: the scheduler, our conn and the locked event"
show processlist;
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
# event_scheduler NULL Connect # Sleeping NULL
# root events_test Connect # User lock select get_lock("test_lock2", 20)
"Release the mutex, the event worker should finish."
select release_lock("test_lock2");
release_lock("test_lock2")
1
drop event закачка;
set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
get_lock("test_lock2_1", 20)
1
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
"Should see 2 processes, one locked on get_lock("
"Shutting down the scheduler, it should wait for the running event"
set global event_scheduler=0;
"Should have only 3 processes: the scheduler, our conn and the locked event"
show processlist;
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
# event_scheduler NULL Connect # Sleeping NULL
# root events_test Connect # User lock select get_lock("test_lock2_1", 20)
"Release the lock so the child process should finish. Hence the scheduler also"
select release_lock("test_lock2_1");
release_lock("test_lock2_1")
1
"Should have only our process now:"
show processlist;
Id User Host db Command Time State Info
# root localhost events_test Query # NULL show processlist
drop event закачка21;
drop database events_test;
......@@ -17,12 +17,12 @@ drop event event2;
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
select sleep(2);
--sleep 2
alter event e_43 do alter event e_43 do set @a = 4;
select sleep(3);
--sleep 2
select db, name, body, status, interval_field, interval_value from mysql.event;
drop event e_43;
select sleep(1);
--sleep 1
set global event_scheduler = 0;
create table t_event3 (a int, b float);
......@@ -107,8 +107,8 @@ drop event one_event;
##INFORMATION_SCHEMA.EVENTS test end
#
--echo "Sleep a bit so the server closes the second connection"
--sleep 2
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
......@@ -129,23 +129,38 @@ set event_scheduler=0;
--error 1231
set global event_scheduler=2;
#set global event_scheduler=0;
#select count(*) from mysql.event;
#select get_lock("test_lock1", 20);
#create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
#select count(*) from mysql.event;
##show processlist;
#select release_lock("test_lock1");
#drop event закачка;
#select count(*) from mysql.event;
--echo "DISABLE the scheduler. Testing that it does not work when the variable is 0"
set global event_scheduler=0;
select definer, name, db from mysql.event;
select get_lock("test_lock1", 20);
create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20);
--echo "Should return 1 row"
select definer, name, db from mysql.event;
--echo "Should be only 1 process"
--replace_column 1 # 6 #
show processlist;
select release_lock("test_lock1");
drop event закачка;
--echo "Should have 0 events"
select count(*) from mysql.event;
#
#set global event_scheduler=1;
#select get_lock("test_lock2", 20);
#create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
#select sleep(2);
#show processlist;
#select release_lock("test_lock2");
#drop event закачка;
#
#
--echo "ENABLE the scheduler and get a lock"
set global event_scheduler=1;
select get_lock("test_lock2", 20);
--echo "Create an event which tries to acquire a mutex. The event locks on the mutex"
create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20);
--echo "Let some time pass to the event starts"
--sleep 2
--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
--replace_column 1 # 6 #
show processlist;
--echo "Release the mutex, the event worker should finish."
select release_lock("test_lock2");
drop event закачка;
##
## 1. get a lock
......@@ -155,26 +170,33 @@ set global event_scheduler=2;
## 5. kill the scheduler, it will wait for the child to stop
## 6. both processes should be there on show processlist
## 7. release the lock and sleep, both scheduler and child should end
#set global event_scheduler=1;
#select get_lock("test_lock2_1", 20);
#create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
#select sleep(2);
##show processlist;
#set global event_scheduler=0;
#select sleep(2);
##show processlist;
#select release_lock("test_lock2_1");
#select sleep(2);
##show processlist;
#drop event закачка21;
#set global event_scheduler=1;
#select get_lock("test_lock3", 20);
#create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
#select sleep(2);
set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20);
--sleep 1
--echo "Should see 2 processes, one locked on get_lock("
#show processlist;
#drop event закачка;
#select release_lock("test_lock3");
--echo "Shutting down the scheduler, it should wait for the running event"
set global event_scheduler=0;
--sleep 1
--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
--replace_column 1 # 6 #
show processlist;
--echo "Release the lock so the child process should finish. Hence the scheduler also"
select release_lock("test_lock2_1");
--sleep 1
--echo "Should have only our process now:"
--replace_column 1 # 6 #
show processlist;
drop event закачка21;
##set global event_scheduler=1;
##select get_lock("test_lock3", 20);
##create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20);
##select sleep(2);
##show processlist;
##drop event закачка;
##select release_lock("test_lock3");
#
# test with very often occuring event
......@@ -182,14 +204,15 @@ set global event_scheduler=2;
##select get_lock("test_lock4", 20);
##create event закачка4 on schedule every 1 second do select get_lock("test_lock4", 20);
##select sleep(3);
##--replace_column 1 # 6 #
##show processlist;
##drop event закачка4;
##select release_lock("test_lock4");
#set global event_scheduler=0;
#select sleep(2);
##set global event_scheduler=0;
##select sleep(2);
##--replace_column 1 # 6 #
##show processlist;
##the following locks for some reason and is a bug, commented for now
##select count(*) from mysql.event;
drop database events_test;
......@@ -704,11 +704,17 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
}
/*
0 - OK can drop from outside
1 - Scheduled from dropping, don't drop from outside
*/
static int
evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
bool is_drop)
{
uint i;
int ret= 0;
DBUG_ENTER("evex_remove_from_cache");
/*
......@@ -738,7 +744,8 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
DBUG_PRINT("evex_remove_from_cache",
("running.defer mem free. is_drop=%d", is_drop));
et->flags|= EVENT_EXEC_NO_MORE;
et->dropped= is_drop;
if ((et->dropped= is_drop))
ret= 1;
}
DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
evex_queue_delete_element(&EVEX_EQ_NAME, i);
......@@ -751,7 +758,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
if (use_lock)
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
DBUG_RETURN(0);
DBUG_RETURN(ret);
}
......@@ -866,21 +873,25 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name,
Drops an event
SYNOPSIS
evex_drop_event()
db_drop_event()
thd THD
et event's name
drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres
*/
int
evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
uint *rows_affected)
{
TABLE *table;
int ret= EVEX_OPEN_TABLE_FAILED;
DBUG_ENTER("evex_drop_event");
Open_tables_state backup;
uint ret;
DBUG_ENTER("db_drop_event");
ret= EVEX_OPEN_TABLE_FAILED;
thd->reset_n_backup_open_tables_state(&backup);
if (evex_open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
......@@ -908,10 +919,6 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
goto done;
}
VOID(pthread_mutex_lock(&LOCK_evex_running));
if (evex_is_running)
ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
VOID(pthread_mutex_unlock(&LOCK_evex_running));
done:
/*
......@@ -919,6 +926,44 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
we have to close our thread tables.
*/
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(ret);
}
/*
Drops an event
SYNOPSIS
evex_drop_event()
thd THD
et event's name
drop_if_exists if set and the event not existing => warning onto the stack
rows_affected affected number of rows is returned heres
*/
int
evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
uint *rows_affected)
{
TABLE *table;
int ret= 0;
DBUG_ENTER("evex_drop_event");
VOID(pthread_mutex_lock(&LOCK_evex_running));
if (evex_is_running)
ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
VOID(pthread_mutex_unlock(&LOCK_evex_running));
if (ret == 1)
ret= 0;
else if (ret == 0)
ret= db_drop_event(thd, et, drop_if_exists, rows_affected);
else
my_error(ER_UNKNOWN_ERROR, MYF(0));
DBUG_RETURN(ret);
}
......
......@@ -40,6 +40,9 @@ evex_db_find_event_aux(THD *thd, const LEX_STRING dbname,
int
event_timed_compare_q(void *vptr, byte* a, byte *b);
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
uint *rows_affected);
#define EXEC_QUEUE_QUEUE_NAME executing_queue
#define EXEC_QUEUE_DARR_NAME evex_executing_queue
......
......@@ -877,20 +877,10 @@ int
event_timed::drop(THD *thd)
{
TABLE *table;
int ret= 0;
uint tmp= 0;
DBUG_ENTER("event_timed::drop");
if (evex_open_event_table(thd, TL_WRITE, &table))
DBUG_RETURN(-1);
if (evex_db_find_event_aux(thd, dbname, name, definer, table))
DBUG_RETURN(-2);
if ((ret= table->file->ha_delete_row(table->record[0])))
DBUG_RETURN(ret);
close_thread_tables(thd);
DBUG_RETURN(0);
DBUG_RETURN(db_drop_event(thd, this, false, &tmp));
}
......
......@@ -3723,6 +3723,8 @@ mysql_execute_command(THD *thd)
res= evex_drop_event(thd, lex->et, lex->drop_if_exists, &rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
res, rows_affected));
if (!res)
send_ok(thd, rows_affected);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment