MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
lock0wait.cc
Go to the documentation of this file.
1 /*****************************************************************************
2 
3 Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
4 
5 This program is free software; you can redistribute it and/or modify it under
6 the terms of the GNU General Public License as published by the Free Software
7 Foundation; version 2 of the License.
8 
9 This program is distributed in the hope that it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12 
13 You should have received a copy of the GNU General Public License along with
14 this program; if not, write to the Free Software Foundation, Inc.,
15 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
16 
17 *****************************************************************************/
18 
19 /**************************************************/
26 #define LOCK_MODULE_IMPLEMENTATION
27 
28 #include "srv0mon.h"
29 #include "que0que.h"
30 #include "lock0lock.h"
31 #include "row0mysql.h"
32 #include "srv0start.h"
33 #include "ha_prototypes.h"
34 #include "lock0priv.h"
35 
36 /*********************************************************************/
38 static
39 void
40 lock_wait_table_print(void)
41 /*=======================*/
42 {
43  ulint i;
44  const srv_slot_t* slot;
45 
47 
48  slot = lock_sys->waiting_threads;
49 
50  for (i = 0; i < OS_THREAD_MAX_N; i++, ++slot) {
51 
52  fprintf(stderr,
53  "Slot %lu: thread type %lu,"
54  " in use %lu, susp %lu, timeout %lu, time %lu\n",
55  (ulong) i,
56  (ulong) slot->type,
57  (ulong) slot->in_use,
58  (ulong) slot->suspended,
59  slot->wait_timeout,
60  (ulong) difftime(ut_time(), slot->suspend_time));
61  }
62 }
63 
64 /*********************************************************************/
67 static
68 void
69 lock_wait_table_release_slot(
70 /*=========================*/
71  srv_slot_t* slot)
72 {
73 #ifdef UNIV_DEBUG
74  srv_slot_t* upper = lock_sys->waiting_threads + OS_THREAD_MAX_N;
75 #endif /* UNIV_DEBUG */
76 
78 
79  ut_ad(slot->in_use);
80  ut_ad(slot->thr != NULL);
81  ut_ad(slot->thr->slot != NULL);
82  ut_ad(slot->thr->slot == slot);
83 
84  /* Must be within the array boundaries. */
85  ut_ad(slot >= lock_sys->waiting_threads);
86  ut_ad(slot < upper);
87 
88  /* Note: When we reserve the slot we use the trx_t::mutex to update
89  the slot values to change the state to reserved. Here we are using the
90  lock mutex to change the state of the slot to free. This is by design,
91  because when we query the slot state we always hold both the lock and
92  trx_t::mutex. To reduce contention on the lock mutex when reserving the
93  slot we avoid acquiring the lock mutex. */
94 
96 
97  slot->thr->slot = NULL;
98  slot->thr = NULL;
99  slot->in_use = FALSE;
100 
101  lock_mutex_exit();
102 
103  /* Scan backwards and adjust the last free slot pointer. */
104  for (slot = lock_sys->last_slot;
105  slot > lock_sys->waiting_threads && !slot->in_use;
106  --slot) {
107  /* No op */
108  }
109 
110  /* Either the array is empty or the last scanned slot is in use. */
111  ut_ad(slot->in_use || slot == lock_sys->waiting_threads);
112 
113  lock_sys->last_slot = slot + 1;
114 
115  /* The last slot is either outside of the array boundary or it's
116  on an empty slot. */
117  ut_ad(lock_sys->last_slot == upper || !lock_sys->last_slot->in_use);
118 
120  ut_ad(lock_sys->last_slot <= upper);
121 
123 }
124 
125 /*********************************************************************/
128 static
129 srv_slot_t*
130 lock_wait_table_reserve_slot(
131 /*=========================*/
132  que_thr_t* thr,
134  ulong wait_timeout)
135 {
136  ulint i;
137  srv_slot_t* slot;
138 
141 
142  slot = lock_sys->waiting_threads;
143 
144  for (i = OS_THREAD_MAX_N; i--; ++slot) {
145  if (!slot->in_use) {
146  slot->in_use = TRUE;
147  slot->thr = thr;
148  slot->thr->slot = slot;
149 
150  if (slot->event == NULL) {
151  slot->event = os_event_create();
152  ut_a(slot->event);
153  }
154 
155  os_event_reset(slot->event);
156  slot->suspended = TRUE;
157  slot->suspend_time = ut_time();
158  slot->wait_timeout = wait_timeout;
159 
160  if (slot == lock_sys->last_slot) {
161  ++lock_sys->last_slot;
162  }
163 
165  <= lock_sys->waiting_threads + OS_THREAD_MAX_N);
166 
167  return(slot);
168  }
169  }
170 
171  ut_print_timestamp(stderr);
172 
173  fprintf(stderr,
174  " InnoDB: There appear to be %lu user"
175  " threads currently waiting\n"
176  "InnoDB: inside InnoDB, which is the"
177  " upper limit. Cannot continue operation.\n"
178  "InnoDB: As a last thing, we print"
179  " a list of waiting threads.\n", (ulong) OS_THREAD_MAX_N);
180 
181  lock_wait_table_print();
182 
183  ut_error;
184  return(NULL);
185 }
186 
187 /***************************************************************/
193 UNIV_INTERN
194 void
196 /*=====================*/
197  que_thr_t* thr)
199 {
200  srv_slot_t* slot;
201  double wait_time;
202  trx_t* trx;
203  ulint had_dict_lock;
204  ibool was_declared_inside_innodb;
205  ib_int64_t start_time = 0;
206  ib_int64_t finish_time;
207  ulint sec;
208  ulint ms;
209  ulong lock_wait_timeout;
210 
211  trx = thr_get_trx(thr);
212 
213  if (trx->mysql_thd != 0) {
214  DEBUG_SYNC_C("lock_wait_suspend_thread_enter");
215  }
216 
217  /* InnoDB system transactions (such as the purge, and
218  incomplete transactions that are being rolled back after crash
219  recovery) will use the global value of
220  innodb_lock_wait_timeout, because trx->mysql_thd == NULL. */
221  lock_wait_timeout = trx_lock_wait_timeout_get(trx);
222 
224 
225  trx_mutex_enter(trx);
226 
227  trx->error_state = DB_SUCCESS;
228 
229  if (thr->state == QUE_THR_RUNNING) {
230 
231  ut_ad(thr->is_active);
232 
233  /* The lock has already been released or this transaction
234  was chosen as a deadlock victim: no need to suspend */
235 
237 
238  trx->error_state = DB_DEADLOCK;
239  trx->lock.was_chosen_as_deadlock_victim = FALSE;
240  }
241 
243  trx_mutex_exit(trx);
244  return;
245  }
246 
247  ut_ad(!thr->is_active);
248 
249  slot = lock_wait_table_reserve_slot(thr, lock_wait_timeout);
250 
251  if (thr->lock_state == QUE_THR_LOCK_ROW) {
254 
255  if (ut_usectime(&sec, &ms) == -1) {
256  start_time = -1;
257  } else {
258  start_time = (ib_int64_t) sec * 1000000 + ms;
259  }
260  }
261 
262  /* Wake the lock timeout monitor thread, if it is suspended */
263 
265 
267  trx_mutex_exit(trx);
268 
269  ulint lock_type = ULINT_UNDEFINED;
270 
272 
273  if (const lock_t* wait_lock = trx->lock.wait_lock) {
274  lock_type = lock_get_type_low(wait_lock);
275  }
276 
277  lock_mutex_exit();
278 
279  had_dict_lock = trx->dict_operation_lock_mode;
280 
281  switch (had_dict_lock) {
282  case 0:
283  break;
284  case RW_S_LATCH:
285  /* Release foreign key check latch */
287 
288  DEBUG_SYNC_C("lock_wait_release_s_latch_before_sleep");
289  break;
290  default:
291  /* There should never be a lock wait when the
292  dictionary latch is reserved in X mode. Dictionary
293  transactions should only acquire locks on dictionary
294  tables, not other tables. All access to dictionary
295  tables should be covered by dictionary
296  transactions. */
297  ut_error;
298  }
299 
300  ut_a(trx->dict_operation_lock_mode == 0);
301 
302  /* Suspend this thread and wait for the event. */
303 
304  was_declared_inside_innodb = trx->declared_to_be_inside_innodb;
305 
306  if (was_declared_inside_innodb) {
307  /* We must declare this OS thread to exit InnoDB, since a
308  possible other thread holding a lock which this thread waits
309  for must be allowed to enter, sooner or later */
310 
312  }
313 
314  /* Unknown is also treated like a record lock */
315  if (lock_type == ULINT_UNDEFINED || lock_type == LOCK_REC) {
316  thd_wait_begin(trx->mysql_thd, THD_WAIT_ROW_LOCK);
317  } else {
318  ut_ad(lock_type == LOCK_TABLE);
319  thd_wait_begin(trx->mysql_thd, THD_WAIT_TABLE_LOCK);
320  }
321 
322  os_event_wait(slot->event);
323 
324  thd_wait_end(trx->mysql_thd);
325 
326  /* After resuming, reacquire the data dictionary latch if
327  necessary. */
328 
329  if (was_declared_inside_innodb) {
330 
331  /* Return back inside InnoDB */
332 
334  }
335 
336  if (had_dict_lock) {
337 
338  row_mysql_freeze_data_dictionary(trx);
339  }
340 
341  wait_time = ut_difftime(ut_time(), slot->suspend_time);
342 
343  /* Release the slot for others to use */
344 
345  lock_wait_table_release_slot(slot);
346 
347  if (thr->lock_state == QUE_THR_LOCK_ROW) {
348  ulint diff_time;
349 
350  if (ut_usectime(&sec, &ms) == -1) {
351  finish_time = -1;
352  } else {
353  finish_time = (ib_int64_t) sec * 1000000 + ms;
354  }
355 
356  diff_time = (finish_time > start_time) ?
357  (ulint) (finish_time - start_time) : 0;
358 
360  srv_stats.n_lock_wait_time.add(diff_time);
361 
362  /* Only update the variable if we successfully
363  retrieved the start and finish times. See Bug#36819. */
364  if (diff_time > lock_sys->n_lock_max_wait_time
365  && start_time != -1
366  && finish_time != -1) {
367 
368  lock_sys->n_lock_max_wait_time = diff_time;
369  }
370 
371  /* Record the lock wait time for this thread */
372  thd_set_lock_wait_time(trx->mysql_thd, diff_time);
373 
374  }
375 
376  if (lock_wait_timeout < 100000000
377  && wait_time > (double) lock_wait_timeout) {
378 
380 
381  MONITOR_INC(MONITOR_TIMEOUT);
382  }
383 
384  if (trx_is_interrupted(trx)) {
385 
386  trx->error_state = DB_INTERRUPTED;
387  }
388 }
389 
390 /********************************************************************/
393 UNIV_INTERN
394 void
396 /*==================================*/
397  que_thr_t* thr)
399 {
402 
403  /* We own both the lock mutex and the trx_t::mutex but not the
404  lock wait mutex. This is OK because other threads will see the state
405  of this slot as being in use and no other thread can change the state
406  of the slot to free unless that thread also owns the lock mutex. */
407 
408  if (thr->slot != NULL && thr->slot->in_use && thr->slot->thr == thr) {
409  trx_t* trx = thr_get_trx(thr);
410 
412 
413  trx->error_state = DB_DEADLOCK;
414  trx->lock.was_chosen_as_deadlock_victim = FALSE;
415  }
416 
417  os_event_set(thr->slot->event);
418  }
419 }
420 
421 /*********************************************************************/
424 static
425 void
426 lock_wait_check_and_cancel(
427 /*=======================*/
428  const srv_slot_t* slot)
430 {
431  trx_t* trx;
432  double wait_time;
433  ib_time_t suspend_time = slot->suspend_time;
434 
436 
437  ut_ad(slot->in_use);
438 
439  ut_ad(slot->suspended);
440 
441  wait_time = ut_difftime(ut_time(), suspend_time);
442 
443  trx = thr_get_trx(slot->thr);
444 
445  if (trx_is_interrupted(trx)
446  || (slot->wait_timeout < 100000000
447  && (wait_time > (double) slot->wait_timeout
448  || wait_time < 0))) {
449 
450  /* Timeout exceeded or a wrap-around in system
451  time counter: cancel the lock request queued
452  by the transaction and release possible
453  other transactions waiting behind; it is
454  possible that the lock has already been
455  granted: in that case do nothing */
456 
458 
459  trx_mutex_enter(trx);
460 
461  if (trx->lock.wait_lock) {
462 
464 
466  }
467 
468  lock_mutex_exit();
469 
470  trx_mutex_exit(trx);
471  }
472 
473 }
474 
475 /*********************************************************************/
478 extern "C" UNIV_INTERN
479 os_thread_ret_t
481 /*=====================================*/
482  void* arg __attribute__((unused)))
483  /* in: a dummy parameter required by
484  os_thread_create */
485 {
486  ib_int64_t sig_count = 0;
488 
490 
491 #ifdef UNIV_PFS_THREAD
492  pfs_register_thread(srv_lock_timeout_thread_key);
493 #endif /* UNIV_PFS_THREAD */
494 
496 
497  do {
498  srv_slot_t* slot;
499 
500  /* When someone is waiting for a lock, we wake up every second
501  and check if a timeout has passed for a lock wait */
502 
503  os_event_wait_time_low(event, 1000000, sig_count);
504  sig_count = os_event_reset(event);
505 
507  break;
508  }
509 
511 
512  /* Check all slots for user threads that are waiting
513  on locks, and if they have exceeded the time limit. */
514 
515  for (slot = lock_sys->waiting_threads;
516  slot < lock_sys->last_slot;
517  ++slot) {
518 
519  /* We are doing a read without the lock mutex
520  and/or the trx mutex. This is OK because a slot
521  can't be freed or reserved without the lock wait
522  mutex. */
523 
524  if (slot->in_use) {
525  lock_wait_check_and_cancel(slot);
526  }
527  }
528 
529  sig_count = os_event_reset(event);
530 
532 
534 
536 
537  /* We count the number of threads in os_thread_exit(). A created
538  thread should always use that to exit and not use return() to exit. */
539 
540  os_thread_exit(NULL);
541 
542  OS_THREAD_DUMMY_RETURN;
543 }