You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

794 lines
21 KiB

WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
  1. /* Copyright (C) 2004-2006 MySQL AB
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  12. #include "mysql_priv.h"
  13. #include "event_queue.h"
  14. #include "event_data_objects.h"
  15. /**
  16. @addtogroup Event_Scheduler
  17. @{
  18. */
  19. #define EVENT_QUEUE_INITIAL_SIZE 30
  20. #define EVENT_QUEUE_EXTENT 30
  21. #ifdef __GNUC__
  22. #if __GNUC__ >= 2
  23. #define SCHED_FUNC __FUNCTION__
  24. #endif
  25. #else
  26. #define SCHED_FUNC "<unknown>"
  27. #endif
  28. #define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__)
  29. #define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__)
  30. /*
  31. Compares the execute_at members of two Event_queue_element instances.
  32. Used as callback for the prioritized queue when shifting
  33. elements inside.
  34. SYNOPSIS
  35. event_queue_element_data_compare_q()
  36. vptr Not used (set it to NULL)
  37. a First Event_queue_element object
  38. b Second Event_queue_element object
  39. RETURN VALUE
  40. -1 a->execute_at < b->execute_at
  41. 0 a->execute_at == b->execute_at
  42. 1 a->execute_at > b->execute_at
  43. NOTES
  44. execute_at.second_part is not considered during comparison
  45. */
  46. extern "C" int event_queue_element_compare_q(void *, uchar *, uchar *);
  47. int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b)
  48. {
  49. Event_queue_element *left = (Event_queue_element *)a;
  50. Event_queue_element *right = (Event_queue_element *)b;
  51. my_time_t lhs = left->execute_at;
  52. my_time_t rhs = right->execute_at;
  53. if (left->status == Event_parse_data::DISABLED)
  54. return right->status != Event_parse_data::DISABLED;
  55. if (right->status == Event_parse_data::DISABLED)
  56. return 1;
  57. return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
  58. }
  59. /*
  60. Constructor of class Event_queue.
  61. SYNOPSIS
  62. Event_queue::Event_queue()
  63. */
  64. Event_queue::Event_queue()
  65. :next_activation_at(0),
  66. mutex_last_locked_at_line(0),
  67. mutex_last_unlocked_at_line(0),
  68. mutex_last_attempted_lock_at_line(0),
  69. mutex_last_locked_in_func("n/a"),
  70. mutex_last_unlocked_in_func("n/a"),
  71. mutex_last_attempted_lock_in_func("n/a"),
  72. mutex_queue_data_locked(FALSE),
  73. mutex_queue_data_attempting_lock(FALSE),
  74. waiting_on_cond(FALSE)
  75. {
  76. pthread_mutex_init(&LOCK_event_queue, MY_MUTEX_INIT_FAST);
  77. pthread_cond_init(&COND_queue_state, NULL);
  78. }
  79. Event_queue::~Event_queue()
  80. {
  81. deinit_queue();
  82. pthread_mutex_destroy(&LOCK_event_queue);
  83. pthread_cond_destroy(&COND_queue_state);
  84. }
  85. /*
  86. This is a queue's constructor. Until this method is called, the
  87. queue is unusable. We don't use a C++ constructor instead in
  88. order to be able to check the return value. The queue is
  89. initialized once at server startup. Initialization can fail in
  90. case of a failure reading events from the database or out of
  91. memory.
  92. SYNOPSIS
  93. Event_queue::init()
  94. RETURN VALUE
  95. FALSE OK
  96. TRUE Error
  97. */
  98. bool
  99. Event_queue::init_queue(THD *thd)
  100. {
  101. DBUG_ENTER("Event_queue::init_queue");
  102. DBUG_PRINT("enter", ("this: 0x%lx", (long) this));
  103. LOCK_QUEUE_DATA();
  104. if (init_queue_ex(&queue, EVENT_QUEUE_INITIAL_SIZE , 0 /*offset*/,
  105. 0 /*max_on_top*/, event_queue_element_compare_q,
  106. NULL, EVENT_QUEUE_EXTENT))
  107. {
  108. sql_print_error("Event Scheduler: Can't initialize the execution queue");
  109. goto err;
  110. }
  111. UNLOCK_QUEUE_DATA();
  112. DBUG_RETURN(FALSE);
  113. err:
  114. UNLOCK_QUEUE_DATA();
  115. DBUG_RETURN(TRUE);
  116. }
  117. /*
  118. Deinits the queue. Remove all elements from it and destroys them
  119. too.
  120. SYNOPSIS
  121. Event_queue::deinit_queue()
  122. */
  123. void
  124. Event_queue::deinit_queue()
  125. {
  126. DBUG_ENTER("Event_queue::deinit_queue");
  127. LOCK_QUEUE_DATA();
  128. empty_queue();
  129. delete_queue(&queue);
  130. UNLOCK_QUEUE_DATA();
  131. DBUG_VOID_RETURN;
  132. }
  133. /**
  134. Adds an event to the queue.
  135. Compute the next execution time for an event, and if it is still
  136. active, add it to the queue. Otherwise delete it.
  137. The object is left intact in case of an error. Otherwise
  138. the queue container assumes ownership of it.
  139. @param[in] thd thread handle
  140. @param[in] new_element a new element to add to the queue
  141. @param[out] created set to TRUE if no error and the element is
  142. added to the queue, FALSE otherwise
  143. @retval TRUE an error occured. The value of created is undefined,
  144. the element was not deleted.
  145. @retval FALSE success
  146. */
  147. bool
  148. Event_queue::create_event(THD *thd, Event_queue_element *new_element,
  149. bool *created)
  150. {
  151. DBUG_ENTER("Event_queue::create_event");
  152. DBUG_PRINT("enter", ("thd: 0x%lx et=%s.%s", (long) thd,
  153. new_element->dbname.str, new_element->name.str));
  154. /* Will do nothing if the event is disabled */
  155. new_element->compute_next_execution_time();
  156. if (new_element->status != Event_parse_data::ENABLED)
  157. {
  158. delete new_element;
  159. *created= FALSE;
  160. DBUG_RETURN(FALSE);
  161. }
  162. DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
  163. LOCK_QUEUE_DATA();
  164. *created= (queue_insert_safe(&queue, (uchar *) new_element) == FALSE);
  165. dbug_dump_queue(thd->query_start());
  166. pthread_cond_broadcast(&COND_queue_state);
  167. UNLOCK_QUEUE_DATA();
  168. DBUG_RETURN(!*created);
  169. }
  170. /*
  171. Updates an event from the scheduler queue
  172. SYNOPSIS
  173. Event_queue::update_event()
  174. thd Thread
  175. dbname Schema of the event
  176. name Name of the event
  177. new_schema New schema, in case of RENAME TO, otherwise NULL
  178. new_name New name, in case of RENAME TO, otherwise NULL
  179. */
  180. void
  181. Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
  182. Event_queue_element *new_element)
  183. {
  184. DBUG_ENTER("Event_queue::update_event");
  185. DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str));
  186. if ((new_element->status == Event_parse_data::DISABLED) ||
  187. (new_element->status == Event_parse_data::SLAVESIDE_DISABLED))
  188. {
  189. DBUG_PRINT("info", ("The event is disabled."));
  190. /*
  191. Destroy the object but don't skip to end: because we may have to remove
  192. object from the cache.
  193. */
  194. delete new_element;
  195. new_element= NULL;
  196. }
  197. else
  198. new_element->compute_next_execution_time();
  199. LOCK_QUEUE_DATA();
  200. find_n_remove_event(dbname, name);
  201. /* If not disabled event */
  202. if (new_element)
  203. {
  204. DBUG_PRINT("info", ("new event in the queue: 0x%lx", (long) new_element));
  205. queue_insert_safe(&queue, (uchar *) new_element);
  206. pthread_cond_broadcast(&COND_queue_state);
  207. }
  208. dbug_dump_queue(thd->query_start());
  209. UNLOCK_QUEUE_DATA();
  210. DBUG_VOID_RETURN;
  211. }
  212. /*
  213. Drops an event from the queue
  214. SYNOPSIS
  215. Event_queue::drop_event()
  216. thd Thread
  217. dbname Schema of the event to drop
  218. name Name of the event to drop
  219. */
  220. void
  221. Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
  222. {
  223. DBUG_ENTER("Event_queue::drop_event");
  224. DBUG_PRINT("enter", ("thd: 0x%lx db :%s name: %s", (long) thd,
  225. dbname.str, name.str));
  226. LOCK_QUEUE_DATA();
  227. find_n_remove_event(dbname, name);
  228. dbug_dump_queue(thd->query_start());
  229. UNLOCK_QUEUE_DATA();
  230. /*
  231. We don't signal here because the scheduler will catch the change
  232. next time it wakes up.
  233. */
  234. DBUG_VOID_RETURN;
  235. }
  236. /*
  237. Drops all events from the in-memory queue and disk that match
  238. certain pattern evaluated by a comparator function
  239. SYNOPSIS
  240. Event_queue::drop_matching_events()
  241. thd THD
  242. pattern A pattern string
  243. comparator The function to use for comparing
  244. RETURN VALUE
  245. >=0 Number of dropped events
  246. NOTE
  247. Expected is the caller to acquire lock on LOCK_event_queue
  248. */
  249. void
  250. Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
  251. bool (*comparator)(LEX_STRING, Event_basic *))
  252. {
  253. uint i= 0;
  254. DBUG_ENTER("Event_queue::drop_matching_events");
  255. DBUG_PRINT("enter", ("pattern=%s", pattern.str));
  256. while (i < queue.elements)
  257. {
  258. Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
  259. DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
  260. if (comparator(pattern, et))
  261. {
  262. /*
  263. The queue is ordered. If we remove an element, then all elements
  264. after it will shift one position to the left, if we imagine it as
  265. an array from left to the right. In this case we should not
  266. increment the counter and the (i < queue.elements) condition is ok.
  267. */
  268. queue_remove(&queue, i);
  269. delete et;
  270. }
  271. else
  272. i++;
  273. }
  274. /*
  275. We don't call pthread_cond_broadcast(&COND_queue_state);
  276. If we remove the top event:
  277. 1. The queue is empty. The scheduler will wake up at some time and
  278. realize that the queue is empty. If create_event() comes inbetween
  279. it will signal the scheduler
  280. 2. The queue is not empty, but the next event after the previous top,
  281. won't be executed any time sooner than the element we removed. Hence,
  282. we may not notify the scheduler and it will realize the change when it
  283. wakes up from timedwait.
  284. */
  285. DBUG_VOID_RETURN;
  286. }
  287. /*
  288. Drops all events from the in-memory queue and disk that are from
  289. certain schema.
  290. SYNOPSIS
  291. Event_queue::drop_schema_events()
  292. thd HD
  293. schema The schema name
  294. */
  295. void
  296. Event_queue::drop_schema_events(THD *thd, LEX_STRING schema)
  297. {
  298. DBUG_ENTER("Event_queue::drop_schema_events");
  299. LOCK_QUEUE_DATA();
  300. drop_matching_events(thd, schema, event_basic_db_equal);
  301. UNLOCK_QUEUE_DATA();
  302. DBUG_VOID_RETURN;
  303. }
  304. /*
  305. Searches for an event in the queue
  306. SYNOPSIS
  307. Event_queue::find_n_remove_event()
  308. db The schema of the event to find
  309. name The event to find
  310. NOTE
  311. The caller should do the locking also the caller is responsible for
  312. actual signalling in case an event is removed from the queue.
  313. */
  314. void
  315. Event_queue::find_n_remove_event(LEX_STRING db, LEX_STRING name)
  316. {
  317. uint i;
  318. DBUG_ENTER("Event_queue::find_n_remove_event");
  319. for (i= 0; i < queue.elements; ++i)
  320. {
  321. Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
  322. DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
  323. et->dbname.str, et->name.str));
  324. if (event_basic_identifier_equal(db, name, et))
  325. {
  326. queue_remove(&queue, i);
  327. delete et;
  328. break;
  329. }
  330. }
  331. DBUG_VOID_RETURN;
  332. }
  333. /*
  334. Recalculates activation times in the queue. There is one reason for
  335. that. Because the values (execute_at) by which the queue is ordered are
  336. changed by calls to compute_next_execution_time() on a request from the
  337. scheduler thread, if it is not running then the values won't be updated.
  338. Once the scheduler is started again the values has to be recalculated
  339. so they are right for the current time.
  340. SYNOPSIS
  341. Event_queue::recalculate_activation_times()
  342. thd Thread
  343. */
  344. void
  345. Event_queue::recalculate_activation_times(THD *thd)
  346. {
  347. uint i;
  348. DBUG_ENTER("Event_queue::recalculate_activation_times");
  349. LOCK_QUEUE_DATA();
  350. DBUG_PRINT("info", ("%u loaded events to be recalculated", queue.elements));
  351. for (i= 0; i < queue.elements; i++)
  352. {
  353. ((Event_queue_element*)queue_element(&queue, i))->compute_next_execution_time();
  354. ((Event_queue_element*)queue_element(&queue, i))->update_timing_fields(thd);
  355. }
  356. queue_fix(&queue);
  357. /*
  358. The disabled elements are moved to the end during the `fix`.
  359. Start from the end and remove all of the elements which are
  360. disabled. When we find the first non-disabled one we break, as we
  361. have removed all. The queue has been ordered in a way the disabled
  362. events are at the end.
  363. */
  364. for (i= queue.elements; i > 0; i--)
  365. {
  366. Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1);
  367. if (element->status != Event_parse_data::DISABLED)
  368. break;
  369. /*
  370. This won't cause queue re-order, because we remove
  371. always the last element.
  372. */
  373. queue_remove(&queue, i - 1);
  374. delete element;
  375. }
  376. UNLOCK_QUEUE_DATA();
  377. /*
  378. XXX: The events are dropped only from memory and not from disk
  379. even if `drop_list[j]->dropped` is TRUE. There will be still on the
  380. disk till next server restart.
  381. Please add code here to do it.
  382. */
  383. DBUG_VOID_RETURN;
  384. }
  385. /*
  386. Empties the queue and destroys the Event_queue_element objects in the
  387. queue.
  388. SYNOPSIS
  389. Event_queue::empty_queue()
  390. NOTE
  391. Should be called with LOCK_event_queue locked
  392. */
  393. void
  394. Event_queue::empty_queue()
  395. {
  396. uint i;
  397. DBUG_ENTER("Event_queue::empty_queue");
  398. DBUG_PRINT("enter", ("Purging the queue. %u element(s)", queue.elements));
  399. sql_print_information("Event Scheduler: Purging the queue. %u events",
  400. queue.elements);
  401. /* empty the queue */
  402. for (i= 0; i < queue.elements; ++i)
  403. {
  404. Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
  405. delete et;
  406. }
  407. resize_queue(&queue, 0);
  408. DBUG_VOID_RETURN;
  409. }
  410. /*
  411. Dumps the queue to the trace log.
  412. SYNOPSIS
  413. Event_queue::dbug_dump_queue()
  414. now Current timestamp
  415. */
  416. void
  417. Event_queue::dbug_dump_queue(time_t now)
  418. {
  419. #ifndef DBUG_OFF
  420. Event_queue_element *et;
  421. uint i;
  422. DBUG_ENTER("Event_queue::dbug_dump_queue");
  423. DBUG_PRINT("info", ("Dumping queue . Elements=%u", queue.elements));
  424. for (i = 0; i < queue.elements; i++)
  425. {
  426. et= ((Event_queue_element*)queue_element(&queue, i));
  427. DBUG_PRINT("info", ("et: 0x%lx name: %s.%s", (long) et,
  428. et->dbname.str, et->name.str));
  429. DBUG_PRINT("info", ("exec_at: %lu starts: %lu ends: %lu execs_so_far: %u "
  430. "expr: %ld et.exec_at: %ld now: %ld "
  431. "(et.exec_at - now): %d if: %d",
  432. (long) et->execute_at, (long) et->starts,
  433. (long) et->ends, et->execution_count,
  434. (long) et->expression, (long) et->execute_at,
  435. (long) now, (int) (et->execute_at - now),
  436. et->execute_at <= now));
  437. }
  438. DBUG_VOID_RETURN;
  439. #endif
  440. }
  441. static const char *queue_empty_msg= "Waiting on empty queue";
  442. static const char *queue_wait_msg= "Waiting for next activation";
  443. /*
  444. Checks whether the top of the queue is elligible for execution and
  445. returns an Event_job_data instance in case it should be executed.
  446. `now` is compared against `execute_at` of the top element in the queue.
  447. SYNOPSIS
  448. Event_queue::get_top_for_execution_if_time()
  449. thd [in] Thread
  450. event_name [out] The object to execute
  451. RETURN VALUE
  452. FALSE No error. event_name != NULL
  453. TRUE Serious error
  454. */
  455. bool
  456. Event_queue::get_top_for_execution_if_time(THD *thd,
  457. Event_queue_element_for_exec **event_name)
  458. {
  459. bool ret= FALSE;
  460. *event_name= NULL;
  461. DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
  462. LOCK_QUEUE_DATA();
  463. for (;;)
  464. {
  465. Event_queue_element *top= NULL;
  466. /* Break loop if thd has been killed */
  467. if (thd->killed)
  468. {
  469. DBUG_PRINT("info", ("thd->killed=%d", thd->killed));
  470. goto end;
  471. }
  472. if (!queue.elements)
  473. {
  474. /* There are no events in the queue */
  475. next_activation_at= 0;
  476. /* Wait on condition until signaled. Release LOCK_queue while waiting. */
  477. cond_wait(thd, NULL, queue_empty_msg, SCHED_FUNC, __LINE__);
  478. continue;
  479. }
  480. top= ((Event_queue_element*) queue_element(&queue, 0));
  481. thd->set_current_time(); /* Get current time */
  482. next_activation_at= top->execute_at;
  483. if (next_activation_at > thd->query_start())
  484. {
  485. /*
  486. Not yet time for top event, wait on condition with
  487. time or until signaled. Release LOCK_queue while waiting.
  488. */
  489. struct timespec top_time;
  490. set_timespec(top_time, next_activation_at - thd->query_start());
  491. cond_wait(thd, &top_time, queue_wait_msg, SCHED_FUNC, __LINE__);
  492. continue;
  493. }
  494. if (!(*event_name= new Event_queue_element_for_exec()) ||
  495. (*event_name)->init(top->dbname, top->name))
  496. {
  497. ret= TRUE;
  498. break;
  499. }
  500. DBUG_PRINT("info", ("Ready for execution"));
  501. top->mark_last_executed(thd);
  502. if (top->compute_next_execution_time())
  503. top->status= Event_parse_data::DISABLED;
  504. DBUG_PRINT("info", ("event %s status is %d", top->name.str, top->status));
  505. top->execution_count++;
  506. (*event_name)->dropped= top->dropped;
  507. top->update_timing_fields(thd);
  508. if (top->status == Event_parse_data::DISABLED)
  509. {
  510. DBUG_PRINT("info", ("removing from the queue"));
  511. sql_print_information("Event Scheduler: Last execution of %s.%s. %s",
  512. top->dbname.str, top->name.str,
  513. top->dropped? "Dropping.":"");
  514. delete top;
  515. queue_remove(&queue, 0);
  516. }
  517. else
  518. queue_replaced(&queue);
  519. dbug_dump_queue(thd->query_start());
  520. break;
  521. }
  522. end:
  523. UNLOCK_QUEUE_DATA();
  524. DBUG_PRINT("info", ("returning %d et_new: 0x%lx ",
  525. ret, (long) *event_name));
  526. if (*event_name)
  527. DBUG_PRINT("info", ("db: %s name: %s",
  528. (*event_name)->dbname.str, (*event_name)->name.str));
  529. DBUG_RETURN(ret);
  530. }
  531. /*
  532. Auxiliary function for locking LOCK_event_queue. Used by the
  533. LOCK_QUEUE_DATA macro
  534. SYNOPSIS
  535. Event_queue::lock_data()
  536. func Which function is requesting mutex lock
  537. line On which line mutex lock is requested
  538. */
  539. void
  540. Event_queue::lock_data(const char *func, uint line)
  541. {
  542. DBUG_ENTER("Event_queue::lock_data");
  543. DBUG_PRINT("enter", ("func=%s line=%u", func, line));
  544. mutex_last_attempted_lock_in_func= func;
  545. mutex_last_attempted_lock_at_line= line;
  546. mutex_queue_data_attempting_lock= TRUE;
  547. pthread_mutex_lock(&LOCK_event_queue);
  548. mutex_last_attempted_lock_in_func= "";
  549. mutex_last_attempted_lock_at_line= 0;
  550. mutex_queue_data_attempting_lock= FALSE;
  551. mutex_last_locked_in_func= func;
  552. mutex_last_locked_at_line= line;
  553. mutex_queue_data_locked= TRUE;
  554. DBUG_VOID_RETURN;
  555. }
  556. /*
  557. Auxiliary function for unlocking LOCK_event_queue. Used by the
  558. UNLOCK_QUEUE_DATA macro
  559. SYNOPSIS
  560. Event_queue::unlock_data()
  561. func Which function is requesting mutex unlock
  562. line On which line mutex unlock is requested
  563. */
  564. void
  565. Event_queue::unlock_data(const char *func, uint line)
  566. {
  567. DBUG_ENTER("Event_queue::unlock_data");
  568. DBUG_PRINT("enter", ("func=%s line=%u", func, line));
  569. mutex_last_unlocked_at_line= line;
  570. mutex_queue_data_locked= FALSE;
  571. mutex_last_unlocked_in_func= func;
  572. pthread_mutex_unlock(&LOCK_event_queue);
  573. DBUG_VOID_RETURN;
  574. }
  575. /*
  576. Wrapper for pthread_cond_wait/timedwait
  577. SYNOPSIS
  578. Event_queue::cond_wait()
  579. thd Thread (Could be NULL during shutdown procedure)
  580. msg Message for thd->proc_info
  581. abstime If not null then call pthread_cond_timedwait()
  582. func Which function is requesting cond_wait
  583. line On which line cond_wait is requested
  584. */
  585. void
  586. Event_queue::cond_wait(THD *thd, struct timespec *abstime, const char* msg,
  587. const char *func, uint line)
  588. {
  589. DBUG_ENTER("Event_queue::cond_wait");
  590. waiting_on_cond= TRUE;
  591. mutex_last_unlocked_at_line= line;
  592. mutex_queue_data_locked= FALSE;
  593. mutex_last_unlocked_in_func= func;
  594. thd->enter_cond(&COND_queue_state, &LOCK_event_queue, msg);
  595. DBUG_PRINT("info", ("pthread_cond_%swait", abstime? "timed":""));
  596. if (!abstime)
  597. pthread_cond_wait(&COND_queue_state, &LOCK_event_queue);
  598. else
  599. pthread_cond_timedwait(&COND_queue_state, &LOCK_event_queue, abstime);
  600. mutex_last_locked_in_func= func;
  601. mutex_last_locked_at_line= line;
  602. mutex_queue_data_locked= TRUE;
  603. waiting_on_cond= FALSE;
  604. /*
  605. This will free the lock so we need to relock. Not the best thing to
  606. do but we need to obey cond_wait()
  607. */
  608. thd->exit_cond("");
  609. lock_data(func, line);
  610. DBUG_VOID_RETURN;
  611. }
  612. /*
  613. Dumps the internal status of the queue
  614. SYNOPSIS
  615. Event_queue::dump_internal_status()
  616. */
  617. void
  618. Event_queue::dump_internal_status()
  619. {
  620. DBUG_ENTER("Event_queue::dump_internal_status");
  621. /* element count */
  622. puts("");
  623. puts("Event queue status:");
  624. printf("Element count : %u\n", queue.elements);
  625. printf("Data locked : %s\n", mutex_queue_data_locked? "YES":"NO");
  626. printf("Attempting lock : %s\n", mutex_queue_data_attempting_lock? "YES":"NO");
  627. printf("LLA : %s:%u\n", mutex_last_locked_in_func,
  628. mutex_last_locked_at_line);
  629. printf("LUA : %s:%u\n", mutex_last_unlocked_in_func,
  630. mutex_last_unlocked_at_line);
  631. if (mutex_last_attempted_lock_at_line)
  632. printf("Last lock attempt at: %s:%u\n", mutex_last_attempted_lock_in_func,
  633. mutex_last_attempted_lock_at_line);
  634. printf("WOC : %s\n", waiting_on_cond? "YES":"NO");
  635. MYSQL_TIME time;
  636. my_tz_OFFSET0->gmt_sec_to_TIME(&time, next_activation_at);
  637. if (time.year != 1970)
  638. printf("Next activation : %04d-%02d-%02d %02d:%02d:%02d\n",
  639. time.year, time.month, time.day, time.hour, time.minute, time.second);
  640. else
  641. printf("Next activation : never");
  642. DBUG_VOID_RETURN;
  643. }
  644. /**
  645. @} (End of group Event_Scheduler)
  646. */