3252 Marko Mäkelä 2010-10-19 [merge]
Merge from mysql-5.5-innodb
modified:
storage/innobase/include/os0sync.h
storage/innobase/include/srv0srv.h
storage/innobase/log/log0log.c
storage/innobase/os/os0sync.c
storage/innobase/srv/srv0srv.c
3251 Vasil Dimov 2010-10-19 [merge]
Merge mysql-5.5-innodb -> mysql-trunk-innodb
added:
mysql-test/suite/innodb/r/innodb_bug56632.result
mysql-test/suite/innodb/t/innodb_bug56632.test
modified:
storage/innobase/handler/ha_innodb.cc
=== modified file 'storage/innobase/include/os0sync.h'
--- a/storage/innobase/include/os0sync.h revid:vasil.dimov@stripped18-zsasadnzch4ou4vl
+++ b/storage/innobase/include/os0sync.h revid:marko.makela@stripped2y58vh0h
@@ -76,6 +76,12 @@ struct os_event_struct {
/*!< list of all created events */
};
+/** Denotes an infinite delay for os_event_wait_time() */
+#define OS_SYNC_INFINITE_TIME ULINT_UNDEFINED
+
+/** Return value of os_event_wait_time() when the time is exceeded */
+#define OS_SYNC_TIME_EXCEEDED 1
+
/** Operating system mutex */
typedef struct os_mutex_struct os_mutex_str_t;
/** Operating system mutex handle */
@@ -173,7 +179,23 @@ os_event_wait_low(
os_event_reset(). */
#define os_event_wait(event) os_event_wait_low(event, 0)
+#define os_event_wait_time(e, t) os_event_wait_time_low(event, t, 0)
+/**********************************************************//**
+Waits for an event object until it is in the signaled state or
+a timeout is exceeded. In Unix the timeout is always infinite.
+@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
+UNIV_INTERN
+ulint
+os_event_wait_time_low(
+/*===================*/
+ os_event_t event, /*!< in: event to wait */
+ ulint time_in_usec, /*!< in: timeout in
+ microseconds, or
+ OS_SYNC_INFINITE_TIME */
+ ib_int64_t reset_sig_count); /*!< in: zero or the value
+ returned by previous call of
+ os_event_reset(). */
/*********************************************************//**
Creates an operating system mutex semaphore. Because these are slow, the
mutex semaphore of InnoDB itself (mutex_t) should be used where possible.
=== modified file 'storage/innobase/include/srv0srv.h'
--- a/storage/innobase/include/srv0srv.h revid:vasil.dimov@strippedsadnzch4ou4vl
+++ b/storage/innobase/include/srv0srv.h revid:marko.makela@stripped0h
@@ -57,6 +57,15 @@ extern const char srv_mysql50_table_name
thread starts running */
extern os_event_t srv_lock_timeout_thread_event;
+/* The monitor thread waits on this event. */
+extern os_event_t srv_monitor_event;
+
+/* The lock timeout thread waits on this event. */
+extern os_event_t srv_timeout_event;
+
+/* The error monitor thread waits on this event. */
+extern os_event_t srv_error_event;
+
/* If the last data file is auto-extended, we add this many pages to it
at a time */
#define SRV_AUTO_EXTEND_INCREMENT \
=== modified file 'storage/innobase/log/log0log.c'
--- a/storage/innobase/log/log0log.c revid:vasil.dimov@stripped
+++ b/storage/innobase/log/log0log.c revid:marko.makela@oracle.com-20101019091242-hais946k2y58vh0h
@@ -3137,14 +3137,17 @@ loop:
proceed without waiting for monitor threads. */
if (srv_fast_shutdown < 2
- && (srv_error_monitor_active
- || srv_lock_timeout_active || srv_monitor_active)) {
- const char* thread_active = NULL;
+ && (srv_error_monitor_active
+ || srv_lock_timeout_active
+ || srv_monitor_active)) {
+
+ mutex_exit(&kernel_mutex);
/* Print a message every 60 seconds if we are waiting
for the monitor thread to exit. Master and worker threads
check will be done later. */
if (srv_print_verbose_log && count > 600) {
+ const char* thread_active = NULL;
if (srv_error_monitor_active) {
thread_active = "srv_error_monitor_thread";
@@ -3153,17 +3156,19 @@ loop:
} else if (srv_monitor_active) {
thread_active = "srv_monitor_thread";
}
- }
- mutex_exit(&kernel_mutex);
-
- if (thread_active) {
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Waiting for %s "
- "to exit\n", thread_active);
- count = 0;
+ if (thread_active) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr, " InnoDB: Waiting for %s "
+ "to exit\n", thread_active);
+ count = 0;
+ }
}
+ os_event_set(srv_error_event);
+ os_event_set(srv_monitor_event);
+ os_event_set(srv_timeout_event);
+
goto loop;
}
@@ -3199,6 +3204,8 @@ loop:
log_buffer_flush_to_disk();
+ mutex_exit(&kernel_mutex);
+
return; /* We SKIP ALL THE REST !! */
}
=== modified file 'storage/innobase/os/os0sync.c'
--- a/storage/innobase/os/os0sync.c revid:vasil.dimov@oracle.com-20101019083618-zsasadnzch4ou4vl
+++ b/storage/innobase/os/os0sync.c revid:marko.makela@stripped42-hais946k2y58vh0h
@@ -72,6 +72,9 @@ UNIV_INTERN ulint os_event_count = 0;
UNIV_INTERN ulint os_mutex_count = 0;
UNIV_INTERN ulint os_fast_mutex_count = 0;
+/* The number of microsecnds in a second. */
+static const ulint MICROSECS_IN_A_SECOND = 1000000;
+
/* Because a mutex is embedded inside an event and there is an
event embedded inside a mutex, on free, this generates a recursive call.
This version of the free event function doesn't acquire the global lock */
@@ -122,6 +125,47 @@ os_cond_init(
}
/*********************************************************//**
+Do a timed wait on condition variable.
+@return TRUE if timed out, FALSE otherwise */
+UNIV_INLINE
+ibool
+os_cond_wait_timed(
+/*===============*/
+ os_cond_t* cond, /*!< in: condition variable. */
+ os_fast_mutex_t* mutex, /*!< in: fast mutex */
+#ifndef __WIN__
+ const struct timespec* abstime /*!< in: timeout */
+#else
+ ulint time_in_ms /*!< in: timeout in
+ milliseconds */
+#endif /* !__WIN__ */
+)
+{
+#ifdef __WIN__
+ BOOL ret;
+
+ ut_a(sleep_condition_variable != NULL);
+
+ ret = sleep_condition_variable(cond, mutex, time_in_ms);
+
+ if (!ret && GetLastError() == WAIT_TIMEOUT) {
+ return(TRUE);
+ }
+
+ ut_a(ret);
+
+ return(FALSE);
+#else
+ int ret;
+
+ ret = pthread_cond_timedwait(cond, mutex, abstime);
+
+ ut_a(ret == 0 || ret == ETIMEDOUT);
+
+ return(ret == ETIMEDOUT);
+#endif
+}
+/*********************************************************//**
Wait on condition variable */
UNIV_INLINE
void
@@ -572,6 +616,113 @@ os_event_wait_low(
}
}
+/**********************************************************//**
+Waits for an event object until it is in the signaled state or
+a timeout is exceeded.
+@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
+UNIV_INTERN
+ulint
+os_event_wait_time_low(
+/*===================*/
+ os_event_t event, /*!< in: event to wait */
+ ulint time_in_usec, /*!< in: timeout in
+ microseconds, or
+ OS_SYNC_INFINITE_TIME */
+ ib_int64_t reset_sig_count) /*!< in: zero or the value
+ returned by previous call of
+ os_event_reset(). */
+
+{
+ ibool timed_out;
+ ib_int64_t old_signal_count;
+
+#ifdef __WIN__
+ DWORD time_in_ms = time_in_usec / 1000;
+
+ if (!srv_use_native_conditions) {
+ DWORD err;
+
+ ut_a(event);
+
+ if (time_in_ms != OS_SYNC_INFINITE_TIME) {
+ err = WaitForSingleObject(event->handle, time_in_ms);
+ } else {
+ err = WaitForSingleObject(event->handle, INFINITE);
+ }
+
+ if (err == WAIT_OBJECT_0) {
+ return(0);
+ } else if (err == WAIT_TIMEOUT) {
+ return(OS_SYNC_TIME_EXCEEDED);
+ }
+
+ ut_error;
+ /* Dummy value to eliminate compiler warning. */
+ return(42);
+ } else {
+ ut_a(sleep_condition_variable != NULL);
+ }
+#else
+ struct timeval tv;
+ ulint sec;
+ ulint usec;
+ int ret;
+ struct timespec abstime;
+
+ ret = ut_usectime(&sec, &usec);
+ ut_a(ret == 0);
+
+ tv.tv_sec = sec;
+ tv.tv_usec = usec;
+
+ tv.tv_usec += time_in_usec;
+
+ if ((ulint) tv.tv_usec > MICROSECS_IN_A_SECOND) {
+ tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
+ tv.tv_usec %= MICROSECS_IN_A_SECOND;
+ }
+
+ /* Convert to nano seconds. We ignore overflow. */
+ abstime.tv_sec = tv.tv_sec;
+ abstime.tv_nsec = tv.tv_usec * 1000;
+#endif /* __WIN__ */
+
+ os_fast_mutex_lock(&event->os_mutex);
+
+ if (reset_sig_count) {
+ old_signal_count = reset_sig_count;
+ } else {
+ old_signal_count = event->signal_count;
+ }
+
+ do {
+ if (event->is_set == TRUE
+ || event->signal_count != old_signal_count) {
+
+ break;
+ }
+
+ timed_out = os_cond_wait_timed(
+ &event->cond_var, &event->os_mutex,
+#ifndef __WIN__
+ &abstime
+#else
+ time_in_ms
+#endif /* !__WIN__ */
+ );
+
+ } while (!timed_out);
+
+ os_fast_mutex_unlock(&event->os_mutex);
+
+ if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
+
+ os_thread_exit(NULL);
+ }
+
+ return(timed_out ? OS_SYNC_TIME_EXCEEDED : 0);
+}
+
/*********************************************************//**
Creates an operating system mutex semaphore. Because these are slow, the
mutex semaphore of InnoDB itself (mutex_t) should be used where possible.
=== modified file 'storage/innobase/srv/srv0srv.c'
--- a/storage/innobase/srv/srv0srv.c revid:vasil.dimov@stripped8-zsasadnzch4ou4vl
+++ b/storage/innobase/srv/srv0srv.c revid:marko.makela@strippedh0h
@@ -698,6 +698,12 @@ struct srv_slot_struct{
/* Table for MySQL threads where they will be suspended to wait for locks */
UNIV_INTERN srv_slot_t* srv_mysql_table = NULL;
+UNIV_INTERN os_event_t srv_timeout_event;
+
+UNIV_INTERN os_event_t srv_monitor_event;
+
+UNIV_INTERN os_event_t srv_error_event;
+
UNIV_INTERN os_event_t srv_lock_timeout_thread_event;
UNIV_INTERN srv_sys_t* srv_sys = NULL;
@@ -1015,6 +1021,12 @@ srv_init(void)
ut_a(slot->event);
}
+ srv_error_event = os_event_create(NULL);
+
+ srv_timeout_event = os_event_create(NULL);
+
+ srv_monitor_event = os_event_create(NULL);
+
srv_lock_timeout_thread_event = os_event_create(NULL);
for (i = 0; i < SRV_MASTER + 1; i++) {
@@ -2041,6 +2053,7 @@ srv_monitor_thread(
/*!< in: a dummy parameter required by
os_thread_create */
{
+ ib_int64_t sig_count;
double time_elapsed;
time_t current_time;
time_t last_table_monitor_time;
@@ -2059,26 +2072,28 @@ srv_monitor_thread(
#endif
UT_NOT_USED(arg);
- srv_last_monitor_time = time(NULL);
- last_table_monitor_time = time(NULL);
- last_tablespace_monitor_time = time(NULL);
- last_monitor_time = time(NULL);
+ srv_last_monitor_time = ut_time();
+ last_table_monitor_time = ut_time();
+ last_tablespace_monitor_time = ut_time();
+ last_monitor_time = ut_time();
mutex_skipped = 0;
last_srv_print_monitor = srv_print_innodb_monitor;
loop:
srv_monitor_active = TRUE;
/* Wake up every 5 seconds to see if we need to print
- monitor information. */
+ monitor information or if signalled at shutdown. */
- os_thread_sleep(5000000);
+ sig_count = os_event_reset(srv_monitor_event);
- current_time = time(NULL);
+ os_event_wait_time_low(srv_monitor_event, 5000000, sig_count);
+
+ current_time = ut_time();
time_elapsed = difftime(current_time, last_monitor_time);
if (time_elapsed > 15) {
- last_monitor_time = time(NULL);
+ last_monitor_time = ut_time();
if (srv_print_innodb_monitor) {
/* Reset mutex_skipped counter everytime
@@ -2122,7 +2137,7 @@ loop:
if (srv_print_innodb_tablespace_monitor
&& difftime(current_time,
last_tablespace_monitor_time) > 60) {
- last_tablespace_monitor_time = time(NULL);
+ last_tablespace_monitor_time = ut_time();
fputs("========================"
"========================\n",
@@ -2148,7 +2163,7 @@ loop:
if (srv_print_innodb_table_monitor
&& difftime(current_time, last_table_monitor_time) > 60) {
- last_table_monitor_time = time(NULL);
+ last_table_monitor_time = ut_time();
fputs("===========================================\n",
stderr);
@@ -2208,16 +2223,20 @@ srv_lock_timeout_thread(
ibool some_waits;
double wait_time;
ulint i;
+ ib_int64_t sig_count;
#ifdef UNIV_PFS_THREAD
pfs_register_thread(srv_lock_timeout_thread_key);
#endif
loop:
+
/* When someone is waiting for a lock, we wake up every second
and check if a timeout has passed for a lock wait */
- os_thread_sleep(1000000);
+ sig_count = os_event_reset(srv_timeout_event);
+
+ os_event_wait_time_low(srv_timeout_event, 1000000, sig_count);
srv_lock_timeout_active = TRUE;
@@ -2313,6 +2332,7 @@ srv_error_monitor_thread(
ulint fatal_cnt = 0;
ib_uint64_t old_lsn;
ib_uint64_t new_lsn;
+ ib_int64_t sig_count;
old_lsn = srv_start_lsn;
@@ -2388,7 +2408,9 @@ loop:
fflush(stderr);
- os_thread_sleep(1000000);
+ sig_count = os_event_reset(srv_error_event);
+
+ os_event_wait_time_low(srv_error_event, 1000000, sig_count);
if (srv_shutdown_state < SRV_SHUTDOWN_CLEANUP) {
@@ -2701,6 +2723,21 @@ loop:
for (i = 0; i < 10; i++) {
ulint cur_time = ut_time_ms();
+ /* ALTER TABLE in MySQL requires on Unix that the table handler
+ can drop tables lazily after there no longer are SELECT
+ queries to them. */
+
+ srv_main_thread_op_info = "doing background drop tables";
+
+ row_drop_tables_for_mysql_in_background();
+
+ srv_main_thread_op_info = "";
+
+ if (srv_fast_shutdown && srv_shutdown_state > 0) {
+
+ goto background_loop;
+ }
+
buf_get_total_stat(&buf_stat);
n_ios_old = log_sys->n_log_ios + buf_stat.n_pages_read
@@ -2709,7 +2746,8 @@ loop:
srv_main_thread_op_info = "sleeping";
srv_main_1_second_loops++;
- if (next_itr_time > cur_time) {
+ if (next_itr_time > cur_time
+ && srv_shutdown_state == SRV_SHUTDOWN_NONE) {
/* Get sleep interval in micro seconds. We use
ut_min() to avoid long sleep in case of
@@ -2723,21 +2761,6 @@ loop:
/* Each iteration should happen at 1 second interval. */
next_itr_time = ut_time_ms() + 1000;
- /* ALTER TABLE in MySQL requires on Unix that the table handler
- can drop tables lazily after there no longer are SELECT
- queries to them. */
-
- srv_main_thread_op_info = "doing background drop tables";
-
- row_drop_tables_for_mysql_in_background();
-
- srv_main_thread_op_info = "";
-
- if (srv_fast_shutdown && srv_shutdown_state > 0) {
-
- goto background_loop;
- }
-
/* Flush logs if needed */
srv_sync_log_buffer_in_background();
@@ -2929,7 +2952,9 @@ background_loop:
MySQL tries to drop a table while there are still open handles
to it and we had to put it to the background drop queue.) */
- os_thread_sleep(100000);
+ if (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+ os_thread_sleep(100000);
+ }
}
if (srv_n_purge_threads == 0) {
Attachment: [text/bzr-bundle] bzr/marko.makela@oracle.com-20101019091242-hais946k2y58vh0h.bundle
| Thread |
|---|
| • bzr push into mysql-trunk-innodb branch (marko.makela:3251 to 3252) | marko.makela | 19 Oct |