~akopytov/percona-xtrabackup/bug1166888-2.1

« back to all changes in this revision

Viewing changes to src/libarchive/cpio/test/test_format_newc.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
#include "test.h"
 
26
__FBSDID("$FreeBSD: src/usr.bin/cpio/test/test_format_newc.c,v 1.2 2008/08/22 02:09:10 kientzle Exp $");
 
27
 
 
28
/* Number of bytes needed to pad 'n' to multiple of 'block', assuming
 
29
 * that 'block' is a power of two. This trick can be more easily
 
30
 * remembered as -n & (block - 1), but many compilers quite reasonably
 
31
 * warn about "-n" when n is an unsigned value.  (~(n) + 1) is the
 
32
 * same thing, but written in a way that won't offend anyone. */
 
33
#define PAD(n, block)  ((~(n) + 1) & ((block) - 1))
 
34
 
 
35
static int
 
36
is_hex(const char *p, size_t l)
 
37
{
 
38
        while (l > 0) {
 
39
                if ((*p >= '0' && *p <= '9')
 
40
                    || (*p >= 'a' && *p <= 'f')
 
41
                    || (*p >= 'A' && *p <= 'F'))
 
42
                {
 
43
                        --l;
 
44
                        ++p;
 
45
                } else
 
46
                        return (0);
 
47
 
 
48
        }
 
49
        return (1);
 
50
}
 
51
 
 
52
static int
 
53
from_hex(const char *p, size_t l)
 
54
{
 
55
        int r = 0;
 
56
 
 
57
        while (l > 0) {
 
58
                r *= 16;
 
59
                if (*p >= 'a' && *p <= 'f')
 
60
                        r += *p + 10 - 'a';
 
61
                else if (*p >= 'A' && *p <= 'F')
 
62
                        r += *p + 10 - 'A';
 
63
                else
 
64
                        r += *p - '0';
 
65
                --l;
 
66
                ++p;
 
67
        }
 
68
        return (r);
 
69
}
 
70
 
 
71
DEFINE_TEST(test_format_newc)
 
72
{
 
73
        FILE *list;
 
74
        int r;
 
75
        int devmajor, devminor, ino, gid;
 
76
        int uid = -1;
 
77
        time_t t, t2, now;
 
78
        char *p, *e;
 
79
        size_t s, fs, ns;
 
80
 
 
81
        assertUmask(0);
 
82
 
 
83
#if !defined(_WIN32)
 
84
        uid = getuid();
 
85
#endif
 
86
 
 
87
        /*
 
88
         * Create an assortment of files.
 
89
         * TODO: Extend this to cover more filetypes.
 
90
         */
 
91
        list = fopen("list", "w");
 
92
 
 
93
        /* "file1" */
 
94
        assertMakeFile("file1", 0644, "1234567890");
 
95
        fprintf(list, "file1\n");
 
96
 
 
97
        /* "hardlink" */
 
98
        assertMakeHardlink("hardlink", "file1");
 
99
        fprintf(list, "hardlink\n");
 
100
 
 
101
        /* Another hardlink, but this one won't be archived. */
 
102
        assertMakeHardlink("hardlink2", "file1");
 
103
 
 
104
        /* "symlink" */
 
105
        if (canSymlink()) {
 
106
                assertMakeSymlink("symlink", "file1");
 
107
                fprintf(list, "symlink\n");
 
108
        }
 
109
 
 
110
        /* "dir" */
 
111
        assertMakeDir("dir", 0775);
 
112
        fprintf(list, "dir\n");
 
113
 
 
114
        /* Record some facts about what we just created: */
 
115
        now = time(NULL); /* They were all created w/in last two seconds. */
 
116
 
 
117
        /* Use the cpio program to create an archive. */
 
118
        fclose(list);
 
119
        r = systemf("%s -o --format=newc <list >newc.out 2>newc.err",
 
120
            testprog);
 
121
        if (!assertEqualInt(r, 0))
 
122
                return;
 
123
 
 
124
        /* Verify that nothing went to stderr. */
 
125
        if (canSymlink()) {
 
126
                assertTextFileContents("2 blocks\n", "newc.err");
 
127
        } else {
 
128
                assertTextFileContents("1 block\n", "newc.err");
 
129
        }
 
130
 
 
131
        /* Verify that stdout is a well-formed cpio file in "newc" format. */
 
132
        p = slurpfile(&s, "newc.out");
 
133
        assertEqualInt(s, canSymlink() ? 1024 : 512);
 
134
        e = p;
 
135
 
 
136
        /*
 
137
         * Some of these assertions could be stronger, but it's
 
138
         * a little tricky because they depend on the local environment.
 
139
         */
 
140
 
 
141
        /* First entry is "file1" */
 
142
        assert(is_hex(e, 110)); /* Entire header is octal digits. */
 
143
        assertEqualMem(e + 0, "070701", 6); /* Magic */
 
144
        ino = from_hex(e + 6, 8); /* ino */
 
145
#if defined(_WIN32) && !defined(__CYGWIN__)
 
146
        /* Group members bits and others bits do not work. */ 
 
147
        assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */
 
148
#else
 
149
        assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
 
150
#endif  
 
151
        if (uid < 0)
 
152
                uid = from_hex(e + 22, 8);
 
153
        assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
 
154
        gid = from_hex(e + 30, 8); /* gid */
 
155
        assertEqualMem(e + 38, "00000003", 8); /* nlink */
 
156
        t = from_hex(e + 46, 8); /* mtime */
 
157
        failure("t=0x%08x now=0x%08x=%d", t, now, now);
 
158
        assert(t <= now); /* File wasn't created in future. */
 
159
        failure("t=0x%08x now - 2=0x%08x = %d", t, now - 2, now - 2);
 
160
        assert(t >= now - 2); /* File was created w/in last 2 secs. */
 
161
        failure("newc format stores body only with last appearance of a link\n"
 
162
            "       first appearance should be empty, so this file size\n"
 
163
            "       field should be zero");
 
164
        assertEqualInt(0, from_hex(e + 54, 8)); /* File size */
 
165
        fs = from_hex(e + 54, 8);
 
166
        fs += PAD(fs, 4);
 
167
        devmajor = from_hex(e + 62, 8); /* devmajor */
 
168
        devminor = from_hex(e + 70, 8); /* devminor */
 
169
        assert(is_hex(e + 78, 8)); /* rdevmajor */
 
170
        assert(is_hex(e + 86, 8)); /* rdevminor */
 
171
        assertEqualMem(e + 94, "00000006", 8); /* Name size */
 
172
        ns = from_hex(e + 94, 8);
 
173
        ns += PAD(ns + 2, 4);
 
174
        assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
 
175
        assertEqualMem(e + 110, "file1\0", 6); /* Name contents */
 
176
        /* Since there's another link, no file contents here. */
 
177
        /* But add in file size so that an error here doesn't cascade. */
 
178
        e += 110 + fs + ns;
 
179
 
 
180
        if (canSymlink()) {
 
181
                /* "symlink" pointing to "file1" */
 
182
                assert(is_hex(e, 110));
 
183
                assertEqualMem(e + 0, "070701", 6); /* Magic */
 
184
                assert(is_hex(e + 6, 8)); /* ino */
 
185
                assertEqualInt(0xa1ff, from_hex(e + 14, 8)); /* Mode */
 
186
                assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
 
187
                assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
 
188
                assertEqualMem(e + 38, "00000001", 8); /* nlink */
 
189
                t2 = from_hex(e + 46, 8); /* mtime */
 
190
                failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
 
191
                assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
 
192
                assertEqualMem(e + 54, "00000005", 8); /* File size */
 
193
                fs = from_hex(e + 54, 8);
 
194
                fs += PAD(fs, 4);
 
195
                assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
 
196
                assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
 
197
                assert(is_hex(e + 78, 8)); /* rdevmajor */
 
198
                assert(is_hex(e + 86, 8)); /* rdevminor */
 
199
                assertEqualMem(e + 94, "00000008", 8); /* Name size */
 
200
                ns = from_hex(e + 94, 8);
 
201
                ns += PAD(ns + 2, 4);
 
202
                assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
 
203
                assertEqualMem(e + 110, "symlink\0\0\0", 10); /* Name contents */
 
204
                assertEqualMem(e + 110 + ns, "file1\0\0\0", 8); /* symlink target */
 
205
                e += 110 + fs + ns;
 
206
        }
 
207
 
 
208
        /* "dir" */
 
209
        assert(is_hex(e, 110));
 
210
        assertEqualMem(e + 0, "070701", 6); /* Magic */
 
211
        assert(is_hex(e + 6, 8)); /* ino */
 
212
#if defined(_WIN32) && !defined(__CYGWIN__)
 
213
        /* Group members bits and others bits do not work. */
 
214
        assertEqualInt(0x41c0, from_hex(e + 14, 8) & 0xffc0); /* Mode */
 
215
#else
 
216
        /* Mode: sgid bit sometimes propagates from parent dirs, ignore it. */
 
217
        assertEqualInt(040775, from_hex(e + 14, 8) & ~02000);
 
218
#endif
 
219
        assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
 
220
        assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
 
221
#ifndef NLINKS_INACCURATE_FOR_DIRS
 
222
        assertEqualMem(e + 38, "00000002", 8); /* nlink */
 
223
#endif
 
224
        t2 = from_hex(e + 46, 8); /* mtime */
 
225
        failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
 
226
        assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
 
227
        assertEqualMem(e + 54, "00000000", 8); /* File size */
 
228
        fs = from_hex(e + 54, 8);
 
229
        fs += PAD(fs, 4);
 
230
        assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
 
231
        assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
 
232
        assert(is_hex(e + 78, 8)); /* rdevmajor */
 
233
        assert(is_hex(e + 86, 8)); /* rdevminor */
 
234
        assertEqualMem(e + 94, "00000004", 8); /* Name size */
 
235
        ns = from_hex(e + 94, 8);
 
236
        ns += PAD(ns + 2, 4);
 
237
        assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
 
238
        assertEqualMem(e + 110, "dir\0\0\0", 6); /* Name contents */
 
239
        e += 110 + fs + ns;
 
240
 
 
241
        /* Hardlink identical to "file1" */
 
242
        /* Since we only wrote two of the three links to this
 
243
         * file, this link should get deferred by the hardlink logic. */
 
244
        assert(is_hex(e, 110));
 
245
        assertEqualMem(e + 0, "070701", 6); /* Magic */
 
246
        failure("If these aren't the same, then the hardlink detection failed to match them.");
 
247
        assertEqualInt(ino, from_hex(e + 6, 8)); /* ino */
 
248
#if defined(_WIN32) && !defined(__CYGWIN__)
 
249
        /* Group members bits and others bits do not work. */ 
 
250
        assertEqualInt(0x8180, from_hex(e + 14, 8) & 0xffc0); /* Mode */
 
251
#else
 
252
        assertEqualInt(0x81a4, from_hex(e + 14, 8)); /* Mode */
 
253
#endif
 
254
        assertEqualInt(from_hex(e + 22, 8), uid); /* uid */
 
255
        assertEqualInt(gid, from_hex(e + 30, 8)); /* gid */
 
256
        assertEqualMem(e + 38, "00000003", 8); /* nlink */
 
257
        t2 = from_hex(e + 46, 8); /* mtime */
 
258
        failure("First entry created at t=0x%08x this entry created at t2=0x%08x", t, t2);
 
259
        assert(t2 == t || t2 == t + 1); /* Almost same as first entry. */
 
260
        assertEqualInt(10, from_hex(e + 54, 8)); /* File size */
 
261
        fs = from_hex(e + 54, 8);
 
262
        fs += PAD(fs, 4);
 
263
        assertEqualInt(devmajor, from_hex(e + 62, 8)); /* devmajor */
 
264
        assertEqualInt(devminor, from_hex(e + 70, 8)); /* devminor */
 
265
        assert(is_hex(e + 78, 8)); /* rdevmajor */
 
266
        assert(is_hex(e + 86, 8)); /* rdevminor */
 
267
        assertEqualMem(e + 94, "00000009", 8); /* Name size */
 
268
        ns = from_hex(e + 94, 8);
 
269
        ns += PAD(ns + 2, 4);
 
270
        assertEqualInt(0, from_hex(e + 102, 8)); /* check field */
 
271
        assertEqualMem(e + 110, "hardlink\0\0", 10); /* Name contents */
 
272
        assertEqualMem(e + 110 + ns, "1234567890\0\0", 12); /* File contents */
 
273
        e += 110 + ns + fs;
 
274
 
 
275
        /* Last entry is end-of-archive marker. */
 
276
        assert(is_hex(e, 110));
 
277
        assertEqualMem(e + 0, "070701", 6); /* Magic */
 
278
        assertEqualMem(e + 8, "00000000", 8); /* ino */
 
279
        assertEqualMem(e + 14, "00000000", 8); /* mode */
 
280
        assertEqualMem(e + 22, "00000000", 8); /* uid */
 
281
        assertEqualMem(e + 30, "00000000", 8); /* gid */
 
282
        assertEqualMem(e + 38, "00000001", 8); /* nlink */
 
283
        assertEqualMem(e + 46, "00000000", 8); /* mtime */
 
284
        assertEqualMem(e + 54, "00000000", 8); /* size */
 
285
        assertEqualMem(e + 62, "00000000", 8); /* devmajor */
 
286
        assertEqualMem(e + 70, "00000000", 8); /* devminor */
 
287
        assertEqualMem(e + 78, "00000000", 8); /* rdevmajor */
 
288
        assertEqualMem(e + 86, "00000000", 8); /* rdevminor */
 
289
        assertEqualInt(11, from_hex(e + 94, 8)); /* name size */
 
290
        assertEqualMem(e + 102, "00000000", 8); /* check field */
 
291
        assertEqualMem(e + 110, "TRAILER!!!\0\0", 12); /* Name */
 
292
 
 
293
        free(p);
 
294
}