mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
WL #1034 updates after review
sql/event.cc: - fix TODO (remove things already done) - check the length of the event's name and body during creation and report an error if longer than what can be fit into mysql.event (nothing like non-strict mode here) - report to sql_parse.cc and error when open table failed, otherwise send_ok() was being called and the error have become an warning. - update function documentation a bit - evex_db_find_routine_aux returns 0 and not EVEX_OK sql/event_executor.cc: - CS changes to definitions of the main and worker thread routines - reorder code a bit to prevent crashes because of reading of already freed data -> first wait all events to finish their work, namely all worker threads to finish, and then destroy in-memory structures - more error checking and error reporting at the place of failure. sql/event_priv.h: code simplifying macro sql/event_timed.cc: CS cosmetics
This commit is contained in:
151
sql/event.cc
151
sql/event.cc
@ -27,8 +27,6 @@
|
||||
|
||||
- Use timestamps instead of datetime.
|
||||
|
||||
- Don't use SP's functionality for opening and closing of tables
|
||||
|
||||
- CREATE EVENT should not go into binary log! Does it now? The SQL statements
|
||||
issued by the EVENT are replicated.
|
||||
I have an idea how to solve the problem at failover. So the status field
|
||||
@ -44,31 +42,16 @@
|
||||
ENABLED to DISABLED status change and this is safe for replicating. As well
|
||||
an event may be deleted which is also safe for RBR.
|
||||
|
||||
- Add a lock and use it for guarding access to events_array dynamic array.
|
||||
|
||||
- Add checks everywhere where new instance of THD is created. NULL can be
|
||||
returned and this will crash the server. The server will crash probably
|
||||
later but should not be in this code! Add a global variable, and a lock
|
||||
to guard it, that will specify an error in a worker thread so preventing
|
||||
new threads from being spawned.
|
||||
|
||||
- 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?
|
||||
|
||||
- created & modified in the table should be UTC?
|
||||
|
||||
- Add a lock to event_timed to serialize execution of an event - do not
|
||||
allow parallel executions. Hmm, however how last_executed is marked
|
||||
then? The call to event_timed::mark_last_executed() must be moved to
|
||||
event_timed::execute()?
|
||||
|
||||
Or even deleting it?
|
||||
|
||||
- Consider using conditional variable when doing shutdown instead of
|
||||
waiting some time (tries < 5).
|
||||
waiting till all worker threads end.
|
||||
- Make event_timed::get_show_create_event() work
|
||||
- Add function documentation whenever needed.
|
||||
- Add logging to file
|
||||
@ -77,7 +60,7 @@ 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.
|
||||
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@ -216,17 +199,17 @@ TABLE *evex_open_event_table(THD *thd, enum thr_lock_type lock_type)
|
||||
table TABLE object for open mysql.event table.
|
||||
|
||||
RETURN VALUE
|
||||
SP_OK - Routine found
|
||||
0 - Routine found
|
||||
SP_KEY_NOT_FOUND- No routine with given name
|
||||
*/
|
||||
|
||||
int
|
||||
evex_db_find_routine_aux(THD *thd, const LEX_STRING dbname,
|
||||
const LEX_STRING rname, TABLE *table)
|
||||
const LEX_STRING ev_name, TABLE *table)
|
||||
{
|
||||
byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
|
||||
DBUG_ENTER("evex_db_find_routine_aux");
|
||||
DBUG_PRINT("enter", ("name: %.*s", rname.length, rname.str));
|
||||
DBUG_PRINT("enter", ("name: %.*s", ev_name.length, ev_name.str));
|
||||
|
||||
/*
|
||||
Create key to find row. We have to use field->store() to be able to
|
||||
@ -235,16 +218,16 @@ evex_db_find_routine_aux(THD *thd, const LEX_STRING dbname,
|
||||
'db' and 'name' and the first key is the primary key over the
|
||||
same fields.
|
||||
*/
|
||||
if (rname.length > table->field[1]->field_length)
|
||||
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
||||
if (ev_name.length > table->field[1]->field_length)
|
||||
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
||||
|
||||
table->field[0]->store(dbname.str, dbname.length, &my_charset_bin);
|
||||
table->field[1]->store(rname.str, rname.length, &my_charset_bin);
|
||||
table->field[1]->store(ev_name.str, ev_name.length, &my_charset_bin);
|
||||
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
|
||||
|
||||
if (table->file->index_read_idx(table->record[0], 0, key,
|
||||
table->key_info->key_length,HA_READ_KEY_EXACT))
|
||||
DBUG_RETURN(SP_KEY_NOT_FOUND);
|
||||
table->key_info->key_length,HA_READ_KEY_EXACT))
|
||||
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -394,19 +377,18 @@ db_create_event(THD *thd, event_timed *et)
|
||||
|
||||
restore_record(table, s->default_values); // Get default values for fields
|
||||
|
||||
/* TODO : Uncomment these and add handling in sql_parse.cc or here
|
||||
|
||||
if (sp->m_name.length > table->field[MYSQL_PROC_FIELD_NAME]->field_length)
|
||||
if (et->m_name.length > table->field[EVEX_FIELD_NAME]->field_length)
|
||||
{
|
||||
ret= SP_BAD_IDENTIFIER;
|
||||
goto done;
|
||||
my_error(ER_TOO_LONG_IDENT, MYF(0), et->m_name.str);
|
||||
goto err;
|
||||
}
|
||||
if (sp->m_body.length > table->field[MYSQL_PROC_FIELD_BODY]->field_length)
|
||||
if (et->m_body.length > table->field[EVEX_FIELD_BODY]->field_length)
|
||||
{
|
||||
ret= SP_BODY_TOO_LONG;
|
||||
goto done;
|
||||
my_error(ER_TOO_LONG_BODY, MYF(0), et->m_name.str);
|
||||
goto err;
|
||||
}
|
||||
*/
|
||||
|
||||
if (!(et->m_expr) && !(et->m_execute_at.year))
|
||||
{
|
||||
DBUG_PRINT("error", ("neither m_expr nor m_execute_as are set!"));
|
||||
@ -434,7 +416,8 @@ db_create_event(THD *thd, event_timed *et)
|
||||
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->m_name.str);
|
||||
goto err;
|
||||
}
|
||||
else if (mysql_bin_log.is_open())
|
||||
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
/* Such a statement can always go directly to binlog, no trans cache */
|
||||
@ -472,20 +455,20 @@ static int
|
||||
db_update_event(THD *thd, sp_name *name, event_timed *et)
|
||||
{
|
||||
TABLE *table;
|
||||
int ret;
|
||||
int ret= EVEX_OPEN_TABLE_FAILED;
|
||||
DBUG_ENTER("db_update_event");
|
||||
DBUG_PRINT("enter", ("name: %.*s", et->m_name.length, et->m_name.str));
|
||||
if (name)
|
||||
DBUG_PRINT("enter", ("rename to: %.*s", name->m_name.length, name->m_name.str));
|
||||
|
||||
// Todo: Handle in sql_prepare.cc SP_OPEN_TABLE_FAILED
|
||||
if (!(table= evex_open_event_table(thd, TL_WRITE)))
|
||||
{
|
||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (evex_db_find_routine_aux(thd, et->m_db, et->m_name, table) == SP_KEY_NOT_FOUND)
|
||||
if (EVEX_KEY_NOT_FOUND == evex_db_find_routine_aux(thd, et->m_db, et->m_name,
|
||||
table))
|
||||
{
|
||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->m_name.str);
|
||||
goto err;
|
||||
@ -526,8 +509,21 @@ err:
|
||||
|
||||
|
||||
/*
|
||||
Use sp_name for look up, return in **ett if found
|
||||
Looks for a named event in mysql.event and in case of success returns
|
||||
an object will data loaded from the table.
|
||||
|
||||
SYNOPSIS
|
||||
db_find_event()
|
||||
thd THD
|
||||
name the name of the event to find
|
||||
ett event's data if event is found
|
||||
tbl TABLE object to use when not NULL
|
||||
|
||||
NOTES
|
||||
1) Use sp_name for look up, return in **ett if found
|
||||
2) tbl is not closed at exit
|
||||
*/
|
||||
|
||||
static int
|
||||
db_find_event(THD *thd, sp_name *name, event_timed **ett, TABLE *tbl)
|
||||
{
|
||||
@ -581,6 +577,22 @@ 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
|
||||
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, bool use_lock)
|
||||
{
|
||||
@ -727,7 +739,7 @@ done:
|
||||
|
||||
|
||||
/*
|
||||
Exported functions follow
|
||||
-= Exported functions follow =-
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -754,15 +766,6 @@ evex_create_event(THD *thd, event_timed *et, uint create_options)
|
||||
DBUG_PRINT("enter", ("name: %*s options:%d", et->m_name.length,
|
||||
et->m_name.str, create_options));
|
||||
|
||||
/*
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
if (!evex_is_running)
|
||||
// TODO: put an warning to the user here.
|
||||
// Is it needed? (Andrey, 051129)
|
||||
{}
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
*/
|
||||
|
||||
if ((ret = db_create_event(thd, et)) == EVEX_WRITE_ROW_FAILED &&
|
||||
(create_options & HA_LEX_CREATE_IF_NOT_EXISTS))
|
||||
{
|
||||
@ -821,13 +824,6 @@ evex_update_event(THD *thd, sp_name *name, event_timed *et)
|
||||
DBUG_ENTER("evex_update_event");
|
||||
DBUG_PRINT("enter", ("name: %*s", et->m_name.length, et->m_name.str));
|
||||
|
||||
/*
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
if (!evex_is_running)
|
||||
// put an warning to the user here
|
||||
{}
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
*/
|
||||
/*
|
||||
db_update_event() opens & closes the table to prevent
|
||||
crash later in the code when loading and compiling the new definition
|
||||
@ -837,17 +833,8 @@ evex_update_event(THD *thd, sp_name *name, event_timed *et)
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
if (!evex_is_running)
|
||||
{
|
||||
// not running - therefore no memory structures
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
goto done;
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_evex_running, done);
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
||||
evex_remove_from_cache(&et->m_db, &et->m_name, false);
|
||||
if (et->m_status == MYSQL_EVENT_ENABLED)
|
||||
@ -860,9 +847,14 @@ evex_update_event(THD *thd, sp_name *name, event_timed *et)
|
||||
delete spn;
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
done:
|
||||
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
@ -882,24 +874,17 @@ int
|
||||
evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists)
|
||||
{
|
||||
TABLE *table;
|
||||
int ret;
|
||||
int ret= EVEX_OPEN_TABLE_FAILED;
|
||||
bool opened;
|
||||
DBUG_ENTER("evex_drop_event");
|
||||
|
||||
/*
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
if (!evex_is_running)
|
||||
// put an warning to the user here
|
||||
{}
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
*/
|
||||
////
|
||||
if (!(table= evex_open_event_table(thd, TL_WRITE)))
|
||||
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
|
||||
{
|
||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret= evex_db_find_routine_aux(thd, et->m_db, et->m_name, table);
|
||||
|
||||
if (ret == EVEX_OK)
|
||||
if (!(ret= evex_db_find_routine_aux(thd, et->m_db, et->m_name, table)))
|
||||
{
|
||||
if (ret= table->file->delete_row(table->record[0]))
|
||||
{
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
#define DBUG_FAULTY_THR2
|
||||
|
||||
static uint workers_count;
|
||||
extern ulong thread_created;
|
||||
|
||||
|
||||
pthread_mutex_t LOCK_event_arrays,
|
||||
@ -33,10 +33,8 @@ bool evex_is_running= false;
|
||||
|
||||
ulong opt_event_executor;
|
||||
my_bool event_executor_running_global_var= false;
|
||||
|
||||
extern ulong thread_created;
|
||||
|
||||
static my_bool evex_mutexes_initted= false;
|
||||
static uint workers_count;
|
||||
|
||||
static int
|
||||
evex_load_events_from_db(THD *thd);
|
||||
@ -48,8 +46,11 @@ evex_load_events_from_db(THD *thd);
|
||||
the main thread or not.
|
||||
*/
|
||||
|
||||
pthread_handler_t event_executor_worker(void *arg);
|
||||
pthread_handler_t event_executor_main(void *arg);
|
||||
pthread_handler_t
|
||||
event_executor_worker(void *arg);
|
||||
|
||||
pthread_handler_t
|
||||
event_executor_main(void *arg);
|
||||
|
||||
static
|
||||
void evex_init_mutexes()
|
||||
@ -142,8 +143,8 @@ init_event_thread(THD* thd)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
pthread_handler_t event_executor_main(void *arg)
|
||||
pthread_handler_t
|
||||
event_executor_main(void *arg)
|
||||
{
|
||||
THD *thd; /* needs to be first for thread_stack */
|
||||
ulonglong iter_num= 0;
|
||||
@ -152,13 +153,10 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
DBUG_ENTER("event_executor_main");
|
||||
DBUG_PRINT("event_executor_main", ("EVEX thread started"));
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
evex_is_running= true;
|
||||
event_executor_running_global_var= opt_event_executor;
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
|
||||
// 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();
|
||||
@ -196,6 +194,15 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
VOID(my_init_dynamic_array(&evex_executing_queue, sizeof(event_timed *), 50, 100));
|
||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||
|
||||
/*
|
||||
eventually manifest that we are running, not to crashe because of
|
||||
usage of non-initialized memory structures.
|
||||
*/
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
evex_is_running= true;
|
||||
event_executor_running_global_var= opt_event_executor;
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
|
||||
if (evex_load_events_from_db(thd))
|
||||
goto err;
|
||||
|
||||
@ -208,7 +215,6 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
my_ulonglong cnt;
|
||||
|
||||
DBUG_PRINT("info", ("EVEX External Loop %d", ++cnt));
|
||||
// sql_print_information("[EVEX] External Loop!");
|
||||
thd->proc_info = "Sleeping";
|
||||
my_sleep(1000000);// sleep 1s
|
||||
if (!event_executor_running_global_var)
|
||||
@ -216,16 +222,13 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
time(&now);
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, now);
|
||||
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
||||
for (i= 0; (i < evex_executing_queue.elements) && !thd->killed; ++i)
|
||||
{
|
||||
event_timed **p_et=dynamic_element(&evex_executing_queue,i,event_timed**);
|
||||
event_timed *et= *p_et;
|
||||
// sql_print_information("[EVEX] External Loop 2!");
|
||||
|
||||
event_timed *et= *dynamic_element(&evex_executing_queue,i,event_timed**);
|
||||
// printf("%llu\n", TIME_to_ulonglong_datetime(&et->m_execute_at));
|
||||
if (!event_executor_running_global_var)
|
||||
break;// soon we will do only continue (see the code a bit above)
|
||||
break;
|
||||
|
||||
thd->proc_info = "Iterating";
|
||||
THD_CHECK_SENTRY(thd);
|
||||
@ -233,7 +236,7 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
if this is the first event which is after time_now then no
|
||||
more need to iterate over more elements since the array is sorted.
|
||||
*/
|
||||
if (et->m_execute_at.year &&
|
||||
if (et->m_execute_at.year > 1969 &&
|
||||
my_time_compare(&time_now, &et->m_execute_at) == -1)
|
||||
break;
|
||||
|
||||
@ -250,8 +253,7 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
if (pthread_create(&th, NULL, event_executor_worker, (void*)et))
|
||||
{
|
||||
sql_print_error("Problem while trying to create a thread");
|
||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||
goto err; // for now finish execution of the Executor
|
||||
UNLOCK_MUTEX_AND_BAIL_OUT(LOCK_event_arrays, err);
|
||||
}
|
||||
#else
|
||||
event_executor_worker((void *) et);
|
||||
@ -272,12 +274,12 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
j= 0;
|
||||
while (j < i && j < evex_executing_queue.elements)
|
||||
{
|
||||
event_timed **p_et= dynamic_element(&evex_executing_queue, j, event_timed**);
|
||||
event_timed *et= *p_et;
|
||||
event_timed *et= *dynamic_element(&evex_executing_queue, j, event_timed**);
|
||||
if (et->m_flags & EVENT_EXEC_NO_MORE || et->m_status == MYSQL_EVENT_DISABLED)
|
||||
{
|
||||
delete_dynamic_element(&evex_executing_queue, j);
|
||||
DBUG_PRINT("", ("DELETING FROM EXECUTION QUEUE [%s.%s]",et->m_db.str, et->m_name.str));
|
||||
DBUG_PRINT("EVEX main thread", ("DELETING FROM EXECUTION QUEUE [%s.%s]",
|
||||
et->m_db.str, et->m_name.str));
|
||||
// nulling the position, will delete later
|
||||
if (et->m_dropped)
|
||||
{
|
||||
@ -301,29 +303,44 @@ pthread_handler_t event_executor_main(void *arg)
|
||||
);
|
||||
|
||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||
}// while (!thd->killed)
|
||||
}
|
||||
|
||||
err:
|
||||
// First manifest that this thread does not work and then destroy
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
evex_is_running= false;
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
|
||||
sql_print_information("Event executor stopping");
|
||||
// LEX_STRINGs reside in the memory root and will be destroyed with it.
|
||||
// Hence no need of delete but only freeing of SP
|
||||
for (i=0; i < events_array.elements; ++i)
|
||||
{
|
||||
event_timed *et= dynamic_element(&events_array, i, event_timed*);
|
||||
et->free_sp();
|
||||
}
|
||||
// TODO Andrey: USE lock here!
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
while (workers_count)
|
||||
my_sleep(1000000);// 1s
|
||||
|
||||
/*
|
||||
LEX_STRINGs reside in the memory root and will be destroyed with it.
|
||||
Hence no need of delete but only freeing of SP
|
||||
*/
|
||||
for (i= 0; i < events_array.elements; ++i)
|
||||
dynamic_element(&events_array, i, event_timed*)->free_sp();
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_event_arrays));
|
||||
// No need to use lock here if EVEX is not running but anyway
|
||||
delete_dynamic(&evex_executing_queue);
|
||||
delete_dynamic(&events_array);
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
|
||||
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--;
|
||||
@ -331,28 +348,6 @@ err:
|
||||
delete thd;
|
||||
pthread_mutex_unlock(&LOCK_thread_count);
|
||||
|
||||
/*
|
||||
sleeping some time may help not crash the server. sleeping
|
||||
is done to wait for spawned threads to finish.
|
||||
|
||||
TODO: A better will be with a conditional variable
|
||||
*/
|
||||
{
|
||||
uint tries= 0;
|
||||
while (tries++ < 5)
|
||||
{
|
||||
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));
|
||||
DBUG_PRINT("info", ("Sleep %d", tries));
|
||||
my_sleep(1000000 * tries);// 1s
|
||||
}
|
||||
DBUG_PRINT("info", ("Maybe now it is ok to kill the thread and evex MRoot"));
|
||||
}
|
||||
|
||||
err_no_thd:
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
@ -362,30 +357,25 @@ err_no_thd:
|
||||
free_root(&evex_mem_root, MYF(0));
|
||||
sql_print_information("Event executor stopped");
|
||||
|
||||
// shutdown_events();
|
||||
|
||||
my_thread_end();
|
||||
pthread_exit(0);
|
||||
DBUG_RETURN(0); // Can't return anything here
|
||||
DBUG_RETURN(0);// Can't return anything here
|
||||
}
|
||||
|
||||
|
||||
pthread_handler_t event_executor_worker(void *event_void)
|
||||
pthread_handler_t
|
||||
event_executor_worker(void *event_void)
|
||||
{
|
||||
THD *thd; /* needs to be first for thread_stack */
|
||||
List<Item> empty_item_list;
|
||||
event_timed *event = (event_timed *) event_void;
|
||||
MEM_ROOT mem_root;
|
||||
MEM_ROOT worker_mem_root;
|
||||
|
||||
DBUG_ENTER("event_executor_worker");
|
||||
VOID(pthread_mutex_lock(&LOCK_workers_count));
|
||||
++workers_count;
|
||||
VOID(pthread_mutex_unlock(&LOCK_workers_count));
|
||||
|
||||
init_alloc_root(&mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
|
||||
//we pass this empty list as parameter to the SP_HEAD of the event
|
||||
empty_item_list.empty();
|
||||
init_alloc_root(&worker_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||
|
||||
my_thread_init();
|
||||
|
||||
@ -395,8 +385,10 @@ pthread_handler_t event_executor_worker(void *event_void)
|
||||
goto err_no_thd;
|
||||
}
|
||||
thd->thread_stack = (char*)&thd; // remember where our stack is
|
||||
thd->mem_root= &mem_root;
|
||||
thd->mem_root= &worker_mem_root;
|
||||
|
||||
pthread_detach(pthread_self());
|
||||
|
||||
if (init_event_thread(thd))
|
||||
goto err;
|
||||
|
||||
@ -425,7 +417,7 @@ pthread_handler_t event_executor_worker(void *event_void)
|
||||
my_TIME_to_str(&event->m_execute_at, exec_time);
|
||||
DBUG_PRINT("info", (" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->m_db.str, event->m_name.str,(int) event->m_expr, exec_time));
|
||||
sql_print_information(" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->m_db.str, event->m_name.str,(int) event->m_expr, exec_time);
|
||||
ret= event->execute(thd, &mem_root);
|
||||
ret= event->execute(thd, &worker_mem_root);
|
||||
sql_print_information(" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]. RetCode=%d", event->m_db.str, event->m_name.str,(int) event->m_expr, exec_time, ret);
|
||||
DBUG_PRINT("info", (" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->m_db.str, event->m_name.str,(int) event->m_expr, exec_time));
|
||||
}
|
||||
@ -454,8 +446,7 @@ err:
|
||||
|
||||
err_no_thd:
|
||||
|
||||
free_root(&mem_root, MYF(0));
|
||||
// sql_print_information(" Worker thread exiting");
|
||||
free_root(&worker_mem_root, MYF(0));
|
||||
|
||||
VOID(pthread_mutex_lock(&LOCK_workers_count));
|
||||
--workers_count;
|
||||
@ -496,29 +487,38 @@ evex_load_events_from_db(THD *thd)
|
||||
}
|
||||
DBUG_PRINT("evex_load_events_from_db", ("Loading event from row."));
|
||||
|
||||
if (et->load_from_row(&evex_mem_root, table))
|
||||
//error loading!
|
||||
continue;
|
||||
if ((ret= et->load_from_row(&evex_mem_root, table)))
|
||||
{
|
||||
sql_print_error("Error while loading from mysql.event. "
|
||||
"Table probably corrupted");
|
||||
goto end;
|
||||
}
|
||||
|
||||
DBUG_PRINT("evex_load_events_from_db",
|
||||
("Event %s loaded from row. Time to compile", et->m_name.str));
|
||||
|
||||
if (et->compile(thd, &evex_mem_root))
|
||||
//problem during compile
|
||||
continue;
|
||||
if ((ret= et->compile(thd, &evex_mem_root)))
|
||||
{
|
||||
sql_print_error("Error while compiling %s.%s. Aborting load.",
|
||||
et->m_db.str, et->m_name.str);
|
||||
goto end;
|
||||
}
|
||||
// let's find when to be executed
|
||||
et->compute_next_execution_time();
|
||||
|
||||
DBUG_PRINT("evex_load_events_from_db",
|
||||
("Adding %s to the executor list.", et->m_name.str));
|
||||
VOID(push_dynamic(&events_array,(gptr) et));
|
||||
// we always add at the end so the number of elements - 1 is the place
|
||||
// in the buffer
|
||||
/*
|
||||
We always add at the end so the number of elements - 1 is the place
|
||||
in the buffer.
|
||||
DYNAMIC_ARRAY copies the object bit by bit so we have a hollow copy
|
||||
in event_array. We don't need the original therefore we delete it.
|
||||
*/
|
||||
et_copy= dynamic_element(&events_array, events_array.elements - 1,
|
||||
event_timed*);
|
||||
event_timed*);
|
||||
VOID(push_dynamic(&evex_executing_queue,(gptr) &et_copy));
|
||||
et->m_free_sphead_on_delete= false;
|
||||
DBUG_PRINT("info", (""));
|
||||
delete et;
|
||||
}
|
||||
end_read_record(&read_record_info);
|
||||
@ -536,8 +536,7 @@ evex_load_events_from_db(THD *thd)
|
||||
end:
|
||||
close_thread_tables(thd);
|
||||
|
||||
DBUG_PRINT("evex_load_events_from_db",
|
||||
("Events loaded from DB. Status code %d", ret));
|
||||
DBUG_PRINT("info", ("Finishing with status code %d", ret));
|
||||
DBUG_RETURN(ret);
|
||||
}
|
||||
|
||||
@ -547,7 +546,8 @@ bool sys_var_event_executor::update(THD *thd, set_var *var)
|
||||
{
|
||||
// here start the thread if not running.
|
||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||
if ((my_bool) var->save_result.ulong_value && !evex_is_running) {
|
||||
if ((my_bool) var->save_result.ulong_value && !evex_is_running)
|
||||
{
|
||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||
init_events();
|
||||
} else
|
||||
|
@ -18,6 +18,9 @@
|
||||
#define _EVENT_PRIV_H_
|
||||
|
||||
|
||||
#define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \
|
||||
{ VOID(pthread_mutex_unlock(&__mutex)); goto __label; }
|
||||
|
||||
enum
|
||||
{
|
||||
EVEX_FIELD_DB = 0,
|
||||
|
@ -290,7 +290,7 @@ event_timed::init_ends(THD *thd, Item *ends)
|
||||
if (ends->fix_fields(thd, &ends))
|
||||
DBUG_RETURN(EVEX_PARSE_ERROR);
|
||||
|
||||
// the field was already fixed in init_ends
|
||||
// the field was already fixed in init_ends
|
||||
if ((not_used= ends->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||
DBUG_RETURN(EVEX_BAD_PARAMS);
|
||||
|
||||
@ -537,10 +537,19 @@ event_timed::compute_next_execution_time()
|
||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, now);
|
||||
/*
|
||||
sql_print_information("[%s.%s]", m_db.str, m_name.str);
|
||||
sql_print_information("time_now : [%d-%d-%d %d:%d:%d ]", time_now.year, time_now.month, time_now.day, time_now.hour, time_now.minute, time_now.second);
|
||||
sql_print_information("m_starts : [%d-%d-%d %d:%d:%d ]", m_starts.year, m_starts.month, m_starts.day, m_starts.hour, m_starts.minute, m_starts.second);
|
||||
sql_print_information("m_ends : [%d-%d-%d %d:%d:%d ]", m_ends.year, m_ends.month, m_ends.day, m_ends.hour, m_ends.minute, m_ends.second);
|
||||
sql_print_information("m_last_ex: [%d-%d-%d %d:%d:%d ]", m_last_executed.year, m_last_executed.month, m_last_executed.day, m_last_executed.hour, m_last_executed.minute, m_last_executed.second);
|
||||
sql_print_information("time_now : [%d-%d-%d %d:%d:%d ]",
|
||||
time_now.year, time_now.month, time_now.day,
|
||||
time_now.hour, time_now.minute, time_now.second);
|
||||
sql_print_information("m_starts : [%d-%d-%d %d:%d:%d ]", m_starts.year,
|
||||
m_starts.month, m_starts.day, m_starts.hour,
|
||||
m_starts.minute, m_starts.second);
|
||||
sql_print_information("m_ends : [%d-%d-%d %d:%d:%d ]", m_ends.year,
|
||||
m_ends.month, m_ends.day, m_ends.hour,
|
||||
m_ends.minute, m_ends.second);
|
||||
sql_print_information("m_last_ex: [%d-%d-%d %d:%d:%d ]", m_last_executed.year,
|
||||
m_last_executed.month, m_last_executed.day,
|
||||
m_last_executed.hour, m_last_executed.minute,
|
||||
m_last_executed.second);
|
||||
*/
|
||||
//if time_now is after m_ends don't execute anymore
|
||||
if (m_ends.year && (tmp= my_time_compare(&m_ends, &time_now)) == -1)
|
||||
@ -702,7 +711,6 @@ event_timed::mark_last_executed()
|
||||
bool
|
||||
event_timed::drop(THD *thd)
|
||||
{
|
||||
|
||||
return (bool) evex_drop_event(thd, this, false);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user