diff options
author | Vladislav Vaintroub <wlad@mariadb.com> | 2017-10-09 12:13:05 +0000 |
---|---|---|
committer | Vladislav Vaintroub <wlad@mariadb.com> | 2017-10-10 06:19:50 +0000 |
commit | ff2d9e125f7f2a70f67bc4e7ad40990139a1cf66 (patch) | |
tree | ad133015b1d665ecae3c41f24b56429ef3a36edc | |
parent | fe18e6b064a794f3dd84ead92cff3e831d185fdc (diff) | |
download | mariadb-git-ff2d9e125f7f2a70f67bc4e7ad40990139a1cf66.tar.gz |
MDEV-13941 followup.
Try to fix fragmentation (unsparse files), for pre-existing
installations.
Unsparse the innodb file, when it needs to be extended, unless compression
is used. For Win7/2008R2 unsparse does not work (as documented in MSDN),
therefore for sparse files in older Windows, file extension will be done
via writing zeroes at the end of file.
-rw-r--r-- | storage/innobase/include/os0file.h | 4 | ||||
-rw-r--r-- | storage/innobase/os/os0file.cc | 47 |
2 files changed, 40 insertions, 11 deletions
diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h index e872d6f1df7..c0806ad2977 100644 --- a/storage/innobase/include/os0file.h +++ b/storage/innobase/include/os0file.h @@ -1583,8 +1583,10 @@ os_file_set_umask(ulint umask); Make file sparse, on Windows. @param[in] file file handle +@param[in] is_sparse if true, make file sparse, + otherwise "unsparse" the file @return true on success, false on error */ -bool os_file_set_sparse_win32(os_file_t file); +bool os_file_set_sparse_win32(os_file_t file, bool is_sparse = true); /** Changes file size on Windows diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc index b664cf82c16..2ef1940fdcd 100644 --- a/storage/innobase/os/os0file.cc +++ b/storage/innobase/os/os0file.cc @@ -4743,11 +4743,20 @@ Sets a sparse flag on Windows file. @param[in] file file handle @return true on success, false on error */ -bool os_file_set_sparse_win32(os_file_t file) +#include <versionhelpers.h> +bool os_file_set_sparse_win32(os_file_t file, bool is_sparse) { - + if (!is_sparse && !IsWindows8OrGreater()) { + /* Cannot unset sparse flag on older Windows. + Until Windows8 it is documented to produce unpredictable results, + if there are unallocated ranges in file.*/ + return false; + } DWORD temp; - return os_win32_device_io_control(file, FSCTL_SET_SPARSE, 0, 0, 0, 0,&temp); + FILE_SET_SPARSE_BUFFER sparse_buffer; + sparse_buffer.SetSparse = is_sparse; + return os_win32_device_io_control(file, + FSCTL_SET_SPARSE, &sparse_buffer, sizeof(sparse_buffer), 0, 0,&temp); } @@ -5342,7 +5351,23 @@ os_file_set_size( bool is_sparse) { #ifdef _WIN32 + /* On Windows, changing file size works well and as expected for both + sparse and normal files. + + However, 10.2 up until 10.2.9 made every file sparse in innodb, + causing NTFS fragmentation issues(MDEV-13941). We try to undo + the damage, and unsparse the file.*/ + + if (!is_sparse && os_is_sparse_file_supported(file)) { + if (!os_file_set_sparse_win32(file, false)) + /* Unsparsing file failed. Fallback to writing binary + zeros, to avoid even higher fragmentation.*/ + goto fallback; + } + return os_file_change_size_win32(name, file, size); + +fallback: #else if (is_sparse) { bool success = !ftruncate(file, size); @@ -5368,6 +5393,7 @@ os_file_set_size( errno = err; return(!err); # endif /* HAVE_POSIX_ALLOCATE */ +#endif /* _WIN32*/ /* Write up to 1 megabyte at a time. */ ulint buf_size = ut_min( @@ -5386,13 +5412,14 @@ os_file_set_size( /* Write buffer full of zeros */ memset(buf, 0, buf_size); - if (size >= (os_offset_t) 100 << 20) { + os_offset_t current_size = os_file_get_size(file); + bool write_progress_info = + (size - current_size >= (os_offset_t) 100 << 20); + if (write_progress_info) { ib::info() << "Progress in MB:"; } - os_offset_t current_size = os_file_get_size(file); - while (current_size < size) { ulint n_bytes; @@ -5415,8 +5442,9 @@ os_file_set_size( } /* Print about progress for each 100 MB written */ - if ((current_size + n_bytes) / (100 << 20) - != current_size / (100 << 20)) { + if (write_progress_info && + ((current_size + n_bytes) / (100 << 20) + != current_size / (100 << 20))) { fprintf(stderr, " %lu00", (ulong) ((current_size + n_bytes) @@ -5426,7 +5454,7 @@ os_file_set_size( current_size += n_bytes; } - if (size >= (os_offset_t) 100 << 20) { + if (write_progress_info) { fprintf(stderr, "\n"); } @@ -5434,7 +5462,6 @@ os_file_set_size( ut_free(buf2); return(os_file_flush(file)); -#endif /* !WIN32 */ } /** Truncates a file to a specified size in bytes. |