diff options
Diffstat (limited to 'sql/events.cc')
-rw-r--r-- | sql/events.cc | 263 |
1 files changed, 155 insertions, 108 deletions
diff --git a/sql/events.cc b/sql/events.cc index 9e15a5f47bd..41f6aac5d64 100644 --- a/sql/events.cc +++ b/sql/events.cc @@ -14,6 +14,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include <my_global.h> #include "sql_priv.h" #include "unireg.h" #include "sql_parse.h" // check_access @@ -79,7 +80,8 @@ Event_queue *Events::event_queue; Event_scheduler *Events::scheduler; Event_db_repository *Events::db_repository; ulong Events::opt_event_scheduler= Events::EVENTS_OFF; -bool Events::check_system_tables_error= FALSE; +ulong Events::startup_state= Events::EVENTS_OFF; +ulong Events::inited; /* @@ -113,7 +115,7 @@ bool Events::check_if_system_tables_error() { DBUG_ENTER("Events::check_if_system_tables_error"); - if (check_system_tables_error) + if (!inited) { my_error(ER_EVENTS_DB_ERROR, MYF(0)); DBUG_RETURN(TRUE); @@ -256,10 +258,10 @@ common_1_lev_code: /** - Create a new query string for removing executable comments - for avoiding leak and keeping consistency of the execution + Create a new query string for removing executable comments + for avoiding leak and keeping consistency of the execution on master and slave. - + @param[in] thd Thread handler @param[in] buf Query string @@ -280,7 +282,7 @@ create_query_string(THD *thd, String *buf) thd->lex->stmt_definition_end - thd->lex->stmt_definition_begin)) return 1; - + return 0; } @@ -306,7 +308,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists) { bool ret; - bool save_binlog_row_based, event_already_exists; + bool event_already_exists; + enum_binlog_format save_binlog_format; DBUG_ENTER("Events::create_event"); if (check_if_system_tables_error()) @@ -334,12 +337,11 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, if (parse_data->do_not_create) DBUG_RETURN(FALSE); - /* - Turn off row binlogging of this statement and use statement-based + /* + Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for CREATE EVENT command. */ - if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row())) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); if (lock_object_name(thd, MDL_key::EVENT, parse_data->dbname.str, parse_data->name.str)) @@ -383,8 +385,10 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, String log_query; if (create_query_string(thd, &log_query)) { - sql_print_error("Event Error: An error occurred while creating query " - "string, before writing it into binary log."); + my_message_sql(ER_STARTUP, + "Event Error: An error occurred while creating query " + "string, before writing it into binary log.", + MYF(ME_NOREFRESH)); ret= true; } else @@ -398,10 +402,8 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, } } } - /* Restore the state of binlog format */ - DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); - if (save_binlog_row_based) - thd->set_current_stmt_binlog_format_row(); + + thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); } @@ -431,7 +433,7 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname, LEX_STRING *new_name) { int ret; - bool save_binlog_row_based; + enum_binlog_format save_binlog_format; Event_queue_element *new_element; DBUG_ENTER("Events::update_event"); @@ -474,12 +476,11 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, } } - /* - Turn off row binlogging of this statement and use statement-based + /* + Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for UPDATE EVENT command. */ - if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row())) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); if (lock_object_name(thd, MDL_key::EVENT, parse_data->dbname.str, parse_data->name.str)) @@ -513,11 +514,8 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } } - /* Restore the state of binlog format */ - DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); - if (save_binlog_row_based) - thd->set_current_stmt_binlog_format_row(); + thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); } @@ -550,7 +548,7 @@ bool Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) { int ret; - bool save_binlog_row_based; + enum_binlog_format save_binlog_format; DBUG_ENTER("Events::drop_event"); if (check_if_system_tables_error()) @@ -563,8 +561,7 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) Turn off row binlogging of this statement and use statement-based so that all supporting tables are updated for DROP EVENT command. */ - if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row())) - thd->clear_current_stmt_binlog_format_row(); + save_binlog_format= thd->set_current_stmt_binlog_format_stmt(); if (lock_object_name(thd, MDL_key::EVENT, dbname.str, name.str)) @@ -578,10 +575,8 @@ Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists) DBUG_ASSERT(thd->query() && thd->query_length()); ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length()); } - /* Restore the state of binlog format */ - DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row()); - if (save_binlog_row_based) - thd->set_current_stmt_binlog_format_row(); + + thd->restore_stmt_binlog_format(save_binlog_format); DBUG_RETURN(ret); } @@ -605,6 +600,8 @@ Events::drop_schema_events(THD *thd, char *db) DBUG_ENTER("Events::drop_schema_events"); DBUG_PRINT("enter", ("dropping events from %s", db)); + DBUG_ASSERT(ok_for_lower_case_names(db)); + /* Sic: no check if the scheduler is disabled or system tables are damaged, as intended. @@ -758,6 +755,13 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) int ret; DBUG_ENTER("Events::fill_schema_events"); + /* + If we didn't start events because of --skip-grant-tables, return an + empty set + */ + if (opt_noacl) + DBUG_RETURN(0); + if (check_if_system_tables_error()) DBUG_RETURN(1); @@ -773,6 +777,9 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) NULL, NULL, 0, 0)) DBUG_RETURN(1); db= thd->lex->select_lex.db; + + if (lower_case_table_names) + my_casedn_str(system_charset_info, db); } ret= db_repository->fill_schema_events(thd, tables, db); @@ -783,6 +790,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) /** Initializes the scheduler's structures. + @param THD or null (if called by init) @param opt_noacl_or_bootstrap TRUE if there is --skip-grant-tables or --bootstrap option. In that case we disable the event scheduler. @@ -790,34 +798,55 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) @note This function is not synchronized. @retval FALSE Perhaps there was an error, and the event scheduler - is disabled. But the error is not fatal and the + is disabled. But the error is not fatal and the server start up can continue. @retval TRUE Fatal error. Startup must terminate (call unireg_abort()). */ bool -Events::init(bool opt_noacl_or_bootstrap) +Events::init(THD *thd, bool opt_noacl_or_bootstrap) { - - THD *thd; int err_no; bool res= FALSE; - + bool had_thd= thd != 0; DBUG_ENTER("Events::init"); + DBUG_ASSERT(inited == 0); + + /* + Was disabled explicitly from the command line + */ + if (opt_event_scheduler == Events::EVENTS_DISABLED || + opt_noacl_or_bootstrap) + DBUG_RETURN(FALSE); + /* We need a temporary THD during boot */ - if (!(thd= new THD())) + if (!thd) { - res= TRUE; - goto end; + + if (!(thd= new THD())) + { + res= TRUE; + goto end; + } + /* + The thread stack does not start from this function but we cannot + guess the real value. So better some value that doesn't assert than + no value. + */ + thd->thread_stack= (char*) &thd; + thd->store_globals(); + /* + Set current time for the thread that handles events. + Current time is stored in data member start_time of THD class. + Subsequently, this value is used to check whether event was expired + when make loading events from storage. Check for event expiration time + is done at Event_queue_element::compute_next_execution_time() where + event's status set to Event_parse_data::DISABLED and dropped flag set + to true if event was expired. + */ + thd->set_time(); } - /* - The thread stack does not start from this function but we cannot - guess the real value. So better some value that doesn't assert than - no value. - */ - thd->thread_stack= (char*) &thd; - thd->store_globals(); /* We will need Event_db_repository anyway, even if the scheduler is @@ -838,28 +867,19 @@ Events::init(bool opt_noacl_or_bootstrap) are most likely not there and we're going to disable the event scheduler anyway. */ - if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd)) + if (Event_db_repository::check_system_tables(thd)) { - if (! opt_noacl_or_bootstrap) - { - sql_print_error("Event Scheduler: An error occurred when initializing " - "system tables. Disabling the Event Scheduler."); - check_system_tables_error= TRUE; - } - + delete db_repository; + db_repository= 0; + my_message(ER_STARTUP, + "Event Scheduler: An error occurred when initializing " + "system tables. Disabling the Event Scheduler.", + MYF(ME_NOREFRESH)); /* Disable the scheduler since the system tables are not up to date */ - opt_event_scheduler= EVENTS_DISABLED; + opt_event_scheduler= EVENTS_OFF; goto end; } - /* - Was disabled explicitly from the command line, or because we're running - with --skip-grant-tables, or --bootstrap, or because we have no system - tables. - */ - if (opt_event_scheduler == Events::EVENTS_DISABLED) - goto end; - DBUG_ASSERT(opt_event_scheduler == Events::EVENTS_ON || opt_event_scheduler == Events::EVENTS_OFF); @@ -874,22 +894,20 @@ Events::init(bool opt_noacl_or_bootstrap) if (event_queue->init_queue(thd) || load_events_from_db(thd) || (opt_event_scheduler == EVENTS_ON && scheduler->start(&err_no))) { - sql_print_error("Event Scheduler: Error while loading from disk."); + my_message_sql(ER_STARTUP, + "Event Scheduler: Error while loading from mysql.event table.", + MYF(ME_NOREFRESH)); res= TRUE; /* fatal error: request unireg_abort */ goto end; } Event_worker_thread::init(db_repository); + inited= 1; end: if (res) - { - delete db_repository; - delete event_queue; - delete scheduler; - } - delete thd; - /* Remember that we don't have a THD */ - my_pthread_setspecific_ptr(THR_THD, NULL); + deinit(); + if (!had_thd) + delete thd; DBUG_RETURN(res); } @@ -909,17 +927,14 @@ Events::deinit() { DBUG_ENTER("Events::deinit"); - if (opt_event_scheduler != EVENTS_DISABLED) - { - delete scheduler; - scheduler= NULL; /* safety */ - delete event_queue; - event_queue= NULL; /* safety */ - } - + delete scheduler; + scheduler= NULL; /* For restart */ + delete event_queue; + event_queue= NULL; /* For restart */ delete db_repository; - db_repository= NULL; /* safety */ + db_repository= NULL; /* For restart */ + inited= 0; DBUG_VOID_RETURN; } @@ -948,23 +963,37 @@ static PSI_thread_info all_events_threads[]= { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL}, { &key_thread_event_worker, "event_worker", 0} }; +#endif /* HAVE_PSI_INTERFACE */ + +PSI_stage_info stage_waiting_on_empty_queue= { 0, "Waiting on empty queue", 0}; +PSI_stage_info stage_waiting_for_next_activation= { 0, "Waiting for next activation", 0}; +PSI_stage_info stage_waiting_for_scheduler_to_stop= { 0, "Waiting for the scheduler to stop", 0}; + +#ifdef HAVE_PSI_INTERFACE +PSI_stage_info *all_events_stages[]= +{ + & stage_waiting_on_empty_queue, + & stage_waiting_for_next_activation, + & stage_waiting_for_scheduler_to_stop +}; static void init_events_psi_keys(void) { const char* category= "sql"; int count; - if (PSI_server == NULL) - return; - count= array_elements(all_events_mutexes); - PSI_server->register_mutex(category, all_events_mutexes, count); + mysql_mutex_register(category, all_events_mutexes, count); count= array_elements(all_events_conds); - PSI_server->register_cond(category, all_events_conds, count); + mysql_cond_register(category, all_events_conds, count); count= array_elements(all_events_threads); - PSI_server->register_thread(category, all_events_threads, count); + mysql_thread_register(category, all_events_threads, count); + + count= array_elements(all_events_stages); + mysql_stage_register(category, all_events_stages, count); + } #endif /* HAVE_PSI_INTERFACE */ @@ -1008,7 +1037,7 @@ Events::dump_internal_status() holding LOCK_global_system_variables. */ mysql_mutex_lock(&LOCK_global_system_variables); - if (opt_event_scheduler == EVENTS_DISABLED) + if (!inited) puts("The Event Scheduler is disabled"); else { @@ -1022,11 +1051,13 @@ Events::dump_internal_status() bool Events::start(int *err_no) { + DBUG_ASSERT(inited); return scheduler->start(err_no); } bool Events::stop() { + DBUG_ASSERT(inited); return scheduler->stop(); } @@ -1056,7 +1087,6 @@ Events::load_events_from_db(THD *thd) bool ret= TRUE; uint count= 0; ulong saved_master_access; - DBUG_ENTER("Events::load_events_from_db"); DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd)); @@ -1064,18 +1094,26 @@ Events::load_events_from_db(THD *thd) NOTE: even if we run in read-only mode, we should be able to lock the mysql.event table for writing. In order to achieve this, we should call mysql_lock_tables() under the super user. + + Same goes for transaction access mode. + Temporarily reset it to read-write. */ saved_master_access= thd->security_ctx->master_access; thd->security_ctx->master_access |= SUPER_ACL; + bool save_tx_read_only= thd->tx_read_only; + thd->tx_read_only= false; ret= db_repository->open_event_table(thd, TL_WRITE, &table); + thd->tx_read_only= save_tx_read_only; thd->security_ctx->master_access= saved_master_access; if (ret) { - sql_print_error("Event Scheduler: Failed to open table mysql.event"); + my_message_sql(ER_STARTUP, + "Event Scheduler: Failed to open table mysql.event", + MYF(ME_NOREFRESH)); DBUG_RETURN(TRUE); } @@ -1088,8 +1126,7 @@ Events::load_events_from_db(THD *thd) while (!(read_record_info.read_record(&read_record_info))) { Event_queue_element *et; - bool created; - bool drop_on_completion; + bool created, dropped; if (!(et= new Event_queue_element)) goto end; @@ -1098,16 +1135,18 @@ Events::load_events_from_db(THD *thd) if (et->load_from_row(thd, table)) { - sql_print_error("Event Scheduler: " - "Error while loading events from mysql.event. " - "The table probably contains bad data or is corrupted"); + my_message(ER_STARTUP, + "Event Scheduler: " + "Error while loading events from mysql.event. " + "The table probably contains bad data or is corrupted", + MYF(ME_NOREFRESH)); delete et; goto end; } #ifdef WITH_WSREP // when SST from master node who initials event, the event status is ENABLED // this is problematic because there are two nodes with same events and both enabled. - if (et->originator != thd->server_id) + if (et->originator != (longlong) thd->variables.server_id) { store_record(table, record[1]); table->field[ET_FIELD_STATUS]-> @@ -1118,10 +1157,12 @@ Events::load_events_from_db(THD *thd) continue; } #endif - drop_on_completion= (et->on_completion == - Event_parse_data::ON_COMPLETION_DROP); - - + /** + Since the Event_queue_element object could be deleted inside + Event_queue::create_event we should save the value of dropped flag + into the temporary variable. + */ + dropped= et->dropped; if (event_queue->create_event(thd, et, &created)) { /* Out of memory */ @@ -1130,7 +1171,7 @@ Events::load_events_from_db(THD *thd) } if (created) count++; - else if (drop_on_completion) + else if (dropped) { /* If not created, a stale event - drop if immediately if @@ -1149,9 +1190,12 @@ Events::load_events_from_db(THD *thd) } } } - if (global_system_variables.log_warnings) - sql_print_information("Event Scheduler: Loaded %d event%s", - count, (count == 1) ? "" : "s"); + my_printf_error(ER_STARTUP, + "Event Scheduler: Loaded %d event%s", + MYF(ME_NOREFRESH | + (global_system_variables.log_warnings) ? + ME_JUST_INFO: 0), + count, (count == 1) ? "" : "s"); ret= FALSE; end: @@ -1160,6 +1204,7 @@ end: close_mysql_tables(thd); DBUG_RETURN(ret); } + #ifdef WITH_WSREP int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) { @@ -1167,7 +1212,8 @@ int wsrep_create_event_query(THD *thd, uchar** buf, size_t* buf_len) if (create_query_string(thd, &log_query)) { - WSREP_WARN("events create string failed: %s", thd->query()); + WSREP_WARN("events create string failed: schema: %s, query: %s", + (thd->db ? thd->db : "(null)"), thd->query()); return 1; } return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); @@ -1194,7 +1240,8 @@ int wsrep_alter_event_query(THD *thd, uchar** buf, size_t* buf_len) if (wsrep_alter_query_string(thd, &log_query)) { - WSREP_WARN("events alter string failed: %s", thd->query()); + WSREP_WARN("events alter string failed: schema: %s, query: %s", + (thd->db ? thd->db : "(null)"), thd->query()); return 1; } return wsrep_to_buf_helper(thd, log_query.ptr(), log_query.length(), buf, buf_len); |