Commit a4bcbd51 authored by unknown's avatar unknown
Browse files

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
parent bc3708a5
Loading
Loading
Loading
Loading
+68 −83
Original line number Diff line number Diff line
@@ -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,14 +42,6 @@
   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!

@@ -60,15 +50,8 @@
 - 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()?
 
 - 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
@@ -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);
    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 @@ db_update_event(THD *thd, sp_name *name, event_timed *et)


/*
    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 @@ db_find_event(THD *thd, sp_name *name, event_timed **ett, TABLE *tbl)
}


/*
   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 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock)


/*
                      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));

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.
  */

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);

  ret= evex_db_find_routine_aux(thd, et->m_db, et->m_name, table);
  {
    my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
    goto done;
  }

  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]))
    { 	
+83 −83
Original line number Diff line number Diff line
@@ -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,14 +153,11 @@ 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

  /*
    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)
  {
    event_timed *et= dynamic_element(&events_array, i, event_timed*);
    et->free_sp();
  }
  // TODO Andrey: USE lock here!
    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 @@ pthread_handler_t event_executor_main(void *arg)
  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 @@ pthread_handler_t event_executor_main(void *arg)
  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
}


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 @@ pthread_handler_t event_executor_worker(void *event_void)

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*);
    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 
+3 −0
Original line number Diff line number Diff line
@@ -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,
+14 −6
Original line number Diff line number Diff line
@@ -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);
}