diff options
author | unknown <andrey@lmy004.> | 2006-02-16 00:43:11 +0100 |
---|---|---|
committer | unknown <andrey@lmy004.> | 2006-02-16 00:43:11 +0100 |
commit | fea4742db5b5f5531b0e2d30ccee7883f54b0e80 (patch) | |
tree | 7ade9988cce658b1efc550ee4228f4bef4a4d6d8 /sql/event_timed.cc | |
parent | 7088b39da895cf22a2b71d21a8313cbf0dda3760 (diff) | |
download | mariadb-git-fea4742db5b5f5531b0e2d30ccee7883f54b0e80.tar.gz |
fix for bug#16406 (Events: DROP DATABASE doesn't automatically drop events)
WL#1034
- This changeset also changes the executor so its quite more stable now.
Stressing test case added that executes ~800 events per second and dropping
hundreds of events at once using DROP DATABASE.
(with fixes after review of JimW)
(with fixes after review of Serg)
mysql-test/r/events.result:
update results after TRIGGER_ACL was added
mysql-test/t/events.test:
-redundant line
sql/event.cc:
Implemented evex_db_drop_events() which drops all events
from a specific database. Needed for SQLCOM_DROP_DATABASE
sql/event.h:
- protect the event better (see the changes to event_executor.cc
and event.cc). An event object could be used in a spawned thread
before it's executed but till now the object is marked as being
executed when the anonymous sp_head is executed. However, there are
timeframes before and after that during which the event is not marked
as executed and other thread may delete the object -> so we end with
a nirvana pointer.
sql/event_executor.cc:
- extract some of the code executed in the main thread to a function. Too long
functions are bad for the overview.
- prepend all information/error messages to the console with "SCHEDULER:" for
better overview, and easied searching in the log tables.
sql/event_priv.h:
- change the name, of evex_db_find_event_by_name() and don't
used C++ features like function overloading
- define consts for result returned from event_timed::spawn_now()
sql/event_timed.cc:
- add few methods related to event execution.
now the event spawns the worker thread and
passes itself as parameter. This way it locks itself for exectution
first and then spawning -> no race condition. When the worker thread
has finished working with the reference it calls back
event_timed::spawn_thread_finish() to unlock itself.
sql/sql_db.cc:
- call evex_drop_db_events() on DROP DATABASE
Diffstat (limited to 'sql/event_timed.cc')
-rw-r--r-- | sql/event_timed.cc | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/sql/event_timed.cc b/sql/event_timed.cc index 28d21089b74..19edaf345dd 100644 --- a/sql/event_timed.cc +++ b/sql/event_timed.cc @@ -879,11 +879,12 @@ event_timed::drop(THD *thd) TABLE *table; int ret= 0; DBUG_ENTER("event_timed::drop"); + DBUG_PRINT("info",("%s.%s", dbname.str, name.str)); if (evex_open_event_table(thd, TL_WRITE, &table)) DBUG_RETURN(-1); - if (evex_db_find_event_aux(thd, dbname, name, definer, table)) + if (evex_db_find_event_by_name(thd, dbname, name, definer, table)) DBUG_RETURN(-2); if ((ret= table->file->ha_delete_row(table->record[0]))) @@ -919,7 +920,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]); @@ -1059,6 +1060,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; @@ -1088,7 +1090,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; thd->query= get_show_create_event(thd, &thd->query_length); DBUG_PRINT("event_timed::compile", ("query:%s",thd->query)); @@ -1148,3 +1152,135 @@ done: 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; +} |