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 /storage | |
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.
Diffstat (limited to 'storage')
-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. |