Below is the list of changes that have just been committed into a local
5.1 repository of andrey. When andrey does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2396 06/05/11 17:08:38 andrey@lmy004. +25 -0
manual merge
sql/table.cc
1.214 06/05/11 17:08:29 andrey@lmy004. +0 -10
manual merge
sql/share/errmsg.txt
1.99 06/05/11 17:08:29 andrey@lmy004. +0 -4
manual merge
sql/event_timed.cc
1.52 06/05/11 17:08:29 andrey@lmy004. +1 -6
manual merge
sql/event_executor.cc
1.44 06/05/11 17:08:29 andrey@lmy004. +0 -1
manual merge
sql/event.cc
1.40 06/05/11 17:08:29 andrey@lmy004. +6 -11
manual merge
sql/cmakelists.txt
1.19 06/05/11 17:08:29 andrey@lmy004. +1 -2
manual merge
sql/Makefile.am
1.138 06/05/11 17:08:29 andrey@lmy004. +3 -4
manual merge
mysql-test/t/events_bugs.test
1.7 06/05/11 17:08:29 andrey@lmy004. +3 -8
manual merge
mysql-test/t/events.test
1.29 06/05/11 17:08:29 andrey@lmy004. +10 -11
manual merge
mysql-test/t/disabled.def
1.154 06/05/11 17:08:29 andrey@lmy004. +0 -2
manual merge
mysql-test/r/events_bugs.result
1.9 06/05/11 17:08:28 andrey@lmy004. +3 -27
manual merge
mysql-test/r/events.result
1.33 06/05/11 17:08:28 andrey@lmy004. +7 -16
manual merge
libmysqld/Makefile.am
1.90 06/05/11 17:08:28 andrey@lmy004. +1 -2
manual merge
sql/sql_yacc.yy
1.476 06/05/11 16:41:08 andrey@lmy004. +0 -0
Auto merged
sql/sql_show.cc
1.331 06/05/11 16:41:08 andrey@lmy004. +0 -0
Auto merged
sql/sql_parse.cc
1.546 06/05/11 16:41:08 andrey@lmy004. +0 -0
Auto merged
sql/sql_lex.h
1.229 06/05/11 16:41:07 andrey@lmy004. +0 -0
Auto merged
sql/sql_class.h
1.294 06/05/11 16:41:07 andrey@lmy004. +0 -0
Auto merged
sql/sql_class.cc
1.258 06/05/11 16:41:06 andrey@lmy004. +0 -0
Auto merged
sql/set_var.cc
1.186 06/05/11 16:41:06 andrey@lmy004. +0 -0
Auto merged
sql/repl_failsafe.cc
1.66 06/05/11 16:41:06 andrey@lmy004. +0 -0
Auto merged
sql/mysqld.cc
1.554 06/05/11 16:41:06 andrey@lmy004. +0 -0
Auto merged
sql/mysql_priv.h
1.400 06/05/11 16:41:05 andrey@lmy004. +0 -0
Auto merged
sql/lex.h
1.161 06/05/11 16:41:05 andrey@lmy004. +0 -0
Auto merged
BitKeeper/etc/ignore
1.241 06/05/11 16:38:39 andrey@lmy004. +2 -2
auto-union
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: andrey
# Host: lmy004.
# Root: /work/mysql-5.1-bug17619-new-with_system_thread_fixed_bulk_drop/RESYNC
--- 1.137/sql/Makefile.am 2006-04-29 18:30:00 +02:00
+++ 1.138/sql/Makefile.am 2006-05-11 17:08:29 +02:00
@@ -66,7 +66,7 @@ noinst_HEADERS = item.h item_func.h item
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h event.h event_priv.h \
sql_plugin.h authors.h sql_partition.h \
- partition_info.h partition_element.h
+ partition_info.h partition_element.h event_scheduler.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
@@ -103,7 +103,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
- event_executor.cc event.cc event_timed.cc \
+ event_scheduler.cc event.cc event_timed.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc
--- 1.160/sql/lex.h 2006-05-03 14:59:12 +02:00
+++ 1.161/sql/lex.h 2006-05-11 16:41:05 +02:00
@@ -503,6 +503,7 @@ static SYMBOL symbols[] = {
{ "STARTING", SYM(STARTING)},
{ "STARTS", SYM(STARTS_SYM)},
{ "STATUS", SYM(STATUS_SYM)},
+ { "STATUS_EVENTS", SYM(STATUS_EVENTS_SYM)},
{ "STOP", SYM(STOP_SYM)},
{ "STORAGE", SYM(STORAGE_SYM)},
{ "STRAIGHT_JOIN", SYM(STRAIGHT_JOIN)},
@@ -518,6 +519,7 @@ static SYMBOL symbols[] = {
{ "TEMPORARY", SYM(TEMPORARY)},
{ "TEMPTABLE", SYM(TEMPTABLE_SYM)},
{ "TERMINATED", SYM(TERMINATED)},
+ { "TEST_EVENTS", SYM(TEST_EVENTS_SYM)},
{ "TEXT", SYM(TEXT_SYM)},
{ "THAN", SYM(THAN_SYM)},
{ "THEN", SYM(THEN_SYM)},
--- 1.399/sql/mysql_priv.h 2006-05-05 19:08:37 +02:00
+++ 1.400/sql/mysql_priv.h 2006-05-11 16:41:05 +02:00
@@ -79,7 +79,8 @@ char *sql_strmake_with_convert(const cha
CHARSET_INFO *from_cs,
uint32 max_res_length,
CHARSET_INFO *to_cs, uint32 *result_length);
-void kill_one_thread(THD *thd, ulong id, bool only_kill_query);
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query);
+void sql_kill(THD *thd, ulong id, bool only_kill_query);
bool net_request_file(NET* net, const char* fname);
char* query_table_status(THD *thd,const char *db,const char *table_name);
--- 1.553/sql/mysqld.cc 2006-05-04 21:20:35 +02:00
+++ 1.554/sql/mysqld.cc 2006-05-11 16:41:06 +02:00
@@ -883,6 +883,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
+ events_shutdown();
end_slave();
if (thread_count)
@@ -2992,7 +2993,6 @@ static int init_server_components()
#ifdef HAVE_REPLICATION
init_slave_list();
#endif
- init_events();
/* Setup logs */
@@ -3566,6 +3566,7 @@ we force server id to 2, but this MySQL
if (!opt_noacl)
{
+ events_init();
plugin_load();
#ifdef HAVE_DLOPEN
udf_init();
@@ -3667,7 +3668,6 @@ we force server id to 2, but this MySQL
clean_up(1);
wait_for_signal_thread_to_end();
clean_up_mutexes();
- shutdown_events();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(0);
@@ -4993,7 +4993,7 @@ Disable with --skip-bdb (will save memor
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"event-scheduler", OPT_EVENT_EXECUTOR, "Enable/disable the event scheduler.",
(gptr*) &opt_event_executor, (gptr*) &opt_event_executor, 0, GET_BOOL, NO_ARG,
- 0/*default*/, 0/*min-value*/, 1/*max-value*/, 0, 0, 0},
+ 1/*default*/, 0/*min-value*/, 1/*max-value*/, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option
enabled you can run myisamchk to test (not repair) tables while the MySQL server is
running.",
--- 1.257/sql/sql_class.cc 2006-05-05 19:08:37 +02:00
+++ 1.258/sql/sql_class.cc 2006-05-11 16:41:06 +02:00
@@ -250,7 +250,8 @@ THD::THD()
net.last_error[0]=0; // If error on boot
net.query_cache_query=0; // If error on boot
ull=0;
- system_thread= cleanup_done= abort_on_warning= no_warnings_for_error= 0;
+ system_thread= NON_SYSTEM_THREAD;
+ cleanup_done= abort_on_warning= no_warnings_for_error= 0;
peer_port= 0; // For SHOW PROCESSLIST
#ifdef HAVE_ROW_BASED_REPLICATION
transaction.m_pending_rows_event= 0;
@@ -507,6 +508,8 @@ void add_to_status(STATUS_VAR *to_var, S
void THD::awake(THD::killed_state state_to_set)
{
+ DBUG_ENTER("THD::awake");
+ DBUG_PRINT("enter", ("this=0x%lx", this));
THD_CHECK_SENTRY(this);
safe_mutex_assert_owner(&LOCK_delete);
@@ -544,12 +547,14 @@ void THD::awake(THD::killed_state state_
*/
if (mysys_var->current_cond && mysys_var->current_mutex)
{
+ DBUG_PRINT("info", ("broadcasting mysys_var->current_cond"));
pthread_mutex_lock(mysys_var->current_mutex);
pthread_cond_broadcast(mysys_var->current_cond);
pthread_mutex_unlock(mysys_var->current_mutex);
}
pthread_mutex_unlock(&mysys_var->mutex);
}
+ DBUG_VOID_RETURN;
}
/*
--- 1.293/sql/sql_class.h 2006-05-03 18:40:48 +02:00
+++ 1.294/sql/sql_class.h 2006-05-11 16:41:07 +02:00
@@ -770,6 +770,19 @@ public:
};
+/* Flags for the THD::system_thread variable */
+enum enum_system_thread
+{
+ NON_SYSTEM_THREAD= 0,
+ SYSTEM_THREAD_DELAYED_INSERT= 1,
+ SYSTEM_THREAD_SLAVE_IO= 2,
+ SYSTEM_THREAD_SLAVE_SQL= 4,
+ SYSTEM_THREAD_NDBCLUSTER_BINLOG= 8,
+ SYSTEM_THREAD_EVENT_SCHEDULER= 16,
+ SYSTEM_THREAD_EVENT_WORKER= 32
+};
+
+
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1103,7 +1116,8 @@ public:
long dbug_thread_id;
pthread_t real_id;
uint tmp_table, global_read_lock;
- uint server_status,open_options,system_thread;
+ uint server_status,open_options;
+ enum enum_system_thread system_thread;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
@@ -1402,11 +1416,6 @@ public:
#define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;}
-/* Flags for the THD::system_thread (bitmap) variable */
-#define SYSTEM_THREAD_DELAYED_INSERT 1
-#define SYSTEM_THREAD_SLAVE_IO 2
-#define SYSTEM_THREAD_SLAVE_SQL 4
-#define SYSTEM_THREAD_NDBCLUSTER_BINLOG 8
/*
Used to hold information about file and file structure in exchainge
--- 1.228/sql/sql_lex.h 2006-05-03 18:40:48 +02:00
+++ 1.229/sql/sql_lex.h 2006-05-11 16:41:07 +02:00
@@ -111,7 +111,8 @@ enum enum_sql_command {
SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT,
SQLCOM_SHOW_PLUGINS,
SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
- SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS,
+ SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, SQLCOM_SHOW_EVENTS_TEST,
+ SQLCOM_SHOW_EVENTS_INTERNAL_STATUS,
/* This should be the last !!! */
--- 1.545/sql/sql_parse.cc 2006-05-05 19:08:37 +02:00
+++ 1.546/sql/sql_parse.cc 2006-05-11 16:41:08 +02:00
@@ -2049,7 +2049,7 @@ bool dispatch_command(enum enum_server_c
{
statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
- kill_one_thread(thd,id,false);
+ sql_kill(thd,id,false);
break;
}
case COM_SET_OPTION:
@@ -3880,6 +3880,18 @@ end_with_restore_list:
res= evex_show_create_event(thd, lex->spname, lex->et->definer);
break;
}
+#ifndef DBUG_OFF
+ case SQLCOM_SHOW_EVENTS_TEST:
+ {
+ res= Event_scheduler::tests_run(thd);
+ break;
+ }
+ case SQLCOM_SHOW_EVENTS_INTERNAL_STATUS:
+ {
+ res= Event_scheduler::dump_internal_status(thd);
+ break;
+ }
+#endif
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
@@ -4119,7 +4131,7 @@ end_with_restore_list:
MYF(0));
goto error;
}
- kill_one_thread(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
+ sql_kill(thd, (ulong)it->val_int(), lex->type & ONLY_KILL_QUERY);
break;
}
#ifndef NO_EMBEDDED_ACCESS_CHECKS
@@ -6910,22 +6922,26 @@ bool reload_acl_and_cache(THD *thd, ulon
return result;
}
+
/*
- kill on thread
+ kills a thread
SYNOPSIS
kill_one_thread()
thd Thread class
id Thread id
+ only_kill_query Should it kill the query or the connection
NOTES
This is written such that we have a short lock on LOCK_thread_count
*/
-void kill_one_thread(THD *thd, ulong id, bool only_kill_query)
+uint kill_one_thread(THD *thd, ulong id, bool only_kill_query)
{
THD *tmp;
uint error=ER_NO_SUCH_THREAD;
+ DBUG_ENTER("kill_one_thread");
+ DBUG_PRINT("enter", ("id=%lu only_kill=%d", id, only_kill_query));
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
I_List_iterator<THD> it(threads);
while ((tmp=it++))
@@ -6951,8 +6967,25 @@ void kill_one_thread(THD *thd, ulong id,
error=ER_KILL_DENIED_ERROR;
pthread_mutex_unlock(&tmp->LOCK_delete);
}
+ DBUG_PRINT("exit", ("%d", error));
+ DBUG_RETURN(error);
+}
+
+
+/*
+ kills a thread and sends response
+
+ SYNOPSIS
+ sql_kill()
+ thd Thread class
+ id Thread id
+ only_kill_query Should it kill the query or the connection
+*/
- if (!error)
+void sql_kill(THD *thd, ulong id, bool only_kill_query)
+{
+ uint error;
+ if (!(error= kill_one_thread(thd, id, only_kill_query)))
send_ok(thd);
else
my_error(error, MYF(0), id);
--- 1.330/sql/sql_show.cc 2006-05-03 23:12:22 +02:00
+++ 1.331/sql/sql_show.cc 2006-05-11 16:41:08 +02:00
@@ -4147,13 +4147,10 @@ int fill_schema_events(THD *thd, TABLE_L
event_table->file->ha_index_init(0, 1);
- /*
- see others' events only if you have PROCESS_ACL !!
- thd->lex->verbose is set either if SHOW FULL EVENTS or
- in case of SELECT FROM I_S.EVENTS
- */
- verbose= (thd->lex->verbose
- && (thd->security_ctx->master_access & PROCESS_ACL));
+ /* see others' events only if you have PROCESS_ACL !! */
+ verbose= ((thd->lex->verbose ||
+ thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS) &&
+ (thd->security_ctx->master_access & PROCESS_ACL));
if (verbose && thd->security_ctx->user)
{
--- 1.475/sql/sql_yacc.yy 2006-05-03 23:12:23 +02:00
+++ 1.476/sql/sql_yacc.yy 2006-05-11 16:41:08 +02:00
@@ -608,6 +608,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
%token START_SYM
%token STARTS_SYM
%token STATUS_SYM
+%token STATUS_EVENTS_SYM
%token STD_SYM
%token STDDEV_SAMP_SYM
%token STOP_SYM
@@ -630,6 +631,7 @@ bool my_yyoverflow(short **a, YYSTYPE **
%token TEMPORARY
%token TEMPTABLE_SYM
%token TERMINATED
+%token TEST_EVENTS_SYM
%token TEXT_STRING
%token TEXT_SYM
%token TIMESTAMP
@@ -8058,6 +8060,24 @@ show_param:
if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS))
YYABORT;
}
+ | TEST_EVENTS_SYM
+ {
+#ifndef DBUG_OFF
+ Lex->sql_command= SQLCOM_SHOW_EVENTS_TEST;
+#else
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+#endif
+ }
+ | STATUS_EVENTS_SYM
+ {
+#ifndef DBUG_OFF
+ Lex->sql_command= SQLCOM_SHOW_EVENTS_INTERNAL_STATUS;
+#else
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+#endif
+ }
| TABLE_SYM STATUS_SYM opt_db wild_and_where
{
LEX *lex= Lex;
--- 1.213/sql/table.cc 2006-05-03 14:59:12 +02:00
+++ 1.214/sql/table.cc 2006-05-11 17:08:29 +02:00
@@ -2392,9 +2392,7 @@ table_check_intact(TABLE *table, uint ta
table running on a old server will be valid.
*/
field->sql_type(sql_type);
- if (sql_type.length() < table_def->type.length - 1 ||
- strncmp(sql_type.ptr(),
- table_def->type.str,
+ if (strncmp(sql_type.c_ptr_safe(), table_def->type.str,
table_def->type.length - 1))
{
sql_print_error("(%s) Expected field %s at position %d to have type "
--- 1.32/mysql-test/r/events.result 2006-04-07 11:29:08 +02:00
+++ 1.33/mysql-test/r/events.result 2006-05-11 17:08:28 +02:00
@@ -185,10 +185,10 @@ SHOW CREATE EVENT root20;
Event sql_mode Create Event
root20 CREATE EVENT `root20` ON SCHEDULE EVERY '50 20:12:45' DAY_SECOND ON COMPLETION
NOT PRESERVE ENABLE DO select 1
set names cp1251;
-create event 21 on schedule every '50:23:59:95' day_second COMMENT ' 1251
' do select 1;
-SHOW CREATE EVENT 21;
+create event ðóóò21 on schedule every '50:23:59:95' day_second
COMMENT 'òîâà å 1251
êîìåíòàð' do select 1;
+SHOW CREATE EVENT ðóóò21;
Event sql_mode Create Event
-21 CREATE EVENT `21` ON SCHEDULE EVERY '51 0:0:35' DAY_SECOND ON COMPLETION NOT
PRESERVE ENABLE COMMENT ' 1251 ' DO select 1
+ðóóò21 CREATE EVENT `ðóóò21` ON
SCHEDULE EVERY '51 0:0:35' DAY_SECOND ON COMPLETION NOT PRESERVE ENABLE COMMENT
'òîâà å 1251
êîìåíòàð' DO select 1
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values
(database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
show create event root22;
ERROR 42000: This version of MySQL doesn't yet support 'MICROSECOND'
@@ -213,7 +213,7 @@ drop event root17_1;
drop event root18;
drop event root19;
drop event root20;
-drop event 21;
+drop event ðóóò21;
set names latin1;
CREATE EVENT intact_check ON SCHEDULE EVERY 10 HOUR DO SELECT "nothing";
SHOW EVENTS;
@@ -389,9 +389,10 @@ create event закачка on schedule
select definer, name, db from mysql.event;
definer name db
root@localhost закачка events_test
-"Should be 0 processes"
+"Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
user host db command state info
+event_scheduler localhost NULL Connect Suspended NULL
select release_lock("test_lock1");
release_lock("test_lock1")
1
@@ -409,7 +410,7 @@ get_lock("test_lock2", 20)
create event закачка on schedule every 10 hour do select get_lock("test_lock2",
20);
"Let some time pass to the event starts"
"Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2", 20)
@@ -423,21 +424,17 @@ select get_lock("test_lock2_1", 20);
get_lock("test_lock2_1", 20)
1
create event закачка21 on schedule every 10 hour do select
get_lock("test_lock2_1", 20);
-"Should see 1 process, locked on get_lock("
-"Shutting down the scheduler, it should wait for the running event"
-set global event_scheduler=0;
-"Should have only 2 processes: the scheduler and the locked event"
-select /*4*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
+"Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
user host db command state info
event_scheduler localhost NULL Connect Sleeping NULL
root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
-"Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
-release_lock("test_lock2_1")
-1
-"Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
+set global event_scheduler=0;
+"Should have only our process now:"
+select /*4*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
user host db command state info
+event_scheduler localhost NULL Connect Suspended NULL
+root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule
every 1 second do set @a=5;
--- 1.8/mysql-test/r/events_bugs.result 2006-03-28 12:23:20 +02:00
+++ 1.9/mysql-test/r/events_bugs.result 2006-05-11 17:08:28 +02:00
@@ -5,10 +5,10 @@ CREATE EVENT Lower_case ON SCHEDULE EVER
ERROR HY000: Event 'Lower_case' already exists
DROP EVENT Lower_case;
SET NAMES cp1251;
-CREATE EVENT __1251 ON SCHEDULE EVERY 1 YEAR DO SELECT 100;
-CREATE EVENT __1251 ON SCHEDULE EVERY 2 YEAR DO SELECT 200;
+CREATE EVENT
äîëåí_ðåãèñòúð_1251
ON SCHEDULE EVERY 1 YEAR DO SELECT 100;
+CREATE EVENT
ÄîËåÍ_ðåãèñòúð_1251
ON SCHEDULE EVERY 2 YEAR DO SELECT 200;
ERROR HY000: Event 'ДоЛеН_регистър_1251' already exists
-DROP EVENT __1251;
+DROP EVENT
ÄîËåÍ_ðåãèñòúð_1251;
SET NAMES utf8;
CREATE EVENT долен_регистър_утф8 ON SCHEDULE EVERY 3 YEAR DO SELECT 300;
CREATE EVENT ДОЛЕН_регистър_утф8 ON SCHEDULE EVERY 4 YEAR DO SELECT 400;
--- 1.28/mysql-test/t/events.test 2006-04-22 04:29:18 +02:00
+++ 1.29/mysql-test/t/events.test 2006-05-11 17:08:29 +02:00
@@ -15,11 +15,10 @@ CREATE EVENT e_x2 ON SCHEDULE EVERY 1 SE
connection default;
SHOW DATABASES LIKE 'db_x';
SET GLOBAL event_scheduler=1;
---sleep 2
+--sleep 1.5
SHOW DATABASES LIKE 'db_x';
SHOW TABLES FROM db_x;
SET GLOBAL event_scheduler=0;
---sleep 1
connection priv_conn;
DROP EVENT e_x1;
DROP EVENT e_x2;
@@ -32,7 +31,6 @@ USE events_test;
# END: BUG #17289 Events: missing privilege check for drop database
#
SET GLOBAL event_scheduler=0;
---sleep 1
drop event if exists event1;
create event event1 on schedule every 15 minute starts now() ends date_add(now(),
interval 5 hour) DO begin end;
alter event event1 rename to event2 enable;
@@ -92,7 +90,7 @@ drop event e_43;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values
(800219);
---sleep 2
+--sleep 1
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
@@ -147,8 +145,8 @@ SHOW CREATE EVENT root19;
create event root20 on schedule every '50:20:12:45' day_second do select 1;
SHOW CREATE EVENT root20;
set names cp1251;
-create event 21 on schedule every '50:23:59:95' day_second COMMENT ' 1251
' do select 1;
-SHOW CREATE EVENT 21;
+create event ðóóò21 on schedule every '50:23:59:95' day_second
COMMENT 'òîâà å 1251
êîìåíòàð' do select 1;
+SHOW CREATE EVENT ðóóò21;
insert into mysql.event (db, name, body, definer, interval_value, interval_field) values
(database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND");
--error 1235
show create event root22;
@@ -173,7 +171,7 @@ drop event root17_1;
drop event root18;
drop event root19;
drop event root20;
-drop event 21;
+drop event ðóóò21;
set names latin1;
#
@@ -344,7 +342,7 @@ create event закачка on schedule
--echo "Should return 1 row"
select definer, name, db from mysql.event;
---echo "Should be 0 processes"
+--echo "Should be only 1 process"
select /*1*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
select release_lock("test_lock1");
drop event закачка;
@@ -362,7 +360,7 @@ create event закачка on schedule
--echo "Let some time pass to the event starts"
--sleep 2
--echo "Should have only 2 processes: the scheduler and the locked event"
-select /*1*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
+select /*2*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;--echo "Release the
mutex, the event worker should finish."
--echo "Release the mutex, the event worker should finish."
select release_lock("test_lock2");
drop event закачка;
@@ -379,18 +377,11 @@ set global event_scheduler=1;
select get_lock("test_lock2_1", 20);
create event закачка21 on schedule every 10 hour do select
get_lock("test_lock2_1", 20);
--sleep 1
---echo "Should see 1 process, locked on get_lock("
-#select /*3*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
---echo "Shutting down the scheduler, it should wait for the running event"
+--echo "Should have only 3 processes: the scheduler, our conn and the locked event"
+select /*3*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
set global event_scheduler=0;
---sleep 1
---echo "Should have only 2 processes: the scheduler and the locked event"
+--echo "Should have only our process now:"
select /*4*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
---echo "Release the lock so the child process should finish. Hence the scheduler also"
-select release_lock("test_lock2_1");
---sleep 1
---echo "Should see 0 processes now:"
-select /*5*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
drop event закачка21;
####
@@ -418,6 +409,7 @@ create event white_space on schedule eve
select 2;
select event_schema, event_name, definer, event_body from information_schema.events where
event_name='white_space';
+select event_schema, event_name, definer, event_body from information_schema.events where
event_name='white_space';
drop event white_space;
create event white_space on schedule every 10 hour disable do select 3;
select event_schema, event_name, definer, event_body from information_schema.events where
event_name='white_space';
@@ -426,7 +418,7 @@ drop event white_space;
# END: BUG #17453: Creating Event crash the server
#
-##set global event_scheduler=1;
+#
# Bug#17403 "Events: packets out of order with show create event"
#
create event e1 on schedule every 1 year do set @a = 5;
@@ -440,7 +432,7 @@ drop event e1;
##select get_lock("test_lock3", 20);
##create event закачка on schedule every 10 hour do select get_lock("test_lock3",
20);
##select sleep(2);
-##show processlist;
+##select /*5*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
##drop event закачка;
##select release_lock("test_lock3");
@@ -450,14 +442,14 @@ drop event e1;
##select get_lock("test_lock4", 20);
##create event закачка4 on schedule every 1 second do select
get_lock("test_lock4", 20);
##select sleep(3);
-##--replace_column 1 # 6 #
+##select /*6*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
##drop event закачка4;
##select release_lock("test_lock4");
##set global event_scheduler=0;
##select sleep(2);
##--replace_column 1 # 6 #
+##show processlist;
##select count(*) from mysql.event;
drop database events_test;
-
--- 1.6/mysql-test/t/events_bugs.test 2006-03-28 10:42:40 +02:00
+++ 1.7/mysql-test/t/events_bugs.test 2006-05-11 17:08:29 +02:00
@@ -9,10 +9,10 @@ CREATE EVENT lower_case ON SCHEDULE EVER
CREATE EVENT Lower_case ON SCHEDULE EVERY 2 MINUTE DO SELECT 2;
DROP EVENT Lower_case;
SET NAMES cp1251;
-CREATE EVENT __1251 ON SCHEDULE EVERY 1 YEAR DO SELECT 100;
+CREATE EVENT
äîëåí_ðåãèñòúð_1251
ON SCHEDULE EVERY 1 YEAR DO SELECT 100;
--error ER_EVENT_ALREADY_EXISTS
-CREATE EVENT __1251 ON SCHEDULE EVERY 2 YEAR DO SELECT 200;
-DROP EVENT __1251;
+CREATE EVENT
ÄîËåÍ_ðåãèñòúð_1251
ON SCHEDULE EVERY 2 YEAR DO SELECT 200;
+DROP EVENT
ÄîËåÍ_ðåãèñòúð_1251;
SET NAMES utf8;
CREATE EVENT долен_регистър_утф8 ON SCHEDULE EVERY 3 YEAR DO SELECT 300;
--error ER_EVENT_ALREADY_EXISTS
@@ -121,7 +121,7 @@ set global event_scheduler= 1;
--sleep 1
select /*2*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_2');
---sleep 3
+--sleep 2
select /*3*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
set global event_scheduler= 0;
select * from events_smode_test order by ev_name, a;
@@ -156,7 +156,7 @@ set global event_scheduler= 1;
--echo "Should have 2 locked processes"
select /*4*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
select release_lock('ee_16407_5');
---sleep 3
+--sleep 2
--echo "Should have 0 processes locked"
select /*5*/ user, host, db, command, state, info from information_schema.processlist
where info is null or info not like '%processlist%' order by info;
select * from events_smode_test order by ev_name, a;
--- 1.39/sql/event.cc 2006-04-07 09:13:20 +02:00
+++ 1.40/sql/event.cc 2006-05-11 17:08:29 +02:00
@@ -38,23 +38,8 @@
ENABLED to DISABLED status change and this is safe for replicating. As well
an event may be deleted which is also safe for RBR.
- - Maybe move all allocations during parsing to evex_mem_root thus saving
- double parsing in evex_create_event!
-
- - If the server is killed (stopping) try to kill executing events?
-
- - What happens if one renames an event in the DB while it is in memory?
- Or even deleting it?
-
- - Consider using conditional variable when doing shutdown instead of
- waiting till all worker threads end.
-
- - Make Event_timed::get_show_create_event() work
-
- Add logging to file
- - Move comparison code to class Event_timed
-
Warning:
- For now parallel execution is not possible because the same sp_head cannot be
executed few times!!! There is still no lock attached to particular event.
@@ -65,7 +50,7 @@ Warning:
QUEUE EVEX_EQ_NAME;
MEM_ROOT evex_mem_root;
time_t mysql_event_last_create_time= 0L;
-
+ulong opt_event_executor;
static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
{
@@ -186,30 +171,6 @@ LEX_STRING interval_type_to_name[] = {
};
-
-/*
- Inits the scheduler queue - prioritized queue from mysys/queue.c
-
- Synopsis
- evex_queue_init()
-
- queue - pointer the the memory to be initialized as queue. has to be
- allocated from the caller
-
- Notes
- During initialization the queue is sized for 30 events, and when is full
- will auto extent with 30.
-*/
-
-void
-evex_queue_init(EVEX_QUEUE_TYPE *queue)
-{
- if (init_queue_ex(queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
- event_timed_compare_q, NULL, 30 /*auto_extent*/))
- sql_print_error("Insufficient memory to initialize executing queue.");
-}
-
-
/*
Compares 2 LEX strings regarding case.
@@ -257,14 +218,8 @@ int sortcmp_lex_string(LEX_STRING s, LEX
int
my_time_compare(TIME *a, TIME *b)
{
-
-#ifdef ENABLE_WHEN_WE_HAVE_MILLISECOND_IN_TIMESTAMPS
- my_ulonglong a_t= TIME_to_ulonglong_datetime(a)*100L + a->second_part;
- my_ulonglong b_t= TIME_to_ulonglong_datetime(b)*100L + b->second_part;
-#else
my_ulonglong a_t= TIME_to_ulonglong_datetime(a);
my_ulonglong b_t= TIME_to_ulonglong_datetime(b);
-#endif
if (a_t > b_t)
return 1;
@@ -276,31 +231,6 @@ my_time_compare(TIME *a, TIME *b)
/*
- Compares the execute_at members of 2 Event_timed instances
-
- Synopsis
- event_timed_compare()
-
- a - first Event_timed object
- b - second Event_timed object
-
- RETURNS:
- -1 - a->execute_at < b->execute_at
- 0 - a->execute_at == b->execute_at
- 1 - a->execute_at > b->execute_at
-
- Notes
- execute_at.second_part is not considered during comparison
-*/
-
-int
-event_timed_compare(Event_timed *a, Event_timed *b)
-{
- return my_time_compare(&a->execute_at, &b->execute_at);
-}
-
-
-/*
Compares the execute_at members of 2 Event_timed instances.
Used as callback for the prioritized queue when shifting
elements inside.
@@ -324,7 +254,8 @@ event_timed_compare(Event_timed *a, Even
int
event_timed_compare_q(void *vptr, byte* a, byte *b)
{
- return event_timed_compare((Event_timed *)a, (Event_timed *)b);
+ return my_time_compare(&((Event_timed *)a)->execute_at,
+ &((Event_timed *)b)->execute_at);
}
@@ -462,6 +393,70 @@ common_1_lev_code:
}
+bool events_initted= false;
+
+/*
+ Inits the scheduler's structures.
+
+ Synopsis
+ events_init()
+
+ Note
+ This function is not synchronized.
+
+ Returns
+ 0 OK
+ 1 Error
+*/
+
+int
+events_init()
+{
+ DBUG_ENTER("events_init");
+
+ /* it should be an assignment! */
+ if (opt_event_executor && (events_initted= true) &&
+ Event_scheduler::get_instance()->start(true))
+ {
+ events_initted= false;
+ sql_print_error("SCHEDULER: Error while starting");
+ DBUG_RETURN(1);
+ }
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Cleans up scheduler's resources. Called at sever shutdown.
+
+ SYNOPSIS
+ events_shutdown()
+
+ Note
+ This function is not synchronized.
+*/
+
+void
+events_shutdown()
+{
+ DBUG_ENTER("events_shutdown");
+
+ if (events_initted)
+ {
+ Event_scheduler::get_instance()->shutdown(true);
+
+ if (Event_scheduler::destroy_singleton())
+ {
+ DBUG_ASSERT(0);
+ sql_print_error("SCHEDULER: Trying to destroy while still running!");
+ }
+ events_initted= false;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
/*
Open mysql.event table for read
@@ -721,7 +716,7 @@ trunc_err:
db_update_event. The name of the event is inside "et".
*/
-static int
+int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected)
{
@@ -863,7 +858,7 @@ db_update_event(THD *thd, Event_timed *e
DBUG_ENTER("db_update_event");
DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
- DBUG_PRINT("enter", ("user: %.*s", et->name.length, et->name.str));
+ DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
if (new_name)
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
new_name->m_name.str));
@@ -958,13 +953,13 @@ err:
# error *ett == 0
*/
-static int
+int
db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett,
TABLE *tbl, MEM_ROOT *root)
{
TABLE *table;
int ret;
- Event_timed *et= 0;
+ Event_timed *et=NULL;
DBUG_ENTER("db_find_event");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
@@ -1001,7 +996,7 @@ db_find_event(THD *thd, sp_name *name, L
}
done:
- if (ret)
+ if (ret && et)
{
delete et;
et= 0;
@@ -1015,140 +1010,6 @@ done:
/*
- Looks for a named event in mysql.event and then loads it from
- the table, compiles it and insert it into the cache.
-
- SYNOPSIS
- evex_load_and_compile_event()
- thd THD
- spn the name of the event to alter
- definer who is the owner
- use_lock whether to obtain a lock on LOCK_event_arrays or not
-
- RETURN VALUE
- 0 - OK
- < 0 - error (in this case underlying functions call my_error()).
-*/
-
-static int
-evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
- bool use_lock)
-{
- int ret= 0;
- MEM_ROOT *tmp_mem_root;
- Event_timed *ett;
- Open_tables_state backup;
-
- DBUG_ENTER("db_load_and_compile_event");
- DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
-
- tmp_mem_root= thd->mem_root;
- thd->mem_root= &evex_mem_root;
-
- thd->reset_n_backup_open_tables_state(&backup);
- /* no need to use my_error() here because db_find_event() has done it */
- ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
- thd->restore_backup_open_tables_state(&backup);
- if (ret)
- goto done;
-
- ett->compute_next_execution_time();
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) ett);
-
- /*
- There is a copy in the array which we don't need. sphead won't be
- destroyed.
- */
-
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
-done:
- if (thd->mem_root != tmp_mem_root)
- thd->mem_root= tmp_mem_root;
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- Removes from queue in memory the event which is identified by the tupple
- (db, name).
-
- SYNOPSIS
- evex_remove_from_cache()
-
- db - db name
- name - event name
- use_lock - whether to lock the mutex LOCK_event_arrays or not in case it
- has been already locked outside
- is_drop - if an event is currently being executed then we can also delete
- the Event_timed instance, so we alarm the event that it should
- drop itself if this parameter is set to TRUE. It's false on
- ALTER EVENT.
-
- RETURNS
- 0 OK (always)
-*/
-
-static int
-evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
- bool is_drop)
-{
- //ToDo : Add definer to the tuple (db, name) to become triple
- uint i;
- int ret= 0;
-
- DBUG_ENTER("evex_remove_from_cache");
- /*
- It is possible that 2 (or 1) pass(es) won't find the event in memory.
- The reason is that DISABLED events are not cached.
- */
-
- if (use_lock)
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?",db->str,name->str, et->dbname.str,
- et->name.str));
- if (!sortcmp_lex_string(*name, et->name, system_charset_info) &&
- !sortcmp_lex_string(*db, et->dbname, system_charset_info))
- {
- if (et->can_spawn_now())
- {
- DBUG_PRINT("evex_remove_from_cache", ("not running - free and delete"));
- et->free_sp();
- delete et;
- }
- else
- {
- DBUG_PRINT("evex_remove_from_cache",
- ("running.defer mem free. is_drop=%d", is_drop));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= is_drop;
- }
- DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);
- /* ok, we have cleaned */
- ret= 0;
- goto done;
- }
- }
-
-done:
- if (use_lock)
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
- DBUG_RETURN(ret);
-}
-
-
-/*
The function exported to the world for creating of events.
SYNOPSIS
@@ -1168,26 +1029,20 @@ int
evex_create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected)
{
- int ret = 0;
+ int ret;
DBUG_ENTER("evex_create_event");
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
et->name.str, create_options));
- if ((ret = db_create_event(thd, et,
+ if (!(ret = db_create_event(thd, et,
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
rows_affected)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running && et->status == MYSQL_EVENT_ENABLED)
{
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, et->definer, true);
+ if (events_initted &&
+ (ret= Event_scheduler::get_instance()->add_event(thd, et, true)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
/* No need to close the table, it will be closed in sql_parse::do_command */
DBUG_RETURN(ret);
@@ -1214,41 +1069,26 @@ evex_update_event(THD *thd, Event_timed
uint *rows_affected)
{
int ret;
- bool need_second_pass= true;
DBUG_ENTER("evex_update_event");
DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
-
/*
db_update_event() opens & closes the table to prevent
crash later in the code when loading and compiling the new definition.
Also on error conditions my_error() is called so no need to handle here
*/
- if ((ret= db_update_event(thd, et, new_name)))
- goto done;
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- evex_remove_from_cache(&et->dbname, &et->name, false, false);
- if (et->status == MYSQL_EVENT_ENABLED)
- {
- if (new_name)
- ret= evex_load_and_compile_event(thd, new_name, et->definer, false);
- else
- {
- sp_name spn(et->dbname, et->name);
- ret= evex_load_and_compile_event(thd, &spn, et->definer, false);
- }
- if (ret == EVEX_COMPILE_ERROR)
- my_error(ER_EVENT_COMPILE_ERROR, MYF(0));
+ if (!(ret= db_update_event(thd, et, new_name)))
+ {
+ if (events_initted &&
+ (ret= Event_scheduler::get_instance()->replace_event(thd, et,
+ new_name?
+ &new_name->m_db:
+ NULL,
+ new_name?
+ &new_name->m_name:
+ NULL)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-done:
DBUG_RETURN(ret);
}
@@ -1330,22 +1170,15 @@ int
evex_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected)
{
- int ret= 0;
+ int ret;
DBUG_ENTER("evex_drop_event");
-
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (evex_is_running)
- ret= evex_remove_from_cache(&et->dbname, &et->name, true, true);
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- if (ret == 1)
- ret= 0;
- else if (ret == 0)
- ret= db_drop_event(thd, et, drop_if_exists, rows_affected);
- else
- my_error(ER_UNKNOWN_ERROR, MYF(0));
+ if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected)))
+ {
+ if (events_initted &&
+ (ret= Event_scheduler::get_instance()->drop_event(thd, et)))
+ my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
+ }
DBUG_RETURN(ret);
}
@@ -1379,7 +1212,7 @@ evex_show_create_event(THD *thd, sp_name
ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root);
thd->restore_backup_open_tables_state(&backup);
- if (et)
+ if (!ret && et)
{
Protocol *protocol= thd->protocol;
char show_str_buf[768];
@@ -1389,12 +1222,10 @@ evex_show_create_event(THD *thd, sp_name
ulong sql_mode_len=0;
show_str.length(0);
+ show_str.set_charset(system_charset_info);
if (et->get_create_event(thd, &show_str))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
field_list.push_back(new Item_empty_string("Event", NAME_LEN));
@@ -1408,198 +1239,101 @@ evex_show_create_event(THD *thd, sp_name
show_str.length()));
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
- {
- delete et;
- DBUG_RETURN(1);
- }
+ goto err;
+
protocol->prepare_for_resend();
protocol->store(et->name.str, et->name.length, system_charset_info);
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
- protocol->store(show_str.ptr(), show_str.length(), system_charset_info);
+ protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
ret= protocol->write();
send_eof(thd);
- delete et;
}
-
+ delete et;
DBUG_RETURN(ret);
+err:
+ delete et;
+ DBUG_RETURN(1);
}
/*
- evex_drop_db_events - Drops all events in the selected database
+ Drops all events from a schema
+
+ Synopsis
+ evex_drop_db_events()
+ thd Thread
+ db ASCIIZ schema name
- thd - Thread
- db - ASCIIZ the name of the database
-
Returns:
- 0 - OK
- 1 - Failed to delete a specific row
- 2 - Got NULL while reading db name from a row
-
- Note:
- The algo is the following
- 1. Go through the in-memory cache, if the scheduler is working
- and for every event whose dbname matches the database we drop
- check whether is currently in execution:
- - Event_timed::can_spawn() returns true -> the event is not
- being executed in a child thread. The reason not to use
- Event_timed::is_running() is that the latter shows only if
- it is being executed, which is 99% of the time in the thread
- but there are some initiliazations before and after the
- anonymous SP is being called. So if we delete in this moment
- -=> *boom*, so we have to check whether the thread has been
- spawned and can_spawn() is the right method.
- - Event_timed::can_spawn() returns false -> being runned ATM
- just set the flags so it should drop itself.
+ 0 OK
+ !0 Error
*/
int
-evex_drop_db_events(THD *thd, char *db)
+evex_drop_schema_events(THD *thd, char *db)
{
- TABLE *table;
- READ_RECORD read_record_info;
int ret= 0;
- uint i;
LEX_STRING db_lex= {db, strlen(db)};
DBUG_ENTER("evex_drop_db_events");
- DBUG_PRINT("info",("dropping events from %s", db));
+ DBUG_PRINT("enter", ("dropping events from %s", db));
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
+ if (events_initted)
+ ret= Event_scheduler::get_instance()->drop_schema_events(thd, &db_lex);
+ else
+ ret= db_drop_events_from_table(thd, &db_lex);
- if ((ret= evex_open_event_table(thd, TL_WRITE, &table)))
- {
- sql_print_error("Table mysql.event is damaged.");
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
+ DBUG_RETURN(ret);
+}
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- if (!evex_is_running)
- goto skip_memory;
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- if (sortcmp_lex_string(et->dbname, db_lex, system_charset_info))
- continue;
+/*
+ Drops all events in the selected database, from mysql.event.
- if (et->can_spawn_now_n_lock(thd))
- {
- DBUG_PRINT("info",("event %s not running - direct delete", et->name.str));
- if (!(ret= evex_db_find_event_aux(thd, et, table)))
- {
- DBUG_PRINT("info",("event %s found on disk", et->name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- sql_print_error("Error while deleting a row - dropping "
- "a database. Skipping the rest.");
- my_error(ER_EVENT_DROP_FAILED, MYF(0), et->name.str);
- goto end;
- }
- DBUG_PRINT("info",("deleted event [%s] num [%d]. Time to free mem",
- et->name.str, i));
- }
- else if (ret == EVEX_KEY_NOT_FOUND)
- {
- sql_print_error("Expected to find event %s.%s of %s on disk-not there.",
- et->dbname.str, et->name.str, et->definer.str);
- }
- et->free_sp();
- delete et;
- et= 0;
- /* no need to call et->spawn_unlock because we already cleaned et */
- }
- else
- {
- DBUG_PRINT("info",("event %s is running. setting exec_no_more and dropped",
- et->name.str));
- et->flags|= EVENT_EXEC_NO_MORE;
- et->dropped= TRUE;
- }
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
- DBUG_PRINT("info",("%d elements in the queue",
- evex_queue_num_elements(EVEX_EQ_NAME)));
- /*
- decrease so we start at the same position, there will be
- less elements in the queue, it will still be ordered so on
- next iteration it will be again i the current element or if
- no more we finish.
- */
- --i;
- }
+ Synopsis
+ evex_drop_db_events_from_table()
+ thd Thread
+ db Schema name
+
+ Returns
+ 0 OK
+ !0 Error from ha_delete_row
+*/
-skip_memory:
- /*
- The reasoning behind having two loops is the following:
- If there was only one loop, the table-scan, then for every element which
- matches, the queue in memory has to be searched to remove the element.
- While if we go first over the queue and remove what's in there we have only
- one pass over it and after finishing it, moving to table-scan for the disabled
- events. This needs quite less time and means quite less locking on
- LOCK_event_arrays.
- */
- DBUG_PRINT("info",("Mem-cache checked, now going to db for disabled events"));
+int
+db_drop_events_from_table(THD *thd, LEX_STRING *db)
+{
+ int ret;
+ TABLE *table;
+ READ_RECORD read_record_info;
+ DBUG_ENTER("db_drop_events_from_table");
+ DBUG_PRINT("info", ("dropping events from %s", db->str));
+
+ if ((ret= evex_open_event_table(thd, TL_WRITE, &table)))
+ {
+ sql_print_error("Table mysql.event is damaged.");
+ DBUG_RETURN(ret);
+ }
/* only enabled events are in memory, so we go now and delete the rest */
- init_read_record(&read_record_info, thd, table ,NULL,1,0);
+ init_read_record(&read_record_info, thd, table, NULL, 1, 0);
while (!(read_record_info.read_record(&read_record_info)) && !ret)
{
- char *et_db;
+ char *et_db= get_field(thd->mem_root, table->field[EVEX_FIELD_DB]);
- if ((et_db= get_field(thd->mem_root, table->field[EVEX_FIELD_DB])) == NULL)
- {
- ret= 2;
- break;
- }
-
LEX_STRING et_db_lex= {et_db, strlen(et_db)};
- if (!sortcmp_lex_string(et_db_lex, db_lex, system_charset_info))
+ DBUG_PRINT("info", ("Current event %s.%s", et_db,
+ get_field(thd->mem_root, table->field[EVEX_FIELD_NAME])));
+ if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info))
{
- Event_timed ett;
- char *ptr;
-
- if ((ptr= get_field(thd->mem_root, table->field[EVEX_FIELD_STATUS]))
- == NullS)
- {
- sql_print_error("Error while loading from mysql.event. "
- "Table probably corrupted");
- goto end;
- }
- /*
- When not running nothing is in memory so we have to clean
- everything.
- We don't delete EVENT_ENABLED events when the scheduler is running
- because maybe this is an event which we asked to drop itself when
- it is finished and it hasn't finished yet, so we don't touch it.
- It will drop itself. The not running ENABLED events has been already
- deleted from ha_delete_row() above in the loop over the QUEUE
- (in case the executor is running).
- 'D' stands for DISABLED, 'E' for ENABLED - it's an enum
- */
- if ((evex_is_running && ptr[0] == 'D') || !evex_is_running)
- {
- DBUG_PRINT("info", ("Dropping %s.%s", et_db, ett.name.str));
- if ((ret= table->file->ha_delete_row(table->record[0])))
- {
- my_error(ER_EVENT_DROP_FAILED, MYF(0), ett.name.str);
- goto end;
- }
- }
+ DBUG_PRINT("info", ("Dropping"));
+ if ((ret= table->file->ha_delete_row(table->record[0])))
+ my_error(ER_EVENT_DROP_FAILED, MYF(0),
+ get_field(thd->mem_root, table->field[EVEX_FIELD_NAME]));
}
}
- DBUG_PRINT("info",("Disk checked for disabled events. Finishing."));
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
end_read_record(&read_record_info);
-
thd->version--; /* Force close to free memory */
close_thread_tables(thd);
--- 1.43/sql/event_executor.cc 2006-04-16 03:17:25 +02:00
+++ 1.44/sql/event_executor.cc 2006-05-11 17:08:29 +02:00
@@ -15,996 +15,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "event_priv.h"
-#include "event.h"
-#include "sp.h"
+#include "event_scheduler.h"
-#define WAIT_STATUS_READY 0
-#define WAIT_STATUS_EMPTY_QUEUE 1
-#define WAIT_STATUS_NEW_TOP_EVENT 2
-#define WAIT_STATUS_STOP_EXECUTOR 3
-
-/*
- Make this define DBUG_FAULTY_THR to be able to put breakpoints inside
- code used by the scheduler's thread(s). In this case user connections
- are not possible because the scheduler thread code is ran inside the
- main thread (no spawning takes place. If you want to debug client
- connection then start with --one-thread and make the define
- DBUG_FAULTY_THR !
-*/
-#define DBUG_FAULTY_THR2
-
-extern ulong thread_created;
-extern const char *my_localhost;
-extern pthread_attr_t connection_attrib;
-
-pthread_mutex_t LOCK_event_arrays, // mutex for when working with the queue
- LOCK_workers_count, // mutex for when inc/dec uint
workers_count
- LOCK_evex_running; // mutes for managing bool
evex_is_running
-
-static pthread_mutex_t LOCK_evex_main_thread; // mutex for when working with the queue
-bool scheduler_main_thread_running= false;
-
-bool evex_is_running= false;
-
-ulonglong evex_main_thread_id= 0;
-ulong opt_event_executor;
-my_bool event_executor_running_global_var;
-static my_bool evex_mutexes_initted= FALSE;
-static uint workers_count;
-
-static int
-evex_load_events_from_db(THD *thd);
-
-bool
-evex_print_warnings(THD *thd, Event_timed *et);
-
-/*
- TODO Andrey: Check for command line option whether to start
- the main thread or not.
-*/
-
-pthread_handler_t
-event_executor_worker(void *arg);
-
-pthread_handler_t
-event_executor_main(void *arg);
-
-
-/*
- Returns the seconds difference of 2 TIME structs
-
- SYNOPSIS
- evex_time_diff()
- a - TIME struct 1
- b - TIME struct 2
-
- Returns:
- the seconds difference
-*/
-
-static int
-evex_time_diff(TIME *a, TIME *b)
-{
- return sec_since_epoch_TIME(a) - sec_since_epoch_TIME(b);
-}
-
-
-/*
- Inits the mutexes used by the scheduler module
-
- SYNOPSIS
- evex_init_mutexes()
-
- NOTES
- The mutexes are :
- LOCK_event_arrays
- LOCK_workers_count
- LOCK_evex_running
-*/
-
-static void
-evex_init_mutexes()
-{
- if (evex_mutexes_initted)
- return;
-
- evex_mutexes_initted= TRUE;
- pthread_mutex_init(&LOCK_event_arrays, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_workers_count, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_evex_running, MY_MUTEX_INIT_FAST);
- pthread_mutex_init(&LOCK_evex_main_thread, MY_MUTEX_INIT_FAST);
-
- event_executor_running_global_var= opt_event_executor;
-}
-
-extern TABLE_FIELD_W_TYPE mysql_db_table_fields[];
-extern time_t mysql_db_table_last_check;
-
-/*
- Opens mysql.db and mysql.user and checks whether
- 1. mysql.db has column Event_priv at column 20 (0 based);
- 2. mysql.user has column Event_priv at column 29 (0 based);
-
- Synopsis
- evex_check_system_tables()
-*/
-
-void
-evex_check_system_tables()
-{
- THD *thd= current_thd;
- TABLE_LIST tables;
- Open_tables_state backup;
-
- /* thd is 0x0 during boot of the server. Later it's !=0x0 */
- if (!thd)
- return;
-
- thd->reset_n_backup_open_tables_state(&backup);
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "db";
- tables.lock_type= TL_READ;
-
- if (simple_open_n_lock_tables(thd, &tables))
- sql_print_error("Cannot open mysql.db");
- else
- {
- table_check_intact(tables.table, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields,
- &mysql_db_table_last_check,ER_CANNOT_LOAD_FROM_TABLE);
- close_thread_tables(thd);
- }
-
- bzero((char*) &tables, sizeof(tables));
- tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*) "user";
- tables.lock_type= TL_READ;
-
- if (simple_open_n_lock_tables(thd, &tables))
- sql_print_error("Cannot open mysql.db");
- else
- {
- if (tables.table->s->fields < 29 ||
- strncmp(tables.table->field[29]->field_name,
- STRING_WITH_LEN("Event_priv")))
- sql_print_error("mysql.user has no `Event_priv` column at position 29");
-
- close_thread_tables(thd);
- }
-
- thd->restore_backup_open_tables_state(&backup);
-}
-
-
-/*
- Inits the scheduler. Called on server start and every time the scheduler
- is started with switching the event_scheduler global variable to TRUE
-
- SYNOPSIS
- init_events()
-
- NOTES
- Inits the mutexes used by the scheduler. Done at server start.
-*/
-
-int
-init_events()
-{
- pthread_t th;
- DBUG_ENTER("init_events");
-
- DBUG_PRINT("info",("Starting events main thread"));
-
- evex_check_system_tables();
-
- evex_init_mutexes();
-
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- if (event_executor_running_global_var)
- {
-#ifndef DBUG_FAULTY_THR
- /* TODO Andrey: Change the error code returned! */
- if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
- DBUG_RETURN(ER_SLAVE_THREAD);
-#else
- event_executor_main(NULL);
-#endif
- }
-
- DBUG_RETURN(0);
-}
-
-
-/*
- Cleans up scheduler memory. Called on server shutdown.
-
- SYNOPSIS
- shutdown_events()
-
- NOTES
- Destroys the mutexes.
-*/
-
-void
-shutdown_events()
-{
- DBUG_ENTER("shutdown_events");
-
- if (evex_mutexes_initted)
- {
- evex_mutexes_initted= FALSE;
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- pthread_mutex_destroy(&LOCK_event_arrays);
- pthread_mutex_destroy(&LOCK_workers_count);
- pthread_mutex_destroy(&LOCK_evex_running);
- pthread_mutex_destroy(&LOCK_evex_main_thread);
- }
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Inits an scheduler thread handler, both the main and a worker
-
- SYNOPSIS
- 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.
-
- Returns
- 0 - OK
- -1 - Error
-*/
-
-static int
-init_event_thread(THD* thd)
-{
- DBUG_ENTER("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, 0);
- thd->net.read_timeout = slave_net_timeout;
- thd->slave_thread= 0;
- thd->options|= OPTION_AUTO_IS_NULL;
- thd->client_capabilities= CLIENT_LOCAL_FILES;
- thd->real_id=pthread_self();
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->thread_id= thread_id++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- if (init_thr_lock() || thd->store_globals())
- {
- thd->cleanup();
- delete thd;
- DBUG_RETURN(-1);
- }
-
-#if !defined(__WIN__) && !defined(__NETWARE__)
- sigset_t set;
- VOID(sigemptyset(&set)); // Get mask in use
- VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
-#endif
-
- thd->proc_info= "Initialized";
- thd->version= refresh_version;
- thd->set_time();
- DBUG_RETURN(0);
-}
-
-
-/*
- This function waits till the time next event in the queue should be
- executed.
-
- Returns
- WAIT_STATUS_READY There is an event to be executed right now
- WAIT_STATUS_EMPTY_QUEUE No events or the last event was dropped.
- WAIT_STATUS_NEW_TOP_EVENT New event has entered the queue and scheduled
- on top. Restart ticking.
- WAIT_STATUS_STOP_EXECUTOR The thread was killed or SET global event_scheduler=0;
-*/
-
-static int
-executor_wait_till_next_event_exec(THD *thd)
-{
- Event_timed *et;
- TIME time_now;
- int t2sleep;
-
- DBUG_ENTER("executor_wait_till_next_event_exec");
- /*
- now let's see how much time to sleep, we know there is at least 1
- element in the queue.
- */
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_RETURN(WAIT_STATUS_EMPTY_QUEUE);
- }
- et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
- DBUG_ASSERT(et);
- if (et->status == MYSQL_EVENT_DISABLED)
- {
- DBUG_PRINT("evex main thread",("Now it is disabled-exec no more"));
- if (et->dropped)
- et->drop(thd);
- delete et;
- evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- sql_print_information("Event found disabled, dropping.");
- DBUG_RETURN(1);
- }
-
- DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
- /* set the internal clock of thd */
- thd->end_time();
- my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
- t2sleep= evex_time_diff(&et->execute_at, &time_now);
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
-
- t2sleep*=20;
- DBUG_PRINT("evex main thread",("unlocked LOCK_event_arrays"));
- if (t2sleep > 0)
- {
- ulonglong modified= et->modified;
- /*
- We sleep t2sleep seconds but we check every second whether this thread
- has been killed, or there is a new candidate
- */
- while (t2sleep-- && !thd->killed &&
event_executor_running_global_var &&
- evex_queue_num_elements(EVEX_EQ_NAME) &&
- (evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) == et &&
- evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified ==
- modified))
- {
- DBUG_PRINT("evex main thread",("will sleep a bit more."));
- my_sleep(50000);
- }
- DBUG_PRINT("info",("saved_modified=%llu current=%llu", modified,
- evex_queue_num_elements(EVEX_EQ_NAME)?
- evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*)->modified:
- (ulonglong)~0));
- }
-
- int ret= WAIT_STATUS_READY;
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- ret= WAIT_STATUS_EMPTY_QUEUE;
- else if (evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*) != et)
- ret= WAIT_STATUS_NEW_TOP_EVENT;
- if (thd->killed && event_executor_running_global_var)
- ret= WAIT_STATUS_STOP_EXECUTOR;
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- The main scheduler thread. Inits the priority queue on start and
- destroys it on thread shutdown. Forks child threads for every event
- execution. Sleeps between thread forking and does not do a busy wait.
-
- SYNOPSIS
- event_executor_main()
- arg unused
-
- NOTES
- 1. The host of the thead is my_localhost
- 2. thd->net is initted with NULL - no communication.
-
-*/
-
-pthread_handler_t
-event_executor_main(void *arg)
-{
- THD *thd; /* needs to be first for thread_stack */
- uint i=0, j=0;
- my_ulonglong cnt= 0;
-
- DBUG_ENTER("event_executor_main");
- DBUG_PRINT("event_executor_main", ("EVEX thread started"));
-
- pthread_mutex_lock(&LOCK_evex_main_thread);
- if (!scheduler_main_thread_running)
- scheduler_main_thread_running= true;
- else
- {
- DBUG_PRINT("event_executor_main", ("already running. thd_id=%d",
- evex_main_thread_id));
- pthread_mutex_unlock(&LOCK_evex_main_thread);
- my_thread_end();
- pthread_exit(0);
- DBUG_RETURN(0); // Can't return anything here
- }
- pthread_mutex_unlock(&LOCK_evex_main_thread);
-
- /* init memory root */
- init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
-
- /* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
- my_thread_init();
-
- if (sizeof(my_time_t) != sizeof(time_t))
- {
- sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
- "The scheduler will not work correctly. Stopping.");
- DBUG_ASSERT(0);
- goto err_no_thd;
- }
-
- /* note that contructor of THD uses DBUG_ ! */
- if (!(thd = new THD))
- {
- sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
- goto err_no_thd;
- }
- thd->thread_stack = (char*)&thd; // remember where our stack is
-
- pthread_detach_this_thread();
-
- if (init_event_thread(thd))
- goto finish;
-
- /*
- make this thread visible it has no vio -> show processlist won't see it
- unless it's marked as system thread
- */
- thd->system_thread= 1;
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- threads.append(thd);
- thread_count++;
- thread_running++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- DBUG_PRINT("EVEX main thread", ("Initing events_queue"));
-
- /*
- eventually manifest that we are running, not to crashe because of
- usage of non-initialized memory structures.
- */
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- evex_queue_init(&EVEX_EQ_NAME);
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- evex_is_running= true;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- thd->security_ctx->user= my_strdup("event_scheduler", MYF(0));
-
- if (evex_load_events_from_db(thd))
- goto finish;
-
- evex_main_thread_id= thd->thread_id;
-
- sql_print_information("SCHEDULER: Main thread started");
- while (!thd->killed)
- {
- TIME time_now;
- Event_timed *et;
-
- cnt++;
- DBUG_PRINT("info", ("EVEX External Loop %d thd->k", cnt));
-
- thd->proc_info = "Sleeping";
- if (!event_executor_running_global_var)
- {
- sql_print_information("SCHEDULER: Asked to stop.");
- break;
- }
-
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- my_sleep(100000);// sleep 0.1s
- continue;
- }
-
-restart_ticking:
- switch (executor_wait_till_next_event_exec(thd)) {
- case WAIT_STATUS_READY: // time to execute the event on top
- DBUG_PRINT("evex main thread",("time to execute an event"));
- break;
- case WAIT_STATUS_EMPTY_QUEUE: // no more events
- DBUG_PRINT("evex main thread",("no more events"));
- continue;
- break;
- case WAIT_STATUS_NEW_TOP_EVENT: // new event on top in the queue
- DBUG_PRINT("evex main thread",("restart ticking"));
- goto restart_ticking;
- case WAIT_STATUS_STOP_EXECUTOR:
- sql_print_information("SCHEDULER: Asked to stop.");
- goto finish;
- break;
- default:
- DBUG_ASSERT(0);
- }
-
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- thd->end_time();
- my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
-
- if (!evex_queue_num_elements(EVEX_EQ_NAME))
- {
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- DBUG_PRINT("evex main thread",("empty queue"));
- continue;
- }
- et= evex_queue_first_element(&EVEX_EQ_NAME, Event_timed*);
- DBUG_PRINT("evex main thread",("got event from the queue"));
-
- if (!et->execute_at_null &&
my_time_compare(&time_now,&et->execute_at) == -1)
- {
- DBUG_PRINT("evex main thread",("still not the time for execution"));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- continue;
- }
-
- DBUG_PRINT("evex main thread",("it's right time"));
- if (et->status == MYSQL_EVENT_ENABLED)
- {
- int fork_ret_code;
-
- DBUG_PRINT("evex main thread", ("[%10s] this exec at [%llu]", et->name.str,
- TIME_to_ulonglong_datetime(&et->execute_at)));
- et->mark_last_executed(thd);
- if (et->compute_next_execution_time())
- {
- sql_print_error("SCHEDULER: Error while computing time of %s.%s . "
- "Disabling after execution.",
- et->dbname.str, et->name.str);
- et->status= MYSQL_EVENT_DISABLED;
- }
- DBUG_PRINT("evex main thread", ("[%10s] next exec at [%llu]", et->name.str,
- TIME_to_ulonglong_datetime(&et->execute_at)));
-
- et->update_fields(thd);
-#ifndef DBUG_FAULTY_THR
- thread_safe_increment(workers_count, &LOCK_workers_count);
- switch ((fork_ret_code= et->spawn_now(event_executor_worker))) {
- case EVENT_EXEC_CANT_FORK:
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- sql_print_error("SCHEDULER: Problem while trying to create a thread");
- UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_event_arrays, finish);
- case EVENT_EXEC_ALREADY_EXEC:
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- sql_print_information("SCHEDULER: %s.%s in execution. Skip this time.",
- et->dbname.str, et->name.str);
- break;
- default:
- DBUG_ASSERT(!fork_ret_code);
- if (fork_ret_code)
- thread_safe_decrement(workers_count, &LOCK_workers_count);
- break;
- }
-#else
- event_executor_worker((void *) et);
-#endif
- /*
- 1. For one-time event : year is > 0 and expression is 0
- 2. For recurring, expression is != -=> check execute_at_null in this case
- */
- if ((et->execute_at.year && !et->expression) ||
et->execute_at_null)
- et->flags |= EVENT_EXEC_NO_MORE;
-
- if ((et->flags & EVENT_EXEC_NO_MORE) || et->status ==
MYSQL_EVENT_DISABLED)
- evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
- else
- evex_queue_first_updated(&EVEX_EQ_NAME);
- }
- DBUG_PRINT("evex main thread",("unlocking"));
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- }/* while */
-finish:
-
- /* First manifest that this thread does not work and then destroy */
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- evex_main_thread_id= 0;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
-
- /*
- TODO: A better will be with a conditional variable
- */
- /*
- Read workers_count without lock, no need for locking.
- In the worst case we have to wait 1sec more.
- */
- sql_print_information("SCHEDULER: Stopping. Waiting for worker threads to finish.");
- while (1)
- {
- VOID(pthread_mutex_lock(&LOCK_workers_count));
- if (!workers_count)
- {
- VOID(pthread_mutex_unlock(&LOCK_workers_count));
- break;
- }
- VOID(pthread_mutex_unlock(&LOCK_workers_count));
- my_sleep(1000000);// 1s
- }
-
- /*
- First we free all objects ...
- Lock because a DROP DATABASE could be running in parallel and it locks on these
- */
- sql_print_information("SCHEDULER: Emptying the queue.");
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
- for (i= 0; i < evex_queue_num_elements(EVEX_EQ_NAME); ++i)
- {
- Event_timed *et= evex_queue_element(&EVEX_EQ_NAME, i, Event_timed*);
- et->free_sp();
- delete et;
- }
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- /* ... then we can thrash the whole queue at once */
- evex_queue_destroy(&EVEX_EQ_NAME);
-
- thd->proc_info = "Clearing";
- DBUG_ASSERT(thd->net.buff != 0);
- net_end(&thd->net); // destructor will not free it, because we are weird
- THD_CHECK_SENTRY(thd);
-
- pthread_mutex_lock(&LOCK_thread_count);
- thread_count--;
- thread_running--;
-#ifndef DBUG_FAULTY_THR
- THD_CHECK_SENTRY(thd);
- delete thd;
-#endif
- pthread_mutex_unlock(&LOCK_thread_count);
-
-
-err_no_thd:
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- evex_is_running= false;
- event_executor_running_global_var= false;
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- free_root(&evex_mem_root, MYF(0));
- sql_print_information("SCHEDULER: Stopped.");
-
-#ifndef DBUG_FAULTY_THR
- pthread_mutex_lock(&LOCK_evex_main_thread);
- scheduler_main_thread_running= false;
- pthread_mutex_unlock(&LOCK_evex_main_thread);
-
- my_thread_end();
- pthread_exit(0);
-#endif
- DBUG_RETURN(0); // Can't return anything here
-}
-
-
-/*
- Function that executes an event in a child thread. Setups the
- environment for the event execution and cleans after that.
-
- SYNOPSIS
- event_executor_worker()
- arg The Event_timed object to be processed
-*/
-
-pthread_handler_t
-event_executor_worker(void *event_void)
-{
- THD *thd; /* needs to be first for thread_stack */
- Event_timed *event = (Event_timed *) event_void;
- MEM_ROOT worker_mem_root;
-
- DBUG_ENTER("event_executor_worker");
-
- init_alloc_root(&worker_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
-
-#ifndef DBUG_FAULTY_THR
- my_thread_init();
-
- if (!(thd = new THD)) /* note that contructor of THD uses DBUG_ ! */
- {
- sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
- goto err_no_thd;
- }
- thd->thread_stack = (char*)&thd; // remember where our stack is
- thd->mem_root= &worker_mem_root;
-
- pthread_detach_this_thread();
-
- if (init_event_thread(thd))
- goto err;
-
- thd->init_for_queries();
-
- /* make this thread visible it has no vio -> show processlist needs this flag */
- thd->system_thread= 1;
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- threads.append(thd);
- thread_count++;
- thread_running++;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-#else
- thd= current_thd;
-#endif
-
- thd->enable_slow_log= TRUE;
- {
- int ret;
- sql_print_information("SCHEDULER: Executing event %s.%s of %s [EXPR:%d]",
- event->dbname.str, event->name.str,
- event->definer.str, (int) event->expression);
-
- ret= event->execute(thd, &worker_mem_root);
-
- evex_print_warnings(thd, event);
- sql_print_information("SCHEDULER: Executed event %s.%s of %s [EXPR:%d]. "
- "RetCode=%d", event->dbname.str, event->name.str,
- event->definer.str, (int) event->expression, ret);
- if (ret == EVEX_COMPILE_ERROR)
- sql_print_information("SCHEDULER: COMPILE ERROR for event %s.%s of",
- event->dbname.str, event->name.str,
- event->definer.str);
- else if (ret == EVEX_MICROSECOND_UNSUP)
- sql_print_information("SCHEDULER: MICROSECOND is not supported");
- }
- event->spawn_thread_finish(thd);
-
-
-err:
- VOID(pthread_mutex_lock(&LOCK_thread_count));
-#ifndef DBUG_FAULTY_THR
- thread_count--;
- thread_running--;
- /*
- Some extra safety, which should not been needed (normally, event deletion
- should already have done these assignments (each event which sets these
- variables is supposed to set them to 0 before terminating)).
- */
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
- thd->proc_info = "Clearing";
- DBUG_ASSERT(thd->net.buff != 0);
- net_end(&thd->net); // destructor will not free it, because we are weird
- THD_CHECK_SENTRY(thd);
-
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- THD_CHECK_SENTRY(thd);
- delete thd;
-#endif
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
-
-err_no_thd:
-
- free_root(&worker_mem_root, MYF(0));
- thread_safe_decrement(workers_count, &LOCK_workers_count);
-
-#ifndef DBUG_FAULTY_THR
- my_thread_end();
- pthread_exit(0);
-#endif
- DBUG_RETURN(0); // Can't return anything here
-}
-
-
-/*
- Loads all ENABLED events from mysql.event into the prioritized
- queue. Called during scheduler main thread initialization. Compiles
- the events. Creates Event_timed instances for every ENABLED event
- from mysql.event.
-
- SYNOPSIS
- evex_load_events_from_db()
- thd - Thread context. Used for memory allocation in some cases.
-
- RETURNS
- 0 OK
- !0 Error
-
- NOTES
- Reports the error to the console
-*/
-
-static int
-evex_load_events_from_db(THD *thd)
-{
- TABLE *table;
- READ_RECORD read_record_info;
- int ret= -1;
- uint count= 0;
-
- DBUG_ENTER("evex_load_events_from_db");
-
- if ((ret= evex_open_event_table(thd, TL_READ, &table)))
- {
- sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
- DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- }
-
- VOID(pthread_mutex_lock(&LOCK_event_arrays));
-
- init_read_record(&read_record_info, thd, table ,NULL,1,0);
- while (!(read_record_info.read_record(&read_record_info)))
- {
- Event_timed *et;
- if (!(et= new Event_timed))
- {
- DBUG_PRINT("evex_load_events_from_db", ("Out of memory"));
- ret= -1;
- goto end;
- }
- DBUG_PRINT("evex_load_events_from_db", ("Loading event from row."));
-
- if ((ret= et->load_from_row(&evex_mem_root, table)))
- {
- sql_print_error("SCHEDULER: Error while loading from mysql.event. "
- "Table probably corrupted");
- goto end;
- }
- if (et->status != MYSQL_EVENT_ENABLED)
- {
- DBUG_PRINT("evex_load_events_from_db",("%s is disabled",et->name.str));
- delete et;
- continue;
- }
-
- DBUG_PRINT("evex_load_events_from_db",
- ("Event %s loaded from row. Time to compile", et->name.str));
-
- switch (ret= et->compile(thd, &evex_mem_root)) {
- case EVEX_MICROSECOND_UNSUP:
- sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
- "supported but found in mysql.event");
- goto end;
- case EVEX_COMPILE_ERROR:
- sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
- et->dbname.str, et->name.str);
- goto end;
- default:
- break;
- }
-
- /* let's find when to be executed */
- if (et->compute_next_execution_time())
- {
- sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
- " Skipping", et->dbname.str, et->name.str);
- continue;
- }
-
- DBUG_PRINT("evex_load_events_from_db", ("Adding to the exec list."));
-
- evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et);
- DBUG_PRINT("evex_load_events_from_db", ("%p %*s",
- et, et->name.length,et->name.str));
- count++;
- }
-
- ret= 0;
-
-end:
- VOID(pthread_mutex_unlock(&LOCK_event_arrays));
- end_read_record(&read_record_info);
-
- /* Force close to free memory */
- thd->version--;
-
- close_thread_tables(thd);
- if (!ret)
- sql_print_information("SCHEDULER: Loaded %d event%s", count, (count == 1)?"":"s");
- DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
-
- DBUG_RETURN(ret);
-}
-
-
-/*
- The update method of the global variable event_scheduler.
- If event_scheduler is switched from 0 to 1 then the scheduler main
- thread is started.
-
- SYNOPSIS
- event_executor_worker()
- thd - Thread context (unused)
- car - the new value
-
- Returns
- 0 OK (always)
-*/
-
-bool
-sys_var_event_executor::update(THD *thd, set_var *var)
-{
- /* here start the thread if not running. */
- DBUG_ENTER("sys_var_event_executor::update");
- VOID(pthread_mutex_lock(&LOCK_evex_running));
- *value= var->save_result.ulong_value;
-
- DBUG_PRINT("new_value", ("%d", *value));
- if ((my_bool) *value && !evex_is_running)
- {
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
- init_events();
- } else
- VOID(pthread_mutex_unlock(&LOCK_evex_running));
-
- DBUG_RETURN(0);
-}
-
-
-extern LEX_STRING warning_level_names[];
-
-typedef void (*sql_print_xxx_func)(const char *format, ...);
-static sql_print_xxx_func sql_print_xxx_handlers[3] =
-{
- sql_print_information,
- sql_print_warning,
- sql_print_error
-};
-
-
-/*
- 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
-
- Returns
- 0 - OK (always)
-
-*/
-
-bool
-evex_print_warnings(THD *thd, Event_timed *et)
-{
- MYSQL_ERROR *err;
- DBUG_ENTER("evex_show_warnings");
- char msg_buf[1024];
- char prefix_buf[512];
- String prefix(prefix_buf, sizeof(prefix_buf), system_charset_info);
- prefix.length(0);
-
- 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);
- if (!prefix.length())
- {
- prefix.append("SCHEDULER: [");
-
-
append_identifier(thd,&prefix,et->definer_user.str,et->definer_user.length);
- prefix.append('@');
-
append_identifier(thd,&prefix,et->definer_host.str,et->definer_host.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);
- }
-
- 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_xxx_handlers[err->level])("%*s", err_msg.length(), err_msg.c_ptr());
- }
-
-
- DBUG_RETURN(FALSE);
-}
--- 1.51/sql/event_timed.cc 2006-05-04 18:39:42 +02:00
+++ 1.52/sql/event_timed.cc 2006-05-11 17:08:29 +02:00
@@ -1301,12 +1301,6 @@ Event_timed::execute(THD *thd, MEM_ROOT
running= true;
VOID(pthread_mutex_unlock(&this->LOCK_running));
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access,
thd->security_ctx->db_access));
- change_security_context(thd, &security_ctx, &save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access,
thd->security_ctx->db_access));
-
if (!sphead && (ret= compile(thd, mem_root)))
goto done;
/* Now we are sure we have valid this->sphead so we can copy the context */
@@ -1334,12 +1328,11 @@ Event_timed::execute(THD *thd, MEM_ROOT
definer_host.str, dbname.str));
ret= -99;
}
- restore_security_context(thd, save_ctx);
- DBUG_PRINT("info", ("master_access=%d db_access=%d",
- thd->security_ctx->master_access,
thd->security_ctx->db_access));
VOID(pthread_mutex_lock(&this->LOCK_running));
running= false;
+ /* Will compile every time a new sp_head on different root */
+ free_sp();
VOID(pthread_mutex_unlock(&this->LOCK_running));
done:
@@ -1445,6 +1438,9 @@ Event_timed::compile(THD *thd, MEM_ROOT
CHARSET_INFO *old_character_set_client,
*old_collation_connection,
*old_character_set_results;
+ Security_context *save_ctx;
+ /* this one is local and not needed after exec */
+ Security_context security_ctx;
DBUG_ENTER("Event_timed::compile");
@@ -1490,6 +1486,7 @@ Event_timed::compile(THD *thd, MEM_ROOT
thd->query_length= show_create.length();
DBUG_PRINT("Event_timed::compile", ("query:%s",thd->query));
+ change_security_context(thd, &security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
@@ -1527,6 +1524,7 @@ done:
lex.et->deinit_mutexes();
lex_end(&lex);
+ restore_security_context(thd, save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex;
@@ -1588,12 +1586,10 @@ extern pthread_attr_t connection_attrib;
*/
int
-Event_timed::spawn_now(void * (*thread_func)(void*))
+Event_timed::spawn_now(void * (*thread_func)(void*), void *arg)
{
int ret= EVENT_EXEC_STARTED;
- static uint exec_num= 0;
DBUG_ENTER("Event_timed::spawn_now");
- DBUG_PRINT("info", ("this=0x%lx", this));
DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str));
VOID(pthread_mutex_lock(&this->LOCK_running));
@@ -1601,19 +1597,12 @@ Event_timed::spawn_now(void * (*thread_f
{
pthread_t th;
in_spawned_thread= true;
- if (pthread_create(&th, &connection_attrib, thread_func, (void*)this))
+ if (pthread_create(&th, &connection_attrib, thread_func, arg))
{
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
{
@@ -1630,18 +1619,12 @@ void
Event_timed::spawn_thread_finish(THD *thd)
{
DBUG_ENTER("Event_timed::spawn_thread_finish");
- VOID(pthread_mutex_lock(&this->LOCK_running));
+ VOID(pthread_mutex_lock(&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_PRINT("info", ("Sending COND_finished for thread %d", thread_id));
+ thread_id= 0;
+ pthread_cond_signal(&COND_finished);
+ VOID(pthread_mutex_unlock(&LOCK_running));
DBUG_VOID_RETURN;
}
@@ -1659,7 +1642,7 @@ Event_timed::spawn_unlock(THD *thd)
{
int ret= 0;
VOID(pthread_mutex_lock(&this->LOCK_running));
- if (!in_spawned_thread)
+ if (in_spawned_thread)
{
if (locked_by_thread_id == thd->thread_id)
{
@@ -1677,4 +1660,134 @@ Event_timed::spawn_unlock(THD *thd)
}
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
+}
+
+
+/*
+ Kills a running event
+ Synopsis
+ Event_timed::kill_thread()
+
+ Returns
+ 0 OK
+ -1 EVEX_CANT_KILL
+ !0 Error
+*/
+
+int
+Event_timed::kill_thread(THD *thd)
+{
+ int ret= 0;
+ DBUG_ENTER("Event_timed::kill_thread");
+ pthread_mutex_lock(&LOCK_running);
+ DBUG_PRINT("info", ("thread_id=%lu", thread_id));
+
+ if (thread_id == thd->thread_id)
+ {
+ /*
+ We don't kill ourselves in cases like :
+ alter event e_43 do alter event e_43 do set @a = 4 because
+ we will never receive COND_finished.
+ */
+ DBUG_PRINT("info", ("It's not safe to kill ourselves in self altering queries"));
+ ret= EVEX_CANT_KILL;
+ }
+ else if (thread_id && !(ret= kill_one_thread(thd, thread_id, false)))
+ {
+ thd->enter_cond(&COND_finished, &LOCK_running, "Waiting for finished");
+ DBUG_PRINT("info", ("Waiting for COND_finished from thread %d", thread_id));
+ while (thread_id)
+ pthread_cond_wait(&COND_finished, &LOCK_running);
+
+ DBUG_PRINT("info", ("Got COND_finished"));
+ /* This will implicitly unlock LOCK_running. Hence we return before that */
+ thd->exit_cond("");
+
+ DBUG_RETURN(0);
+ }
+ else if (!thread_id && in_spawned_thread)
+ {
+ /*
+ Because the manager thread waits for the forked thread to update thread_id
+ this situation is impossible.
+ */
+ DBUG_ASSERT(0);
+ }
+ pthread_mutex_unlock(&LOCK_running);
+ DBUG_PRINT("exit", ("%d", ret));
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Checks whether two events have the same name
+
+ Synopsis
+ event_timed_name_equal()
+
+ Returns
+ true names are equal
+ false names are not equal
+*/
+
+bool
+event_timed_name_equal(Event_timed *et, LEX_STRING *name)
+{
+ return !sortcmp_lex_string(et->name, *name, system_charset_info);
+}
+
+
+/*
+ Checks whether two events are in the same schema
+
+ Synopsis
+ event_timed_db_equal()
+
+ Returns
+ true schemas are equal
+ false schemas are not equal
+*/
+
+bool
+event_timed_db_equal(Event_timed *et, LEX_STRING *db)
+{
+ return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
+}
+
+
+/*
+ Checks whether two events have the same definer
+
+ Synopsis
+ event_timed_definer_equal()
+
+ Returns
+ true definers are equal
+ false definers are not equal
+*/
+
+bool
+event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
+{
+ return !sortcmp_lex_string(et->definer, *definer, system_charset_info);
+}
+
+
+/*
+ Checks whether two events are equal by identifiers
+
+ Synopsis
+ event_timed_identifier_equal()
+
+ Returns
+ true equal
+ false not equal
+*/
+
+bool
+event_timed_identifier_equal(Event_timed *a, Event_timed *b)
+{
+ return event_timed_name_equal(a, &b->name) &&
+ event_timed_db_equal(a, &b->dbname) &&
+ event_timed_definer_equal(a, &b->definer);
}
--- 1.185/sql/set_var.cc 2006-05-01 09:14:28 +02:00
+++ 1.186/sql/set_var.cc 2006-05-11 16:41:06 +02:00
@@ -222,9 +222,11 @@ sys_var_long_ptr sys_delayed_insert_time
&delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
&delayed_queue_size);
+
+#include "event_scheduler.h"
sys_var_event_executor sys_event_executor("event_scheduler",
(my_bool *)
- &event_executor_running_global_var);
+ &Event_scheduler::scheduler_working);
sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
&expire_logs_days);
sys_var_bool_ptr sys_flush("flush", &myisam_flush);
@@ -3574,6 +3576,42 @@ byte *sys_var_thd_dbug::value_ptr(THD *t
DBUG_EXPLAIN(buf, sizeof(buf));
return (byte*) thd->strdup(buf);
}
+
+
+/*
+ The update method of the global variable event_scheduler.
+ If event_scheduler is switched from 0 to 1 then the scheduler main
+ thread is started and if from 1 to 0 the scheduler thread is stopped
+
+ SYNOPSIS
+ sys_var_event_executor::update()
+ thd Thread context (unused)
+ var The new value
+
+ Returns
+ 0 OK (always)
+*/
+
+bool
+sys_var_event_executor::update(THD *thd, set_var *var)
+{
+ enum Event_scheduler::enum_error_code res;
+ /* here start the thread if not running. */
+ DBUG_ENTER("sys_var_event_executor::update");
+
+ DBUG_PRINT("new_value", ("%lu", (bool)var->save_result.ulong_value));
+ if ((res= Event_scheduler::get_instance()->
+ suspend_or_resume(var->save_result.ulong_value?
+ Event_scheduler::RESUME:
+ Event_scheduler::SUSPEND)))
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), (uint) res);
+#if ANREY0
+ if ((res= Event_scheduler::start_or_stop(var->save_result.ulong_value)))
+ my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), (uint) res);
+#endif
+ DBUG_RETURN((bool) res);
+}
+
/****************************************************************************
Used templates
--- 1.89/libmysqld/Makefile.am 2006-05-09 00:49:10 +02:00
+++ 1.90/libmysqld/Makefile.am 2006-05-11 17:08:28 +02:00
@@ -68,7 +68,7 @@ sqlsources = derror.cc field.cc field_co
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
- event_executor.cc event.cc event_timed.cc \
+ event_scheduler.cc event.cc event_timed.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc
--- 1.18/sql/cmakelists.txt 2006-04-20 19:37:23 +02:00
+++ 1.19/sql/cmakelists.txt 2006-05-11 17:08:29 +02:00
@@ -51,7 +51,7 @@ ADD_EXECUTABLE(mysqld ../sql-common/clie
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
- rpl_tblmap.cc sql_binlog.cc event_executor.cc event_timed.cc
+ rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
sql_tablespace.cc event.cc ../sql-common/my_user.c
partition_info.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
--- 1.240/BitKeeper/etc/ignore 2006-05-02 07:45:16 +02:00
+++ 1.241/BitKeeper/etc/ignore 2006-05-11 16:38:39 +02:00
@@ -458,6 +458,7 @@ libmysqld/emb_qcache.cpp
libmysqld/errmsg.c
libmysqld/event.cc
libmysqld/event_executor.cc
+libmysqld/event_scheduler.cc
libmysqld/event_timed.cc
libmysqld/examples/client_test.c
libmysqld/examples/client_test.cc
@@ -705,6 +706,7 @@ mysql-test/r/derived.err
mysql-test/r/events.log
mysql-test/r/events_bugs.log
mysql-test/r/events_logs_tests.log
+mysql-test/r/events_stress.log
mysql-test/r/exampledb.err
mysql-test/r/func_encrypt.err
mysql-test/r/im_client_port.log
--- 1.65/sql/repl_failsafe.cc 2006-05-01 20:38:11 +02:00
+++ 1.66/sql/repl_failsafe.cc 2006-05-11 16:41:06 +02:00
@@ -61,12 +61,13 @@ static Slave_log_event* find_slave_event
static int init_failsafe_rpl_thread(THD* thd)
{
DBUG_ENTER("init_failsafe_rpl_thread");
+ thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
/*
thd->bootstrap is to report errors barely to stderr; if this code is
enable again one day, one should check if bootstrap is still needed (maybe
this thread has no other error reporting method).
*/
- thd->system_thread = thd->bootstrap = 1;
+ thd->bootstrap = 1;
thd->security_ctx->skip_grants();
my_net_init(&thd->net, 0);
thd->net.read_timeout = slave_net_timeout;
| Thread |
|---|
| • bk commit into 5.1 tree (andrey:1.2396) | ahristov | 11 May |