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.
2006-05-22 20:46:13 +02:00
|
|
|
/* 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
|
2006-12-27 02:23:51 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
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.
2006-05-22 20:46:13 +02:00
|
|
|
|
|
|
|
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 */
|
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
#include "mysql_priv.h"
|
|
|
|
#include "events.h"
|
|
|
|
#include "event_data_objects.h"
|
|
|
|
#include "event_scheduler.h"
|
|
|
|
#include "event_queue.h"
|
|
|
|
|
|
|
|
#ifdef __GNUC__
|
|
|
|
#if __GNUC__ >= 2
|
|
|
|
#define SCHED_FUNC __FUNCTION__
|
|
|
|
#endif
|
|
|
|
#else
|
|
|
|
#define SCHED_FUNC "<unknown>"
|
|
|
|
#endif
|
|
|
|
|
2006-07-17 16:52:45 +02:00
|
|
|
#define LOCK_DATA() lock_data(SCHED_FUNC, __LINE__)
|
|
|
|
#define UNLOCK_DATA() unlock_data(SCHED_FUNC, __LINE__)
|
|
|
|
#define COND_STATE_WAIT(mythd, abstime, msg) \
|
|
|
|
cond_wait(mythd, abstime, msg, SCHED_FUNC, __LINE__)
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
extern pthread_attr_t connection_attrib;
|
|
|
|
|
|
|
|
static
|
2006-08-17 17:44:16 +02:00
|
|
|
const LEX_STRING scheduler_states_names[] =
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-09-12 12:26:12 +02:00
|
|
|
{ C_STRING_WITH_LEN("UNINITIALIZED") },
|
2006-08-17 17:44:16 +02:00
|
|
|
{ C_STRING_WITH_LEN("INITIALIZED") },
|
|
|
|
{ C_STRING_WITH_LEN("RUNNING") },
|
|
|
|
{ C_STRING_WITH_LEN("STOPPING") }
|
2006-07-12 10:37:30 +02:00
|
|
|
};
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
struct scheduler_param {
|
|
|
|
THD *thd;
|
|
|
|
Event_scheduler *scheduler;
|
|
|
|
};
|
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
Prints the stack of infos, warnings, errors from thd to
|
|
|
|
the console so it can be fetched by the logs-into-tables and
|
|
|
|
checked later.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
evex_print_warnings
|
|
|
|
thd Thread used during the execution of the event
|
|
|
|
et The event itself
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
|
|
|
evex_print_warnings(THD *thd, Event_job_data *et)
|
|
|
|
{
|
|
|
|
MYSQL_ERROR *err;
|
|
|
|
DBUG_ENTER("evex_print_warnings");
|
|
|
|
if (!thd->warn_list.elements)
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
|
|
|
|
char msg_buf[10 * STRING_BUFFER_USUAL_SIZE];
|
|
|
|
char prefix_buf[5 * STRING_BUFFER_USUAL_SIZE];
|
|
|
|
String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
|
|
|
|
prefix.length(0);
|
|
|
|
prefix.append("SCHEDULER: [");
|
|
|
|
|
|
|
|
append_identifier(thd, &prefix, et->definer.str, et->definer.length);
|
|
|
|
prefix.append("][", 2);
|
|
|
|
append_identifier(thd,&prefix, et->dbname.str, et->dbname.length);
|
|
|
|
prefix.append('.');
|
|
|
|
append_identifier(thd,&prefix, et->name.str, et->name.length);
|
|
|
|
prefix.append("] ", 2);
|
|
|
|
|
|
|
|
List_iterator_fast<MYSQL_ERROR> it(thd->warn_list);
|
|
|
|
while ((err= it++))
|
|
|
|
{
|
|
|
|
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
|
|
|
|
/* set it to 0 or we start adding at the end. That's the trick ;) */
|
|
|
|
err_msg.length(0);
|
|
|
|
err_msg.append(prefix);
|
|
|
|
err_msg.append(err->msg, strlen(err->msg), system_charset_info);
|
|
|
|
err_msg.append("]");
|
|
|
|
DBUG_ASSERT(err->level < 3);
|
|
|
|
(sql_print_message_handlers[err->level])("%*s", err_msg.length(),
|
|
|
|
err_msg.c_ptr());
|
|
|
|
}
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
/*
|
|
|
|
Performs post initialization of structures in a new thread.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
post_init_event_thread()
|
|
|
|
thd Thread
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
post_init_event_thread(THD *thd)
|
|
|
|
{
|
|
|
|
my_thread_init();
|
|
|
|
pthread_detach_this_thread();
|
|
|
|
thd->real_id= pthread_self();
|
|
|
|
if (init_thr_lock() || thd->store_globals())
|
|
|
|
{
|
|
|
|
thd->cleanup();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
|
|
|
|
sigset_t set;
|
|
|
|
VOID(sigemptyset(&set)); // Get mask in use
|
|
|
|
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
|
|
|
|
#endif
|
2006-08-11 16:51:50 +02:00
|
|
|
pthread_mutex_lock(&LOCK_thread_count);
|
|
|
|
threads.append(thd);
|
|
|
|
thread_count++;
|
|
|
|
thread_running++;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
return FALSE;
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Cleans up the THD and the threaded environment of the thread.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
deinit_event_thread()
|
|
|
|
thd Thread
|
|
|
|
*/
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
void
|
2006-07-12 10:37:30 +02:00
|
|
|
deinit_event_thread(THD *thd)
|
|
|
|
{
|
|
|
|
thd->proc_info= "Clearing";
|
|
|
|
DBUG_ASSERT(thd->net.buff != 0);
|
|
|
|
net_end(&thd->net);
|
2006-07-17 16:52:45 +02:00
|
|
|
DBUG_PRINT("exit", ("Event thread finishing"));
|
2006-07-12 10:37:30 +02:00
|
|
|
pthread_mutex_lock(&LOCK_thread_count);
|
|
|
|
thread_count--;
|
|
|
|
thread_running--;
|
|
|
|
delete thd;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
|
|
|
|
my_thread_end();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
/*
|
|
|
|
Performs pre- pthread_create() initialisation of THD. Do this
|
|
|
|
in the thread that will pass THD to the child thread. In the
|
|
|
|
child thread call post_init_event_thread().
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
pre_init_event_thread()
|
|
|
|
thd The THD of the thread. Has to be allocated by the caller.
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
1. The host of the thead is my_localhost
|
|
|
|
2. thd->net is initted with NULL - no communication.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
pre_init_event_thread(THD* thd)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("pre_init_event_thread");
|
|
|
|
thd->client_capabilities= 0;
|
|
|
|
thd->security_ctx->master_access= 0;
|
|
|
|
thd->security_ctx->db_access= 0;
|
|
|
|
thd->security_ctx->host_or_ip= (char*)my_localhost;
|
|
|
|
my_net_init(&thd->net, NULL);
|
|
|
|
thd->security_ctx->set_user((char*)"event_scheduler");
|
|
|
|
thd->net.read_timeout= slave_net_timeout;
|
|
|
|
thd->slave_thread= 0;
|
|
|
|
thd->options|= OPTION_AUTO_IS_NULL;
|
|
|
|
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
|
|
|
|
pthread_mutex_lock(&LOCK_thread_count);
|
|
|
|
thd->thread_id= thread_id++;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
|
|
|
|
/*
|
|
|
|
Guarantees that we will see the thread in SHOW PROCESSLIST though its
|
|
|
|
vio is NULL.
|
|
|
|
*/
|
|
|
|
|
|
|
|
thd->proc_info= "Initialized";
|
|
|
|
thd->version= refresh_version;
|
|
|
|
thd->set_time();
|
|
|
|
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
/*
|
|
|
|
Function that executes the scheduler,
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
event_scheduler_thread()
|
|
|
|
arg Pointer to `struct scheduler_param`
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
0 OK
|
|
|
|
*/
|
|
|
|
|
|
|
|
pthread_handler_t
|
|
|
|
event_scheduler_thread(void *arg)
|
|
|
|
{
|
|
|
|
/* needs to be first for thread_stack */
|
2006-07-13 10:59:58 +02:00
|
|
|
THD *thd= (THD *)((struct scheduler_param *) arg)->thd;
|
|
|
|
Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler;
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
my_free((char*)arg, MYF(0));
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
thd->thread_stack= (char *)&thd; // remember where our stack is
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
DBUG_ENTER("event_scheduler_thread");
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
if (!post_init_event_thread(thd))
|
|
|
|
scheduler->run(thd);
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
deinit_event_thread(thd);
|
|
|
|
|
|
|
|
DBUG_RETURN(0); // Against gcc warnings
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Function that executes an event in a child thread. Setups the
|
|
|
|
environment for the event execution and cleans after that.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
event_worker_thread()
|
|
|
|
arg The Event_job_data object to be processed
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
0 OK
|
|
|
|
*/
|
|
|
|
|
|
|
|
pthread_handler_t
|
|
|
|
event_worker_thread(void *arg)
|
|
|
|
{
|
|
|
|
/* needs to be first for thread_stack */
|
|
|
|
THD *thd;
|
|
|
|
Event_job_data *event= (Event_job_data *)arg;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
thd= event->thd;
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
thd->thread_stack= (char *) &thd; // remember where our stack is
|
|
|
|
DBUG_ENTER("event_worker_thread");
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
if (!post_init_event_thread(thd))
|
|
|
|
{
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("Baikonur, time is %ld, BURAN reporting and operational."
|
|
|
|
"THD: 0x%lx",
|
|
|
|
(long) time(NULL), (long) thd));
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-17 16:52:45 +02:00
|
|
|
sql_print_information("SCHEDULER: [%s.%s of %s] executing in thread %lu. "
|
|
|
|
"Execution %u",
|
2006-07-13 16:24:55 +02:00
|
|
|
event->dbname.str, event->name.str,
|
2006-07-17 16:52:45 +02:00
|
|
|
event->definer.str, thd->thread_id,
|
|
|
|
event->execution_count);
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
thd->enable_slow_log= TRUE;
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
ret= event->execute(thd);
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
evex_print_warnings(thd, event);
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-17 16:52:45 +02:00
|
|
|
sql_print_information("SCHEDULER: [%s.%s of %s] executed in thread %lu. "
|
|
|
|
"RetCode=%d", event->dbname.str, event->name.str,
|
2006-07-13 16:24:55 +02:00
|
|
|
event->definer.str, thd->thread_id, ret);
|
|
|
|
if (ret == EVEX_COMPILE_ERROR)
|
|
|
|
sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of %s",
|
|
|
|
event->dbname.str, event->name.str,
|
|
|
|
event->definer.str);
|
|
|
|
else if (ret == EVEX_MICROSECOND_UNSUP)
|
|
|
|
sql_print_information("SCHEDULER: MICROSECOND is not supported");
|
|
|
|
}
|
2006-07-12 10:37:30 +02:00
|
|
|
DBUG_PRINT("info", ("BURAN %s.%s is landing!", event->dbname.str,
|
|
|
|
event->name.str));
|
|
|
|
delete event;
|
|
|
|
|
|
|
|
deinit_event_thread(thd);
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
DBUG_RETURN(0); // Can't return anything here
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Performs initialization of the scheduler data, outside of the
|
|
|
|
threading primitives.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::init_scheduler()
|
|
|
|
*/
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
void
|
2006-07-12 10:37:30 +02:00
|
|
|
Event_scheduler::init_scheduler(Event_queue *q)
|
|
|
|
{
|
2006-07-13 16:24:55 +02:00
|
|
|
LOCK_DATA();
|
2006-07-12 10:37:30 +02:00
|
|
|
queue= q;
|
|
|
|
started_events= 0;
|
2006-08-31 17:18:39 +02:00
|
|
|
scheduler_thd= NULL;
|
2006-07-13 16:24:55 +02:00
|
|
|
state= INITIALIZED;
|
|
|
|
UNLOCK_DATA();
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
Event_scheduler::deinit_scheduler() {}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Inits scheduler's threading primitives.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::init_mutexes()
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Event_scheduler::init_mutexes()
|
|
|
|
{
|
|
|
|
pthread_mutex_init(&LOCK_scheduler_state, MY_MUTEX_INIT_FAST);
|
|
|
|
pthread_cond_init(&COND_state, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Deinits scheduler's threading primitives.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::deinit_mutexes()
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Event_scheduler::deinit_mutexes()
|
|
|
|
{
|
|
|
|
pthread_mutex_destroy(&LOCK_scheduler_state);
|
|
|
|
pthread_cond_destroy(&COND_state);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Starts the scheduler (again). Creates a new THD and passes it to
|
|
|
|
a forked thread. Does not wait for acknowledgement from the new
|
|
|
|
thread that it has started. Asynchronous starting. Most of the
|
|
|
|
needed initializations are done in the current thread to minimize
|
|
|
|
the chance of failure in the spawned thread.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::start()
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error (not reported)
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
Event_scheduler::start()
|
|
|
|
{
|
|
|
|
THD *new_thd= NULL;
|
|
|
|
bool ret= FALSE;
|
|
|
|
pthread_t th;
|
2006-07-13 10:59:58 +02:00
|
|
|
struct scheduler_param *scheduler_param_value;
|
2006-07-12 10:37:30 +02:00
|
|
|
DBUG_ENTER("Event_scheduler::start");
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
LOCK_DATA();
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str));
|
2006-07-12 10:37:30 +02:00
|
|
|
if (state > INITIALIZED)
|
|
|
|
goto end;
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
if (!(new_thd= new THD))
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-08-17 14:22:59 +02:00
|
|
|
sql_print_error("SCHEDULER: Cannot init manager event thread");
|
2006-07-12 10:37:30 +02:00
|
|
|
ret= TRUE;
|
|
|
|
goto end;
|
|
|
|
}
|
2006-07-13 10:59:58 +02:00
|
|
|
pre_init_event_thread(new_thd);
|
2006-07-12 10:37:30 +02:00
|
|
|
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
|
|
|
|
new_thd->command= COM_DAEMON;
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
scheduler_param_value=
|
|
|
|
(struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0));
|
|
|
|
scheduler_param_value->thd= new_thd;
|
|
|
|
scheduler_param_value->scheduler= this;
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-08-31 17:18:39 +02:00
|
|
|
scheduler_thd= new_thd;
|
|
|
|
DBUG_PRINT("info", ("Setting state go RUNNING"));
|
|
|
|
state= RUNNING;
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD: 0x%lx", (long) new_thd));
|
2006-07-12 10:37:30 +02:00
|
|
|
if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
|
2006-07-13 10:59:58 +02:00
|
|
|
(void*)scheduler_param_value))
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
|
|
|
DBUG_PRINT("error", ("cannot create a new thread"));
|
|
|
|
state= INITIALIZED;
|
2006-08-31 17:18:39 +02:00
|
|
|
scheduler_thd= NULL;
|
2006-07-12 10:37:30 +02:00
|
|
|
ret= TRUE;
|
|
|
|
|
|
|
|
new_thd->proc_info= "Clearing";
|
|
|
|
DBUG_ASSERT(new_thd->net.buff != 0);
|
|
|
|
net_end(&new_thd->net);
|
|
|
|
pthread_mutex_lock(&LOCK_thread_count);
|
|
|
|
thread_count--;
|
|
|
|
thread_running--;
|
|
|
|
delete new_thd;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
}
|
2006-08-31 17:18:39 +02:00
|
|
|
end:
|
|
|
|
UNLOCK_DATA();
|
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
DBUG_RETURN(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
The main loop of the scheduler.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::run()
|
|
|
|
thd Thread
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error (Serious error)
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
Event_scheduler::run(THD *thd)
|
|
|
|
{
|
2006-08-17 14:22:59 +02:00
|
|
|
int res= FALSE;
|
2006-07-12 10:37:30 +02:00
|
|
|
Event_job_data *job_data;
|
|
|
|
DBUG_ENTER("Event_scheduler::run");
|
|
|
|
|
|
|
|
sql_print_information("SCHEDULER: Manager thread started with id %lu",
|
2006-08-31 17:18:39 +02:00
|
|
|
thd->thread_id);
|
2006-07-12 10:37:30 +02:00
|
|
|
/*
|
|
|
|
Recalculate the values in the queue because there could have been stops
|
|
|
|
in executions of the scheduler and some times could have passed by.
|
|
|
|
*/
|
|
|
|
queue->recalculate_activation_times(thd);
|
2006-08-31 17:18:39 +02:00
|
|
|
|
|
|
|
while (is_running())
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
|
|
|
/* Gets a minimized version */
|
2006-08-31 17:18:39 +02:00
|
|
|
if (queue->get_top_for_execution_if_time(thd, &job_data))
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-08-31 17:18:39 +02:00
|
|
|
sql_print_information("SCHEDULER: Serious error during getting next "
|
|
|
|
"event to execute. Stopping");
|
2006-07-12 10:37:30 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("get_top returned job_data: 0x%lx", (long) job_data));
|
2006-08-31 17:18:39 +02:00
|
|
|
if (job_data)
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-08-31 17:18:39 +02:00
|
|
|
if ((res= execute_top(thd, job_data)))
|
|
|
|
break;
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-08-31 17:18:39 +02:00
|
|
|
DBUG_ASSERT(thd->killed);
|
|
|
|
DBUG_PRINT("info", ("job_data is NULL, the thread was killed"));
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
DBUG_PRINT("info", ("state=%s", scheduler_states_names[state].str));
|
|
|
|
}
|
2006-08-31 17:18:39 +02:00
|
|
|
LOCK_DATA();
|
2006-07-12 10:37:30 +02:00
|
|
|
DBUG_PRINT("info", ("Signalling back to the stopper COND_state"));
|
|
|
|
state= INITIALIZED;
|
2006-08-31 17:18:39 +02:00
|
|
|
pthread_cond_signal(&COND_state);
|
2006-07-13 16:24:55 +02:00
|
|
|
UNLOCK_DATA();
|
2006-07-12 10:37:30 +02:00
|
|
|
sql_print_information("SCHEDULER: Stopped");
|
|
|
|
|
|
|
|
DBUG_RETURN(res);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Creates a new THD instance and then forks a new thread, while passing
|
|
|
|
the THD pointer and job_data to it.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::execute_top()
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
FALSE OK
|
|
|
|
TRUE Error (Serious error)
|
|
|
|
*/
|
|
|
|
|
|
|
|
bool
|
|
|
|
Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
|
|
|
|
{
|
|
|
|
THD *new_thd;
|
|
|
|
pthread_t th;
|
|
|
|
int res= 0;
|
|
|
|
DBUG_ENTER("Event_scheduler::execute_top");
|
2006-08-17 14:22:59 +02:00
|
|
|
if (!(new_thd= new THD()))
|
2006-07-12 10:37:30 +02:00
|
|
|
goto error;
|
|
|
|
|
2006-07-13 10:59:58 +02:00
|
|
|
pre_init_event_thread(new_thd);
|
2006-07-12 10:37:30 +02:00
|
|
|
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
|
|
|
|
job_data->thd= new_thd;
|
|
|
|
DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
|
|
|
|
job_data->dbname.str, job_data->name.str));
|
|
|
|
|
|
|
|
/* Major failure */
|
|
|
|
if ((res= pthread_create(&th, &connection_attrib, event_worker_thread,
|
|
|
|
job_data)))
|
|
|
|
goto error;
|
|
|
|
|
2006-08-31 17:18:39 +02:00
|
|
|
++started_events;
|
|
|
|
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("Launch succeeded. BURAN is in THD: 0x%lx", (long) new_thd));
|
2006-07-12 10:37:30 +02:00
|
|
|
DBUG_RETURN(FALSE);
|
|
|
|
|
|
|
|
error:
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("error", ("Baikonur, we have a problem! res: %d", res));
|
2006-07-12 10:37:30 +02:00
|
|
|
if (new_thd)
|
|
|
|
{
|
|
|
|
new_thd->proc_info= "Clearing";
|
|
|
|
DBUG_ASSERT(new_thd->net.buff != 0);
|
|
|
|
net_end(&new_thd->net);
|
|
|
|
pthread_mutex_lock(&LOCK_thread_count);
|
|
|
|
thread_count--;
|
|
|
|
thread_running--;
|
|
|
|
delete new_thd;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
}
|
|
|
|
delete job_data;
|
|
|
|
DBUG_RETURN(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-31 17:18:39 +02:00
|
|
|
/*
|
2006-09-01 14:08:50 +02:00
|
|
|
Checks whether the state of the scheduler is RUNNING
|
2006-08-31 17:18:39 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::is_running()
|
|
|
|
|
|
|
|
RETURN VALUE
|
|
|
|
TRUE RUNNING
|
|
|
|
FALSE Not RUNNING
|
|
|
|
*/
|
|
|
|
|
2006-09-01 14:15:47 +02:00
|
|
|
bool
|
2006-08-31 17:18:39 +02:00
|
|
|
Event_scheduler::is_running()
|
|
|
|
{
|
|
|
|
LOCK_DATA();
|
|
|
|
bool ret= (state == RUNNING);
|
|
|
|
UNLOCK_DATA();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
/*
|
2006-07-13 16:24:55 +02:00
|
|
|
Stops the scheduler (again). Waits for acknowledgement from the
|
|
|
|
scheduler that it has stopped - synchronous stopping.
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
2006-07-13 16:24:55 +02:00
|
|
|
Event_scheduler::stop()
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
RETURN VALUE
|
2006-07-13 16:24:55 +02:00
|
|
|
FALSE OK
|
|
|
|
TRUE Error (not reported)
|
2006-07-12 10:37:30 +02:00
|
|
|
*/
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
bool
|
|
|
|
Event_scheduler::stop()
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-07-13 16:24:55 +02:00
|
|
|
THD *thd= current_thd;
|
|
|
|
DBUG_ENTER("Event_scheduler::stop");
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
|
2006-07-13 16:24:55 +02:00
|
|
|
|
|
|
|
LOCK_DATA();
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("state before action %s", scheduler_states_names[state].str));
|
2006-07-13 16:24:55 +02:00
|
|
|
if (state != RUNNING)
|
|
|
|
goto end;
|
|
|
|
|
|
|
|
/* Guarantee we don't catch spurious signals */
|
|
|
|
do {
|
|
|
|
DBUG_PRINT("info", ("Waiting for COND_started_or_stopped from the manager "
|
|
|
|
"thread. Current value of state is %s . "
|
|
|
|
"workers count=%d", scheduler_states_names[state].str,
|
|
|
|
workers_count()));
|
2006-08-31 17:18:39 +02:00
|
|
|
/*
|
|
|
|
NOTE: We don't use kill_one_thread() because it can't kill COM_DEAMON
|
|
|
|
threads. In addition, kill_one_thread() requires THD but during shutdown
|
|
|
|
current_thd is NULL. Hence, if kill_one_thread should be used it has to
|
|
|
|
be modified to kill also daemons, by adding a flag, and also we have to
|
|
|
|
create artificial THD here. To save all this work, we just do what
|
|
|
|
kill_one_thread() does to kill a thread. See also sql_repl.cc for similar
|
|
|
|
usage.
|
|
|
|
*/
|
|
|
|
|
|
|
|
state= STOPPING;
|
2006-11-27 00:47:38 +01:00
|
|
|
DBUG_PRINT("info", ("Manager thread has id %lu", scheduler_thd->thread_id));
|
2006-08-31 17:18:39 +02:00
|
|
|
/* Lock from delete */
|
|
|
|
pthread_mutex_lock(&scheduler_thd->LOCK_delete);
|
|
|
|
/* This will wake up the thread if it waits on Queue's conditional */
|
|
|
|
sql_print_information("SCHEDULER: Killing manager thread %lu",
|
|
|
|
scheduler_thd->thread_id);
|
|
|
|
scheduler_thd->awake(THD::KILL_CONNECTION);
|
|
|
|
pthread_mutex_unlock(&scheduler_thd->LOCK_delete);
|
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
/* thd could be 0x0, when shutting down */
|
2006-08-31 17:18:39 +02:00
|
|
|
sql_print_information("SCHEDULER: Waiting the manager thread to reply");
|
2006-07-17 16:52:45 +02:00
|
|
|
COND_STATE_WAIT(thd, NULL, "Waiting scheduler to stop");
|
2006-07-13 16:24:55 +02:00
|
|
|
} while (state == STOPPING);
|
|
|
|
DBUG_PRINT("info", ("Manager thread has cleaned up. Set state to INIT"));
|
2006-08-31 17:18:39 +02:00
|
|
|
/*
|
|
|
|
The rationale behind setting it to NULL here but not destructing it
|
|
|
|
beforehand is because the THD will be deinited in event_scheduler_thread().
|
|
|
|
It's more clear when the post_init and the deinit is done in one function.
|
|
|
|
Here we just mark that the scheduler doesn't have a THD anymore. Though for
|
|
|
|
milliseconds the old thread could exist we can't use it anymore. When we
|
|
|
|
unlock the mutex in this function a little later the state will be
|
|
|
|
INITIALIZED. Therefore, a connection thread could enter the critical section
|
|
|
|
and will create a new THD object.
|
|
|
|
*/
|
|
|
|
scheduler_thd= NULL;
|
2006-07-13 16:24:55 +02:00
|
|
|
end:
|
|
|
|
UNLOCK_DATA();
|
|
|
|
DBUG_RETURN(FALSE);
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Returns the number of living event worker threads.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::workers_count()
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint
|
|
|
|
Event_scheduler::workers_count()
|
|
|
|
{
|
|
|
|
THD *tmp;
|
|
|
|
uint count= 0;
|
|
|
|
|
|
|
|
DBUG_ENTER("Event_scheduler::workers_count");
|
|
|
|
pthread_mutex_lock(&LOCK_thread_count); // For unlink from list
|
|
|
|
I_List_iterator<THD> it(threads);
|
|
|
|
while ((tmp=it++))
|
|
|
|
if (tmp->system_thread == SYSTEM_THREAD_EVENT_WORKER)
|
|
|
|
++count;
|
|
|
|
pthread_mutex_unlock(&LOCK_thread_count);
|
|
|
|
DBUG_PRINT("exit", ("%d", count));
|
|
|
|
DBUG_RETURN(count);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Auxiliary function for locking LOCK_scheduler_state. Used
|
2006-07-13 16:24:55 +02:00
|
|
|
by the LOCK_DATA macro.
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::lock_data()
|
|
|
|
func Which function is requesting mutex lock
|
|
|
|
line On which line mutex lock is requested
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Event_scheduler::lock_data(const char *func, uint line)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Event_scheduler::lock_data");
|
|
|
|
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
|
|
|
|
pthread_mutex_lock(&LOCK_scheduler_state);
|
|
|
|
mutex_last_locked_in_func= func;
|
|
|
|
mutex_last_locked_at_line= line;
|
|
|
|
mutex_scheduler_data_locked= TRUE;
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Auxiliary function for unlocking LOCK_scheduler_state. Used
|
2006-07-13 16:24:55 +02:00
|
|
|
by the UNLOCK_DATA macro.
|
2006-07-12 10:37:30 +02:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::unlock_data()
|
|
|
|
func Which function is requesting mutex unlock
|
|
|
|
line On which line mutex unlock is requested
|
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
|
|
|
Event_scheduler::unlock_data(const char *func, uint line)
|
|
|
|
{
|
|
|
|
DBUG_ENTER("Event_scheduler::unlock_data");
|
|
|
|
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
|
|
|
|
mutex_last_unlocked_at_line= line;
|
|
|
|
mutex_scheduler_data_locked= FALSE;
|
|
|
|
mutex_last_unlocked_in_func= func;
|
|
|
|
pthread_mutex_unlock(&LOCK_scheduler_state);
|
|
|
|
DBUG_VOID_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Wrapper for pthread_cond_wait/timedwait
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::cond_wait()
|
2006-07-17 16:52:45 +02:00
|
|
|
thd Thread (Could be NULL during shutdown procedure)
|
|
|
|
abstime If not null then call pthread_cond_timedwait()
|
2006-08-31 17:18:39 +02:00
|
|
|
msg Message for thd->proc_info
|
2006-07-17 16:52:45 +02:00
|
|
|
func Which function is requesting cond_wait
|
|
|
|
line On which line cond_wait is requested
|
2006-07-12 10:37:30 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
void
|
2006-07-17 16:52:45 +02:00
|
|
|
Event_scheduler::cond_wait(THD *thd, struct timespec *abstime, const char* msg,
|
|
|
|
const char *func, uint line)
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
2006-07-17 16:52:45 +02:00
|
|
|
DBUG_ENTER("Event_scheduler::cond_wait");
|
2006-07-12 10:37:30 +02:00
|
|
|
waiting_on_cond= TRUE;
|
|
|
|
mutex_last_unlocked_at_line= line;
|
|
|
|
mutex_scheduler_data_locked= FALSE;
|
|
|
|
mutex_last_unlocked_in_func= func;
|
2006-07-17 16:52:45 +02:00
|
|
|
if (thd)
|
|
|
|
thd->enter_cond(&COND_state, &LOCK_scheduler_state, msg);
|
|
|
|
|
|
|
|
DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
|
2006-07-13 16:24:55 +02:00
|
|
|
if (!abstime)
|
2006-07-12 10:37:30 +02:00
|
|
|
pthread_cond_wait(&COND_state, &LOCK_scheduler_state);
|
2006-07-13 16:24:55 +02:00
|
|
|
else
|
|
|
|
pthread_cond_timedwait(&COND_state, &LOCK_scheduler_state, abstime);
|
2006-07-17 16:52:45 +02:00
|
|
|
if (thd)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
This will free the lock so we need to relock. Not the best thing to
|
|
|
|
do but we need to obey cond_wait()
|
|
|
|
*/
|
|
|
|
thd->exit_cond("");
|
|
|
|
LOCK_DATA();
|
|
|
|
}
|
2006-07-12 10:37:30 +02:00
|
|
|
mutex_last_locked_in_func= func;
|
|
|
|
mutex_last_locked_at_line= line;
|
|
|
|
mutex_scheduler_data_locked= TRUE;
|
|
|
|
waiting_on_cond= FALSE;
|
2006-07-17 16:52:45 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2006-07-13 16:24:55 +02:00
|
|
|
}
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-07-13 16:24:55 +02:00
|
|
|
|
2006-07-12 10:37:30 +02:00
|
|
|
/*
|
|
|
|
Dumps the internal status of the scheduler
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
Event_scheduler::dump_internal_status()
|
|
|
|
*/
|
|
|
|
|
2006-09-12 12:26:12 +02:00
|
|
|
void
|
|
|
|
Event_scheduler::dump_internal_status()
|
2006-07-12 10:37:30 +02:00
|
|
|
{
|
|
|
|
DBUG_ENTER("Event_scheduler::dump_internal_status");
|
|
|
|
|
2006-09-12 12:26:12 +02:00
|
|
|
puts("");
|
|
|
|
puts("Event scheduler status:");
|
|
|
|
printf("State : %s\n", scheduler_states_names[state].str);
|
|
|
|
printf("Thread id : %lu\n", scheduler_thd? scheduler_thd->thread_id : 0);
|
|
|
|
printf("LLA : %s:%u\n", mutex_last_locked_in_func,
|
|
|
|
mutex_last_locked_at_line);
|
|
|
|
printf("LUA : %s:%u\n", mutex_last_unlocked_in_func,
|
|
|
|
mutex_last_unlocked_at_line);
|
|
|
|
printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
|
|
|
|
printf("Workers : %u\n", workers_count());
|
2006-11-27 17:16:08 +01:00
|
|
|
printf("Executed : %lu\n", (ulong) started_events);
|
2006-09-12 12:26:12 +02:00
|
|
|
printf("Data locked: %s\n", mutex_scheduler_data_locked ? "YES":"NO");
|
2006-07-12 10:37:30 +02:00
|
|
|
|
2006-09-12 12:26:12 +02:00
|
|
|
DBUG_VOID_RETURN;
|
2006-07-12 10:37:30 +02:00
|
|
|
}
|