~akopytov/percona-xtrabackup/bug1166888-2.1

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive_fe/matching.c

  • Committer: Alexey Kopytov
  • Date: 2012-02-10 20:05:56 UTC
  • mto: (391.1.5 staging)
  • mto: This revision was merged to the branch mainline in revision 390.
  • Revision ID: akopytov@gmail.com-20120210200556-6kx41z8wwrqfucro
Rebase of the parallel compression patch on new trunk + post-review
fixes.

Implementation of parallel compression and streaming for XtraBackup.

This revision implements the following changes:

* InnoDB files are now streamed by the xtrabackup binary rather than
innobackupex. As a result, integrity is now verified by xtrabackup and
thus tar4ibd is no longer needed, so it was removed.

* xtrabackup binary now accepts the new '--stream' option which has
exactly the same semantics as the '--stream' option in
innobackupex: it tells xtrabackup to stream all files to the standard
output in the specified format rather than storing them locally.

* The xtrabackup binary can now do parallel compression using the
quicklz library. Two new options were added to xtrabackup to support
this feature:

- '--compress' tells xtrabackup to compress all output data, including
the transaction log file and meta data files, using the specified
compression algorithm. The only currently supported algorithm is
'quicklz'. The resulting files have the qpress archive format,
i.e. every *.qp file produced by xtrabackup is essentially a one-file
qpress archive and can be extracted and uncompressed by the qpress
file archiver (http://www.quicklz.com/).

- '--compress-threads' specifies the number of worker threads used by
xtrabackup for parallel data compression. This option defaults to 1.

Parallel compression ('--compress-threads') can be used together with
parallel file copying ('--parallel'). For example, '--parallel=4
--compress --compress-threads=2' will create 4 IO threads that will
read the data and pipe it to 2 compression threads.

* To support simultaneous compression and streaming, a new custom
streaming format called 'xbstream' was introduced to XtraBackup in
addition to the 'tar' format. That was required to overcome some
limitations of traditional archive formats such as 'tar', 'cpio' and
others that do not allow streaming dynamically generated files, for
example dynamically compressed files.  Other advantages of xbstream over
traditional streaming/archive formats include ability to stream multiple
files concurrently (so it is possible to use streaming in the xbstream
format together with the --parallel option) and more compact data
storage.

* To allow streaming and extracting files to/from the xbstream format
produced by xtrabackup, a new utility aptly called 'xbstream' was
added to the XtraBackup distribution. This utility has a tar-like
interface:

- with the '-x' option it extracts files from the stream read from its
standard input to the current directory unless specified otherwise
with the '-C' option.

- with the '-c' option it streams files specified on the command line
to its standard output.

The utility also tries to minimize its impact on the OS page cache by
using the appropriate posix_fadvise() calls when available.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2003-2007 Tim Kientzle
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
 
 
26
#include "lafe_platform.h"
 
27
__FBSDID("$FreeBSD: src/usr.bin/cpio/matching.c,v 1.2 2008/06/21 02:20:20 kientzle Exp $");
 
28
 
 
29
#ifdef HAVE_ERRNO_H
 
30
#include <errno.h>
 
31
#endif
 
32
#ifdef HAVE_STDLIB_H
 
33
#include <stdlib.h>
 
34
#endif
 
35
#ifdef HAVE_STRING_H
 
36
#include <string.h>
 
37
#endif
 
38
 
 
39
#include "err.h"
 
40
#include "line_reader.h"
 
41
#include "matching.h"
 
42
#include "pathmatch.h"
 
43
 
 
44
struct match {
 
45
        struct match     *next;
 
46
        int               matches;
 
47
        char              pattern[1];
 
48
};
 
49
 
 
50
struct lafe_matching {
 
51
        struct match     *exclusions;
 
52
        int               exclusions_count;
 
53
        struct match     *inclusions;
 
54
        int               inclusions_count;
 
55
        int               inclusions_unmatched_count;
 
56
};
 
57
 
 
58
static void     add_pattern(struct match **list, const char *pattern);
 
59
static void     initialize_matching(struct lafe_matching **);
 
60
static int      match_exclusion(struct match *, const char *pathname);
 
61
static int      match_inclusion(struct match *, const char *pathname);
 
62
 
 
63
/*
 
64
 * The matching logic here needs to be re-thought.  I started out to
 
65
 * try to mimic gtar's matching logic, but it's not entirely
 
66
 * consistent.  In particular 'tar -t' and 'tar -x' interpret patterns
 
67
 * on the command line as anchored, but --exclude doesn't.
 
68
 */
 
69
 
 
70
/*
 
71
 * Utility functions to manage exclusion/inclusion patterns
 
72
 */
 
73
 
 
74
int
 
75
lafe_exclude(struct lafe_matching **matching, const char *pattern)
 
76
{
 
77
 
 
78
        if (*matching == NULL)
 
79
                initialize_matching(matching);
 
80
        add_pattern(&((*matching)->exclusions), pattern);
 
81
        (*matching)->exclusions_count++;
 
82
        return (0);
 
83
}
 
84
 
 
85
int
 
86
lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
 
87
{
 
88
        struct lafe_line_reader *lr;
 
89
        const char *p;
 
90
        int ret = 0;
 
91
 
 
92
        lr = lafe_line_reader(pathname, 0);
 
93
        while ((p = lafe_line_reader_next(lr)) != NULL) {
 
94
                if (lafe_exclude(matching, p) != 0)
 
95
                        ret = -1;
 
96
        }
 
97
        lafe_line_reader_free(lr);
 
98
        return (ret);
 
99
}
 
100
 
 
101
int
 
102
lafe_include(struct lafe_matching **matching, const char *pattern)
 
103
{
 
104
 
 
105
        if (*matching == NULL)
 
106
                initialize_matching(matching);
 
107
        add_pattern(&((*matching)->inclusions), pattern);
 
108
        (*matching)->inclusions_count++;
 
109
        (*matching)->inclusions_unmatched_count++;
 
110
        return (0);
 
111
}
 
112
 
 
113
int
 
114
lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
 
115
    int nullSeparator)
 
116
{
 
117
        struct lafe_line_reader *lr;
 
118
        const char *p;
 
119
        int ret = 0;
 
120
 
 
121
        lr = lafe_line_reader(pathname, nullSeparator);
 
122
        while ((p = lafe_line_reader_next(lr)) != NULL) {
 
123
                if (lafe_include(matching, p) != 0)
 
124
                        ret = -1;
 
125
        }
 
126
        lafe_line_reader_free(lr);
 
127
        return (ret);
 
128
}
 
129
 
 
130
static void
 
131
add_pattern(struct match **list, const char *pattern)
 
132
{
 
133
        struct match *match;
 
134
        size_t len;
 
135
 
 
136
        len = strlen(pattern);
 
137
        match = malloc(sizeof(*match) + len + 1);
 
138
        if (match == NULL)
 
139
                lafe_errc(1, errno, "Out of memory");
 
140
        strcpy(match->pattern, pattern);
 
141
        /* Both "foo/" and "foo" should match "foo/bar". */
 
142
        if (len && match->pattern[len - 1] == '/')
 
143
                match->pattern[strlen(match->pattern)-1] = '\0';
 
144
        match->next = *list;
 
145
        *list = match;
 
146
        match->matches = 0;
 
147
}
 
148
 
 
149
 
 
150
int
 
151
lafe_excluded(struct lafe_matching *matching, const char *pathname)
 
152
{
 
153
        struct match *match;
 
154
        struct match *matched;
 
155
 
 
156
        if (matching == NULL)
 
157
                return (0);
 
158
 
 
159
        /* Exclusions take priority */
 
160
        for (match = matching->exclusions; match != NULL; match = match->next){
 
161
                if (match_exclusion(match, pathname))
 
162
                        return (1);
 
163
        }
 
164
 
 
165
        /* Then check for inclusions */
 
166
        matched = NULL;
 
167
        for (match = matching->inclusions; match != NULL; match = match->next){
 
168
                if (match_inclusion(match, pathname)) {
 
169
                        /*
 
170
                         * If this pattern has never been matched,
 
171
                         * then we're done.
 
172
                         */
 
173
                        if (match->matches == 0) {
 
174
                                match->matches++;
 
175
                                matching->inclusions_unmatched_count--;
 
176
                                return (0);
 
177
                        }
 
178
                        /*
 
179
                         * Otherwise, remember the match but keep checking
 
180
                         * in case we can tick off an unmatched pattern.
 
181
                         */
 
182
                        matched = match;
 
183
                }
 
184
        }
 
185
        /*
 
186
         * We didn't find a pattern that had never been matched, but
 
187
         * we did find a match, so count it and exit.
 
188
         */
 
189
        if (matched != NULL) {
 
190
                matched->matches++;
 
191
                return (0);
 
192
        }
 
193
 
 
194
        /* If there were inclusions, default is to exclude. */
 
195
        if (matching->inclusions != NULL)
 
196
            return (1);
 
197
 
 
198
        /* No explicit inclusions, default is to match. */
 
199
        return (0);
 
200
}
 
201
 
 
202
/*
 
203
 * This is a little odd, but it matches the default behavior of
 
204
 * gtar.  In particular, 'a*b' will match 'foo/a1111/222b/bar'
 
205
 *
 
206
 */
 
207
static int
 
208
match_exclusion(struct match *match, const char *pathname)
 
209
{
 
210
        return (lafe_pathmatch(match->pattern,
 
211
                    pathname,
 
212
                    PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END));
 
213
}
 
214
 
 
215
/*
 
216
 * Again, mimic gtar:  inclusions are always anchored (have to match
 
217
 * the beginning of the path) even though exclusions are not anchored.
 
218
 */
 
219
static int
 
220
match_inclusion(struct match *match, const char *pathname)
 
221
{
 
222
#if 0
 
223
        return (lafe_pathmatch(match->pattern, pathname, 0));
 
224
#else
 
225
        return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
 
226
#endif  
 
227
}
 
228
 
 
229
void
 
230
lafe_cleanup_exclusions(struct lafe_matching **matching)
 
231
{
 
232
        struct match *p, *q;
 
233
 
 
234
        if (*matching == NULL)
 
235
                return;
 
236
 
 
237
        for (p = (*matching)->inclusions; p != NULL; ) {
 
238
                q = p;
 
239
                p = p->next;
 
240
                free(q);
 
241
        }
 
242
 
 
243
        for (p = (*matching)->exclusions; p != NULL; ) {
 
244
                q = p;
 
245
                p = p->next;
 
246
                free(q);
 
247
        }
 
248
 
 
249
        free(*matching);
 
250
        *matching = NULL;
 
251
}
 
252
 
 
253
static void
 
254
initialize_matching(struct lafe_matching **matching)
 
255
{
 
256
        *matching = calloc(sizeof(**matching), 1);
 
257
        if (*matching == NULL)
 
258
                lafe_errc(1, errno, "No memory");
 
259
}
 
260
 
 
261
int
 
262
lafe_unmatched_inclusions(struct lafe_matching *matching)
 
263
{
 
264
 
 
265
        if (matching == NULL)
 
266
                return (0);
 
267
        return (matching->inclusions_unmatched_count);
 
268
}
 
269
 
 
270
int
 
271
lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
 
272
{
 
273
        struct match *p;
 
274
 
 
275
        if (matching == NULL)
 
276
                return (0);
 
277
 
 
278
        for (p = matching->inclusions; p != NULL; p = p->next) {
 
279
                if (p->matches == 0)
 
280
                        lafe_warnc(0, "%s: %s", p->pattern, msg);
 
281
        }
 
282
 
 
283
        return (matching->inclusions_unmatched_count);
 
284
}