Merge lp:~akopytov/percona-xtrabackup/bug1095249-2.1 into lp:percona-xtrabackup/2.1

Proposed by Alexey Kopytov
Status: Merged
Approved by: Laurynas Biveinis
Approved revision: no longer in the source branch.
Merged at revision: 473
Proposed branch: lp:~akopytov/percona-xtrabackup/bug1095249-2.1
Merge into: lp:percona-xtrabackup/2.1
Diff against target: 395 lines (+272/-6)
8 files modified
src/Makefile (+2/-1)
src/datasink.c (+4/-0)
src/datasink.h (+2/-1)
src/ds_buffer.c (+186/-0)
src/ds_buffer.h (+31/-0)
src/ds_compress.c (+0/-2)
src/xtrabackup.c (+15/-2)
test/t/ib_compress_basic.sh (+32/-0)
To merge this branch: bzr merge lp:~akopytov/percona-xtrabackup/bug1095249-2.1
Reviewer Review Type Date Requested Status
Laurynas Biveinis (community) Approve
George Ormond Lorch III (community) g2 Approve
Review via email: mp+141770@code.launchpad.net
To post a comment you must log in.
Revision history for this message
George Ormond Lorch III (gl-az) wrote :

Looks good except for tw things:
1 - diff line 292, #include "ds_buffer.h" in ds_compress.c, is that really necessary since in 2.1 ds_compress has no explicit interaction with ds_buffer?
2 - there is no call to ds_buffer_set_size to set the buffering size to 1M from the default 64K...does it make sense to make this a program option?

This brings up two issue in/with the 2.1 encryption work, small writes from compress->encrypt (encrypting extremely small buffers) and inefficient i/o. Also IIRC the encryption work implemented similar test case for basic encryption as I found it was missing. Should probably echo these comments on that MP and fix topology creation and destruction accordingly. This could be our first case of using multiple instances of a single data sink if we choose to go that route:
ds_compress -> ds_buffer -> ds_encrypt -> ds_buffer -> ds_local

review: Approve (g2)
Revision history for this message
Alexey Kopytov (akopytov) wrote :

Hi George,

On Thu, 03 Jan 2013 17:47:22 -0000, George Ormond Lorch III wrote:
> Review: Approve g2
>
> Looks good except for tw things:
> 1 - diff line 292, #include "ds_buffer.h" in ds_compress.c, is that really necessary since in 2.1 ds_compress has no explicit interaction with ds_buffer?
> 2 - there is no call to ds_buffer_set_size to set the buffering size to 1M from the default 64K...does it make sense to make this a program option?
>

Good catch. Removed redundant includes and added a ds_buffer_set_size()
call.

Regarding making it a program option. We have
https://blueprints.launchpad.net/percona-xtrabackup/+spec/specify-io-block-size
which can make both read and write buffers configurable. So far they are
both hardcoded to 1 MB.

> This brings up two issue in/with the 2.1 encryption work, small writes from compress->encrypt (encrypting extremely small buffers) and inefficient i/o. Also IIRC the encryption work implemented similar test case for basic encryption as I found it was missing. Should probably echo these comments on that MP and fix topology creation and destruction accordingly. This could be our first case of using multiple instances of a single data sink if we choose to go that route:
> ds_compress -> ds_buffer -> ds_encrypt -> ds_buffer -> ds_local
>

Yes, I see encryption also writes metadata in a separate write call, so
it will still be affected by the same problem even when compression will
use buffering (or no compression is used).

Thanks!

Revision history for this message
Alexey Kopytov (akopytov) wrote :

No idea why Launchpad decided to change the status to Merged. Reverting.

Revision history for this message
George Ormond Lorch III (gl-az) wrote :

> Hi George,
>
> On Thu, 03 Jan 2013 17:47:22 -0000, George Ormond Lorch III wrote:
> > Review: Approve g2
> >
> > Looks good except for tw things:
> > 1 - diff line 292, #include "ds_buffer.h" in ds_compress.c, is that really
> necessary since in 2.1 ds_compress has no explicit interaction with ds_buffer?
> > 2 - there is no call to ds_buffer_set_size to set the buffering size to 1M
> from the default 64K...does it make sense to make this a program option?
> >
>
> Good catch. Removed redundant includes and added a ds_buffer_set_size()
> call.
>
> Regarding making it a program option. We have
> https://blueprints.launchpad.net/percona-xtrabackup/+spec/specify-io-block-
> size
> which can make both read and write buffers configurable. So far they are
> both hardcoded to 1 MB.
>
> > This brings up two issue in/with the 2.1 encryption work, small writes from
> compress->encrypt (encrypting extremely small buffers) and inefficient i/o.
> Also IIRC the encryption work implemented similar test case for basic
> encryption as I found it was missing. Should probably echo these comments on
> that MP and fix topology creation and destruction accordingly. This could be
> our first case of using multiple instances of a single data sink if we choose
> to go that route:
> > ds_compress -> ds_buffer -> ds_encrypt -> ds_buffer -> ds_local
> >
>
> Yes, I see encryption also writes metadata in a separate write call, so
> it will still be affected by the same problem even when compression will
> use buffering (or no compression is used).
>
> Thanks!

Also FYI in case you really haven't had a chance to review much of the encryption work yet, I went ahead and exposed both compress and encrypt block sizes as program options which allow tuning of the individual compress and encrypt worker thread block sizes. In my testing these can actually have a pretty decent impact on overall backup speed when set properly (and the tuning ratios are not entirely intuitive). This is what lead me to propose the PLMCE 2013 tutorial on tuning XB options for best results. With this new i/o buffer, it may make the current results much more interesting. Once this change is merged into 2.1, I will rebase the encryption branch and also look into implementing the i/o block size program options ahead of it which should be simple enough. It would be nice to have all of these in the trunk by the time for PLMCE 2013 and included into my talk.

Revision history for this message
Alexey Kopytov (akopytov) wrote :

http://jenkins.percona.com/view/XtraBackup/job/percona-xtrabackup-2.1-param/135/ (though compression tests are not currently executed by Jenkins anyway).

Revision history for this message
Laurynas Biveinis (laurynas-biveinis) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Makefile'
--- src/Makefile 2012-05-25 11:38:15 +0000
+++ src/Makefile 2013-01-07 06:21:20 +0000
@@ -28,6 +28,7 @@
28 ds_local.o \28 ds_local.o \
29 ds_compress.o \29 ds_compress.o \
30 ds_tmpfile.o \30 ds_tmpfile.o \
31 ds_buffer.o \
31 datasink.o \32 datasink.o \
32 write_filt.o \33 write_filt.o \
33 fil_cur.o \34 fil_cur.o \
@@ -185,7 +186,7 @@
185xbstream.o xbstream_read.o: %.o: %.c186xbstream.o xbstream_read.o: %.o: %.c
186 $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@187 $(CC) $(CFLAGS) $(INC) $(DEFS) -c $< -o $@
187188
188xbstream: $(XBSTREAMOBJS) $(MYSQLOBJS) ds_local.o datasink.o189xbstream: $(XBSTREAMOBJS) $(MYSQLOBJS) ds_local.o ds_buffer.o datasink.o
189 $(CC) $(CFLAGS) $^ $(INC) $(MYSQLOBJS) $(LIBS) -o $@190 $(CC) $(CFLAGS) $^ $(INC) $(MYSQLOBJS) $(LIBS) -o $@
190191
191xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h192xtrabackup.o: xtrabackup.c xb_regex.h write_filt.h fil_cur.h xtrabackup.h
192193
=== modified file 'src/datasink.c'
--- src/datasink.c 2012-02-16 18:02:07 +0000
+++ src/datasink.c 2013-01-07 06:21:20 +0000
@@ -25,6 +25,7 @@
25#include "ds_stream.h"25#include "ds_stream.h"
26#include "ds_local.h"26#include "ds_local.h"
27#include "ds_tmpfile.h"27#include "ds_tmpfile.h"
28#include "ds_buffer.h"
2829
29/************************************************************************30/************************************************************************
30Create a datasink of the specified type */31Create a datasink of the specified type */
@@ -47,6 +48,9 @@
47 case DS_TYPE_TMPFILE:48 case DS_TYPE_TMPFILE:
48 ds = &datasink_tmpfile;49 ds = &datasink_tmpfile;
49 break;50 break;
51 case DS_TYPE_BUFFER:
52 ds = &datasink_buffer;
53 break;
50 default:54 default:
51 msg("Unknown datasink type: %d\n", type);55 msg("Unknown datasink type: %d\n", type);
52 return NULL;56 return NULL;
5357
=== modified file 'src/datasink.h'
--- src/datasink.h 2012-02-16 18:02:07 +0000
+++ src/datasink.h 2013-01-07 06:21:20 +0000
@@ -53,7 +53,8 @@
53 DS_TYPE_LOCAL,53 DS_TYPE_LOCAL,
54 DS_TYPE_STREAM,54 DS_TYPE_STREAM,
55 DS_TYPE_COMPRESS,55 DS_TYPE_COMPRESS,
56 DS_TYPE_TMPFILE56 DS_TYPE_TMPFILE,
57 DS_TYPE_BUFFER
57} ds_type_t;58} ds_type_t;
5859
59/************************************************************************60/************************************************************************
6061
=== added file 'src/ds_buffer.c'
--- src/ds_buffer.c 1970-01-01 00:00:00 +0000
+++ src/ds_buffer.c 2013-01-07 06:21:20 +0000
@@ -0,0 +1,186 @@
1/******************************************************
2Copyright (c) 2012 Percona Ireland Ltd.
3
4buffer datasink for XtraBackup.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19*******************************************************/
20
21/* Does buffered output to a destination datasink set with ds_set_pipe().
22Writes to the destination datasink are guaranteed to not be smaller than a
23specified buffer size (DS_DEFAULT_BUFFER_SIZE by default), with the only
24exception for the last write for a file. */
25
26#include <my_base.h>
27#include "common.h"
28#include "datasink.h"
29
30#define DS_DEFAULT_BUFFER_SIZE (64 * 1024)
31
32typedef struct {
33 ds_file_t *dst_file;
34 char *buf;
35 size_t pos;
36 size_t size;
37} ds_buffer_file_t;
38
39typedef struct {
40 size_t buffer_size;
41} ds_buffer_ctxt_t;
42
43static ds_ctxt_t *buffer_init(const char *root);
44static ds_file_t *buffer_open(ds_ctxt_t *ctxt, const char *path,
45 MY_STAT *mystat);
46static int buffer_write(ds_file_t *file, const void *buf, size_t len);
47static int buffer_close(ds_file_t *file);
48static void buffer_deinit(ds_ctxt_t *ctxt);
49
50datasink_t datasink_buffer = {
51 &buffer_init,
52 &buffer_open,
53 &buffer_write,
54 &buffer_close,
55 &buffer_deinit
56};
57
58/* Change the default buffer size */
59void ds_buffer_set_size(ds_ctxt_t *ctxt, size_t size)
60{
61 ds_buffer_ctxt_t *buffer_ctxt = (ds_buffer_ctxt_t *) ctxt->ptr;
62
63 buffer_ctxt->buffer_size = size;
64}
65
66static ds_ctxt_t *
67buffer_init(const char *root)
68{
69 ds_ctxt_t *ctxt;
70 ds_buffer_ctxt_t *buffer_ctxt;
71
72 ctxt = my_malloc(sizeof(ds_ctxt_t) + sizeof(ds_buffer_ctxt_t),
73 MYF(MY_FAE));
74 buffer_ctxt = (ds_buffer_ctxt_t *) (ctxt + 1);
75 buffer_ctxt->buffer_size = DS_DEFAULT_BUFFER_SIZE;
76
77 ctxt->ptr = buffer_ctxt;
78 ctxt->root = my_strdup(root, MYF(MY_FAE));
79
80 return ctxt;
81}
82
83static ds_file_t *
84buffer_open(ds_ctxt_t *ctxt, const char *path, MY_STAT *mystat)
85{
86 ds_buffer_ctxt_t *buffer_ctxt;
87 ds_ctxt_t *pipe_ctxt;
88 ds_file_t *dst_file;
89 ds_file_t *file;
90 ds_buffer_file_t *buffer_file;
91
92 pipe_ctxt = ctxt->pipe_ctxt;
93 xb_a(pipe_ctxt != NULL);
94
95 dst_file = ds_open(pipe_ctxt, path, mystat);
96 if (dst_file == NULL) {
97 exit(EXIT_FAILURE);
98 }
99
100 buffer_ctxt = (ds_buffer_ctxt_t *) ctxt->ptr;
101
102 file = (ds_file_t *) my_malloc(sizeof(ds_file_t) +
103 sizeof(ds_buffer_file_t) +
104 buffer_ctxt->buffer_size,
105 MYF(MY_FAE));
106
107 buffer_file = (ds_buffer_file_t *) (file + 1);
108 buffer_file->dst_file = dst_file;
109 buffer_file->buf = (char *) (buffer_file + 1);
110 buffer_file->size = buffer_ctxt->buffer_size;
111 buffer_file->pos = 0;
112
113 file->path = dst_file->path;
114 file->ptr = buffer_file;
115
116 return file;
117}
118
119static int
120buffer_write(ds_file_t *file, const void *buf, size_t len)
121{
122 ds_buffer_file_t *buffer_file;
123
124 buffer_file = (ds_buffer_file_t *) file->ptr;
125
126 while (len > 0) {
127 if (buffer_file->pos + len > buffer_file->size) {
128 if (buffer_file->pos > 0) {
129 size_t bytes;
130
131 bytes = buffer_file->size - buffer_file->pos;
132 memcpy(buffer_file->buf + buffer_file->pos, buf,
133 bytes);
134
135 if (ds_write(buffer_file->dst_file,
136 buffer_file->buf,
137 buffer_file->size)) {
138 return 1;
139 }
140
141 buffer_file->pos = 0;
142
143 buf = (const char *) buf + bytes;
144 len -= bytes;
145 } else {
146 /* We don't have any buffered bytes, just write
147 the entire source buffer */
148 if (ds_write(buffer_file->dst_file, buf, len)) {
149 return 1;
150 }
151 break;
152 }
153 } else {
154 memcpy(buffer_file->buf + buffer_file->pos, buf, len);
155 buffer_file->pos += len;
156 break;
157 }
158 }
159
160 return 0;
161}
162
163static int
164buffer_close(ds_file_t *file)
165{
166 ds_buffer_file_t *buffer_file;
167
168 buffer_file = (ds_buffer_file_t *) file->ptr;
169 if (buffer_file->pos > 0) {
170 ds_write(buffer_file->dst_file, buffer_file->buf,
171 buffer_file->pos);
172 }
173
174 ds_close(buffer_file->dst_file);
175
176 MY_FREE(file);
177
178 return 0;
179}
180
181static void
182buffer_deinit(ds_ctxt_t *ctxt)
183{
184 MY_FREE(ctxt->root);
185 MY_FREE(ctxt);
186}
0187
=== added file 'src/ds_buffer.h'
--- src/ds_buffer.h 1970-01-01 00:00:00 +0000
+++ src/ds_buffer.h 2013-01-07 06:21:20 +0000
@@ -0,0 +1,31 @@
1/******************************************************
2Copyright (c) 2012 Percona Ireland Ltd.
3
4buffer datasink for XtraBackup.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; version 2 of the License.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
19*******************************************************/
20
21#ifndef DS_BUFFER_H
22#define DS_BUFFER_H
23
24#include "datasink.h"
25
26extern datasink_t datasink_buffer;
27
28/* Change the default buffer size */
29void ds_buffer_set_size(ds_ctxt_t *ctxt, size_t size);
30
31#endif
032
=== modified file 'src/ds_compress.c'
--- src/ds_compress.c 2012-06-14 14:48:55 +0000
+++ src/ds_compress.c 2013-01-07 06:21:20 +0000
@@ -25,8 +25,6 @@
25#include <zlib.h>25#include <zlib.h>
26#include "common.h"26#include "common.h"
27#include "datasink.h"27#include "datasink.h"
28#include "ds_stream.h"
29#include "ds_local.h"
3028
31#define COMPRESS_CHUNK_SIZE (64 * 1024UL)29#define COMPRESS_CHUNK_SIZE (64 * 1024UL)
32#define MY_QLZ_COMPRESS_OVERHEAD 40030#define MY_QLZ_COMPRESS_OVERHEAD 400
3331
=== modified file 'src/xtrabackup.c'
--- src/xtrabackup.c 2012-11-21 13:51:49 +0000
+++ src/xtrabackup.c 2013-01-07 06:21:20 +0000
@@ -87,6 +87,7 @@
87#include "fil_cur.h"87#include "fil_cur.h"
88#include "write_filt.h"88#include "write_filt.h"
89#include "xtrabackup.h"89#include "xtrabackup.h"
90#include "ds_buffer.h"
9091
91my_bool innodb_inited= 0;92my_bool innodb_inited= 0;
9293
@@ -261,6 +262,7 @@
261static ds_ctxt_t *ds_compress = NULL;262static ds_ctxt_t *ds_compress = NULL;
262static ds_ctxt_t *ds_tmpfile = NULL;263static ds_ctxt_t *ds_tmpfile = NULL;
263static ds_ctxt_t *ds_stream = NULL;264static ds_ctxt_t *ds_stream = NULL;
265static ds_ctxt_t *ds_buffer = NULL;
264266
265/* ======== Datafiles iterator ======== */267/* ======== Datafiles iterator ======== */
266typedef struct {268typedef struct {
@@ -2124,21 +2126,28 @@
2124 if (xtrabackup_compress) {2126 if (xtrabackup_compress) {
2125 ds_compress = ds_create(xtrabackup_target_dir,2127 ds_compress = ds_create(xtrabackup_target_dir,
2126 DS_TYPE_COMPRESS);2128 DS_TYPE_COMPRESS);
2129 /* Use a 1 MB buffer for compressed output stream */
2130 ds_buffer = ds_create(xtrabackup_target_dir,
2131 DS_TYPE_BUFFER);
2132 ds_buffer_set_size(ds_buffer, 1024 * 1024);
2133
2127 ds_data = ds_compress;2134 ds_data = ds_compress;
21282135
2129 if (xtrabackup_stream) {2136 if (xtrabackup_stream) {
2130 /* Streaming compressed backup */2137 /* Streaming compressed backup */
2131 ds_set_pipe(ds_compress, ds_stream);2138 ds_set_pipe(ds_buffer, ds_stream);
2132 /* Bypass compression for meta files */2139 /* Bypass compression for meta files */
2133 ds_meta = ds_stream;2140 ds_meta = ds_stream;
2134 } else {2141 } else {
2135 /* Local compressed backup */2142 /* Local compressed backup */
2136 ds_local = ds_create(xtrabackup_target_dir,2143 ds_local = ds_create(xtrabackup_target_dir,
2137 DS_TYPE_LOCAL);2144 DS_TYPE_LOCAL);
2138 ds_set_pipe(ds_compress, ds_local);2145 ds_set_pipe(ds_buffer, ds_local);
2139 /* Bypass compression for meta files */2146 /* Bypass compression for meta files */
2140 ds_meta = ds_local;2147 ds_meta = ds_local;
2141 }2148 }
2149
2150 ds_set_pipe(ds_compress, ds_buffer);
2142 } else {2151 } else {
2143 /* Streaming uncompressed backup */2152 /* Streaming uncompressed backup */
2144 ds_data = ds_stream;2153 ds_data = ds_stream;
@@ -2177,6 +2186,10 @@
2177 ds_destroy(ds_compress);2186 ds_destroy(ds_compress);
2178 ds_compress = NULL;2187 ds_compress = NULL;
2179 }2188 }
2189 if (ds_buffer != NULL) {
2190 ds_destroy(ds_buffer);
2191 ds_buffer = NULL;
2192 }
2180 if (ds_stream != NULL) {2193 if (ds_stream != NULL) {
2181 ds_destroy(ds_stream);2194 ds_destroy(ds_stream);
2182 ds_stream = NULL;2195 ds_stream = NULL;
21832196
=== added file 'test/t/ib_compress_basic.sh'
--- test/t/ib_compress_basic.sh 1970-01-01 00:00:00 +0000
+++ test/t/ib_compress_basic.sh 2013-01-07 06:21:20 +0000
@@ -0,0 +1,32 @@
1########################################################################
2# Basic test for local compressed backups
3########################################################################
4
5. inc/common.sh
6
7if ! which qpress > /dev/null 2>&1 ; then
8 echo "Requires qpress to be installed" > $SKIPPED_REASON
9 exit $SKIPPED_EXIT_CODE
10fi
11
12start_server --innodb_file_per_table
13load_sakila
14
15innobackupex --compress --no-timestamp $topdir/backup
16
17stop_server
18rm -rf ${MYSQLD_DATADIR}/*
19
20cd $topdir/backup
21
22for i in *.qp; do qpress -d $i ./; done; \
23for i in sakila/*.qp; do qpress -d $i sakila/; done
24
25innobackupex --apply-log $topdir/backup
26
27innobackupex --copy-back $topdir/backup
28
29start_server
30
31# TODO: proper validation
32run_cmd ${MYSQL} ${MYSQL_ARGS} -e "SELECT count(*) from actor" sakila

Subscribers

People subscribed via source and target branches

to all changes: