summaryrefslogtreecommitdiff
path: root/sql/event_executor.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/event_executor.cc')
-rw-r--r--sql/event_executor.cc995
1 files changed, 0 insertions, 995 deletions
diff --git a/sql/event_executor.cc b/sql/event_executor.cc
index 21464dd777b..f236fb47771 100644
--- a/sql/event_executor.cc
+++ b/sql/event_executor.cc
@@ -13,998 +13,3 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-
-#include "event_priv.h"
-#include "event.h"
-#include "sp.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);
-}