Commit 2158add8 authored by andrey@lmy004's avatar andrey@lmy004

merge

parents 00b188cc d3e08757
CREATE DATABASE IF NOT EXISTS events_test;
CREATE DATABASE events_test2;
USE events_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
3
DROP DATABASE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
0
"Now testing stability - dropping db -> events while they are running"
CREATE DATABASE events_test2;
USE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
1000
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
0
CREATE DATABASE events_test3;
USE events_test3;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
COUNT(*)
950
CREATE DATABASE events_test4;
USE events_test4;
CREATE DATABASE events_test2;
USE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
COUNT(*)
1050
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
DROP DATABASE events_test3;
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test4;
SET GLOBAL event_scheduler=1;
USE events_test;
DROP DATABASE events_test;
...@@ -274,7 +274,6 @@ drop event one_event; ...@@ -274,7 +274,6 @@ drop event one_event;
--echo "Sleep a bit so the server closes the second connection" --echo "Sleep a bit so the server closes the second connection"
--sleep 2 --sleep 2
create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5; 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; select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
drop event e_26; drop event e_26;
......
CREATE DATABASE IF NOT EXISTS events_test;
#
# DROP DATABASE test start (bug #16406)
#
CREATE DATABASE events_test2;
USE events_test2;
CREATE EVENT ev_drop1 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop2 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
CREATE EVENT ev_drop3 ON SCHEDULE EVERY 10 MINUTE DISABLE DO SELECT 1;
USE events_test;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
DROP DATABASE events_test2;
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
--echo "Now testing stability - dropping db -> events while they are running"
CREATE DATABASE events_test2;
USE events_test2;
--disable_query_log
let $1= 1000;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
SET GLOBAL event_scheduler=1;
--sleep 4
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
--sleep 2
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
CREATE DATABASE events_test3;
USE events_test3;
--disable_query_log
let $1= 950;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test3';
--sleep 3
CREATE DATABASE events_test4;
USE events_test4;
--disable_query_log
let $1= 860;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
CREATE DATABASE events_test2;
USE events_test2;
--disable_query_log
let $1= 1050;
while ($1)
{
eval CREATE EVENT ev_drop$1 ON SCHEDULE EVERY 1 SECOND DO SELECT $1;
dec $1;
}
--enable_query_log
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_test2';
--sleep 6
DROP DATABASE events_test2;
SET GLOBAL event_scheduler=0;
DROP DATABASE events_test3;
SET GLOBAL event_scheduler=1;
DROP DATABASE events_test4;
SET GLOBAL event_scheduler=1;
USE events_test;
#
# DROP DATABASE test end (bug #16406)
#
DROP DATABASE events_test;
This diff is collapsed.
...@@ -79,6 +79,8 @@ class event_timed ...@@ -79,6 +79,8 @@ class event_timed
{ {
event_timed(const event_timed &); /* Prevent use of these */ event_timed(const event_timed &); /* Prevent use of these */
void operator=(event_timed &); void operator=(event_timed &);
my_bool in_spawned_thread;
ulong locked_by_thread_id;
my_bool running; my_bool running;
pthread_mutex_t LOCK_running; pthread_mutex_t LOCK_running;
...@@ -117,13 +119,14 @@ class event_timed ...@@ -117,13 +119,14 @@ class event_timed
bool free_sphead_on_delete; bool free_sphead_on_delete;
uint flags;//all kind of purposes uint flags;//all kind of purposes
event_timed():running(0), status_changed(false), last_executed_changed(false), event_timed():in_spawned_thread(0),locked_by_thread_id(0),
expression(0), created(0), modified(0), running(0), status_changed(false),
on_completion(MYSQL_EVENT_ON_COMPLETION_DROP), last_executed_changed(false), expression(0), created(0),
status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0), modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
body_begin(0), dropped(false), free_sphead_on_delete(true), status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
flags(0) body_begin(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{ {
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST); pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
init(); init();
...@@ -200,7 +203,44 @@ class event_timed ...@@ -200,7 +203,44 @@ class event_timed
return ret; return ret;
} }
void free_sp() /*
Checks whether the object is being used in a spawned thread.
This method is for very basic checking. Use ::can_spawn_now_n_lock()
for most of the cases.
*/
my_bool
can_spawn_now()
{
my_bool ret;
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= !in_spawned_thread;
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
/*
Checks whether this thread can lock the object for modification ->
preventing being spawned for execution, and locks if possible.
use ::can_spawn_now() only for basic checking because a race
condition may occur between the check and eventual modification (deletion)
of the object.
*/
my_bool
can_spawn_now_n_lock(THD *thd);
int
spawn_unlock(THD *thd);
int
spawn_now(void * (*thread_func)(void*));
void
spawn_thread_finish(THD *thd);
void
free_sp()
{ {
delete sphead; delete sphead;
sphead= 0; sphead= 0;
...@@ -239,6 +279,10 @@ event_reconstruct_interval_expression(String *buf, ...@@ -239,6 +279,10 @@ event_reconstruct_interval_expression(String *buf,
interval_type interval, interval_type interval,
longlong expression); longlong expression);
int
evex_drop_db_events(THD *thd, char *db);
int int
init_events(); init_events();
......
This diff is collapsed.
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#define EVENT_EXEC_STARTED 0
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
#define EVEX_USE_QUEUE #define EVEX_USE_QUEUE
#define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \ #define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
...@@ -32,10 +36,10 @@ int ...@@ -32,10 +36,10 @@ int
my_time_compare(TIME *a, TIME *b); my_time_compare(TIME *a, TIME *b);
int int
evex_db_find_event_aux(THD *thd, const LEX_STRING dbname, evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING rname, const LEX_STRING ev_name,
const LEX_STRING definer, const LEX_STRING user_name,
TABLE *table); TABLE *table);
int int
event_timed_compare_q(void *vptr, byte* a, byte *b); event_timed_compare_q(void *vptr, byte* a, byte *b);
......
...@@ -908,7 +908,7 @@ event_timed::drop(THD *thd) ...@@ -908,7 +908,7 @@ event_timed::drop(THD *thd)
Saves status and last_executed_at to the disk if changed. Saves status and last_executed_at to the disk if changed.
SYNOPSIS SYNOPSIS
event_timed::drop() event_timed::update_fields()
thd - thread context thd - thread context
RETURN VALUE RETURN VALUE
...@@ -945,7 +945,7 @@ event_timed::update_fields(THD *thd) ...@@ -945,7 +945,7 @@ event_timed::update_fields(THD *thd)
} }
if ((ret= evex_db_find_event_aux(thd, dbname, name, definer, table))) if ((ret= evex_db_find_event_by_name(thd, dbname, name, definer, table)))
goto done; goto done;
store_record(table,record[1]); store_record(table,record[1]);
...@@ -1204,6 +1204,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1204,6 +1204,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
MEM_ROOT *tmp_mem_root= 0; MEM_ROOT *tmp_mem_root= 0;
LEX *old_lex= thd->lex, lex; LEX *old_lex= thd->lex, lex;
char *old_db; char *old_db;
int old_db_length;
event_timed *ett; event_timed *ett;
sp_name *spn; sp_name *spn;
char *old_query; char *old_query;
...@@ -1237,7 +1238,9 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1237,7 +1238,9 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
old_query_len= thd->query_length; old_query_len= thd->query_length;
old_query= thd->query; old_query= thd->query;
old_db= thd->db; old_db= thd->db;
old_db_length= thd->db_length;
thd->db= dbname.str; thd->db= dbname.str;
thd->db_length= dbname.length;
get_create_event(thd, &show_create); get_create_event(thd, &show_create);
...@@ -1303,3 +1306,135 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1303,3 +1306,135 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
/*
Checks whether this thread can lock the object for modification ->
preventing being spawned for execution, and locks if possible.
use ::can_spawn_now() only for basic checking because a race
condition may occur between the check and eventual modification (deletion)
of the object.
Returns
true - locked
false - cannot lock
*/
my_bool
event_timed::can_spawn_now_n_lock(THD *thd)
{
my_bool ret= FALSE;
VOID(pthread_mutex_lock(&this->LOCK_running));
if (!in_spawned_thread)
{
in_spawned_thread= TRUE;
ret= TRUE;
locked_by_thread_id= thd->thread_id;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
extern pthread_attr_t connection_attrib;
/*
Checks whether is possible and forks a thread. Passes self as argument.
Returns
EVENT_EXEC_STARTED - OK
EVENT_EXEC_ALREADY_EXEC - Thread not forked, already working
EVENT_EXEC_CANT_FORK - Unable to spawn thread (error)
*/
int
event_timed::spawn_now(void * (*thread_func)(void*))
{
int ret= EVENT_EXEC_STARTED;
static uint exec_num= 0;
DBUG_ENTER("event_timed::spawn_now");
DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
VOID(pthread_mutex_lock(&this->LOCK_running));
if (!in_spawned_thread)
{
pthread_t th;
in_spawned_thread= true;
if (pthread_create(&th, &connection_attrib, thread_func, (void*)this))
{
DBUG_PRINT("info", ("problem while spawning thread"));
ret= EVENT_EXEC_CANT_FORK;
in_spawned_thread= false;
}
#ifndef DBUG_OFF
else
{
sql_print_information("SCHEDULER: Started thread %d", ++exec_num);
DBUG_PRINT("info", ("thread spawned"));
}
#endif
}
else
{
DBUG_PRINT("info", ("already in spawned thread. skipping"));
ret= EVENT_EXEC_ALREADY_EXEC;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
DBUG_RETURN(ret);
}
void
event_timed::spawn_thread_finish(THD *thd)
{
DBUG_ENTER("event_timed::spawn_thread_finish");
VOID(pthread_mutex_lock(&this->LOCK_running));
in_spawned_thread= false;
if ((flags & EVENT_EXEC_NO_MORE) || status == MYSQL_EVENT_DISABLED)
{
DBUG_PRINT("info", ("%s exec no more. to drop=%d", name.str, dropped));
if (dropped)
drop(thd);
VOID(pthread_mutex_unlock(&this->LOCK_running));
delete this;
DBUG_VOID_RETURN;
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
DBUG_VOID_RETURN;
}
/*
Unlocks the object after it has been locked with ::can_spawn_now_n_lock()
Returns
0 - ok
1 - not locked by this thread
*/
int
event_timed::spawn_unlock(THD *thd)
{
int ret= 0;
VOID(pthread_mutex_lock(&this->LOCK_running));
if (!in_spawned_thread)
{
if (locked_by_thread_id == thd->thread_id)
{
in_spawned_thread= FALSE;
locked_by_thread_id= 0;
}
else
{
sql_print_error("A thread tries to unlock when he hasn't locked. "
"thread_id=%ld locked by %ld",
thd->thread_id, locked_by_thread_id);
DBUG_ASSERT(0);
ret= 1;
}
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include <mysys_err.h> #include <mysys_err.h>
#include "sp.h" #include "sp.h"
#include "event.h"
#include <my_dir.h> #include <my_dir.h>
#include <m_ctype.h> #include <m_ctype.h>
#ifdef __WIN__ #ifdef __WIN__
...@@ -870,6 +871,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) ...@@ -870,6 +871,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit: exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */ (void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
(void)evex_drop_db_events(thd, db); /* QQ Ignore errors for now */
start_waiting_global_read_lock(thd); start_waiting_global_read_lock(thd);
/* /*
If this database was the client's selected database, we silently change the If this database was the client's selected database, we silently change the
......
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