summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVladislav Vaintroub <wlad@mariadb.com>2017-10-09 12:13:05 +0000
committerVladislav Vaintroub <wlad@mariadb.com>2017-10-10 06:19:50 +0000
commitff2d9e125f7f2a70f67bc4e7ad40990139a1cf66 (patch)
treead133015b1d665ecae3c41f24b56429ef3a36edc
parentfe18e6b064a794f3dd84ead92cff3e831d185fdc (diff)
downloadmariadb-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.h4
-rw-r--r--storage/innobase/os/os0file.cc47
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.