WL #3337 (Events new architecture)
Final stroke, events should be loaded from disk on server startup. Also check the validity of their bodies if possible during loading.
This commit is contained in:
parent
3f4e1f5c69
commit
dd31d45789
10
mysql-test/r/events_restart_phase1.result
Normal file
10
mysql-test/r/events_restart_phase1.result
Normal file
@ -0,0 +1,10 @@
|
||||
create database if not exists mysqltest_events_test;
|
||||
use mysqltest_events_test;
|
||||
set global event_scheduler=2;
|
||||
create table execution_log(name char(10));
|
||||
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
|
||||
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
|
||||
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
|
||||
"Now we restart the server"
|
6
mysql-test/r/events_restart_phase2.result
Normal file
6
mysql-test/r/events_restart_phase2.result
Normal file
@ -0,0 +1,6 @@
|
||||
use mysqltest_events_test;
|
||||
"Should get 0 rows because the queue aborted run
|
||||
select distinct name from execution_log order by name;
|
||||
name
|
||||
delete from mysql.event where name like 'bad%';
|
||||
"Now restart the server again"
|
9
mysql-test/r/events_restart_phase3.result
Normal file
9
mysql-test/r/events_restart_phase3.result
Normal file
@ -0,0 +1,9 @@
|
||||
use mysqltest_events_test;
|
||||
"Should get 3 rows : abc1, abc2, abc3
|
||||
select distinct name from execution_log order by name;
|
||||
name
|
||||
drop event abc1;
|
||||
drop event abc2;
|
||||
drop event abc3;
|
||||
drop table execution_log;
|
||||
drop database mysqltest_events_test;
|
17
mysql-test/t/events_restart_phase1.test
Normal file
17
mysql-test/t/events_restart_phase1.test
Normal file
@ -0,0 +1,17 @@
|
||||
# Can't test with embedded server that doesn't support grants
|
||||
-- source include/not_embedded.inc
|
||||
|
||||
--disable_warnings
|
||||
create database if not exists mysqltest_events_test;
|
||||
--enable_warnings
|
||||
|
||||
use mysqltest_events_test;
|
||||
set global event_scheduler=2;
|
||||
create table execution_log(name char(10));
|
||||
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
|
||||
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
|
||||
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
|
||||
|
||||
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
|
||||
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
|
||||
--echo "Now we restart the server"
|
1
mysql-test/t/events_restart_phase2-master.opt
Normal file
1
mysql-test/t/events_restart_phase2-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--event-scheduler=1
|
9
mysql-test/t/events_restart_phase2.test
Normal file
9
mysql-test/t/events_restart_phase2.test
Normal file
@ -0,0 +1,9 @@
|
||||
# Can't test with embedded server that doesn't support grants
|
||||
-- source include/not_embedded.inc
|
||||
|
||||
use mysqltest_events_test;
|
||||
--sleep 1.5
|
||||
--echo "Should get 0 rows because the queue aborted run
|
||||
select distinct name from execution_log order by name;
|
||||
delete from mysql.event where name like 'bad%';
|
||||
--echo "Now restart the server again"
|
1
mysql-test/t/events_restart_phase3-master.opt
Normal file
1
mysql-test/t/events_restart_phase3-master.opt
Normal file
@ -0,0 +1 @@
|
||||
--event-scheduler=1
|
14
mysql-test/t/events_restart_phase3.test
Normal file
14
mysql-test/t/events_restart_phase3.test
Normal file
@ -0,0 +1,14 @@
|
||||
# Can't test with embedded server that doesn't support grants
|
||||
-- source include/not_embedded.inc
|
||||
|
||||
use mysqltest_events_test;
|
||||
--sleep 2
|
||||
--echo "Should get 3 rows : abc1, abc2, abc3
|
||||
select distinct name from execution_log order by name;
|
||||
|
||||
drop event abc1;
|
||||
drop event abc2;
|
||||
drop event abc3;
|
||||
drop table execution_log;
|
||||
|
||||
drop database mysqltest_events_test;
|
@ -731,7 +731,7 @@ Event_timed::~Event_timed()
|
||||
*/
|
||||
|
||||
Event_job_data::Event_job_data():
|
||||
thd(NULL), sphead(0), sql_mode(0)
|
||||
thd(NULL), sphead(NULL), sql_mode(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -745,7 +745,10 @@ Event_job_data::Event_job_data():
|
||||
|
||||
Event_job_data::~Event_job_data()
|
||||
{
|
||||
free_sp();
|
||||
DBUG_ENTER("Event_job_data::~Event_job_data");
|
||||
delete sphead;
|
||||
sphead= NULL;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -1605,20 +1608,6 @@ Event_job_data::get_fake_create_event(THD *thd, String *buf)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Frees the memory of the sp_head object we hold
|
||||
SYNOPSIS
|
||||
Event_job_data::free_sp()
|
||||
*/
|
||||
|
||||
void
|
||||
Event_job_data::free_sp()
|
||||
{
|
||||
delete sphead;
|
||||
sphead= NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Compiles an event before it's execution. Compiles the anonymous
|
||||
sp_head object held by the event
|
||||
@ -1651,9 +1640,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *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;
|
||||
Security_context save_ctx;
|
||||
|
||||
DBUG_ENTER("Event_job_data::compile");
|
||||
|
||||
@ -1699,10 +1686,9 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
|
||||
thd->query_length= show_create.length();
|
||||
DBUG_PRINT("info", ("query:%s",thd->query));
|
||||
|
||||
thd->change_security_context(definer_user, definer_host, dbname,
|
||||
&security_ctx, &save_ctx);
|
||||
thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
|
||||
thd->lex= &lex;
|
||||
lex_start(thd, (uchar*)thd->query, thd->query_length);
|
||||
mysql_init_query(thd, (uchar*) thd->query, thd->query_length);
|
||||
if (MYSQLparse((void *)thd) || thd->is_fatal_error)
|
||||
{
|
||||
DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d",
|
||||
@ -1713,13 +1699,10 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
|
||||
*/
|
||||
sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d",
|
||||
dbname.str, name.str, thd->is_fatal_error);
|
||||
if (lex.sphead)
|
||||
{
|
||||
if (&lex != thd->lex)
|
||||
thd->lex->sphead->restore_lex(thd);
|
||||
delete lex.sphead;
|
||||
lex.sphead= 0;
|
||||
}
|
||||
|
||||
lex.unit.cleanup();
|
||||
delete lex.sphead;
|
||||
sphead= lex.sphead= NULL;
|
||||
ret= EVEX_COMPILE_ERROR;
|
||||
goto done;
|
||||
}
|
||||
@ -1734,7 +1717,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
|
||||
done:
|
||||
|
||||
lex_end(&lex);
|
||||
thd->restore_security_context(save_ctx);
|
||||
thd->restore_security_context(&save_ctx);
|
||||
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
|
||||
|
||||
thd->lex= old_lex;
|
||||
@ -1772,20 +1755,17 @@ done:
|
||||
int
|
||||
Event_job_data::execute(THD *thd)
|
||||
{
|
||||
Security_context *save_ctx;
|
||||
Security_context save_ctx;
|
||||
/* this one is local and not needed after exec */
|
||||
Security_context security_ctx;
|
||||
int ret= 0;
|
||||
|
||||
DBUG_ENTER("Event_job_data::execute");
|
||||
DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
|
||||
|
||||
|
||||
if ((ret= compile(thd, NULL)))
|
||||
goto done;
|
||||
|
||||
thd->change_security_context(definer_user, definer_host, dbname,
|
||||
&security_ctx, &save_ctx);
|
||||
thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
|
||||
/*
|
||||
THD::~THD will clean this or if there is DROP DATABASE in the SP then
|
||||
it will be free there. It should not point to our buffer which is allocated
|
||||
@ -1810,9 +1790,10 @@ Event_job_data::execute(THD *thd)
|
||||
ret= -99;
|
||||
}
|
||||
|
||||
thd->restore_security_context(save_ctx);
|
||||
thd->restore_security_context(&save_ctx);
|
||||
done:
|
||||
free_sp();
|
||||
thd->end_statement();
|
||||
thd->cleanup_after_query();
|
||||
|
||||
DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
|
||||
|
||||
|
@ -178,15 +178,12 @@ public:
|
||||
|
||||
int
|
||||
execute(THD *thd);
|
||||
private:
|
||||
int
|
||||
get_fake_create_event(THD *thd, String *buf);
|
||||
|
||||
int
|
||||
compile(THD *thd, MEM_ROOT *mem_root);
|
||||
|
||||
void
|
||||
free_sp();
|
||||
private:
|
||||
int
|
||||
get_fake_create_event(THD *thd, String *buf);
|
||||
|
||||
Event_job_data(const Event_job_data &); /* Prevent use of these */
|
||||
void operator=(Event_job_data &);
|
||||
|
@ -35,6 +35,14 @@
|
||||
#define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__)
|
||||
#define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__)
|
||||
|
||||
struct event_queue_param
|
||||
{
|
||||
THD *thd;
|
||||
Event_queue *queue;
|
||||
pthread_mutex_t LOCK_loaded;
|
||||
pthread_cond_t COND_loaded;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Compares the execute_at members of two Event_queue_element instances.
|
||||
@ -64,6 +72,31 @@ event_queue_element_compare_q(void *vptr, byte* a, byte *b)
|
||||
}
|
||||
|
||||
|
||||
pthread_handler_t
|
||||
event_queue_loader_thread(void *arg)
|
||||
{
|
||||
/* needs to be first for thread_stack */
|
||||
THD *thd= (THD *)((struct event_queue_param *) arg)->thd;
|
||||
struct event_queue_param *param= (struct event_queue_param *) arg;
|
||||
thd->thread_stack= (char *) &thd;
|
||||
|
||||
if (post_init_event_thread(thd))
|
||||
goto end;
|
||||
|
||||
DBUG_ENTER("event_queue_loader_thread");
|
||||
|
||||
pthread_mutex_lock(¶m->LOCK_loaded);
|
||||
param->queue->load_events_from_db(thd);
|
||||
pthread_cond_signal(¶m->COND_loaded);
|
||||
pthread_mutex_unlock(¶m->LOCK_loaded);
|
||||
|
||||
end:
|
||||
deinit_event_thread(thd);
|
||||
|
||||
DBUG_RETURN(0); // Against gcc warnings
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Constructor of class Event_queue.
|
||||
|
||||
@ -80,6 +113,8 @@ Event_queue::Event_queue()
|
||||
mutex_last_attempted_lock_in_func= "";
|
||||
|
||||
mutex_queue_data_locked= mutex_queue_data_attempting_lock= FALSE;
|
||||
|
||||
queue_loaded= FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -125,8 +160,11 @@ Event_queue::deinit_mutexes()
|
||||
bool
|
||||
Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
|
||||
{
|
||||
int i= 0;
|
||||
bool ret= FALSE;
|
||||
THD *new_thd;
|
||||
pthread_t th;
|
||||
bool res;
|
||||
struct event_queue_param *event_queue_param_value= NULL;
|
||||
|
||||
DBUG_ENTER("Event_queue::init_queue");
|
||||
DBUG_PRINT("enter", ("this=0x%lx", this));
|
||||
|
||||
@ -139,8 +177,7 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
|
||||
NULL, EVENT_QUEUE_EXTENT))
|
||||
{
|
||||
sql_print_error("SCHEDULER: Can't initialize the execution queue");
|
||||
ret= TRUE;
|
||||
goto end;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (sizeof(my_time_t) != sizeof(time_t))
|
||||
@ -148,13 +185,43 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
|
||||
sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
|
||||
"The scheduler may not work correctly. Stopping.");
|
||||
DBUG_ASSERT(0);
|
||||
ret= TRUE;
|
||||
goto end;
|
||||
goto err;
|
||||
}
|
||||
|
||||
end:
|
||||
if (!(new_thd= new THD))
|
||||
goto err;
|
||||
|
||||
pre_init_event_thread(new_thd);
|
||||
|
||||
event_queue_param_value= (struct event_queue_param *)
|
||||
my_malloc(sizeof(struct event_queue_param), MYF(0));
|
||||
event_queue_param_value->thd= new_thd;
|
||||
event_queue_param_value->queue= this;
|
||||
pthread_mutex_init(&event_queue_param_value->LOCK_loaded, MY_MUTEX_INIT_FAST);
|
||||
pthread_cond_init(&event_queue_param_value->COND_loaded, NULL);
|
||||
|
||||
pthread_mutex_lock(&event_queue_param_value->LOCK_loaded);
|
||||
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
|
||||
if (!(res= pthread_create(&th, &connection_attrib, event_queue_loader_thread,
|
||||
(void*)event_queue_param_value)))
|
||||
{
|
||||
do {
|
||||
pthread_cond_wait(&event_queue_param_value->COND_loaded,
|
||||
&event_queue_param_value->LOCK_loaded);
|
||||
} while (queue_loaded == FALSE);
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&event_queue_param_value->LOCK_loaded);
|
||||
pthread_mutex_destroy(&event_queue_param_value->LOCK_loaded);
|
||||
pthread_cond_destroy(&event_queue_param_value->COND_loaded);
|
||||
my_free((char *)event_queue_param_value, MYF(0));
|
||||
|
||||
UNLOCK_QUEUE_DATA();
|
||||
DBUG_RETURN(ret);
|
||||
DBUG_RETURN(res);
|
||||
|
||||
err:
|
||||
UNLOCK_QUEUE_DATA();
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
@ -498,7 +565,7 @@ Event_queue::load_events_from_db(THD *thd)
|
||||
READ_RECORD read_record_info;
|
||||
int ret= -1;
|
||||
uint count= 0;
|
||||
bool clean_the_queue= FALSE;
|
||||
bool clean_the_queue= TRUE;
|
||||
/* Compile the events on this root but only for syntax check, then discard */
|
||||
MEM_ROOT boot_root;
|
||||
|
||||
@ -518,14 +585,12 @@ Event_queue::load_events_from_db(THD *thd)
|
||||
if (!(et= new Event_queue_element))
|
||||
{
|
||||
DBUG_PRINT("info", ("Out of memory"));
|
||||
clean_the_queue= TRUE;
|
||||
break;
|
||||
}
|
||||
DBUG_PRINT("info", ("Loading event from row."));
|
||||
|
||||
if ((ret= et->load_from_row(table)))
|
||||
{
|
||||
clean_the_queue= TRUE;
|
||||
sql_print_error("SCHEDULER: Error while loading from mysql.event. "
|
||||
"Table probably corrupted");
|
||||
break;
|
||||
@ -536,27 +601,6 @@ Event_queue::load_events_from_db(THD *thd)
|
||||
delete et;
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
|
||||
|
||||
/* We load only on scheduler root just to check whether the body compiles */
|
||||
switch (ret= et->compile(thd, &boot_root)) {
|
||||
case EVEX_MICROSECOND_UNSUP:
|
||||
et->free_sp();
|
||||
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:
|
||||
/* Free it, it will be compiled again on the worker thread */
|
||||
et->free_sp();
|
||||
break;
|
||||
}
|
||||
free_root(&boot_root, MYF(0));
|
||||
|
||||
/* let's find when to be executed */
|
||||
if (et->compute_next_execution_time())
|
||||
@ -565,11 +609,40 @@ Event_queue::load_events_from_db(THD *thd)
|
||||
" Skipping", et->dbname.str, et->name.str);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
Event_job_data temp_job_data;
|
||||
DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
|
||||
|
||||
temp_job_data.load_from_row(table);
|
||||
|
||||
/* We load only on scheduler root just to check whether the body compiles */
|
||||
switch (ret= temp_job_data.compile(thd, thd->mem_root)) {
|
||||
case EVEX_MICROSECOND_UNSUP:
|
||||
sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
|
||||
"supported but found in mysql.event");
|
||||
break;
|
||||
case EVEX_COMPILE_ERROR:
|
||||
sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
|
||||
et->dbname.str, et->name.str);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
thd->end_statement();
|
||||
thd->cleanup_after_query();
|
||||
}
|
||||
if (ret)
|
||||
{
|
||||
delete et;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list."));
|
||||
queue_insert_safe(&queue, (byte *) et);
|
||||
count++;
|
||||
}
|
||||
clean_the_queue= FALSE;
|
||||
end:
|
||||
end_read_record(&read_record_info);
|
||||
|
||||
@ -585,10 +658,12 @@ end:
|
||||
}
|
||||
|
||||
/* Force close to free memory */
|
||||
thd->version--;
|
||||
thd->version--;
|
||||
|
||||
close_thread_tables(thd);
|
||||
|
||||
queue_loaded= TRUE;
|
||||
|
||||
DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
@ -713,6 +788,7 @@ Event_queue::empty_queue()
|
||||
uint i;
|
||||
DBUG_ENTER("Event_queue::empty_queue");
|
||||
DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements));
|
||||
sql_print_information("SCHEDULER: Purging queue. %u events", queue.elements);
|
||||
/* empty the queue */
|
||||
for (i= 0; i < queue.elements; ++i)
|
||||
{
|
||||
|
@ -68,12 +68,13 @@ public:
|
||||
bool
|
||||
dump_internal_status(THD *thd);
|
||||
|
||||
int
|
||||
load_events_from_db(THD *thd);
|
||||
|
||||
protected:
|
||||
Event_queue_element *
|
||||
find_n_remove_event(LEX_STRING db, LEX_STRING name);
|
||||
|
||||
int
|
||||
load_events_from_db(THD *thd);
|
||||
|
||||
void
|
||||
drop_matching_events(THD *thd, LEX_STRING pattern,
|
||||
@ -82,11 +83,24 @@ protected:
|
||||
void
|
||||
empty_queue();
|
||||
|
||||
void
|
||||
notify_observers();
|
||||
|
||||
void
|
||||
dbug_dump_queue(time_t now);
|
||||
|
||||
/* LOCK_event_queue is the mutex which protects the access to the queue. */
|
||||
pthread_mutex_t LOCK_event_queue;
|
||||
|
||||
Event_db_repository *db_repository;
|
||||
|
||||
Event_scheduler *scheduler;
|
||||
|
||||
/* The sorted queue with the Event_job_data objects */
|
||||
QUEUE queue;
|
||||
|
||||
bool queue_loaded;
|
||||
|
||||
uint mutex_last_locked_at_line;
|
||||
uint mutex_last_unlocked_at_line;
|
||||
uint mutex_last_attempted_lock_at_line;
|
||||
@ -95,24 +109,13 @@ protected:
|
||||
const char* mutex_last_attempted_lock_in_func;
|
||||
bool mutex_queue_data_locked;
|
||||
bool mutex_queue_data_attempting_lock;
|
||||
|
||||
|
||||
/* helper functions for working with mutexes & conditionals */
|
||||
void
|
||||
lock_data(const char *func, uint line);
|
||||
|
||||
void
|
||||
unlock_data(const char *func, uint line);
|
||||
|
||||
void
|
||||
notify_observers();
|
||||
|
||||
void
|
||||
dbug_dump_queue(time_t now);
|
||||
|
||||
Event_scheduler *scheduler;
|
||||
|
||||
/* The sorted queue with the Event_job_data objects */
|
||||
QUEUE queue;
|
||||
};
|
||||
|
||||
#endif /* _EVENT_QUEUE_H_ */
|
||||
|
@ -40,9 +40,6 @@ struct scheduler_param
|
||||
Event_scheduler *scheduler;
|
||||
};
|
||||
|
||||
struct scheduler_param scheduler_param_value;
|
||||
|
||||
|
||||
|
||||
static
|
||||
LEX_STRING scheduler_states_names[] =
|
||||
@ -103,25 +100,23 @@ evex_print_warnings(THD *thd, Event_job_data *et)
|
||||
|
||||
|
||||
/*
|
||||
Inits an scheduler thread handler, both the main and a worker
|
||||
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
|
||||
init_event_thread()
|
||||
thd - the THD of the thread. Has to be allocated by the caller.
|
||||
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.
|
||||
|
||||
RETURN VALUE
|
||||
0 OK
|
||||
-1 Error
|
||||
*/
|
||||
|
||||
static int
|
||||
init_scheduler_thread(THD* thd)
|
||||
void
|
||||
pre_init_event_thread(THD* thd)
|
||||
{
|
||||
DBUG_ENTER("init_event_thread");
|
||||
DBUG_ENTER("pre_init_event_thread");
|
||||
thd->client_capabilities= 0;
|
||||
thd->security_ctx->master_access= 0;
|
||||
thd->security_ctx->db_access= 0;
|
||||
@ -148,7 +143,36 @@ init_scheduler_thread(THD* thd)
|
||||
thd->version= refresh_version;
|
||||
thd->set_time();
|
||||
|
||||
DBUG_RETURN(0);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
@ -160,7 +184,7 @@ init_scheduler_thread(THD* thd)
|
||||
thd Thread
|
||||
*/
|
||||
|
||||
static void
|
||||
void
|
||||
deinit_event_thread(THD *thd)
|
||||
{
|
||||
thd->proc_info= "Clearing";
|
||||
@ -192,29 +216,18 @@ pthread_handler_t
|
||||
event_scheduler_thread(void *arg)
|
||||
{
|
||||
/* needs to be first for thread_stack */
|
||||
THD *thd= (THD *)(*(struct scheduler_param *) arg).thd;
|
||||
THD *thd= (THD *)((struct scheduler_param *) arg)->thd;
|
||||
Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler;
|
||||
|
||||
my_free((char*)arg, MYF(0));
|
||||
|
||||
thd->thread_stack= (char *)&thd; // remember where our stack is
|
||||
|
||||
DBUG_ENTER("event_scheduler_thread");
|
||||
|
||||
my_thread_init();
|
||||
pthread_detach_this_thread();
|
||||
thd->real_id=pthread_self();
|
||||
if (init_thr_lock() || thd->store_globals())
|
||||
{
|
||||
thd->cleanup();
|
||||
goto end;
|
||||
}
|
||||
if (!post_init_event_thread(thd))
|
||||
scheduler->run(thd);
|
||||
|
||||
#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
|
||||
|
||||
((struct scheduler_param *) arg)->scheduler->run(thd);
|
||||
|
||||
end:
|
||||
deinit_event_thread(thd);
|
||||
|
||||
DBUG_RETURN(0); // Against gcc warnings
|
||||
@ -242,27 +255,13 @@ event_worker_thread(void *arg)
|
||||
int ret;
|
||||
|
||||
thd= event->thd;
|
||||
thd->thread_stack= (char *) &thd;
|
||||
|
||||
|
||||
my_thread_init();
|
||||
pthread_detach_this_thread();
|
||||
thd->real_id=pthread_self();
|
||||
if (init_thr_lock() || thd->store_globals())
|
||||
{
|
||||
thd->cleanup();
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
#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
|
||||
thd->init_for_queries();
|
||||
|
||||
thd->thread_stack= (char *) &thd; // remember where our stack is
|
||||
DBUG_ENTER("event_worker_thread");
|
||||
|
||||
if (post_init_event_thread(thd))
|
||||
goto end;
|
||||
|
||||
DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational."
|
||||
"THD=0x%lx", time(NULL), thd));
|
||||
|
||||
@ -375,6 +374,7 @@ Event_scheduler::start()
|
||||
THD *new_thd= NULL;
|
||||
bool ret= FALSE;
|
||||
pthread_t th;
|
||||
struct scheduler_param *scheduler_param_value;
|
||||
DBUG_ENTER("Event_scheduler::start");
|
||||
|
||||
LOCK_SCHEDULER_DATA();
|
||||
@ -382,21 +382,24 @@ Event_scheduler::start()
|
||||
if (state > INITIALIZED)
|
||||
goto end;
|
||||
|
||||
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
|
||||
if (!(new_thd= new THD))
|
||||
{
|
||||
sql_print_error("SCHEDULER: Cannot init manager event thread.");
|
||||
ret= TRUE;
|
||||
goto end;
|
||||
}
|
||||
pre_init_event_thread(new_thd);
|
||||
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
|
||||
new_thd->command= COM_DAEMON;
|
||||
|
||||
scheduler_param_value.thd= new_thd;
|
||||
scheduler_param_value.scheduler= this;
|
||||
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;
|
||||
|
||||
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
|
||||
if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
|
||||
(void*)&scheduler_param_value))
|
||||
(void*)scheduler_param_value))
|
||||
{
|
||||
DBUG_PRINT("error", ("cannot create a new thread"));
|
||||
state= INITIALIZED;
|
||||
@ -588,9 +591,10 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
|
||||
pthread_t th;
|
||||
int res= 0;
|
||||
DBUG_ENTER("Event_scheduler::execute_top");
|
||||
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
|
||||
if (!(new_thd= new THD))
|
||||
goto error;
|
||||
|
||||
pre_init_event_thread(new_thd);
|
||||
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",
|
||||
|
@ -19,6 +19,15 @@
|
||||
class Event_queue;
|
||||
class Event_job_data;
|
||||
|
||||
void
|
||||
pre_init_event_thread(THD* thd);
|
||||
|
||||
bool
|
||||
post_init_event_thread(THD* thd);
|
||||
|
||||
void
|
||||
deinit_event_thread(THD *thd);
|
||||
|
||||
class Event_scheduler
|
||||
{
|
||||
public:
|
||||
|
@ -556,11 +556,16 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
|
||||
1 Error in case the scheduler can't start
|
||||
*/
|
||||
|
||||
int
|
||||
bool
|
||||
Events::init()
|
||||
{
|
||||
int res;
|
||||
DBUG_ENTER("Events::init");
|
||||
event_queue->init_queue(db_repository, scheduler);
|
||||
if (event_queue->init_queue(db_repository, scheduler))
|
||||
{
|
||||
sql_print_information("SCHEDULER: Error while loading from disk.");
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
scheduler->init_scheduler(event_queue);
|
||||
|
||||
/* it should be an assignment! */
|
||||
@ -571,7 +576,7 @@ Events::init()
|
||||
DBUG_RETURN(scheduler->start());
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ public:
|
||||
static ulong opt_event_scheduler;
|
||||
static TYPELIB opt_typelib;
|
||||
|
||||
int
|
||||
bool
|
||||
init();
|
||||
|
||||
void
|
||||
|
@ -3675,7 +3675,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
|
||||
|
||||
if (!opt_noacl)
|
||||
{
|
||||
Events::get_instance()->init();
|
||||
if (Events::get_instance()->init())
|
||||
unireg_abort(1);
|
||||
}
|
||||
#if defined(__NT__) || defined(HAVE_SMEM)
|
||||
handle_connections_methods();
|
||||
|
@ -640,10 +640,12 @@ sp_head::create(THD *thd)
|
||||
|
||||
sp_head::~sp_head()
|
||||
{
|
||||
DBUG_ENTER("sp_head::~sp_head");
|
||||
destroy();
|
||||
delete m_next_cached_sp;
|
||||
if (m_thd)
|
||||
restore_thd_mem_root(m_thd);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2085,21 +2085,20 @@ bool Security_context::set_user(char *user_arg)
|
||||
|
||||
bool
|
||||
THD::change_security_context(LEX_STRING user, LEX_STRING host,
|
||||
LEX_STRING db, Security_context *s_ctx,
|
||||
Security_context **backup)
|
||||
LEX_STRING db, Security_context *backup)
|
||||
{
|
||||
DBUG_ENTER("change_security_context");
|
||||
DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
s_ctx->init();
|
||||
*backup= 0;
|
||||
if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
|
||||
|
||||
*backup= main_security_ctx;
|
||||
if (acl_getroot_no_password(&main_security_ctx, user.str, host.str, host.str,
|
||||
db.str))
|
||||
{
|
||||
my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
*backup= security_ctx;
|
||||
security_ctx= s_ctx;
|
||||
security_ctx= &main_security_ctx;
|
||||
#endif
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
@ -2119,7 +2118,10 @@ THD::restore_security_context(Security_context *backup)
|
||||
DBUG_ENTER("restore_security_context");
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (backup)
|
||||
security_ctx= backup;
|
||||
{
|
||||
main_security_ctx= *backup;
|
||||
security_ctx= &main_security_ctx;
|
||||
}
|
||||
#endif
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -871,8 +871,7 @@ public:
|
||||
|
||||
bool
|
||||
change_security_context(LEX_STRING user, LEX_STRING host,
|
||||
LEX_STRING db, Security_context *s_ctx,
|
||||
Security_context **backup);
|
||||
LEX_STRING db, Security_context *backup);
|
||||
|
||||
void
|
||||
restore_security_context(Security_context *backup);
|
||||
|
@ -171,6 +171,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
|
||||
lex->sql_command= SQLCOM_END;
|
||||
lex->duplicates= DUP_ERROR;
|
||||
lex->ignore= 0;
|
||||
lex->spname= NULL;
|
||||
lex->sphead= NULL;
|
||||
lex->spcont= NULL;
|
||||
lex->proc_list.first= 0;
|
||||
|
@ -4652,6 +4652,13 @@ alter:
|
||||
YYTHD->client_capabilities is set back to original value
|
||||
*/
|
||||
{
|
||||
/*
|
||||
It is safe to use Lex->spname because
|
||||
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
|
||||
is not allowed. Lex->spname is used in the case of RENAME TO
|
||||
If it had to be supported spname had to be added to
|
||||
Event_parse_data.
|
||||
*/
|
||||
Lex->spname= NULL;
|
||||
|
||||
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user