diff options
Diffstat (limited to 'storage/xtradb/os/os0file.c')
-rw-r--r-- | storage/xtradb/os/os0file.c | 56 |
1 files changed, 45 insertions, 11 deletions
diff --git a/storage/xtradb/os/os0file.c b/storage/xtradb/os/os0file.c index 8fe8bab5d9a..ea7abb2549e 100644 --- a/storage/xtradb/os/os0file.c +++ b/storage/xtradb/os/os0file.c @@ -334,6 +334,8 @@ os_aio_validate_skip(void) #ifdef _WIN32 /** IO completion port used by background io threads */ static HANDLE completion_port; +/** IO completion port used by background io READ threads */ +static HANDLE read_completion_port; /** Thread local storage index for the per-thread event used for synchronous IO */ static DWORD tls_sync_io = TLS_OUT_OF_INDEXES; #endif @@ -3518,9 +3520,10 @@ os_aio_init( os_last_printout = time(NULL); #ifdef _WIN32 - ut_a(completion_port == 0); + ut_a(completion_port == 0 && read_completion_port == 0); completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); - ut_a(completion_port); + read_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); + ut_a(completion_port && read_completion_port); #endif return(TRUE); @@ -3571,6 +3574,7 @@ os_aio_array_wake_win_aio_at_shutdown( if(completion_port) { PostQueuedCompletionStatus(completion_port, 0, IOCP_SHUTDOWN_KEY, NULL); + PostQueuedCompletionStatus(read_completion_port, 0, IOCP_SHUTDOWN_KEY, NULL); } } #endif @@ -4244,6 +4248,9 @@ err_exit: } #ifdef WIN_ASYNC_IO +#define READ_SEGMENT(x) (x < srv_n_read_io_threads) +#define WRITE_SEGMENT(x) !READ_SEGMENT(x) + /**********************************************************************//** This function is only used in Windows asynchronous i/o. Waits for an aio operation to complete. This function is used to wait the @@ -4282,18 +4289,45 @@ os_aio_windows_handle( DWORD len; BOOL retry = FALSE; ULONG_PTR key; + HANDLE port = READ_SEGMENT(segment)? read_completion_port : completion_port; - ret = GetQueuedCompletionStatus(completion_port, &len, &key, - (OVERLAPPED **)&slot, INFINITE); + for(;;) { + ret = GetQueuedCompletionStatus(port, &len, &key, + (OVERLAPPED **)&slot, INFINITE); - /* If shutdown key was received, repost the shutdown message and exit */ - if (ret && (key == IOCP_SHUTDOWN_KEY)) { - PostQueuedCompletionStatus(completion_port, 0, key, NULL); - os_thread_exit(NULL); - } + /* If shutdown key was received, repost the shutdown message and exit */ + if (ret && (key == IOCP_SHUTDOWN_KEY)) { + PostQueuedCompletionStatus(port, 0, key, NULL); + os_thread_exit(NULL); + } + + if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { + os_thread_exit(NULL); + } - if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) { - os_thread_exit(NULL); + if(WRITE_SEGMENT(segment)&& slot->type == OS_FILE_READ) { + /* + Redirect read completions to the dedicated completion port + and thread. We need to split read and write threads. If we do not + do that, and just allow all io threads process all IO, it is possible + to get stuck in a deadlock in buffer pool code, + + Currently, the problem is solved this way - "write io" threads + always get all completion notifications, from both async reads and + writes. Write completion is handled in the same thread that gets it. + Read completion is forwarded via PostQueueCompletionStatus()) + to the second completion port dedicated solely to reads. One of the + "read io" threads waiting on this port will finally handle the IO. + + Forwarding IO completion this way costs a context switch , and this + seems tolerable since asynchronous reads are by far less frequent. + */ + ut_a(PostQueuedCompletionStatus(read_completion_port, len, key, + &slot->control)); + } + else { + break; + } } *message1 = slot->message1; |