Commit af86422f authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-13023 mariabackup does not preserve holes for page compressed tables.

Changed "local" datasink logic to detect page compressed Innodb tables.

Whenever such table is detected, holes in the copied files are created by
skipping over binary zeros at the end of each compressed page.
parent ca291015
...@@ -61,7 +61,7 @@ MYSQL_ADD_EXECUTABLE(mariabackup ...@@ -61,7 +61,7 @@ MYSQL_ADD_EXECUTABLE(mariabackup
datasink.c datasink.c
ds_buffer.c ds_buffer.c
ds_compress.c ds_compress.c
ds_local.c ds_local.cc
ds_stdout.c ds_stdout.c
ds_tmpfile.c ds_tmpfile.c
ds_xbstream.c ds_xbstream.c
...@@ -98,7 +98,7 @@ ENDIF() ...@@ -98,7 +98,7 @@ ENDIF()
######################################################################## ########################################################################
MYSQL_ADD_EXECUTABLE(mbstream MYSQL_ADD_EXECUTABLE(mbstream
ds_buffer.c ds_buffer.c
ds_local.c ds_local.cc
ds_stdout.c ds_stdout.c
datasink.c datasink.c
xbstream.c xbstream.c
...@@ -112,6 +112,7 @@ TARGET_LINK_LIBRARIES(mbstream ...@@ -112,6 +112,7 @@ TARGET_LINK_LIBRARIES(mbstream
mysys mysys
crc crc
) )
ADD_DEPENDENCIES(mbstream GenError)
IF(MSVC) IF(MSVC)
SET_TARGET_PROPERTIES(mbstream PROPERTIES LINK_FLAGS setargv.obj) SET_TARGET_PROPERTIES(mbstream PROPERTIES LINK_FLAGS setargv.obj)
......
...@@ -108,7 +108,7 @@ Write to a datasink file. ...@@ -108,7 +108,7 @@ Write to a datasink file.
int int
ds_write(ds_file_t *file, const void *buf, size_t len) ds_write(ds_file_t *file, const void *buf, size_t len)
{ {
return file->datasink->write(file, buf, len); return file->datasink->write(file, (const uchar *)buf, len);
} }
/************************************************************************ /************************************************************************
......
...@@ -48,7 +48,7 @@ typedef struct { ...@@ -48,7 +48,7 @@ typedef struct {
struct datasink_struct { struct datasink_struct {
ds_ctxt_t *(*init)(const char *root); ds_ctxt_t *(*init)(const char *root);
ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat); ds_file_t *(*open)(ds_ctxt_t *ctxt, const char *path, MY_STAT *stat);
int (*write)(ds_file_t *file, const void *buf, size_t len); int (*write)(ds_file_t *file, const unsigned char *buf, size_t len);
int (*close)(ds_file_t *file); int (*close)(ds_file_t *file);
void (*deinit)(ds_ctxt_t *ctxt); void (*deinit)(ds_ctxt_t *ctxt);
}; };
......
...@@ -45,7 +45,7 @@ typedef struct { ...@@ -45,7 +45,7 @@ typedef struct {
static ds_ctxt_t *buffer_init(const char *root); static ds_ctxt_t *buffer_init(const char *root);
static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int buffer_write(ds_file_t *file, const void *buf, size_t len); static int buffer_write(ds_file_t *file, const uchar *buf, size_t len);
static int buffer_close(ds_file_t *file); static int buffer_close(ds_file_t *file);
static void buffer_deinit(ds_ctxt_t *ctxt); static void buffer_deinit(ds_ctxt_t *ctxt);
...@@ -119,7 +119,7 @@ buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) ...@@ -119,7 +119,7 @@ buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
} }
static int static int
buffer_write(ds_file_t *file, const void *buf, size_t len) buffer_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
ds_buffer_file_t *buffer_file; ds_buffer_file_t *buffer_file;
......
...@@ -65,7 +65,7 @@ extern ulonglong xtrabackup_compress_chunk_size; ...@@ -65,7 +65,7 @@ extern ulonglong xtrabackup_compress_chunk_size;
static ds_ctxt_t *compress_init(const char *root); static ds_ctxt_t *compress_init(const char *root);
static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *compress_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int compress_write(ds_file_t *file, const void *buf, size_t len); static int compress_write(ds_file_t *file, const uchar *buf, size_t len);
static int compress_close(ds_file_t *file); static int compress_close(ds_file_t *file);
static void compress_deinit(ds_ctxt_t *ctxt); static void compress_deinit(ds_ctxt_t *ctxt);
...@@ -178,7 +178,7 @@ compress_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) ...@@ -178,7 +178,7 @@ compress_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
static static
int int
compress_write(ds_file_t *file, const void *buf, size_t len) compress_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
ds_compress_file_t *comp_file; ds_compress_file_t *comp_file;
ds_compress_ctxt_t *comp_ctxt; ds_compress_ctxt_t *comp_ctxt;
......
...@@ -18,23 +18,34 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ...@@ -18,23 +18,34 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*******************************************************/ *******************************************************/
#include <my_config.h>
#include <mysql_version.h> #include <mysql_version.h>
#include <my_base.h> #include <my_base.h>
#include <mysys_err.h> #include <mysys_err.h>
#include "common.h" #include "common.h"
#include "datasink.h" #include "datasink.h"
#include "univ.i"
#include "fsp0fsp.h"
#ifdef _WIN32
#include <winioctl.h>
#endif
typedef struct { typedef struct {
File fd; File fd;
my_bool init_ibd_done;
my_bool is_ibd;
my_bool compressed;
size_t pagesize;
} ds_local_file_t; } ds_local_file_t;
static ds_ctxt_t *local_init(const char *root); static ds_ctxt_t *local_init(const char *root);
static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *local_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int local_write(ds_file_t *file, const void *buf, size_t len); static int local_write(ds_file_t *file, const uchar *buf, size_t len);
static int local_close(ds_file_t *file); static int local_close(ds_file_t *file);
static void local_deinit(ds_ctxt_t *ctxt); static void local_deinit(ds_ctxt_t *ctxt);
extern "C" {
datasink_t datasink_local = { datasink_t datasink_local = {
&local_init, &local_init,
&local_open, &local_open,
...@@ -42,6 +53,7 @@ datasink_t datasink_local = { ...@@ -42,6 +53,7 @@ datasink_t datasink_local = {
&local_close, &local_close,
&local_deinit &local_deinit
}; };
}
static static
ds_ctxt_t * ds_ctxt_t *
...@@ -59,7 +71,7 @@ local_init(const char *root) ...@@ -59,7 +71,7 @@ local_init(const char *root)
return NULL; return NULL;
} }
ctxt = my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE)); ctxt = (ds_ctxt_t *)my_malloc(sizeof(ds_ctxt_t), MYF(MY_FAE));
ctxt->root = my_strdup(root, MYF(MY_FAE)); ctxt->root = my_strdup(root, MYF(MY_FAE));
...@@ -106,7 +118,10 @@ local_open(ds_ctxt_t *ctxt, const char *path, ...@@ -106,7 +118,10 @@ local_open(ds_ctxt_t *ctxt, const char *path,
local_file = (ds_local_file_t *) (file + 1); local_file = (ds_local_file_t *) (file + 1);
local_file->fd = fd; local_file->fd = fd;
local_file->init_ibd_done = 0;
local_file->is_ibd = (path_len > 5) && !strcmp(fullpath + path_len - 5, ".ibd");
local_file->compressed = 0;
local_file->pagesize = 0;
file->path = (char *) local_file + sizeof(ds_local_file_t); file->path = (char *) local_file + sizeof(ds_local_file_t);
memcpy(file->path, fullpath, path_len); memcpy(file->path, fullpath, path_len);
...@@ -115,31 +130,124 @@ local_open(ds_ctxt_t *ctxt, const char *path, ...@@ -115,31 +130,124 @@ local_open(ds_ctxt_t *ctxt, const char *path,
return file; return file;
} }
/* Calculate size of data without trailing zero bytes. */
static size_t trim_binary_zeros(uchar *buf, size_t pagesize)
{
size_t i;
for (i = pagesize; (i > 0) && (buf[i - 1] == 0); i--) {};
return i;
}
/* Write data to the output file, and punch "holes" if needed. */
static int write_compressed(File fd, uchar *data, size_t len, size_t pagesize)
{
uchar *ptr = data;
for (size_t written= 0; written < len;)
{
size_t n_bytes = MY_MIN(pagesize, len - written);
size_t datasize= trim_binary_zeros(ptr,n_bytes);
if (datasize > 0) {
if (!my_write(fd, ptr, datasize, MYF(MY_WME | MY_NABP)))
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
else
return 1;
}
if (datasize < n_bytes) {
/* This punches a "hole" in the file. */
size_t hole_bytes = n_bytes - datasize;
if (my_seek(fd, hole_bytes, MY_SEEK_CUR, MYF(MY_WME | MY_NABP))
== MY_FILEPOS_ERROR)
return 1;
}
written += n_bytes;
ptr += n_bytes;
}
return 0;
}
/* Calculate Innodb tablespace specific data, when first page is written.
We're interested in page compression and page size.
*/
static void init_ibd_data(ds_local_file_t *local_file, const uchar *buf, size_t len)
{
if (len < FIL_PAGE_DATA + FSP_SPACE_FLAGS) {
/* Weird, bail out.*/
return;
}
ulint flags = mach_read_from_4(&buf[FIL_PAGE_DATA + FSP_SPACE_FLAGS]);
ulint ssize = FSP_FLAGS_GET_PAGE_SSIZE(flags);
local_file->pagesize= ssize == 0 ? UNIV_PAGE_SIZE_ORIG : ((UNIV_ZIP_SIZE_MIN >> 1) << ssize);
local_file->compressed = (my_bool)FSP_FLAGS_HAS_PAGE_COMPRESSION(flags);
#if defined(_WIN32) && (MYSQL_VERSION_ID > 100200)
/* Make compressed file sparse, on Windows.
In 10.1, we do not use sparse files. */
if (local_file->compressed) {
HANDLE handle= my_get_osfhandle(local_file->fd);
if (!DeviceIoControl(handle, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, NULL, 0)) {
fprintf(stderr, "Warning: cannot make file sparse");
local_file->compressed = 0;
}
}
#endif
}
static static
int int
local_write(ds_file_t *file, const void *buf, size_t len) local_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
File fd = ((ds_local_file_t *) file->ptr)->fd; uchar *b = (uchar*)buf;
ds_local_file_t *local_file= (ds_local_file_t *)file->ptr;
File fd = local_file->fd;
if (local_file->is_ibd && !local_file->init_ibd_done) {
init_ibd_data(local_file, b , len);
local_file->init_ibd_done= 1;
}
if (local_file->compressed) {
return write_compressed(fd, b, len, local_file->pagesize);
}
if (!my_write(fd, buf, len, MYF(MY_WME | MY_NABP))) { if (!my_write(fd, b , len, MYF(MY_WME | MY_NABP))) {
posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED); posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
return 0; return 0;
} }
return 1; return 1;
} }
/* Set EOF at file's current position.*/
static int set_eof(File fd)
{
#ifdef _WIN32
return !SetEndOfFile(my_get_osfhandle(fd));
#elif defined(HAVE_FTRUNCATE)
return ftruncate(fd, my_tell(fd, MYF(MY_WME)));
#else
#error no ftruncate
#endif
}
static static
int int
local_close(ds_file_t *file) local_close(ds_file_t *file)
{ {
File fd = ((ds_local_file_t *) file->ptr)->fd; ds_local_file_t *local_file= (ds_local_file_t *)file->ptr;
File fd = local_file->fd;
int ret= 0;
my_free(file); if (local_file->compressed) {
ret = set_eof(fd);
my_sync(fd, MYF(MY_WME)); }
return my_close(fd, MYF(MY_WME)); my_close(fd, MYF(MY_WME));
my_free(file);
return ret;
} }
static static
......
...@@ -23,6 +23,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA ...@@ -23,6 +23,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#include "datasink.h" #include "datasink.h"
extern datasink_t datasink_local; #ifdef __cplusplus
extern "C"
#else
extern
#endif
datasink_t datasink_local;
#endif #endif
...@@ -30,7 +30,7 @@ typedef struct { ...@@ -30,7 +30,7 @@ typedef struct {
static ds_ctxt_t *stdout_init(const char *root); static ds_ctxt_t *stdout_init(const char *root);
static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *stdout_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int stdout_write(ds_file_t *file, const void *buf, size_t len); static int stdout_write(ds_file_t *file, const uchar *buf, size_t len);
static int stdout_close(ds_file_t *file); static int stdout_close(ds_file_t *file);
static void stdout_deinit(ds_ctxt_t *ctxt); static void stdout_deinit(ds_ctxt_t *ctxt);
...@@ -91,7 +91,7 @@ stdout_open(ds_ctxt_t *ctxt __attribute__((unused)), ...@@ -91,7 +91,7 @@ stdout_open(ds_ctxt_t *ctxt __attribute__((unused)),
static static
int int
stdout_write(ds_file_t *file, const void *buf, size_t len) stdout_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
File fd = ((ds_stdout_file_t *) file->ptr)->fd; File fd = ((ds_stdout_file_t *) file->ptr)->fd;
......
...@@ -41,7 +41,7 @@ typedef struct { ...@@ -41,7 +41,7 @@ typedef struct {
static ds_ctxt_t *tmpfile_init(const char *root); static ds_ctxt_t *tmpfile_init(const char *root);
static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *tmpfile_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int tmpfile_write(ds_file_t *file, const void *buf, size_t len); static int tmpfile_write(ds_file_t *file, const uchar *buf, size_t len);
static int tmpfile_close(ds_file_t *file); static int tmpfile_close(ds_file_t *file);
static void tmpfile_deinit(ds_ctxt_t *ctxt); static void tmpfile_deinit(ds_ctxt_t *ctxt);
...@@ -143,7 +143,7 @@ tmpfile_open(ds_ctxt_t *ctxt, const char *path, ...@@ -143,7 +143,7 @@ tmpfile_open(ds_ctxt_t *ctxt, const char *path,
} }
static int static int
tmpfile_write(ds_file_t *file, const void *buf, size_t len) tmpfile_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
File fd = ((ds_tmp_file_t *) file->ptr)->fd; File fd = ((ds_tmp_file_t *) file->ptr)->fd;
......
...@@ -41,7 +41,7 @@ General streaming interface */ ...@@ -41,7 +41,7 @@ General streaming interface */
static ds_ctxt_t *xbstream_init(const char *root); static ds_ctxt_t *xbstream_init(const char *root);
static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path, static ds_file_t *xbstream_open(ds_ctxt_t *ctxt, const char *path,
MY_STAT *mystat); MY_STAT *mystat);
static int xbstream_write(ds_file_t *file, const void *buf, size_t len); static int xbstream_write(ds_file_t *file, const uchar *buf, size_t len);
static int xbstream_close(ds_file_t *file); static int xbstream_close(ds_file_t *file);
static void xbstream_deinit(ds_ctxt_t *ctxt); static void xbstream_deinit(ds_ctxt_t *ctxt);
...@@ -166,7 +166,7 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat) ...@@ -166,7 +166,7 @@ xbstream_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
static static
int int
xbstream_write(ds_file_t *file, const void *buf, size_t len) xbstream_write(ds_file_t *file, const uchar *buf, size_t len)
{ {
ds_stream_file_t *stream_file; ds_stream_file_t *stream_file;
xb_wstream_file_t *xbstream_file; xb_wstream_file_t *xbstream_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