Commit 95e87f08 authored by andrey@lmy004's avatar andrey@lmy004

Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new

into lmy004.:/work/mysql-5.1-bug16406
parents 6892c2a5 2158add8
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;
--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;
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
{
event_timed(const event_timed &); /* Prevent use of these */
void operator=(event_timed &);
my_bool in_spawned_thread;
ulong locked_by_thread_id;
my_bool running;
pthread_mutex_t LOCK_running;
......@@ -117,13 +119,14 @@ class event_timed
bool free_sphead_on_delete;
uint flags;//all kind of purposes
event_timed():running(0), status_changed(false), last_executed_changed(false),
expression(0), created(0), modified(0),
on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
body_begin(0), dropped(false), free_sphead_on_delete(true),
flags(0)
event_timed():in_spawned_thread(0),locked_by_thread_id(0),
running(0), status_changed(false),
last_executed_changed(false), expression(0), created(0),
modified(0), on_completion(MYSQL_EVENT_ON_COMPLETION_DROP),
status(MYSQL_EVENT_ENABLED), sphead(0), sql_mode(0),
body_begin(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
init();
......@@ -200,7 +203,44 @@ class event_timed
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;
sphead= 0;
......@@ -239,6 +279,10 @@ event_reconstruct_interval_expression(String *buf,
interval_type interval,
longlong expression);
int
evex_drop_db_events(THD *thd, char *db);
int
init_events();
......
This diff is collapsed.
......@@ -19,6 +19,10 @@
#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 UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
......@@ -32,10 +36,10 @@ int
my_time_compare(TIME *a, TIME *b);
int
evex_db_find_event_aux(THD *thd, const LEX_STRING dbname,
const LEX_STRING rname,
const LEX_STRING definer,
TABLE *table);
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
const LEX_STRING user_name,
TABLE *table);
int
event_timed_compare_q(void *vptr, byte* a, byte *b);
......
......@@ -908,7 +908,7 @@ event_timed::drop(THD *thd)
Saves status and last_executed_at to the disk if changed.
SYNOPSIS
event_timed::drop()
event_timed::update_fields()
thd - thread context
RETURN VALUE
......@@ -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;
store_record(table,record[1]);
......@@ -1204,6 +1204,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
MEM_ROOT *tmp_mem_root= 0;
LEX *old_lex= thd->lex, lex;
char *old_db;
int old_db_length;
event_timed *ett;
sp_name *spn;
char *old_query;
......@@ -1237,7 +1238,9 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
old_query_len= thd->query_length;
old_query= thd->query;
old_db= thd->db;
old_db_length= thd->db_length;
thd->db= dbname.str;
thd->db_length= dbname.length;
get_create_event(thd, &show_create);
......@@ -1303,3 +1306,135 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
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 @@
#include "mysql_priv.h"
#include <mysys_err.h>
#include "sp.h"
#include "event.h"
#include <my_dir.h>
#include <m_ctype.h>
#ifdef __WIN__
......@@ -870,6 +871,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(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);
/*
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