Commit ff2d9e12 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

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.
parent fe18e6b0
...@@ -1583,8 +1583,10 @@ os_file_set_umask(ulint umask); ...@@ -1583,8 +1583,10 @@ os_file_set_umask(ulint umask);
Make file sparse, on Windows. Make file sparse, on Windows.
@param[in] file file handle @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 */ @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 Changes file size on Windows
......
...@@ -4743,11 +4743,20 @@ Sets a sparse flag on Windows file. ...@@ -4743,11 +4743,20 @@ Sets a sparse flag on Windows file.
@param[in] file file handle @param[in] file file handle
@return true on success, false on error @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; 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( ...@@ -5342,7 +5351,23 @@ os_file_set_size(
bool is_sparse) bool is_sparse)
{ {
#ifdef _WIN32 #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); return os_file_change_size_win32(name, file, size);
fallback:
#else #else
if (is_sparse) { if (is_sparse) {
bool success = !ftruncate(file, size); bool success = !ftruncate(file, size);
...@@ -5368,6 +5393,7 @@ os_file_set_size( ...@@ -5368,6 +5393,7 @@ os_file_set_size(
errno = err; errno = err;
return(!err); return(!err);
# endif /* HAVE_POSIX_ALLOCATE */ # endif /* HAVE_POSIX_ALLOCATE */
#endif /* _WIN32*/
/* Write up to 1 megabyte at a time. */ /* Write up to 1 megabyte at a time. */
ulint buf_size = ut_min( ulint buf_size = ut_min(
...@@ -5386,13 +5412,14 @@ os_file_set_size( ...@@ -5386,13 +5412,14 @@ os_file_set_size(
/* Write buffer full of zeros */ /* Write buffer full of zeros */
memset(buf, 0, buf_size); 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:"; ib::info() << "Progress in MB:";
} }
os_offset_t current_size = os_file_get_size(file);
while (current_size < size) { while (current_size < size) {
ulint n_bytes; ulint n_bytes;
...@@ -5415,8 +5442,9 @@ os_file_set_size( ...@@ -5415,8 +5442,9 @@ os_file_set_size(
} }
/* Print about progress for each 100 MB written */ /* Print about progress for each 100 MB written */
if ((current_size + n_bytes) / (100 << 20) if (write_progress_info &&
!= current_size / (100 << 20)) { ((current_size + n_bytes) / (100 << 20)
!= current_size / (100 << 20))) {
fprintf(stderr, " %lu00", fprintf(stderr, " %lu00",
(ulong) ((current_size + n_bytes) (ulong) ((current_size + n_bytes)
...@@ -5426,7 +5454,7 @@ os_file_set_size( ...@@ -5426,7 +5454,7 @@ os_file_set_size(
current_size += n_bytes; current_size += n_bytes;
} }
if (size >= (os_offset_t) 100 << 20) { if (write_progress_info) {
fprintf(stderr, "\n"); fprintf(stderr, "\n");
} }
...@@ -5434,7 +5462,6 @@ os_file_set_size( ...@@ -5434,7 +5462,6 @@ os_file_set_size(
ut_free(buf2); ut_free(buf2);
return(os_file_flush(file)); return(os_file_flush(file));
#endif /* !WIN32 */
} }
/** Truncates a file to a specified size in bytes. /** Truncates a file to a specified size in bytes.
......
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