Commit c612a1e7 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

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.
parent 1dd3c8f8
...@@ -47,7 +47,7 @@ IF(CMAKE_C_COMPILER MATCHES "icl") ...@@ -47,7 +47,7 @@ IF(CMAKE_C_COMPILER MATCHES "icl")
ENDIF() ENDIF()
ADD_DEFINITIONS(-D_WINDOWS -D__WIN__ -D_CRT_SECURE_NO_DEPRECATE) 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 # We do not want the windows.h macros min/max
ADD_DEFINITIONS(-DNOMINMAX) ADD_DEFINITIONS(-DNOMINMAX)
# Speed up build process excluding unused header files # Speed up build process excluding unused header files
......
...@@ -4109,6 +4109,32 @@ os_file_readdir_next_file( ...@@ -4109,6 +4109,32 @@ os_file_readdir_next_file(
return(status); 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 /** NOTE! Use the corresponding macro os_file_create(), not directly
this function! this function!
Opens an existing file or creates a new. Opens an existing file or creates a new.
...@@ -4284,46 +4310,57 @@ os_file_create_func( ...@@ -4284,46 +4310,57 @@ os_file_create_func(
access |= GENERIC_WRITE; access |= GENERIC_WRITE;
} }
do { for (;;) {
const char *operation;
/* Use default security attributes and no template file. */ /* Use default security attributes and no template file. */
file = CreateFile( file = CreateFile(
(LPCTSTR) name, access, share_mode, NULL, name, access, share_mode, NULL,
create_flag, attributes, NULL); create_flag, attributes, NULL);
if (file == INVALID_HANDLE_VALUE) { /* If FILE_FLAG_NO_BUFFERING was set, check if this can work at all,
const char* operation; 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 *success = (file != INVALID_HANDLE_VALUE);
&& !read_only) if (*success) {
? "create" : "open"; break;
}
*success = false; operation = (create_mode == OS_FILE_CREATE && !read_only) ?
"create" : "open";
if (on_error_no_exit) { if (on_error_no_exit) {
retry = os_file_handle_error_no_exit( retry = os_file_handle_error_no_exit(
name, operation, on_error_silent); name, operation, on_error_silent);
} else { }
retry = os_file_handle_error(name, operation); else {
} retry = os_file_handle_error(name, operation);
} else { }
retry = false;
*success = true; if (!retry) {
break;
}
}
if (srv_use_native_aio && ((attributes & FILE_FLAG_OVERLAPPED) != 0)) { if (*success && srv_use_native_aio && (attributes & FILE_FLAG_OVERLAPPED)) {
/* Bind the file handle to completion port. Completion port /* Bind the file handle to completion port. Completion port
might not be created yet, in some stages of backup, but might not be created yet, in some stages of backup, but
must always be there for the server.*/ must always be there for the server.*/
HANDLE port =(type == OS_LOG_FILE)? HANDLE port = (type == OS_LOG_FILE) ?
log_completion_port : data_completion_port; log_completion_port : data_completion_port;
ut_a(port || srv_operation != SRV_OPERATION_NORMAL); ut_a(port || srv_operation != SRV_OPERATION_NORMAL);
if (port) { if (port) {
ut_a(CreateIoCompletionPort(file, port, 0, 0)); ut_a(CreateIoCompletionPort(file, port, 0, 0));
}
}
} }
} while (retry); }
return(file); return(file);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment