summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BitKeeper/etc/logging_ok1
-rw-r--r--innobase/include/que0que.h6
-rw-r--r--innobase/include/srv0srv.h5
-rw-r--r--innobase/include/sync0rw.h8
-rw-r--r--innobase/include/sync0sync.h24
-rw-r--r--innobase/include/sync0sync.ic6
-rw-r--r--innobase/include/univ.i1
-rw-r--r--innobase/que/que0que.c1
-rw-r--r--innobase/row/row0mysql.c7
-rw-r--r--innobase/row/row0sel.c4
-rw-r--r--innobase/srv/srv0srv.c50
-rw-r--r--innobase/sync/sync0rw.c7
-rw-r--r--innobase/sync/sync0sync.c260
-rw-r--r--innobase/ut/ut0ut.c15
-rw-r--r--mysql-test/r/innodb.result15
-rw-r--r--mysql-test/r/variables.result8
-rw-r--r--mysql-test/t/innodb.test8
-rw-r--r--mysql-test/t/variables.test6
-rw-r--r--sql/ha_innodb.cc107
-rw-r--r--sql/ha_innodb.h1
-rw-r--r--sql/lex.h1
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/mysqld.cc8
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc7
-rw-r--r--sql/sql_yacc.yy4
27 files changed, 444 insertions, 123 deletions
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index 107e4cadacf..81686ff0163 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -230,6 +230,7 @@ ulli@morbus.(none)
venu@hundin.mysql.fi
venu@myvenu.com
venu@work.mysql.com
+vtkachenko@intelp4d.mysql.com
vva@eagle.mysql.r18.ru
vva@genie.(none)
vva@mysql.r18.ru
diff --git a/innobase/include/que0que.h b/innobase/include/que0que.h
index e1874edcaf2..d45ae032ddb 100644
--- a/innobase/include/que0que.h
+++ b/innobase/include/que0que.h
@@ -359,6 +359,7 @@ struct que_thr_struct{
the control came */
ulint resource; /* resource usage of the query thread
thus far */
+ ulint lock_state; /* lock state of thread (table or row) */
};
#define QUE_THR_MAGIC_N 8476583
@@ -482,6 +483,11 @@ struct que_fork_struct{
#define QUE_THR_SUSPENDED 7
#define QUE_THR_ERROR 8
+/* Query thread lock states */
+#define QUE_THR_LOCK_NOLOCK 0
+#define QUE_THR_LOCK_ROW 1
+#define QUE_THR_LOCK_TABLE 2
+
/* From where the cursor position is counted */
#define QUE_CUR_NOT_DEFINED 1
#define QUE_CUR_START 2
diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h
index 84b7d14ca00..5f752717fcc 100644
--- a/innobase/include/srv0srv.h
+++ b/innobase/include/srv0srv.h
@@ -525,6 +525,11 @@ struct export_var_struct{
ulint innodb_pages_created;
ulint innodb_pages_read;
ulint innodb_pages_written;
+ ulint innodb_row_lock_waits;
+ ulint innodb_row_lock_current_waits;
+ ib_longlong innodb_row_lock_time;
+ ulint innodb_row_lock_time_avg;
+ ulint innodb_row_lock_time_max;
ulint innodb_rows_read;
ulint innodb_rows_inserted;
ulint innodb_rows_updated;
diff --git a/innobase/include/sync0rw.h b/innobase/include/sync0rw.h
index 9a988a03e92..6e3a4cf4dc7 100644
--- a/innobase/include/sync0rw.h
+++ b/innobase/include/sync0rw.h
@@ -61,8 +61,9 @@ Creates, or rather, initializes an rw-lock object in a specified memory
location (which must be appropriately aligned). The rw-lock is initialized
to the non-locked state. Explicit freeing of the rw-lock with rw_lock_free
is necessary only if the memory block containing it is freed. */
-
-#define rw_lock_create(L) rw_lock_create_func((L), __FILE__, __LINE__)
+#define rw_lock_create(L) rw_lock_create_func(\
+ (L), __FILE__, __LINE__, __STRING(L))
+
/*=====================*/
/**********************************************************************
Creates, or rather, initializes an rw-lock object in a specified memory
@@ -75,7 +76,8 @@ rw_lock_create_func(
/*================*/
rw_lock_t* lock, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline); /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name); /* in: mutex name */
/**********************************************************************
Calling this function is obligatory only if the memory buffer containing
the rw-lock is freed. Removes an rw-lock object from the global list. The
diff --git a/innobase/include/sync0sync.h b/innobase/include/sync0sync.h
index 8e0ec715b12..98d61c129b1 100644
--- a/innobase/include/sync0sync.h
+++ b/innobase/include/sync0sync.h
@@ -17,6 +17,8 @@ Created 9/5/1995 Heikki Tuuri
#include "os0sync.h"
#include "sync0arr.h"
+extern my_bool timed_mutexes;
+
/**********************************************************************
Initializes the synchronization data structures. */
@@ -35,8 +37,7 @@ location (which must be appropriately aligned). The mutex is initialized
in the reset state. Explicit freeing of the mutex with mutex_free is
necessary only if the memory block containing it is freed. */
-
-#define mutex_create(M) mutex_create_func((M), __FILE__, __LINE__)
+#define mutex_create(M) mutex_create_func((M), __FILE__, __LINE__, __STRING(M))
/*===================*/
/**********************************************************************
Creates, or rather, initializes a mutex object in a specified memory
@@ -49,7 +50,8 @@ mutex_create_func(
/*==============*/
mutex_t* mutex, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline); /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name); /* in: mutex name */
/**********************************************************************
Calling this function is obligatory only if the memory buffer containing
the mutex is freed. Removes a mutex object from the mutex list. The mutex
@@ -471,6 +473,15 @@ struct mutex_struct {
const char* cfile_name;/* File name where mutex created */
ulint cline; /* Line where created */
ulint magic_n;
+ ulong count_using; /* count of times mutex used */
+ ulong count_spin_loop; /* count of spin loops */
+ ulong count_spin_rounds; /* count of spin rounds */
+ ulong count_os_wait; /* count of os_wait */
+ ulong count_os_yield; /* count of os_wait */
+ ulonglong lspent_time; /* mutex os_wait timer msec */
+ ulonglong lmax_spent_time; /* mutex os_wait timer msec */
+ const char* cmutex_name;/* mutex name */
+ ulint mutex_type;/* 0 - usual mutex 1 - rw_lock mutex */
};
#define MUTEX_MAGIC_N (ulint)979585
@@ -504,6 +515,13 @@ extern ibool sync_order_checks_on;
/* This variable is set to TRUE when sync_init is called */
extern ibool sync_initialized;
+/* Global list of database mutexes (not OS mutexes) created. */
+UT_LIST_BASE_NODE_T(mutex_t) mutex_list;
+
+/* Mutex protecting the mutex_list variable */
+mutex_t mutex_list_mutex;
+
+
#ifndef UNIV_NONINL
#include "sync0sync.ic"
#endif
diff --git a/innobase/include/sync0sync.ic b/innobase/include/sync0sync.ic
index aaf5e1fd9e9..1731b47db58 100644
--- a/innobase/include/sync0sync.ic
+++ b/innobase/include/sync0sync.ic
@@ -249,8 +249,11 @@ mutex_enter_func(
/* Note that we do not peek at the value of lock_word before trying
the atomic test_and_set; we could peek, and possibly save time. */
+
+ mutex->count_using++;
- if (!mutex_test_and_set(mutex)) {
+ if (!mutex_test_and_set(mutex))
+ {
#ifdef UNIV_SYNC_DEBUG
mutex_set_debug_info(mutex, file_name, line);
#endif
@@ -258,4 +261,5 @@ mutex_enter_func(
}
mutex_spin_wait(mutex, file_name, line);
+
}
diff --git a/innobase/include/univ.i b/innobase/include/univ.i
index be71d4211b3..80024f71992 100644
--- a/innobase/include/univ.i
+++ b/innobase/include/univ.i
@@ -88,6 +88,7 @@ memory is read outside the allocated blocks. */
#define UNIV_SEARCH_DEBUG
#define UNIV_SYNC_PERF_STAT
#define UNIV_SEARCH_PERF_STAT
+#define UNIV_SRV_PRINT_LATCH_WAITS;
*/
#define UNIV_LIGHT_MEM_DEBUG
diff --git a/innobase/que/que0que.c b/innobase/que/que0que.c
index 22878dec27f..a0a6adf9b83 100644
--- a/innobase/que/que0que.c
+++ b/innobase/que/que0que.c
@@ -163,6 +163,7 @@ que_thr_create(
thr->run_node = NULL;
thr->resource = 0;
+ thr->lock_state = QUE_THR_LOCK_NOLOCK;
UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c
index e959c28f6bb..0a2e9e5eaad 100644
--- a/innobase/row/row0mysql.c
+++ b/innobase/row/row0mysql.c
@@ -937,9 +937,10 @@ run_again:
if (err != DB_SUCCESS) {
que_thr_stop_for_mysql(thr);
-
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;
if (was_lock_wait) {
goto run_again;
}
@@ -1171,9 +1172,11 @@ run_again:
return((int) err);
}
-
+
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr,
&savept);
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;;
if (was_lock_wait) {
goto run_again;
}
diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c
index a3d844d1dac..c079557ca8b 100644
--- a/innobase/row/row0sel.c
+++ b/innobase/row/row0sel.c
@@ -3791,8 +3791,10 @@ lock_wait_or_error:
que_thr_stop_for_mysql(thr);
+ thr->lock_state= QUE_THR_LOCK_ROW;
was_lock_wait = row_mysql_handle_errors(&err, trx, thr, NULL);
-
+ thr->lock_state= QUE_THR_LOCK_NOLOCK;
+
if (was_lock_wait) {
mtr_start(&mtr);
diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c
index 83d4fb4d39d..aa2a7fa9169 100644
--- a/innobase/srv/srv0srv.c
+++ b/innobase/srv/srv0srv.c
@@ -346,6 +346,12 @@ static ulint srv_n_rows_updated_old = 0;
static ulint srv_n_rows_deleted_old = 0;
static ulint srv_n_rows_read_old = 0;
+ulint srv_n_lock_wait_count= 0;
+ulint srv_n_lock_wait_current_count= 0;
+ib_longlong srv_n_lock_wait_time= 0;
+ulint srv_n_lock_max_wait_time= 0;
+
+
/*
Set the following to 0 if you want InnoDB to write messages on
stderr on startup/shutdown
@@ -1378,7 +1384,11 @@ srv_suspend_mysql_thread(
trx_t* trx;
ibool had_dict_lock = FALSE;
ibool was_declared_inside_innodb = FALSE;
-
+ ib_longlong start_time, finish_time;
+ ulint diff_time;
+ ulint sec;
+ ulint ms;
+
#ifdef UNIV_SYNC_DEBUG
ut_ad(!mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
@@ -1420,7 +1430,15 @@ srv_suspend_mysql_thread(
os_event_reset(event);
slot->suspend_time = ut_time();
+ if (thr->lock_state == QUE_THR_LOCK_ROW)
+ {
+ srv_n_lock_wait_count++;
+ srv_n_lock_wait_current_count++;
+
+ ut_usectime(&sec, &ms);
+ start_time= (ib_longlong)sec * 1000000 + ms;
+ }
/* Wake the lock timeout monitor thread, if it is suspended */
os_event_set(srv_lock_timeout_thread_event);
@@ -1471,7 +1489,22 @@ srv_suspend_mysql_thread(
slot->in_use = FALSE;
wait_time = ut_difftime(ut_time(), slot->suspend_time);
-
+
+ if (thr->lock_state == QUE_THR_LOCK_ROW)
+ {
+ ut_usectime(&sec, &ms);
+ finish_time= (ib_longlong)sec * 1000000 + ms;
+
+ diff_time= finish_time-start_time;
+
+ srv_n_lock_wait_current_count--;
+ srv_n_lock_wait_time= srv_n_lock_wait_time + diff_time;
+ if (diff_time > srv_n_lock_max_wait_time)
+ {
+ srv_n_lock_max_wait_time= diff_time;
+ }
+ }
+
if (trx->was_chosen_as_deadlock_victim) {
trx->error_state = DB_DEADLOCK;
@@ -1689,15 +1722,14 @@ srv_printf_innodb_monitor(
(srv_n_rows_read - srv_n_rows_read_old)
/ time_elapsed);
- srv_n_rows_inserted_old = srv_n_rows_inserted;
+ srv_n_rows_inserted_old = srv_n_rows_inserted;
srv_n_rows_updated_old = srv_n_rows_updated;
srv_n_rows_deleted_old = srv_n_rows_deleted;
srv_n_rows_read_old = srv_n_rows_read;
- fputs("----------------------------\n"
+ fputs("----------------------------\n"
"END OF INNODB MONITOR OUTPUT\n"
"============================\n", file);
-
mutex_exit(&srv_innodb_monitor_mutex);
fflush(file);
}
@@ -1746,11 +1778,19 @@ srv_export_innodb_status(void)
export_vars.innodb_pages_created= buf_pool->n_pages_created;
export_vars.innodb_pages_read= buf_pool->n_pages_read;
export_vars.innodb_pages_written= buf_pool->n_pages_written;
+ export_vars.innodb_row_lock_waits= srv_n_lock_wait_count;
+ export_vars.innodb_row_lock_current_waits= srv_n_lock_wait_current_count;
+ export_vars.innodb_row_lock_time= srv_n_lock_wait_time / 10000;
+ export_vars.innodb_row_lock_time_avg=
+ (srv_n_lock_wait_count > 0) ?
+ (srv_n_lock_wait_time / 10000 / srv_n_lock_wait_count) : 0;
+ export_vars.innodb_row_lock_time_max= srv_n_lock_max_wait_time / 10000;
export_vars.innodb_rows_read= srv_n_rows_read;
export_vars.innodb_rows_inserted= srv_n_rows_inserted;
export_vars.innodb_rows_updated= srv_n_rows_updated;
export_vars.innodb_rows_deleted= srv_n_rows_deleted;
mutex_exit(&srv_innodb_monitor_mutex);
+
}
/*************************************************************************
diff --git a/innobase/sync/sync0rw.c b/innobase/sync/sync0rw.c
index 77757685208..e57974a375b 100644
--- a/innobase/sync/sync0rw.c
+++ b/innobase/sync/sync0rw.c
@@ -90,7 +90,8 @@ rw_lock_create_func(
/*================*/
rw_lock_t* lock, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline) /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name) /* in: mutex name */
{
/* If this is the very first time a synchronization
object is created, then the following call initializes
@@ -101,7 +102,9 @@ rw_lock_create_func(
lock->mutex.cfile_name = cfile_name;
lock->mutex.cline = cline;
-
+ lock->mutex.cmutex_name = cmutex_name;
+ lock->mutex.mutex_type = 1;
+
rw_lock_set_waiters(lock, 0);
rw_lock_set_writer(lock, RW_LOCK_NOT_LOCKED);
lock->writer_count = 0;
diff --git a/innobase/sync/sync0sync.c b/innobase/sync/sync0sync.c
index 86306e49cac..fb46c692830 100644
--- a/innobase/sync/sync0sync.c
+++ b/innobase/sync/sync0sync.c
@@ -129,11 +129,6 @@ sync_array_t* sync_primary_wait_array;
/* This variable is set to TRUE when sync_init is called */
ibool sync_initialized = FALSE;
-/* Global list of database mutexes (not OS mutexes) created. */
-UT_LIST_BASE_NODE_T(mutex_t) mutex_list;
-
-/* Mutex protecting the mutex_list variable */
-mutex_t mutex_list_mutex;
typedef struct sync_level_struct sync_level_t;
typedef struct sync_thread_struct sync_thread_t;
@@ -202,7 +197,8 @@ mutex_create_func(
/*==============*/
mutex_t* mutex, /* in: pointer to memory */
const char* cfile_name, /* in: file name where created */
- ulint cline) /* in: file line where created */
+ ulint cline, /* in: file line where created */
+ const char* cmutex_name) /* in: mutex name */
{
#if defined(_WIN32) && defined(UNIV_CAN_USE_X86_ASSEMBLER)
mutex_reset_lock_word(mutex);
@@ -219,6 +215,16 @@ mutex_create_func(
mutex->level = SYNC_LEVEL_NONE;
mutex->cfile_name = cfile_name;
mutex->cline = cline;
+ mutex->cmutex_name= cmutex_name;
+ mutex->count_using= 0;
+ mutex->mutex_type= 0;
+ mutex->lspent_time= 0;
+ mutex->lmax_spent_time= 0;
+ mutex->count_spin_loop= 0;
+ mutex->count_spin_rounds= 0;
+ mutex->count_os_wait= 0;
+ mutex->count_os_yield= 0;
+
/* Check that lock_word is aligned; this is important on Intel */
ut_ad(((ulint)(&(mutex->lock_word))) % 4 == 0);
@@ -355,135 +361,180 @@ for the mutex before suspending the thread. */
void
mutex_spin_wait(
/*============*/
- mutex_t* mutex, /* in: pointer to mutex */
- const char* file_name, /* in: file name where
- mutex requested */
- ulint line) /* in: line where requested */
+ mutex_t* mutex, /* in: pointer to mutex */
+ const char* file_name, /* in: file name where
+ mutex requested */
+ ulint line) /* in: line where requested */
{
- ulint index; /* index of the reserved wait cell */
- ulint i; /* spin round count */
-
- ut_ad(mutex);
+ ulint index; /* index of the reserved wait cell */
+ ulint i; /* spin round count */
+ ib_longlong lstart_time, lfinish_time; /* for timing os_wait */
+ ulint ltime_diff;
+ ulint sec;
+ ulint ms;
-mutex_loop:
+ uint timer_started = 0;
- i = 0;
+ ut_ad(mutex);
- /* Spin waiting for the lock word to become zero. Note that we do not
- have to assume that the read access to the lock word is atomic, as the
- actual locking is always committed with atomic test-and-set. In
- reality, however, all processors probably have an atomic read of a
- memory word. */
-
-spin_loop:
- mutex_spin_wait_count++;
+mutex_loop:
- while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS) {
+ i = 0;
- if (srv_spin_wait_delay) {
- ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
- }
-
- i++;
- }
+/* Spin waiting for the lock word to become zero. Note that we do not
+ have to assume that the read access to the lock word is atomic, as the
+ actual locking is always committed with atomic test-and-set. In
+ reality, however, all processors probably have an atomic read of a
+ memory word. */
- if (i == SYNC_SPIN_ROUNDS) {
- os_thread_yield();
- }
+spin_loop:
+ mutex_spin_wait_count++;
+ mutex->count_spin_loop++;
+
+ while (mutex_get_lock_word(mutex) != 0 && i < SYNC_SPIN_ROUNDS)
+ {
+ if (srv_spin_wait_delay)
+ {
+ ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
+ }
+
+ i++;
+ }
+
+ if (i == SYNC_SPIN_ROUNDS)
+ {
+ mutex->count_os_yield++;
+ if (timed_mutexes == 1 && timer_started==0)
+ {
+ ut_usectime(&sec, &ms);
+ lstart_time= (ib_longlong)sec * 1000000 + ms;
+ timer_started = 1;
+ }
+ os_thread_yield();
+ }
+
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr,
+ "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
+ mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
+#endif
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu spin wait mutex at %p cfile %s cline %lu rnds %lu\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
- mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
- }
+ mutex_spin_round_count += i;
- mutex_spin_round_count += i;
+ mutex->count_spin_rounds += i;
- if (mutex_test_and_set(mutex) == 0) {
- /* Succeeded! */
+ if (mutex_test_and_set(mutex) == 0)
+ {
+ /* Succeeded! */
#ifdef UNIV_SYNC_DEBUG
- mutex_set_debug_info(mutex, file_name, line);
+ mutex_set_debug_info(mutex, file_name, line);
#endif
- return;
- }
+ goto finish_timing;
+ }
- /* We may end up with a situation where lock_word is
- 0 but the OS fast mutex is still reserved. On FreeBSD
- the OS does not seem to schedule a thread which is constantly
- calling pthread_mutex_trylock (in mutex_test_and_set
- implementation). Then we could end up spinning here indefinitely.
- The following 'i++' stops this infinite spin. */
+ /* We may end up with a situation where lock_word is
+ 0 but the OS fast mutex is still reserved. On FreeBSD
+ the OS does not seem to schedule a thread which is constantly
+ calling pthread_mutex_trylock (in mutex_test_and_set
+ implementation). Then we could end up spinning here indefinitely.
+ The following 'i++' stops this infinite spin. */
- i++;
-
- if (i < SYNC_SPIN_ROUNDS) {
+ i++;
- goto spin_loop;
- }
+ if (i < SYNC_SPIN_ROUNDS)
+ {
+ goto spin_loop;
+ }
- sync_array_reserve_cell(sync_primary_wait_array, mutex,
- SYNC_MUTEX,
- file_name, line,
- &index);
+ sync_array_reserve_cell(sync_primary_wait_array, mutex,
+ SYNC_MUTEX, file_name, line, &index);
- mutex_system_call_count++;
+ mutex_system_call_count++;
- /* The memory order of the array reservation and the change in the
- waiters field is important: when we suspend a thread, we first
- reserve the cell and then set waiters field to 1. When threads are
- released in mutex_exit, the waiters field is first set to zero and
- then the event is set to the signaled state. */
-
- mutex_set_waiters(mutex, 1);
+ /* The memory order of the array reservation and the change in the
+ waiters field is important: when we suspend a thread, we first
+ reserve the cell and then set waiters field to 1. When threads are
+ released in mutex_exit, the waiters field is first set to zero and
+ then the event is set to the signaled state. */
+
+ mutex_set_waiters(mutex, 1);
- /* Try to reserve still a few times */
- for (i = 0; i < 4; i++) {
- if (mutex_test_and_set(mutex) == 0) {
+ /* Try to reserve still a few times */
+ for (i = 0; i < 4; i++)
+ {
+ if (mutex_test_and_set(mutex) == 0)
+ {
+ /* Succeeded! Free the reserved wait cell */
- /* Succeeded! Free the reserved wait cell */
+ sync_array_free_cell(sync_primary_wait_array, index);
- sync_array_free_cell(sync_primary_wait_array, index);
-
#ifdef UNIV_SYNC_DEBUG
- mutex_set_debug_info(mutex, file_name, line);
+ mutex_set_debug_info(mutex, file_name, line);
#endif
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu spin wait succeeds at 2:"
- " mutex at %p\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()),
- mutex);
- }
-
- return;
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr, "Thread %lu spin wait succeeds at 2:"
+ " mutex at %p\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()),
+ mutex);
+#endif
- /* Note that in this case we leave the waiters field
- set to 1. We cannot reset it to zero, as we do not know
- if there are other waiters. */
- }
- }
+ goto finish_timing;
- /* Now we know that there has been some thread holding the mutex
- after the change in the wait array and the waiters field was made.
- Now there is no risk of infinite wait on the event. */
+ /* Note that in this case we leave the waiters field
+ set to 1. We cannot reset it to zero, as we do not know
+ if there are other waiters. */
+ }
+ }
- if (srv_print_latch_waits) {
- fprintf(stderr,
- "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
- (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
- mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
- }
-
- mutex_system_call_count++;
- mutex_os_wait_count++;
+ /* Now we know that there has been some thread holding the mutex
+ after the change in the wait array and the waiters field was made.
+Now there is no risk of infinite wait on the event. */
- sync_array_wait_event(sync_primary_wait_array, index);
+#ifdef UNIV_SRV_PRINT_LATCH_WAITS
+ fprintf(stderr,
+ "Thread %lu OS wait mutex at %p cfile %s cline %lu rnds %lu\n",
+ (ulong) os_thread_pf(os_thread_get_curr_id()), mutex,
+ mutex->cfile_name, (ulong) mutex->cline, (ulong) i);
+#endif
- goto mutex_loop;
+ mutex_system_call_count++;
+ mutex_os_wait_count++;
+
+ mutex->count_os_wait++;
+
+ /*
+ !!!!! Sometimes os_wait can be called without os_thread_yield
+ */
+
+ if (timed_mutexes == 1 && timer_started==0)
+ {
+ ut_usectime(&sec, &ms);
+ lstart_time= (ib_longlong)sec * 1000000 + ms;
+ timer_started = 1;
+ }
+
+
+ sync_array_wait_event(sync_primary_wait_array, index);
+ goto mutex_loop;
+
+finish_timing:
+ if (timed_mutexes == 1 && timer_started==1)
+ {
+ ut_usectime(&sec, &ms);
+ lfinish_time= (ib_longlong)sec * 1000000 + ms;
+
+ ltime_diff= lfinish_time - lstart_time;
+ mutex->lspent_time += ltime_diff;
+ if (mutex->lmax_spent_time < ltime_diff)
+ {
+ mutex->lmax_spent_time= ltime_diff;
+ }
+ }
+ return;
}
/**********************************************************************
@@ -555,6 +606,7 @@ mutex_set_level(
mutex->level = level;
}
+
#ifdef UNIV_SYNC_DEBUG
/**********************************************************************
Checks that the current thread owns the mutex. Works only in the debug
diff --git a/innobase/ut/ut0ut.c b/innobase/ut/ut0ut.c
index 732380bcb1f..21c2833b6d6 100644
--- a/innobase/ut/ut0ut.c
+++ b/innobase/ut/ut0ut.c
@@ -74,6 +74,21 @@ ut_time(void)
}
/**************************************************************
+Returns system time. We do not specify the format of the time returned:
+the only way to manipulate it is to use the function ut_difftime. */
+
+void
+ut_usectime(ulint* sec, ulint* ms)
+/*=========*/
+{
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ *sec = (ulint) tv.tv_sec;
+ *ms = (ulint) tv.tv_usec;
+ return;
+}
+
+/**************************************************************
Returns the difference of two times in seconds. */
double
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index fe99961f964..06940d65a79 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -1700,5 +1700,20 @@ Innodb_rows_read 80161
show status like "Innodb_rows_updated";
Variable_name Value
Innodb_rows_updated 29530
+show status like "Innodb_row_lock_waits";
+Variable_name Value
+Innodb_row_lock_waits 0
+show status like "Innodb_row_lock_current_waits";
+Variable_name Value
+Innodb_row_lock_current_waits 0
+show status like "Innodb_row_lock_time";
+Variable_name Value
+Innodb_row_lock_time 0
+show status like "Innodb_row_lock_time_max";
+Variable_name Value
+Innodb_row_lock_time_max 0
+show status like "Innodb_row_lock_time_avg";
+Variable_name Value
+Innodb_row_lock_time_avg 0
create table t1 (v varchar(16384)) engine=innodb;
ERROR 42000: Column length too big for column 'v' (max = 255); use BLOB instead
diff --git a/mysql-test/r/variables.result b/mysql-test/r/variables.result
index b2d58df5798..0612f4b3941 100644
--- a/mysql-test/r/variables.result
+++ b/mysql-test/r/variables.result
@@ -137,6 +137,14 @@ set global concurrent_insert=DEFAULT;
show variables like 'concurrent_insert';
Variable_name Value
concurrent_insert ON
+set global timed_mutexes=1;
+show variables like 'timed_mutexes';
+Variable_name Value
+timed_mutexes ON
+set global timed_mutexes=0;
+show variables like 'timed_mutexes';
+Variable_name Value
+timed_mutexes OFF
set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="INNODB";
show local variables like 'storage_engine';
Variable_name Value
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index e7f08f11a2d..cee216e9e29 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -1210,6 +1210,14 @@ show status like "Innodb_rows_deleted";
show status like "Innodb_rows_inserted";
show status like "Innodb_rows_read";
show status like "Innodb_rows_updated";
+
+# Test for row locks InnoDB status variables.
+show status like "Innodb_row_lock_waits";
+show status like "Innodb_row_lock_current_waits";
+show status like "Innodb_row_lock_time";
+show status like "Innodb_row_lock_time_max";
+show status like "Innodb_row_lock_time_avg";
+
#
# Test varchar
#
diff --git a/mysql-test/t/variables.test b/mysql-test/t/variables.test
index 6563f7117cd..760a08555ce 100644
--- a/mysql-test/t/variables.test
+++ b/mysql-test/t/variables.test
@@ -83,6 +83,12 @@ show variables like 'concurrent_insert';
set global concurrent_insert=DEFAULT;
show variables like 'concurrent_insert';
+set global timed_mutexes=1;
+show variables like 'timed_mutexes';
+set global timed_mutexes=0;
+show variables like 'timed_mutexes';
+
+
set storage_engine=MYISAM, storage_engine="HEAP", global storage_engine="INNODB";
show local variables like 'storage_engine';
show global variables like 'storage_engine';
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index cb23e31225b..2ae1ff5672d 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -231,6 +231,16 @@ struct show_var_st innodb_status_variables[]= {
(char*) &export_vars.innodb_pages_read, SHOW_LONG},
{"pages_written",
(char*) &export_vars.innodb_pages_written, SHOW_LONG},
+ {"row_lock_waits",
+ (char*) &export_vars.innodb_row_lock_waits, SHOW_LONG},
+ {"row_lock_current_waits",
+ (char*) &export_vars.innodb_row_lock_current_waits, SHOW_LONG},
+ {"row_lock_time",
+ (char*) &export_vars.innodb_row_lock_time, SHOW_LONGLONG},
+ {"row_lock_time_max",
+ (char*) &export_vars.innodb_row_lock_time_max, SHOW_LONG},
+ {"row_lock_time_avg",
+ (char*) &export_vars.innodb_row_lock_time_avg, SHOW_LONG},
{"rows_deleted",
(char*) &export_vars.innodb_rows_deleted, SHOW_LONG},
{"rows_inserted",
@@ -5506,6 +5516,103 @@ innodb_show_status(
}
/****************************************************************************
+Implements the SHOW MUTEX STATUS command. . */
+
+bool
+innodb_mutex_show_status(
+/*===============*/
+ THD* thd) /* in: the MySQL query thread of the caller */
+{
+ Protocol *protocol= thd->protocol;
+ List<Item> field_list;
+ mutex_t* mutex;
+ const char* file_name;
+ ulint line;
+ ulint rw_lock_count= 0;
+ ulint rw_lock_count_spin_loop= 0;
+ ulint rw_lock_count_spin_rounds= 0;
+ ulint rw_lock_count_os_wait= 0;
+ ulint rw_lock_count_os_yield= 0;
+ ulonglong rw_lock_wait_time= 0;
+
+ DBUG_ENTER("innodb_mutex_show_status");
+
+ field_list.push_back(new Item_empty_string("Mutex", FN_REFLEN));
+ field_list.push_back(new Item_empty_string("Module", FN_REFLEN));
+ field_list.push_back(new Item_uint("Count", 21));
+ field_list.push_back(new Item_uint("Spin_waits", 21));
+ field_list.push_back(new Item_uint("Spin_rounds", 21));
+ field_list.push_back(new Item_uint("OS_waits", 21));
+ field_list.push_back(new Item_uint("OS_yields", 21));
+ field_list.push_back(new Item_uint("OS_waits_time", 21));
+
+ if (protocol->send_fields(&field_list,
+ Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+ DBUG_RETURN(TRUE);
+
+// mutex_enter(&mutex_list_mutex);
+
+ mutex = UT_LIST_GET_FIRST(mutex_list);
+
+ while ( mutex != NULL )
+ {
+ if (mutex->mutex_type != 1)
+ {
+ if (mutex->count_using > 0)
+ {
+ protocol->prepare_for_resend();
+ protocol->store(mutex->cmutex_name, system_charset_info);
+ protocol->store(mutex->cfile_name, system_charset_info);
+ protocol->store((ulonglong)mutex->count_using);
+ protocol->store((ulonglong)mutex->count_spin_loop);
+ protocol->store((ulonglong)mutex->count_spin_rounds);
+ protocol->store((ulonglong)mutex->count_os_wait);
+ protocol->store((ulonglong)mutex->count_os_yield);
+ protocol->store((ulonglong)mutex->lspent_time/1000);
+
+ if (protocol->write())
+ {
+// mutex_exit(&mutex_list_mutex);
+ DBUG_RETURN(1);
+ }
+ }
+ }
+ else
+ {
+ rw_lock_count += mutex->count_using;
+ rw_lock_count_spin_loop += mutex->count_spin_loop;
+ rw_lock_count_spin_rounds += mutex->count_spin_rounds;
+ rw_lock_count_os_wait += mutex->count_os_wait;
+ rw_lock_count_os_yield += mutex->count_os_yield;
+ rw_lock_wait_time += mutex->lspent_time;
+ }
+
+ mutex = UT_LIST_GET_NEXT(list, mutex);
+ }
+
+ protocol->prepare_for_resend();
+ protocol->store("rw_lock_mutexes", system_charset_info);
+ protocol->store("", system_charset_info);
+ protocol->store((ulonglong)rw_lock_count);
+ protocol->store((ulonglong)rw_lock_count_spin_loop);
+ protocol->store((ulonglong)rw_lock_count_spin_rounds);
+ protocol->store((ulonglong)rw_lock_count_os_wait);
+ protocol->store((ulonglong)rw_lock_count_os_yield);
+ protocol->store((ulonglong)rw_lock_wait_time/1000);
+
+ if (protocol->write())
+ {
+// mutex_exit(&mutex_list_mutex);
+ DBUG_RETURN(1);
+ }
+
+
+// mutex_exit(&mutex_list_mutex);
+ send_eof(thd);
+ DBUG_RETURN(FALSE);
+}
+
+/****************************************************************************
Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking.
****************************************************************************/
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index bb8823fd1bb..fcb9165de64 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -242,6 +242,7 @@ int innobase_savepoint(
int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path);
bool innodb_show_status(THD* thd);
+bool innodb_mutex_show_status(THD* thd);
void innodb_export_status(void);
my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name,
diff --git a/sql/lex.h b/sql/lex.h
index cf0059a1397..b052479d413 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -323,6 +323,7 @@ static SYMBOL symbols[] = {
{ "MULTILINESTRING", SYM(MULTILINESTRING)},
{ "MULTIPOINT", SYM(MULTIPOINT)},
{ "MULTIPOLYGON", SYM(MULTIPOLYGON)},
+ { "MUTEX", SYM(MUTEX_SYM)},
{ "NAME", SYM(NAME_SYM)},
{ "NAMES", SYM(NAMES_SYM)},
{ "NATIONAL", SYM(NATIONAL_SYM)},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 2fc82e05f31..3d6e23cceaf 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -998,6 +998,7 @@ extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout;
extern ulong max_user_connections;
+extern my_bool timed_mutexes;
extern ulong what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index c5698469341..196e7502d25 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -325,6 +325,7 @@ ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
ulong max_connections,max_used_connections,
max_connect_errors, max_user_connections = 0;
ulong thread_id=1L,current_pid;
+my_bool timed_mutexes= 0;
ulong slow_launch_threads = 0, sync_binlog_period;
ulong expire_logs_days = 0;
ulong rpl_recovery_rank=0;
@@ -4200,7 +4201,8 @@ enum options_mysqld
OPT_OPTIMIZER_PRUNE_LEVEL,
OPT_UPDATABLE_VIEWS_WITH_LIMIT,
OPT_AUTO_INCREMENT, OPT_AUTO_INCREMENT_OFFSET,
- OPT_ENABLE_LARGE_PAGES
+ OPT_ENABLE_LARGE_PAGES,
+ OPT_TIMED_MUTEXES
};
@@ -4799,6 +4801,10 @@ log and this option does nothing anymore.",
"Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.",
(gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1,
0, 0, 0, 0, 0},
+ {"timed_mutexes", OPT_TIMED_MUTEXES,
+ "Specify whether to time mutexes (only InnoDB mutexes are currently supported)",
+ (gptr*) &timed_mutexes, (gptr*) &timed_mutexes, 0, GET_BOOL, NO_ARG, 0,
+ 0, 0, 0, 0, 0},
{"tmpdir", 't',
"Path for temporary files. Several paths may be specified, separated by a "
#if defined(__WIN__) || defined(OS2) || defined(__NETWARE__)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index da6341597f1..4e74ad02ea5 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -361,6 +361,8 @@ sys_var_thd_enum sys_tx_isolation("tx_isolation",
fix_tx_isolation);
sys_var_thd_ulong sys_tmp_table_size("tmp_table_size",
&SV::tmp_table_size);
+sys_var_bool_ptr sys_timed_mutexes("timed_mutexes",
+ &timed_mutexes);
sys_var_thd_ulong sys_net_wait_timeout("wait_timeout",
&SV::net_wait_timeout);
@@ -635,6 +637,7 @@ sys_var *sys_variables[]=
&sys_table_type,
&sys_thread_cache_size,
&sys_time_format,
+ &sys_timed_mutexes,
&sys_timestamp,
&sys_time_zone,
&sys_tmp_table_size,
@@ -901,6 +904,7 @@ struct show_var_st init_vars[]= {
{"thread_stack", (char*) &thread_stack, SHOW_LONG},
{sys_time_format.name, (char*) &sys_time_format, SHOW_SYS},
{"time_zone", (char*) &sys_time_zone, SHOW_SYS},
+ {sys_timed_mutexes.name, (char*) &sys_timed_mutexes, SHOW_SYS},
{sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS},
{"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR},
{sys_trans_alloc_block_size.name, (char*) &sys_trans_alloc_block_size,
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 721febab548..ea084b5735f 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -53,7 +53,7 @@ enum enum_sql_command {
SQLCOM_SHOW_DATABASES, SQLCOM_SHOW_TABLES, SQLCOM_SHOW_FIELDS,
SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS,
- SQLCOM_SHOW_INNODB_STATUS,
+ SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_MUTEX_STATUS,
SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT,
SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS,
SQLCOM_SHOW_COLLATIONS, SQLCOM_SHOW_CREATE_DB, SQLCOM_SHOW_TABLE_STATUS,
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 0dec6e820be..a622568d9dc 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2488,6 +2488,13 @@ mysql_execute_command(THD *thd)
res = innodb_show_status(thd);
break;
}
+ case SQLCOM_SHOW_MUTEX_STATUS:
+ {
+ if (check_global_access(thd, SUPER_ACL))
+ goto error;
+ res = innodb_mutex_show_status(thd);
+ break;
+ }
#endif
#ifdef HAVE_REPLICATION
case SQLCOM_LOAD_MASTER_TABLE:
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 88cd3daf924..eba3b5298af 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -337,6 +337,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token MAX_UPDATES_PER_HOUR
%token MEDIUM_SYM
%token MIN_ROWS
+%token MUTEX_SYM
%token NAMES_SYM
%token NAME_SYM
%token NATIONAL_SYM
@@ -5986,6 +5987,8 @@ show_param:
}
| INNOBASE_SYM STATUS_SYM
{ Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS; WARN_DEPRECATED("SHOW INNODB STATUS", "SHOW ENGINE INNODB STATUS"); }
+ | MUTEX_SYM STATUS_SYM
+ { Lex->sql_command = SQLCOM_SHOW_MUTEX_STATUS; }
| opt_full PROCESSLIST_SYM
{ Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;}
| opt_var_type VARIABLES wild
@@ -6987,6 +6990,7 @@ keyword:
| MULTILINESTRING {}
| MULTIPOINT {}
| MULTIPOLYGON {}
+ | MUTEX_SYM {}
| NAME_SYM {}
| NAMES_SYM {}
| NATIONAL_SYM {}