From c612a1e77c36abe08576d67de30b7e45365cad30 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 30 Jun 2018 11:02:49 +0100 Subject: [PATCH] MDEV-16596 : Windows - redo log does not work on native 4K sector disks. Disks with native 4K sectors need 4K alignment and size for unbuffered IO (i.e for files opened with FILE_FLAG_NO_BUFFERING) Innodb opens redo log with FILE_FLAG_NO_BUFFERING, however it always does 512byte IOs. Thus, the IO on 4K native sectors will fail, rendering Innodb non-functional. The fix is to check whether OS_FILE_LOG_BLOCK_SIZE is multiple of logical sector size, and if it is not, reopen the redo log without FILE_FLAG_NO_BUFFERING flag. --- cmake/os/Windows.cmake | 2 +- storage/innobase/os/os0file.cc | 97 +++++++++++++++++++++++----------- 2 files changed, 68 insertions(+), 31 deletions(-) diff --git a/cmake/os/Windows.cmake b/cmake/os/Windows.cmake index c6cbfca2346..e94099670f9 100644 --- a/cmake/os/Windows.cmake +++ b/cmake/os/Windows.cmake @@ -47,7 +47,7 @@ IF(CMAKE_C_COMPILER MATCHES "icl") ENDIF() ADD_DEFINITIONS(-D_WINDOWS -D__WIN__ -D_CRT_SECURE_NO_DEPRECATE) -ADD_DEFINITIONS(-D_WIN32_WINNT=0x0600) +ADD_DEFINITIONS(-D_WIN32_WINNT=0x0A00) # We do not want the windows.h macros min/max ADD_DEFINITIONS(-DNOMINMAX) # Speed up build process excluding unused header files diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index 01b801461d6..45fb04600f3 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4109,6 +4109,32 @@ next_file: return(status); } +/** Check that IO of specific size is possible for the file +opened with FILE_FLAG_NO_BUFFERING. + +The requirement is that IO is multiple of the disk sector size. + +@param[in] file file handle +@param[in] io_size expected io size +@return true - unbuffered io of requested size is possible, false otherwise. + +@note: this function only works correctly with Windows 8 or later, +(GetFileInformationByHandleEx with FileStorageInfo is only supported there). +It will return true on earlier Windows version. + */ +static bool unbuffered_io_possible(HANDLE file, size_t io_size) +{ + FILE_STORAGE_INFO info; + if (GetFileInformationByHandleEx( + file, FileStorageInfo, &info, sizeof(info))) { + ULONG sector_size = info.LogicalBytesPerSector; + if (sector_size) + return io_size % sector_size == 0; + } + return true; +} + + /** NOTE! Use the corresponding macro os_file_create(), not directly this function! Opens an existing file or creates a new. @@ -4284,46 +4310,57 @@ os_file_create_func( access |= GENERIC_WRITE; } - do { + for (;;) { + const char *operation; + /* Use default security attributes and no template file. */ file = CreateFile( - (LPCTSTR) name, access, share_mode, NULL, + name, access, share_mode, NULL, create_flag, attributes, NULL); - if (file == INVALID_HANDLE_VALUE) { - const char* operation; + /* If FILE_FLAG_NO_BUFFERING was set, check if this can work at all, + for expected IO sizes. Reopen without the unbuffered flag, if it is won't work*/ + if ((file != INVALID_HANDLE_VALUE) + && (attributes & FILE_FLAG_NO_BUFFERING) + && (type == OS_LOG_FILE) + && !unbuffered_io_possible(file, OS_FILE_LOG_BLOCK_SIZE)) { + ut_a(CloseHandle(file)); + attributes &= ~FILE_FLAG_NO_BUFFERING; + continue; + } - operation = (create_mode == OS_FILE_CREATE - && !read_only) - ? "create" : "open"; + *success = (file != INVALID_HANDLE_VALUE); + if (*success) { + break; + } - *success = false; + operation = (create_mode == OS_FILE_CREATE && !read_only) ? + "create" : "open"; - if (on_error_no_exit) { - retry = os_file_handle_error_no_exit( - name, operation, on_error_silent); - } else { - retry = os_file_handle_error(name, operation); - } - } else { - - retry = false; + if (on_error_no_exit) { + retry = os_file_handle_error_no_exit( + name, operation, on_error_silent); + } + else { + retry = os_file_handle_error(name, operation); + } - *success = true; + if (!retry) { + break; + } + } - if (srv_use_native_aio && ((attributes & FILE_FLAG_OVERLAPPED) != 0)) { - /* Bind the file handle to completion port. Completion port - might not be created yet, in some stages of backup, but - must always be there for the server.*/ - HANDLE port =(type == OS_LOG_FILE)? - log_completion_port : data_completion_port; - ut_a(port || srv_operation != SRV_OPERATION_NORMAL); - if (port) { - ut_a(CreateIoCompletionPort(file, port, 0, 0)); - } - } + if (*success && srv_use_native_aio && (attributes & FILE_FLAG_OVERLAPPED)) { + /* Bind the file handle to completion port. Completion port + might not be created yet, in some stages of backup, but + must always be there for the server.*/ + HANDLE port = (type == OS_LOG_FILE) ? + log_completion_port : data_completion_port; + ut_a(port || srv_operation != SRV_OPERATION_NORMAL); + if (port) { + ut_a(CreateIoCompletionPort(file, port, 0, 0)); } - } while (retry); + } return(file); }