diff options
author | unknown <andrey@lmy004.> | 2006-05-22 20:46:13 +0200 |
---|---|---|
committer | unknown <andrey@lmy004.> | 2006-05-22 20:46:13 +0200 |
commit | f4781a7e4cf2825d42e9df481a42d47a48b1dfb3 (patch) | |
tree | 3d492384ce369edfba63a049dc688265d9d27a21 /sql/event_scheduler.h | |
parent | 61bd3fa055e6d3e39ac20ed3c7568cccf955cf6e (diff) | |
download | mariadb-git-f4781a7e4cf2825d42e9df481a42d47a48b1dfb3.tar.gz |
fix for bug #17619 Scheduler race conditions
- Scheduler is either initialized at server start or never.
Starting & stopping is now suspending & resuming.
- The scheduler has clear OO interface
- Now all calls to the scheduler are synchronous
- GLOBAL event_scheduler uses thd::sys_var_tmp (see set_var.cc)
- External API is encapsulated into class Events
- Includes fixes for all comments of Kostja's review of 19.05.2005
Starting to merge into 5.1-release (5.1.10) and push
BitKeeper/etc/ignore:
Added libmysqld/event_scheduler.cc to the ignore list
libmysqld/Makefile.am:
executor -> scheduler
mysql-test/r/events.result:
update result
mysql-test/r/events_bugs.result:
update result
mysql-test/r/events_logs_tests.result:
update result
mysql-test/r/events_microsec.result:
update result
mysql-test/r/events_scheduling.result:
update result
mysql-test/r/events_stress.result:
update result
mysql-test/t/disabled.def:
enable these tests
mysql-test/t/events.test:
optimize the test a bit for speed, save some seconds runtime
remove FULL from SHOW EVENTS
mostly use I_S.EVENTS
mysql-test/t/events_bugs.test:
Skip irrelevant for the current design tests - all events are loaded
on server startup. Change in mysql.event will be visible on next server start.
Don't use numeric error codes.
mysql-test/t/events_logs_tests.test:
optimize the test a bit for speed
mysql-test/t/events_microsec.test:
Skip irrelevant for the current design tests - all events are loaded
on server startup. Change in mysql.event will be visible on next server start.
Don't use numeric error codes.
mysql-test/t/events_scheduling.test:
broader test
mysql-test/t/events_stress.test:
Rework the test to the new architecture of suspending/resuming.
Use less events, no need for thousands, hundreds is still ok.
sql/Makefile.am:
executor -> scheduler
sql/cmakelists.txt:
executor -> scheduler
sql/event.cc:
- remove todo comments
- remove unneded evex_queue abstraction functions
- move events_init() and events_shutdown() from event_executor.cc to here
- export db_create_event
- remove evex_load_and_compile_event, part of class Event_scheduler
- integrate the public interface found in event.h and used by sql_parse.cc
to use the new class Event_scheduler.
sql/event.h:
- add COND_finished so if one thread kills a running event it waits on this
- export callback event_timed_definer_equal, event_timed_identifier_equal(),
event_timed_name_equal and event_timed_db_equal()
to be used by Event_scheduler::drop_matching_events()
- cleanup event.h
- encapsulated all external interface into class Events
sql/event_executor.cc:
make it empty, will delete after that
sql/event_priv.h:
- more things in the private header
- remove event queue abstraction functions. tightly bind to QUEUE
- export privately db_drop_event, db_find_event, db_create_event()
- made change_security_context() and restore_security_context() free functions
sql/event_timed.cc:
- fix calculation of time when ENDS is set (STARTS is always set)
- during Event_timed::compile() set the right Security_ctx. Prevents a crash
during Event_scheduler::load_events_from_db()
- add Event_timed::kill_thread()
- implement event_timed_*_equal()
- made change_security_context() and restore_security_context() free functions.
- Comments cleanups
sql/lex.h:
new word scheduler for SHOW SCHEDULER STATUS (available only debug builds)
sql/log.cc:
move these from event_scheduler.cc
sql/mysql_priv.h:
refactor kill_one_thread
export sql_print_message_func and sql_print_message_handlers
sql/mysqld.cc:
In close_connections, called by kill_server() skip the main scheduler
thread and use events_shutdown() for shutting down the scheduler, in the same
manner it's done for RPL.
Add a new value to --event-scheduler :
0 <- No scheduler available
1 <- Start with scheduler enabled
2 <- Start with scheduler suspended
sql/repl_failsafe.cc:
refactor thd::system_thread to be an enum
sql/set_var.cc:
move sys_var_event_executor::update() to set_var.cc
executor -> scheduler
use thd::sys_var_tmp
sql/set_var.h:
executor -> scheduler
sql/share/errmsg.txt:
3 new error messages
sql/sql_class.cc:
refactor thd::system_thread to be an enum . more type-safety
sql/sql_class.h:
refactor thd::system_thread to be an enum . more type-safety
sql/sql_db.cc:
get the error from evex_drop_schema_events
sql/sql_error.h:
export warning_level_names
sql/sql_lex.h:
new command SHOW SCHEDULER STATUS, available only in debug build and
for debug purposes.
sql/sql_parse.cc:
refactor kill_one_thread() -> does the *dirty* work, and sql_kill
just the reporting.
add handler for SQLCOM_SHOW_SCHEDULER_STATUS
sql/sql_show.cc:
fix verbosity handling (this will be obsoleted anyway by the fix for 17394).
sql/sql_yacc.yy:
remove FULL from SHOW EVENTS
add SHOW SCHEDULER STATUS in debug builds
sql/table.cc:
Fix valgrind warning.
Diffstat (limited to 'sql/event_scheduler.h')
-rw-r--r-- | sql/event_scheduler.h | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/sql/event_scheduler.h b/sql/event_scheduler.h new file mode 100644 index 00000000000..e7bf4b633c5 --- /dev/null +++ b/sql/event_scheduler.h @@ -0,0 +1,254 @@ +#ifndef _EVENT_SCHEDULER_H_ +#define _EVENT_SCHEDULER_H_ +/* Copyright (C) 2004-2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +class THD; +typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*); + +int +events_init(); + +void +events_shutdown(); + + +class Event_scheduler +{ +public: + /* Return codes */ + enum enum_error_code + { + OP_OK= 0, + OP_NOT_RUNNING, + OP_CANT_KILL, + OP_CANT_INIT, + OP_DISABLED_EVENT, + OP_LOAD_ERROR, + OP_ALREADY_EXISTS + }; + + enum enum_state + { + UNINITIALIZED= 0, + INITIALIZED, + COMMENCING, + CANTSTART, + RUNNING, + SUSPENDED, + IN_SHUTDOWN + }; + + enum enum_suspend_or_resume + { + SUSPEND= 1, + RESUME= 2 + }; + + /* Singleton access */ + static Event_scheduler* + get_instance(); + + /* Methods for queue management follow */ + + enum enum_error_code + add_event(THD *thd, Event_timed *et, bool check_existence); + + bool + drop_event(THD *thd, Event_timed *et); + + enum enum_error_code + replace_event(THD *thd, Event_timed *et, LEX_STRING *new_schema, + LEX_STRING *new_name); + + int + drop_schema_events(THD *thd, LEX_STRING *schema); + + int + drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num) + { DBUG_ASSERT(0); return 0;} + + uint + events_count(); + + /* State changing methods follow */ + + bool + start(); + + enum enum_error_code + stop(); + + bool + start_suspended(); + + bool + run(THD *thd); + + enum enum_error_code + suspend_or_resume(enum enum_suspend_or_resume action); + + bool + init(); + + void + destroy(); + + static void + init_mutexes(); + + static void + destroy_mutexes(); + + void + report_error_during_start(); + + /* Information retrieving methods follow */ + + enum enum_state + get_state(); + + bool + initialized(); + + static int + dump_internal_status(THD *thd); + + static bool + check_system_tables(THD *thd); + +private: + Event_timed * + find_event(Event_timed *etn, bool remove_from_q); + + uint + workers_count(); + + bool + is_running_or_suspended(); + + /* helper functions */ + bool + execute_top(THD *thd); + + void + clean_queue(THD *thd); + + void + stop_all_running_events(THD *thd); + + enum enum_error_code + load_event(THD *thd, Event_timed *etn, Event_timed **etn_new); + + int + load_events_from_db(THD *thd); + + void + drop_matching_events(THD *thd, LEX_STRING *pattern, + bool (*)(Event_timed *,LEX_STRING *)); + + bool + check_n_suspend_if_needed(THD *thd); + + bool + check_n_wait_for_non_empty_queue(THD *thd); + + /* Singleton DP is used */ + Event_scheduler(); + + enum enum_cond_vars + { + COND_NONE= -1, + /* + COND_new_work is a conditional used to signal that there is a change + of the queue that should inform the executor thread that new event should + be executed sooner than previously expected, because of add/replace event. + */ + COND_new_work= 0, + /* + COND_started is a conditional used to synchronize the thread in which + ::start() was called and the spawned thread. ::start() spawns a new thread + and then waits on COND_started but also checks when awaken that `state` is + either RUNNING or CANTSTART. Then it returns back. + */ + COND_started_or_stopped, + /* + Conditional used for signalling from the scheduler thread back to the + thread that calls ::suspend() or ::resume. Synchronizing the calls. + */ + COND_suspend_or_resume, + /* Must be always last */ + COND_LAST, + }; + + /* Singleton instance */ + static Event_scheduler singleton; + + /* This is the current status of the life-cycle of the manager. */ + enum enum_state state; + + /* Set to start the scheduler in suspended state */ + bool start_scheduler_suspended; + + /* + LOCK_scheduler_data is the mutex which protects the access to the + manager's queue as well as used when signalling COND_new_work, + COND_started and COND_shutdown. + */ + pthread_mutex_t LOCK_scheduler_data; + + /* + Holds the thread id of the executor thread or 0 if the executor is not + running. It is used by ::shutdown() to know which thread to kill with + kill_one_thread(). The latter wake ups a thread if it is waiting on a + conditional variable and sets thd->killed to non-zero. + */ + ulong thread_id; + + pthread_cond_t cond_vars[COND_LAST]; + static const char * const cond_vars_names[COND_LAST]; + + /* The MEM_ROOT of the object */ + MEM_ROOT scheduler_root; + + /* The sorted queue with the Event_timed objects */ + QUEUE queue; + + uint mutex_last_locked_at_line; + uint mutex_last_unlocked_at_line; + const char* mutex_last_locked_in_func; + const char* mutex_last_unlocked_in_func; + enum enum_cond_vars cond_waiting_on; + bool mutex_scheduler_data_locked; + + /* helper functions for working with mutexes & conditionals */ + int + lock_data(const char *func, uint line); + + int + unlock_data(const char *func, uint line); + + int + cond_wait(enum enum_cond_vars, pthread_mutex_t *mutex); + +private: + /* Prevent use of these */ + Event_scheduler(const Event_scheduler &); + void operator=(Event_scheduler &); +}; + +#endif /* _EVENT_SCHEDULER_H_ */ |