~hartmut-php/maria/bug-917662

« back to all changes in this revision

Viewing changes to storage/xtradb/os/os0file.c

  • Committer: Vladislav Vaintroub
  • Date: 2012-01-08 20:14:07 UTC
  • Revision ID: wlad@montyprogram.com-20120108201407-mtxueky7hicy89e1
MDEV-77 - possible deadlock in XtraDB async io subsystem on Windows.

Split IO threads into ones that handle only read completion and ones that handle only write completion, as it was originally done, but got lost with "completion port" patch. The reason we need to have dedicated read and dedicated write threads is that read completion routine can block waiting for write io to complete, and in rare cases where all io threads are handling async reads, it can deadlock.

Show diffs side-by-side

added added

removed removed

Lines of Context:
249
249
#ifdef _WIN32
250
250
/** IO completion port used by background io threads */
251
251
static HANDLE completion_port;
 
252
/** IO completion port used by background io READ threads */
 
253
static HANDLE read_completion_port;
252
254
/** Thread local storage index for the per-thread event used for synchronous IO */
253
255
static DWORD tls_sync_io = TLS_OUT_OF_INDEXES;
254
256
#endif
3251
3253
 
3252
3254
        os_last_printout = time(NULL);
3253
3255
#ifdef _WIN32
3254
 
        ut_a(completion_port == 0);
 
3256
        ut_a(completion_port == 0 && read_completion_port == 0);
3255
3257
        completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
3256
 
        ut_a(completion_port);
 
3258
        read_completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
 
3259
        ut_a(completion_port && read_completion_port);
3257
3260
#endif
3258
3261
}
3259
3262
 
3299
3302
        if(completion_port)
3300
3303
        {
3301
3304
                PostQueuedCompletionStatus(completion_port, 0, IOCP_SHUTDOWN_KEY, NULL);
 
3305
                PostQueuedCompletionStatus(read_completion_port, 0, IOCP_SHUTDOWN_KEY, NULL);
3302
3306
        }
3303
3307
}
3304
3308
#endif
3860
3864
}
3861
3865
 
3862
3866
#ifdef WIN_ASYNC_IO
 
3867
#define READ_SEGMENT(x) (x < srv_n_read_io_threads)
 
3868
#define WRITE_SEGMENT(x) !READ_SEGMENT(x)
 
3869
 
3863
3870
/**********************************************************************//**
3864
3871
This function is only used in Windows asynchronous i/o.
3865
3872
Waits for an aio operation to complete. This function is used to wait the
3898
3905
        DWORD           len;
3899
3906
        BOOL            retry           = FALSE;
3900
3907
        ULONG_PTR key;
3901
 
 
3902
 
        ret = GetQueuedCompletionStatus(completion_port, &len, &key, 
3903
 
                (OVERLAPPED **)&slot, INFINITE);
3904
 
 
3905
 
        /* If shutdown key was received, repost the shutdown message and exit */
3906
 
        if (ret && (key == IOCP_SHUTDOWN_KEY)) {
3907
 
                PostQueuedCompletionStatus(completion_port, 0, key, NULL);
3908
 
                os_thread_exit(NULL);
3909
 
        }
3910
 
 
3911
 
        if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
3912
 
                os_thread_exit(NULL);
 
3908
        HANDLE port = READ_SEGMENT(segment)? read_completion_port : completion_port;
 
3909
 
 
3910
        for(;;) {
 
3911
                ret = GetQueuedCompletionStatus(port, &len, &key, 
 
3912
                        (OVERLAPPED **)&slot, INFINITE);
 
3913
 
 
3914
                /* If shutdown key was received, repost the shutdown message and exit */
 
3915
                if (ret && (key == IOCP_SHUTDOWN_KEY)) {
 
3916
                        PostQueuedCompletionStatus(port, 0, key, NULL);
 
3917
                        os_thread_exit(NULL);
 
3918
                }
 
3919
 
 
3920
                if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
 
3921
                        os_thread_exit(NULL);
 
3922
                }
 
3923
 
 
3924
                if(WRITE_SEGMENT(segment)&& slot->type == OS_FILE_READ) {
 
3925
                        /*
 
3926
                        Redirect read completions  to the dedicated completion port 
 
3927
                        and thread. We need to split read and write threads. If we do not
 
3928
                        do that, and just allow all io threads process all IO, it is possible 
 
3929
                        to get stuck in a deadlock in buffer pool code,
 
3930
 
 
3931
                        Currently, the problem is solved this way - "write io" threads  
 
3932
                        always get all completion notifications, from both async reads and
 
3933
                        writes. Write completion is handled in the same thread that gets it.
 
3934
                        Read completion is forwarded via PostQueueCompletionStatus())
 
3935
                        to the second completion port dedicated solely to reads. One of the
 
3936
                        "read io" threads waiting on this port will finally handle the IO.
 
3937
 
 
3938
                        Forwarding IO completion this way costs a context switch , and this 
 
3939
                        seems tolerable  since asynchronous reads are by far less frequent.
 
3940
                        */
 
3941
                        ut_a(PostQueuedCompletionStatus(read_completion_port, len, key,
 
3942
                                &slot->control));
 
3943
                }
 
3944
                else {
 
3945
                        break;
 
3946
                }
3913
3947
        }
3914
3948
 
3915
3949