MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
event_queue.cc
1 /* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software Foundation,
14  51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
15 
16 #include "sql_priv.h"
17 #include "unireg.h"
18 #include "event_queue.h"
19 #include "event_data_objects.h"
20 #include "event_db_repository.h"
21 #include "events.h"
22 #include "sql_audit.h"
23 #include "tztime.h" // my_tz_find, my_tz_OFFSET0, struct Time_zone
24 #include "log.h" // sql_print_error
25 #include "sql_class.h" // struct THD
26 
32 #define EVENT_QUEUE_INITIAL_SIZE 30
33 #define EVENT_QUEUE_EXTENT 30
34 
35 #ifdef __GNUC__
36 #if __GNUC__ >= 2
37 #define SCHED_FUNC __FUNCTION__
38 #endif
39 #else
40 #define SCHED_FUNC "<unknown>"
41 #endif
42 
43 #define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__)
44 #define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__)
45 
46 /*
47  Compares the execute_at members of two Event_queue_element instances.
48  Used as callback for the prioritized queue when shifting
49  elements inside.
50 
51  SYNOPSIS
52  event_queue_element_data_compare_q()
53  vptr Not used (set it to NULL)
54  a First Event_queue_element object
55  b Second Event_queue_element object
56 
57  RETURN VALUE
58  -1 a->execute_at < b->execute_at
59  0 a->execute_at == b->execute_at
60  1 a->execute_at > b->execute_at
61 
62  NOTES
63  execute_at.second_part is not considered during comparison
64 */
65 
66 extern "C" int event_queue_element_compare_q(void *, uchar *, uchar *);
67 
68 int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b)
69 {
72  my_time_t lhs = left->execute_at;
73  my_time_t rhs = right->execute_at;
74 
75  if (left->status == Event_parse_data::DISABLED)
76  return right->status != Event_parse_data::DISABLED;
77 
78  if (right->status == Event_parse_data::DISABLED)
79  return 1;
80 
81  return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
82 }
83 
84 
85 /*
86  Constructor of class Event_queue.
87 
88  SYNOPSIS
89  Event_queue::Event_queue()
90 */
91 
92 Event_queue::Event_queue()
93  :next_activation_at(0),
94  mutex_last_locked_at_line(0),
95  mutex_last_unlocked_at_line(0),
96  mutex_last_attempted_lock_at_line(0),
97  mutex_last_locked_in_func("n/a"),
98  mutex_last_unlocked_in_func("n/a"),
99  mutex_last_attempted_lock_in_func("n/a"),
100  mutex_queue_data_locked(FALSE),
101  mutex_queue_data_attempting_lock(FALSE),
102  waiting_on_cond(FALSE)
103 {
104  mysql_mutex_init(key_LOCK_event_queue, &LOCK_event_queue, MY_MUTEX_INIT_FAST);
105  mysql_cond_init(key_COND_queue_state, &COND_queue_state, NULL);
106 }
107 
108 
109 Event_queue::~Event_queue()
110 {
111  deinit_queue();
112  mysql_mutex_destroy(&LOCK_event_queue);
113  mysql_cond_destroy(&COND_queue_state);
114 }
115 
116 
117 /*
118  This is a queue's constructor. Until this method is called, the
119  queue is unusable. We don't use a C++ constructor instead in
120  order to be able to check the return value. The queue is
121  initialized once at server startup. Initialization can fail in
122  case of a failure reading events from the database or out of
123  memory.
124 
125  SYNOPSIS
126  Event_queue::init()
127 
128  RETURN VALUE
129  FALSE OK
130  TRUE Error
131 */
132 
133 bool
134 Event_queue::init_queue(THD *thd)
135 {
136  DBUG_ENTER("Event_queue::init_queue");
137  DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
138 
139  LOCK_QUEUE_DATA();
140 
141  if (init_queue_ex(&queue, EVENT_QUEUE_INITIAL_SIZE , 0 /*offset*/,
142  0 /*max_on_top*/, event_queue_element_compare_q,
143  NULL, EVENT_QUEUE_EXTENT))
144  {
145  sql_print_error("Event Scheduler: Can't initialize the execution queue");
146  goto err;
147  }
148 
149  UNLOCK_QUEUE_DATA();
150  DBUG_RETURN(FALSE);
151 
152 err:
153  UNLOCK_QUEUE_DATA();
154  DBUG_RETURN(TRUE);
155 }
156 
157 
158 /*
159  Deinits the queue. Remove all elements from it and destroys them
160  too.
161 
162  SYNOPSIS
163  Event_queue::deinit_queue()
164 */
165 
166 void
167 Event_queue::deinit_queue()
168 {
169  DBUG_ENTER("Event_queue::deinit_queue");
170 
171  LOCK_QUEUE_DATA();
172  empty_queue();
173  delete_queue(&queue);
174  UNLOCK_QUEUE_DATA();
175 
176  DBUG_VOID_RETURN;
177 }
178 
179 
198 bool
200  bool *created)
201 {
202  DBUG_ENTER("Event_queue::create_event");
203  DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd,
204  new_element->dbname.str, new_element->name.str));
205 
206  /* Will do nothing if the event is disabled */
207  new_element->compute_next_execution_time();
208  if (new_element->status != Event_parse_data::ENABLED)
209  {
210  delete new_element;
211  *created= FALSE;
212  DBUG_RETURN(FALSE);
213  }
214 
215  DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
216 
217  LOCK_QUEUE_DATA();
218  *created= (queue_insert_safe(&queue, (uchar *) new_element) == FALSE);
219  dbug_dump_queue(thd->query_start());
220  mysql_cond_broadcast(&COND_queue_state);
221  UNLOCK_QUEUE_DATA();
222 
223  DBUG_RETURN(!*created);
224 }
225 
226 
227 /*
228  Updates an event from the scheduler queue
229 
230  SYNOPSIS
231  Event_queue::update_event()
232  thd Thread
233  dbname Schema of the event
234  name Name of the event
235  new_schema New schema, in case of RENAME TO, otherwise NULL
236  new_name New name, in case of RENAME TO, otherwise NULL
237 */
238 
239 void
240 Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
241  Event_queue_element *new_element)
242 {
243  DBUG_ENTER("Event_queue::update_event");
244  DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str));
245 
246  if ((new_element->status == Event_parse_data::DISABLED) ||
247  (new_element->status == Event_parse_data::SLAVESIDE_DISABLED))
248  {
249  DBUG_PRINT("info", ("The event is disabled."));
250  /*
251  Destroy the object but don't skip to end: because we may have to remove
252  object from the cache.
253  */
254  delete new_element;
255  new_element= NULL;
256  }
257  else
258  new_element->compute_next_execution_time();
259 
260  LOCK_QUEUE_DATA();
261  find_n_remove_event(dbname, name);
262 
263  /* If not disabled event */
264  if (new_element)
265  {
266  DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
267  queue_insert_safe(&queue, (uchar *) new_element);
268  mysql_cond_broadcast(&COND_queue_state);
269  }
270 
271  dbug_dump_queue(thd->query_start());
272  UNLOCK_QUEUE_DATA();
273 
274  DBUG_VOID_RETURN;
275 }
276 
277 
278 /*
279  Drops an event from the queue
280 
281  SYNOPSIS
282  Event_queue::drop_event()
283  thd Thread
284  dbname Schema of the event to drop
285  name Name of the event to drop
286 */
287 
288 void
289 Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
290 {
291  DBUG_ENTER("Event_queue::drop_event");
292  DBUG_PRINT("enter", ("thd: 0x%lx db :%s name: %s", (long) thd,
293  dbname.str, name.str));
294 
295  LOCK_QUEUE_DATA();
296  find_n_remove_event(dbname, name);
297  dbug_dump_queue(thd->query_start());
298  UNLOCK_QUEUE_DATA();
299 
300  /*
301  We don't signal here because the scheduler will catch the change
302  next time it wakes up.
303  */
304 
305  DBUG_VOID_RETURN;
306 }
307 
308 
309 /*
310  Drops all events from the in-memory queue and disk that match
311  certain pattern evaluated by a comparator function
312 
313  SYNOPSIS
314  Event_queue::drop_matching_events()
315  thd THD
316  pattern A pattern string
317  comparator The function to use for comparing
318 
319  RETURN VALUE
320  >=0 Number of dropped events
321 
322  NOTE
323  Expected is the caller to acquire lock on LOCK_event_queue
324 */
325 
326 void
327 Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
328  bool (*comparator)(LEX_STRING, Event_basic *))
329 {
330  uint i= 0;
331  DBUG_ENTER("Event_queue::drop_matching_events");
332  DBUG_PRINT("enter", ("pattern=%s", pattern.str));
333 
334  while (i < queue.elements)
335  {
336  Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
337  DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
338  if (comparator(pattern, et))
339  {
340  /*
341  The queue is ordered. If we remove an element, then all elements
342  after it will shift one position to the left, if we imagine it as
343  an array from left to the right. In this case we should not
344  increment the counter and the (i < queue.elements) condition is ok.
345  */
346  queue_remove(&queue, i);
347  delete et;
348  }
349  else
350  i++;
351  }
352  /*
353  We don't call mysql_cond_broadcast(&COND_queue_state);
354  If we remove the top event:
355  1. The queue is empty. The scheduler will wake up at some time and
356  realize that the queue is empty. If create_event() comes inbetween
357  it will signal the scheduler
358  2. The queue is not empty, but the next event after the previous top,
359  won't be executed any time sooner than the element we removed. Hence,
360  we may not notify the scheduler and it will realize the change when it
361  wakes up from timedwait.
362  */
363 
364  DBUG_VOID_RETURN;
365 }
366 
367 
368 /*
369  Drops all events from the in-memory queue and disk that are from
370  certain schema.
371 
372  SYNOPSIS
373  Event_queue::drop_schema_events()
374  thd HD
375  schema The schema name
376 */
377 
378 void
379 Event_queue::drop_schema_events(THD *thd, LEX_STRING schema)
380 {
381  DBUG_ENTER("Event_queue::drop_schema_events");
382  LOCK_QUEUE_DATA();
383  drop_matching_events(thd, schema, event_basic_db_equal);
384  UNLOCK_QUEUE_DATA();
385  DBUG_VOID_RETURN;
386 }
387 
388 
389 /*
390  Searches for an event in the queue
391 
392  SYNOPSIS
393  Event_queue::find_n_remove_event()
394  db The schema of the event to find
395  name The event to find
396 
397  NOTE
398  The caller should do the locking also the caller is responsible for
399  actual signalling in case an event is removed from the queue.
400 */
401 
402 void
403 Event_queue::find_n_remove_event(LEX_STRING db, LEX_STRING name)
404 {
405  uint i;
406  DBUG_ENTER("Event_queue::find_n_remove_event");
407 
408  for (i= 0; i < queue.elements; ++i)
409  {
410  Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
411  DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
412  et->dbname.str, et->name.str));
413  if (event_basic_identifier_equal(db, name, et))
414  {
415  queue_remove(&queue, i);
416  delete et;
417  break;
418  }
419  }
420 
421  DBUG_VOID_RETURN;
422 }
423 
424 
425 /*
426  Recalculates activation times in the queue. There is one reason for
427  that. Because the values (execute_at) by which the queue is ordered are
428  changed by calls to compute_next_execution_time() on a request from the
429  scheduler thread, if it is not running then the values won't be updated.
430  Once the scheduler is started again the values has to be recalculated
431  so they are right for the current time.
432 
433  SYNOPSIS
434  Event_queue::recalculate_activation_times()
435  thd Thread
436 */
437 
438 void
439 Event_queue::recalculate_activation_times(THD *thd)
440 {
441  uint i;
442  DBUG_ENTER("Event_queue::recalculate_activation_times");
443 
444  LOCK_QUEUE_DATA();
445  DBUG_PRINT("info", ("%u loaded events to be recalculated", queue.elements));
446  for (i= 0; i < queue.elements; i++)
447  {
448  ((Event_queue_element*)queue_element(&queue, i))->compute_next_execution_time();
449  }
450  queue_fix(&queue);
451  /*
452  The disabled elements are moved to the end during the `fix`.
453  Start from the end and remove all of the elements which are
454  disabled. When we find the first non-disabled one we break, as we
455  have removed all. The queue has been ordered in a way the disabled
456  events are at the end.
457  */
458  for (i= queue.elements; i > 0; i--)
459  {
460  Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1);
461  if (element->status != Event_parse_data::DISABLED)
462  break;
463  /*
464  This won't cause queue re-order, because we remove
465  always the last element.
466  */
467  queue_remove(&queue, i - 1);
468  delete element;
469  }
470  UNLOCK_QUEUE_DATA();
471 
472  /*
473  XXX: The events are dropped only from memory and not from disk
474  even if `drop_list[j]->dropped` is TRUE. There will be still on the
475  disk till next server restart.
476  Please add code here to do it.
477  */
478 
479  DBUG_VOID_RETURN;
480 }
481 
482 
483 /*
484  Empties the queue and destroys the Event_queue_element objects in the
485  queue.
486 
487  SYNOPSIS
488  Event_queue::empty_queue()
489 
490  NOTE
491  Should be called with LOCK_event_queue locked
492 */
493 
494 void
495 Event_queue::empty_queue()
496 {
497  uint i;
498  DBUG_ENTER("Event_queue::empty_queue");
499  DBUG_PRINT("enter", ("Purging the queue. %u element(s)", queue.elements));
500  sql_print_information("Event Scheduler: Purging the queue. %u events",
501  queue.elements);
502  /* empty the queue */
503  for (i= 0; i < queue.elements; ++i)
504  {
505  Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
506  delete et;
507  }
508  resize_queue(&queue, 0);
509  DBUG_VOID_RETURN;
510 }
511 
512 
513 /*
514  Dumps the queue to the trace log.
515 
516  SYNOPSIS
517  Event_queue::dbug_dump_queue()
518  now Current timestamp
519 */
520 
521 void
522 Event_queue::dbug_dump_queue(time_t now)
523 {
524 #ifndef DBUG_OFF
526  uint i;
527  DBUG_ENTER("Event_queue::dbug_dump_queue");
528  DBUG_PRINT("info", ("Dumping queue . Elements=%u", queue.elements));
529  for (i = 0; i < queue.elements; i++)
530  {
531  et= ((Event_queue_element*)queue_element(&queue, i));
532  DBUG_PRINT("info", ("et: 0x%lx name: %s.%s", (long) et,
533  et->dbname.str, et->name.str));
534  DBUG_PRINT("info", ("exec_at: %lu starts: %lu ends: %lu execs_so_far: %u "
535  "expr: %ld et.exec_at: %ld now: %ld "
536  "(et.exec_at - now): %d if: %d",
537  (long) et->execute_at, (long) et->starts,
538  (long) et->ends, et->execution_count,
539  (long) et->expression, (long) et->execute_at,
540  (long) now, (int) (et->execute_at - now),
541  et->execute_at <= now));
542  }
543  DBUG_VOID_RETURN;
544 #endif
545 }
546 
547 /*
548  Checks whether the top of the queue is elligible for execution and
549  returns an Event_job_data instance in case it should be executed.
550  `now` is compared against `execute_at` of the top element in the queue.
551 
552  SYNOPSIS
553  Event_queue::get_top_for_execution_if_time()
554  thd [in] Thread
555  event_name [out] The object to execute
556 
557  RETURN VALUE
558  FALSE No error. event_name != NULL
559  TRUE Serious error
560 */
561 
562 bool
563 Event_queue::get_top_for_execution_if_time(THD *thd,
564  Event_queue_element_for_exec **event_name)
565 {
566  bool ret= FALSE;
567  *event_name= NULL;
568  my_time_t UNINIT_VAR(last_executed);
569  int UNINIT_VAR(status);
570  DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
571 
572  LOCK_QUEUE_DATA();
573  for (;;)
574  {
575  Event_queue_element *top= NULL;
576 
577  /* Break loop if thd has been killed */
578  if (thd->killed)
579  {
580  DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
581  goto end;
582  }
583 
584  if (!queue.elements)
585  {
586  /* There are no events in the queue */
587  next_activation_at= 0;
588 
589  /* Release any held audit resources before waiting */
590  mysql_audit_release(thd);
591 
592  /* Wait on condition until signaled. Release LOCK_queue while waiting. */
593  cond_wait(thd, NULL, & stage_waiting_on_empty_queue, SCHED_FUNC, __FILE__, __LINE__);
594 
595  continue;
596  }
597 
598  top= ((Event_queue_element*) queue_element(&queue, 0));
599 
600  thd->set_current_time(); /* Get current time */
601 
602  next_activation_at= top->execute_at;
603  if (next_activation_at > thd->query_start())
604  {
605  /*
606  Not yet time for top event, wait on condition with
607  time or until signaled. Release LOCK_queue while waiting.
608  */
609  struct timespec top_time;
610  set_timespec(top_time, next_activation_at - thd->query_start());
611 
612  /* Release any held audit resources before waiting */
613  mysql_audit_release(thd);
614 
615  cond_wait(thd, &top_time, &stage_waiting_for_next_activation, SCHED_FUNC, __FILE__, __LINE__);
616 
617  continue;
618  }
619 
620  if (!(*event_name= new Event_queue_element_for_exec()) ||
621  (*event_name)->init(top->dbname, top->name))
622  {
623  ret= TRUE;
624  break;
625  }
626 
627  DBUG_PRINT("info", ("Ready for execution"));
628  top->mark_last_executed(thd);
629  if (top->compute_next_execution_time())
630  top->status= Event_parse_data::DISABLED;
631  DBUG_PRINT("info", ("event %s status is %d", top->name.str, top->status));
632 
633  top->execution_count++;
634  (*event_name)->dropped= top->dropped;
635  /*
636  Save new values of last_executed timestamp and event status on stack
637  in order to be able to update event description in system table once
638  QUEUE_DATA lock is released.
639  */
640  last_executed= top->last_executed;
641  status= top->status;
642 
643  if (top->status == Event_parse_data::DISABLED)
644  {
645  DBUG_PRINT("info", ("removing from the queue"));
646  sql_print_information("Event Scheduler: Last execution of %s.%s. %s",
647  top->dbname.str, top->name.str,
648  top->dropped? "Dropping.":"");
649  delete top;
650  queue_remove(&queue, 0);
651  }
652  else
653  queue_replaced(&queue);
654 
655  dbug_dump_queue(thd->query_start());
656  break;
657  }
658 end:
659  UNLOCK_QUEUE_DATA();
660 
661  DBUG_PRINT("info", ("returning %d et_new: 0x%lx ",
662  ret, (long) *event_name));
663 
664  if (*event_name)
665  {
666  DBUG_PRINT("info", ("db: %s name: %s",
667  (*event_name)->dbname.str, (*event_name)->name.str));
668 
669  Event_db_repository *db_repository= Events::get_db_repository();
670  (void) db_repository->update_timing_fields_for_event(thd,
671  (*event_name)->dbname, (*event_name)->name,
672  last_executed, (ulonglong) status);
673  }
674 
675  DBUG_RETURN(ret);
676 }
677 
678 
679 /*
680  Auxiliary function for locking LOCK_event_queue. Used by the
681  LOCK_QUEUE_DATA macro
682 
683  SYNOPSIS
684  Event_queue::lock_data()
685  func Which function is requesting mutex lock
686  line On which line mutex lock is requested
687 */
688 
689 void
690 Event_queue::lock_data(const char *func, uint line)
691 {
692  DBUG_ENTER("Event_queue::lock_data");
693  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
694  mutex_last_attempted_lock_in_func= func;
695  mutex_last_attempted_lock_at_line= line;
696  mutex_queue_data_attempting_lock= TRUE;
697  mysql_mutex_lock(&LOCK_event_queue);
698  mutex_last_attempted_lock_in_func= "";
699  mutex_last_attempted_lock_at_line= 0;
700  mutex_queue_data_attempting_lock= FALSE;
701 
702  mutex_last_locked_in_func= func;
703  mutex_last_locked_at_line= line;
704  mutex_queue_data_locked= TRUE;
705 
706  DBUG_VOID_RETURN;
707 }
708 
709 
710 /*
711  Auxiliary function for unlocking LOCK_event_queue. Used by the
712  UNLOCK_QUEUE_DATA macro
713 
714  SYNOPSIS
715  Event_queue::unlock_data()
716  func Which function is requesting mutex unlock
717  line On which line mutex unlock is requested
718 */
719 
720 void
721 Event_queue::unlock_data(const char *func, uint line)
722 {
723  DBUG_ENTER("Event_queue::unlock_data");
724  DBUG_PRINT("enter", ("func=%s line=%u", func, line));
725  mutex_last_unlocked_at_line= line;
726  mutex_queue_data_locked= FALSE;
727  mutex_last_unlocked_in_func= func;
728  mysql_mutex_unlock(&LOCK_event_queue);
729  DBUG_VOID_RETURN;
730 }
731 
732 
733 /*
734  Wrapper for mysql_cond_wait/timedwait
735 
736  SYNOPSIS
737  Event_queue::cond_wait()
738  thd Thread (Could be NULL during shutdown procedure)
739  msg Message for thd->proc_info
740  abstime If not null then call mysql_cond_timedwait()
741  func Which function is requesting cond_wait
742  line On which line cond_wait is requested
743 */
744 
745 void
746 Event_queue::cond_wait(THD *thd, struct timespec *abstime, const PSI_stage_info *stage,
747  const char *src_func, const char *src_file, uint src_line)
748 {
749  DBUG_ENTER("Event_queue::cond_wait");
750  waiting_on_cond= TRUE;
751  mutex_last_unlocked_at_line= src_line;
752  mutex_queue_data_locked= FALSE;
753  mutex_last_unlocked_in_func= src_func;
754 
755  thd->enter_cond(&COND_queue_state, &LOCK_event_queue, stage, NULL, src_func, src_file, src_line);
756 
757  if (!thd->killed)
758  {
759  if (!abstime)
760  mysql_cond_wait(&COND_queue_state, &LOCK_event_queue);
761  else
762  mysql_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime);
763  }
764 
765  mutex_last_locked_in_func= src_func;
766  mutex_last_locked_at_line= src_line;
767  mutex_queue_data_locked= TRUE;
768  waiting_on_cond= FALSE;
769 
770  /*
771  This will free the lock so we need to relock. Not the best thing to
772  do but we need to obey cond_wait()
773  */
774  thd->exit_cond(NULL, src_func, src_file, src_line);
775  lock_data(src_func, src_line);
776 
777  DBUG_VOID_RETURN;
778 }
779 
780 
781 /*
782  Dumps the internal status of the queue
783 
784  SYNOPSIS
785  Event_queue::dump_internal_status()
786 */
787 
788 void
789 Event_queue::dump_internal_status()
790 {
791  DBUG_ENTER("Event_queue::dump_internal_status");
792 
793  /* element count */
794  puts("");
795  puts("Event queue status:");
796  printf("Element count : %u\n", queue.elements);
797  printf("Data locked : %s\n", mutex_queue_data_locked? "YES":"NO");
798  printf("Attempting lock : %s\n", mutex_queue_data_attempting_lock? "YES":"NO");
799  printf("LLA : %s:%u\n", mutex_last_locked_in_func,
800  mutex_last_locked_at_line);
801  printf("LUA : %s:%u\n", mutex_last_unlocked_in_func,
802  mutex_last_unlocked_at_line);
803  if (mutex_last_attempted_lock_at_line)
804  printf("Last lock attempt at: %s:%u\n", mutex_last_attempted_lock_in_func,
805  mutex_last_attempted_lock_at_line);
806  printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
807 
808  MYSQL_TIME time;
809  my_tz_OFFSET0->gmt_sec_to_TIME(&time, next_activation_at);
810  if (time.year != 1970)
811  printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
812  time.year, time.month, time.day, time.hour, time.minute, time.second);
813  else
814  printf("Next activation : never");
815 
816  DBUG_VOID_RETURN;
817 }
818