~tplavcic/percona-xtrabackup/bld-26-2.0

« back to all changes in this revision

Viewing changes to src/libarchive/examples/minitar/minitar.c

  • Committer: Alexey Kopytov
  • Date: 2012-02-10 20:05:56 UTC
  • 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
 * This file is in the public domain.
 
3
 * Do with it as you will.
 
4
 */
 
5
 
 
6
/*-
 
7
 * This is a compact "tar" program whose primary goal is small size.
 
8
 * Statically linked, it can be very small indeed.  This serves a number
 
9
 * of goals:
 
10
 *   o a testbed for libarchive (to check for link pollution),
 
11
 *   o a useful tool for space-constrained systems (boot floppies, etc),
 
12
 *   o a place to experiment with new implementation ideas for bsdtar,
 
13
 *   o a small program to demonstrate libarchive usage.
 
14
 *
 
15
 * Use the following macros to suppress features:
 
16
 *   NO_BZIP2 - Implies NO_BZIP2_CREATE and NO_BZIP2_EXTRACT
 
17
 *   NO_BZIP2_CREATE - Suppress bzip2 compression support.
 
18
 *   NO_BZIP2_EXTRACT - Suppress bzip2 auto-detection and decompression.
 
19
 *   NO_COMPRESS - Implies NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT
 
20
 *   NO_COMPRESS_CREATE - Suppress compress(1) compression support
 
21
 *   NO_COMPRESS_EXTRACT - Suppress compress(1) auto-detect and decompression.
 
22
 *   NO_CREATE - Suppress all archive creation support.
 
23
 *   NO_CPIO_EXTRACT - Suppress auto-detect and dearchiving of cpio archives.
 
24
 *   NO_GZIP - Implies NO_GZIP_CREATE and NO_GZIP_EXTRACT
 
25
 *   NO_GZIP_CREATE - Suppress gzip compression support.
 
26
 *   NO_GZIP_EXTRACT - Suppress gzip auto-detection and decompression.
 
27
 *   NO_LOOKUP - Try to avoid getpw/getgr routines, which can be very large
 
28
 *   NO_TAR_EXTRACT - Suppress tar extraction
 
29
 *
 
30
 * With all of the above macros defined (except NO_TAR_EXTRACT), you
 
31
 * get a very small program that can recognize and extract essentially
 
32
 * any uncompressed tar archive.  On FreeBSD 5.1, this minimal program
 
33
 * is under 64k, statically linked, which compares rather favorably to
 
34
 *         main(){printf("hello, world");}
 
35
 * which is over 60k statically linked on the same operating system.
 
36
 * Without any of the above macros, you get a static executable of
 
37
 * about 180k with a lot of very sophisticated modern features.
 
38
 * Obviously, it's trivial to add support for ISO, Zip, mtree,
 
39
 * lzma/xz, etc.  Just fill in the appropriate setup calls.
 
40
 */
 
41
 
 
42
#include <sys/types.h>
 
43
__FBSDID("$FreeBSD$");
 
44
 
 
45
#include <sys/stat.h>
 
46
 
 
47
#include <archive.h>
 
48
#include <archive_entry.h>
 
49
#include <fcntl.h>
 
50
#include <stdio.h>
 
51
#include <stdlib.h>
 
52
#include <string.h>
 
53
#include <unistd.h>
 
54
 
 
55
#ifndef NO_CREATE
 
56
#include "tree.h"
 
57
#endif
 
58
 
 
59
/*
 
60
 * NO_CREATE implies NO_BZIP2_CREATE and NO_GZIP_CREATE and NO_COMPRESS_CREATE.
 
61
 */
 
62
#ifdef NO_CREATE
 
63
#undef NO_BZIP2_CREATE
 
64
#define NO_BZIP2_CREATE
 
65
#undef NO_COMPRESS_CREATE
 
66
#define NO_COMPRESS_CREATE
 
67
#undef NO_GZIP_CREATE
 
68
#define NO_GZIP_CREATE
 
69
#endif
 
70
 
 
71
/*
 
72
 * The combination of NO_BZIP2_CREATE and NO_BZIP2_EXTRACT is
 
73
 * equivalent to NO_BZIP2.
 
74
 */
 
75
#ifdef NO_BZIP2_CREATE
 
76
#ifdef NO_BZIP2_EXTRACT
 
77
#undef NO_BZIP2
 
78
#define NO_BZIP2
 
79
#endif
 
80
#endif
 
81
 
 
82
#ifdef NO_BZIP2
 
83
#undef NO_BZIP2_EXTRACT
 
84
#define NO_BZIP2_EXTRACT
 
85
#undef NO_BZIP2_CREATE
 
86
#define NO_BZIP2_CREATE
 
87
#endif
 
88
 
 
89
/*
 
90
 * The combination of NO_COMPRESS_CREATE and NO_COMPRESS_EXTRACT is
 
91
 * equivalent to NO_COMPRESS.
 
92
 */
 
93
#ifdef NO_COMPRESS_CREATE
 
94
#ifdef NO_COMPRESS_EXTRACT
 
95
#undef NO_COMPRESS
 
96
#define NO_COMPRESS
 
97
#endif
 
98
#endif
 
99
 
 
100
#ifdef NO_COMPRESS
 
101
#undef NO_COMPRESS_EXTRACT
 
102
#define NO_COMPRESS_EXTRACT
 
103
#undef NO_COMPRESS_CREATE
 
104
#define NO_COMPRESS_CREATE
 
105
#endif
 
106
 
 
107
/*
 
108
 * The combination of NO_GZIP_CREATE and NO_GZIP_EXTRACT is
 
109
 * equivalent to NO_GZIP.
 
110
 */
 
111
#ifdef NO_GZIP_CREATE
 
112
#ifdef NO_GZIP_EXTRACT
 
113
#undef NO_GZIP
 
114
#define NO_GZIP
 
115
#endif
 
116
#endif
 
117
 
 
118
#ifdef NO_GZIP
 
119
#undef NO_GZIP_EXTRACT
 
120
#define NO_GZIP_EXTRACT
 
121
#undef NO_GZIP_CREATE
 
122
#define NO_GZIP_CREATE
 
123
#endif
 
124
 
 
125
#ifndef NO_CREATE
 
126
static void     create(const char *filename, int compress, const char **argv);
 
127
#endif
 
128
static void     errmsg(const char *);
 
129
static void     extract(const char *filename, int do_extract, int flags);
 
130
static int      copy_data(struct archive *, struct archive *);
 
131
static void     msg(const char *);
 
132
static void     usage(void);
 
133
 
 
134
static int verbose = 0;
 
135
 
 
136
int
 
137
main(int argc, const char **argv)
 
138
{
 
139
        const char *filename = NULL;
 
140
        int compress, flags, mode, opt;
 
141
 
 
142
        (void)argc;
 
143
        mode = 'x';
 
144
        verbose = 0;
 
145
        compress = '\0';
 
146
        flags = ARCHIVE_EXTRACT_TIME;
 
147
 
 
148
        /* Among other sins, getopt(3) pulls in printf(3). */
 
149
        while (*++argv != NULL && **argv == '-') {
 
150
                const char *p = *argv + 1;
 
151
 
 
152
                while ((opt = *p++) != '\0') {
 
153
                        switch (opt) {
 
154
#ifndef NO_CREATE
 
155
                        case 'c':
 
156
                                mode = opt;
 
157
                                break;
 
158
#endif
 
159
                        case 'f':
 
160
                                if (*p != '\0')
 
161
                                        filename = p;
 
162
                                else
 
163
                                        filename = *++argv;
 
164
                                p += strlen(p);
 
165
                                break;
 
166
#ifndef NO_BZIP2_CREATE
 
167
                        case 'j':
 
168
                                compress = opt;
 
169
                                break;
 
170
#endif
 
171
                        case 'p':
 
172
                                flags |= ARCHIVE_EXTRACT_PERM;
 
173
                                flags |= ARCHIVE_EXTRACT_ACL;
 
174
                                flags |= ARCHIVE_EXTRACT_FFLAGS;
 
175
                                break;
 
176
                        case 't':
 
177
                                mode = opt;
 
178
                                break;
 
179
                        case 'v':
 
180
                                verbose++;
 
181
                                break;
 
182
                        case 'x':
 
183
                                mode = opt;
 
184
                                break;
 
185
#ifndef NO_BZIP2_CREATE
 
186
                        case 'y':
 
187
                                compress = opt;
 
188
                                break;
 
189
#endif
 
190
#ifndef NO_COMPRESS_CREATE
 
191
                        case 'Z':
 
192
                                compress = opt;
 
193
                                break;
 
194
#endif
 
195
#ifndef NO_GZIP_CREATE
 
196
                        case 'z':
 
197
                                compress = opt;
 
198
                                break;
 
199
#endif
 
200
                        default:
 
201
                                usage();
 
202
                        }
 
203
                }
 
204
        }
 
205
 
 
206
        switch (mode) {
 
207
#ifndef NO_CREATE
 
208
        case 'c':
 
209
                create(filename, compress, argv);
 
210
                break;
 
211
#endif
 
212
        case 't':
 
213
                extract(filename, 0, flags);
 
214
                break;
 
215
        case 'x':
 
216
                extract(filename, 1, flags);
 
217
                break;
 
218
        }
 
219
 
 
220
        return (0);
 
221
}
 
222
 
 
223
 
 
224
#ifndef NO_CREATE
 
225
static char buff[16384];
 
226
 
 
227
static void
 
228
create(const char *filename, int compress, const char **argv)
 
229
{
 
230
        struct archive *a;
 
231
        struct archive *disk;
 
232
        struct archive_entry *entry;
 
233
        ssize_t len;
 
234
        int fd;
 
235
 
 
236
        a = archive_write_new();
 
237
        switch (compress) {
 
238
#ifndef NO_BZIP2_CREATE
 
239
        case 'j': case 'y':
 
240
                archive_write_set_compression_bzip2(a);
 
241
                break;
 
242
#endif
 
243
#ifndef NO_COMPRESS_CREATE
 
244
        case 'Z':
 
245
                archive_write_set_compression_compress(a);
 
246
                break;
 
247
#endif
 
248
#ifndef NO_GZIP_CREATE
 
249
        case 'z':
 
250
                archive_write_set_compression_gzip(a);
 
251
                break;
 
252
#endif
 
253
        default:
 
254
                archive_write_set_compression_none(a);
 
255
                break;
 
256
        }
 
257
        archive_write_set_format_ustar(a);
 
258
        if (strcmp(filename, "-") == 0)
 
259
                filename = NULL;
 
260
        archive_write_open_file(a, filename);
 
261
 
 
262
        disk = archive_read_disk_new();
 
263
#ifndef NO_LOOKUP
 
264
        archive_read_disk_set_standard_lookup(disk);
 
265
#endif
 
266
        while (*argv != NULL) {
 
267
                struct tree *t = tree_open(*argv);
 
268
                while (tree_next(t)) {
 
269
                        entry = archive_entry_new();
 
270
                        archive_entry_set_pathname(entry, tree_current_path(t));
 
271
                        archive_read_disk_entry_from_file(disk, entry, -1,
 
272
                            tree_current_stat(t));
 
273
                        if (verbose) {
 
274
                                msg("a ");
 
275
                                msg(tree_current_path(t));
 
276
                        }
 
277
                        archive_write_header(a, entry);
 
278
                        fd = open(tree_current_access_path(t), O_RDONLY);
 
279
                        len = read(fd, buff, sizeof(buff));
 
280
                        while (len > 0) {
 
281
                                archive_write_data(a, buff, len);
 
282
                                len = read(fd, buff, sizeof(buff));
 
283
                        }
 
284
                        close(fd);
 
285
                        archive_entry_free(entry);
 
286
                        if (verbose)
 
287
                                msg("\n");
 
288
                }
 
289
                argv++;
 
290
        }
 
291
        archive_write_close(a);
 
292
        archive_write_finish(a);
 
293
}
 
294
#endif
 
295
 
 
296
static void
 
297
extract(const char *filename, int do_extract, int flags)
 
298
{
 
299
        struct archive *a;
 
300
        struct archive *ext;
 
301
        struct archive_entry *entry;
 
302
        int r;
 
303
 
 
304
        a = archive_read_new();
 
305
        ext = archive_write_disk_new();
 
306
        archive_write_disk_set_options(ext, flags);
 
307
#ifndef NO_BZIP2_EXTRACT
 
308
        archive_read_support_compression_bzip2(a);
 
309
#endif
 
310
#ifndef NO_GZIP_EXTRACT
 
311
        archive_read_support_compression_gzip(a);
 
312
#endif
 
313
#ifndef NO_COMPRESS_EXTRACT
 
314
        archive_read_support_compression_compress(a);
 
315
#endif
 
316
#ifndef NO_TAR_EXTRACT
 
317
        archive_read_support_format_tar(a);
 
318
#endif
 
319
#ifndef NO_CPIO_EXTRACT
 
320
        archive_read_support_format_cpio(a);
 
321
#endif
 
322
#ifndef NO_LOOKUP
 
323
        archive_write_disk_set_standard_lookup(ext);
 
324
#endif
 
325
        if (filename != NULL && strcmp(filename, "-") == 0)
 
326
                filename = NULL;
 
327
        if ((r = archive_read_open_file(a, filename, 10240))) {
 
328
                errmsg(archive_error_string(a));
 
329
                errmsg("\n");
 
330
                exit(r);
 
331
        }
 
332
        for (;;) {
 
333
                r = archive_read_next_header(a, &entry);
 
334
                if (r == ARCHIVE_EOF)
 
335
                        break;
 
336
                if (r != ARCHIVE_OK) {
 
337
                        errmsg(archive_error_string(a));
 
338
                        errmsg("\n");
 
339
                        exit(1);
 
340
                }
 
341
                if (verbose && do_extract)
 
342
                        msg("x ");
 
343
                if (verbose || !do_extract)
 
344
                        msg(archive_entry_pathname(entry));
 
345
                if (do_extract) {
 
346
                        r = archive_write_header(ext, entry);
 
347
                        if (r != ARCHIVE_OK)
 
348
                                errmsg(archive_error_string(a));
 
349
                        else
 
350
                                copy_data(a, ext);
 
351
                }
 
352
                if (verbose || !do_extract)
 
353
                        msg("\n");
 
354
        }
 
355
        archive_read_close(a);
 
356
        archive_read_finish(a);
 
357
        exit(0);
 
358
}
 
359
 
 
360
static int
 
361
copy_data(struct archive *ar, struct archive *aw)
 
362
{
 
363
        int r;
 
364
        const void *buff;
 
365
        size_t size;
 
366
        off_t offset;
 
367
 
 
368
        for (;;) {
 
369
                r = archive_read_data_block(ar, &buff, &size, &offset);
 
370
                if (r == ARCHIVE_EOF) {
 
371
                        errmsg(archive_error_string(ar));
 
372
                        return (ARCHIVE_OK);
 
373
                }
 
374
                if (r != ARCHIVE_OK)
 
375
                        return (r);
 
376
                r = archive_write_data_block(aw, buff, size, offset);
 
377
                if (r != ARCHIVE_OK) {
 
378
                        errmsg(archive_error_string(ar));
 
379
                        return (r);
 
380
                }
 
381
        }
 
382
}
 
383
 
 
384
static void
 
385
msg(const char *m)
 
386
{
 
387
        write(1, m, strlen(m));
 
388
}
 
389
 
 
390
static void
 
391
errmsg(const char *m)
 
392
{
 
393
        write(2, m, strlen(m));
 
394
}
 
395
 
 
396
static void
 
397
usage(void)
 
398
{
 
399
/* Many program options depend on compile options. */
 
400
        const char *m = "Usage: minitar [-"
 
401
#ifndef NO_CREATE
 
402
            "c"
 
403
#endif
 
404
#ifndef NO_BZIP2
 
405
            "j"
 
406
#endif
 
407
            "tvx"
 
408
#ifndef NO_BZIP2
 
409
            "y"
 
410
#endif
 
411
#ifndef NO_COMPRESS
 
412
            "Z"
 
413
#endif
 
414
#ifndef NO_GZIP
 
415
            "z"
 
416
#endif
 
417
            "] [-f file] [file]\n";
 
418
 
 
419
        errmsg(m);
 
420
        exit(1);
 
421
}