summaryrefslogtreecommitdiff
path: root/sql/event_timed.cc
diff options
context:
space:
mode:
authorunknown <andrey@lmy004.>2006-02-16 00:43:11 +0100
committerunknown <andrey@lmy004.>2006-02-16 00:43:11 +0100
commitfea4742db5b5f5531b0e2d30ccee7883f54b0e80 (patch)
tree7ade9988cce658b1efc550ee4228f4bef4a4d6d8 /sql/event_timed.cc
parent7088b39da895cf22a2b71d21a8313cbf0dda3760 (diff)
downloadmariadb-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.cc140
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;
+}