Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5e73a60

Browse files
committed
Switch pg_dump to use compression specifications
Compression specifications are currently used by pg_basebackup and pg_receivewal, and are able to let the user control in an extended way the method and level of compression used. As an effect of this commit, pg_dump's -Z/--compress is now able to use more than just an integer, as of the grammar "method[:detail]". The method can be either "none" or "gzip", and can optionally take a detail string. If the detail string is only an integer, it defines the compression level. A comma-separated list of keywords can also be used method allows for more options, the only keyword supported now is "level". The change is backward-compatible, hence specifying only an integer leads to no compression for a level of 0 and gzip compression when the level is greater than 0. Most of the code changes are straight-forward, as pg_dump was relying on an integer tracking the compression level to check for gzip or no compression. These are changed to use a compression specification and the algorithm stored in it. As of this change, note that the dump format is not bumped because there is no need yet to track the compression algorithm in the TOC entries. Hence, we still rely on the compression level to make the difference when reading them. This will be mandatory once a new compression method is added, though. In order to keep the code simpler when parsing the compression specification, the code is changed so as pg_dump now fails hard when using gzip on -Z/--compress without its support compiled, rather than enforcing no compression without the user knowing about it except through a warning. Like before this commit, archive and custom formats are compressed by default when the code is compiled with gzip, and left uncompressed without gzip. Author: Georgios Kokolatos Reviewed-by: Michael Paquier Discussion: https://postgr.es/m/O4mutIrCES8ZhlXJiMvzsivT7ztAMja2lkdL1LJx6O5f22I2W8PBIeLKz7mDLwxHoibcnRAYJXm1pH4tyUNC4a8eDzLn22a6Pb1S74Niexg=@pm.me
1 parent edf12e7 commit 5e73a60

14 files changed

+260
-160
lines changed

doc/src/sgml/ref/pg_dump.sgml

+30-8
Original file line numberDiff line numberDiff line change
@@ -644,17 +644,39 @@ PostgreSQL documentation
644644
</varlistentry>
645645

646646
<varlistentry>
647-
<term><option>-Z <replaceable class="parameter">0..9</replaceable></option></term>
648-
<term><option>--compress=<replaceable class="parameter">0..9</replaceable></option></term>
647+
<term><option>-Z <replaceable class="parameter">level</replaceable></option></term>
648+
<term><option>-Z <replaceable class="parameter">method</replaceable></option>[:<replaceable>detail</replaceable>]</term>
649+
<term><option>--compress=<replaceable class="parameter">level</replaceable></option></term>
650+
<term><option>--compress=<replaceable class="parameter">method</replaceable></option>[:<replaceable>detail</replaceable>]</term>
649651
<listitem>
650652
<para>
651-
Specify the compression level to use. Zero means no compression.
653+
Specify the compression method and/or the compression level to use.
654+
The compression method can be set to <literal>gzip</literal> or
655+
<literal>none</literal> for no compression.
656+
A compression detail string can optionally be specified. If the
657+
detail string is an integer, it specifies the compression level.
658+
Otherwise, it should be a comma-separated list of items, each of the
659+
form <literal>keyword</literal> or <literal>keyword=value</literal>.
660+
Currently, the only supported keyword is <literal>level</literal>.
661+
</para>
662+
663+
<para>
664+
If no compression level is specified, the default compression
665+
level will be used. If only a level is specified without mentioning
666+
an algorithm, <literal>gzip</literal> compression will be used if
667+
the level is greater than <literal>0</literal>, and no compression
668+
will be used if the level is <literal>0</literal>.
669+
</para>
670+
671+
<para>
652672
For the custom and directory archive formats, this specifies compression of
653-
individual table-data segments, and the default is to compress
654-
at a moderate level.
655-
For plain text output, setting a nonzero compression level causes
656-
the entire output file to be compressed, as though it had been
657-
fed through <application>gzip</application>; but the default is not to compress.
673+
individual table-data segments, and the default is to compress using
674+
<literal>gzip</literal> at a moderate level. For plain text output,
675+
setting a nonzero compression level causes the entire output file to be compressed,
676+
as though it had been fed through <application>gzip</application>; but the default
677+
is not to compress.
678+
</para>
679+
<para>
658680
The tar archive format currently does not support compression at all.
659681
</para>
660682
</listitem>

src/bin/pg_dump/compress_io.c

+44-63
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
/* typedef appears in compress_io.h */
6565
struct CompressorState
6666
{
67-
CompressionAlgorithm comprAlg;
67+
pg_compress_specification compression_spec;
6868
WriteFunc writeF;
6969

7070
#ifdef HAVE_LIBZ
@@ -74,9 +74,6 @@ struct CompressorState
7474
#endif
7575
};
7676

77-
static void ParseCompressionOption(int compression, CompressionAlgorithm *alg,
78-
int *level);
79-
8077
/* Routines that support zlib compressed data I/O */
8178
#ifdef HAVE_LIBZ
8279
static void InitCompressorZlib(CompressorState *cs, int level);
@@ -93,57 +90,30 @@ static void ReadDataFromArchiveNone(ArchiveHandle *AH, ReadFunc readF);
9390
static void WriteDataToArchiveNone(ArchiveHandle *AH, CompressorState *cs,
9491
const char *data, size_t dLen);
9592

96-
/*
97-
* Interprets a numeric 'compression' value. The algorithm implied by the
98-
* value (zlib or none at the moment), is returned in *alg, and the
99-
* zlib compression level in *level.
100-
*/
101-
static void
102-
ParseCompressionOption(int compression, CompressionAlgorithm *alg, int *level)
103-
{
104-
if (compression == Z_DEFAULT_COMPRESSION ||
105-
(compression > 0 && compression <= 9))
106-
*alg = COMPR_ALG_LIBZ;
107-
else if (compression == 0)
108-
*alg = COMPR_ALG_NONE;
109-
else
110-
{
111-
pg_fatal("invalid compression code: %d", compression);
112-
*alg = COMPR_ALG_NONE; /* keep compiler quiet */
113-
}
114-
115-
/* The level is just the passed-in value. */
116-
if (level)
117-
*level = compression;
118-
}
119-
12093
/* Public interface routines */
12194

12295
/* Allocate a new compressor */
12396
CompressorState *
124-
AllocateCompressor(int compression, WriteFunc writeF)
97+
AllocateCompressor(const pg_compress_specification compression_spec,
98+
WriteFunc writeF)
12599
{
126100
CompressorState *cs;
127-
CompressionAlgorithm alg;
128-
int level;
129-
130-
ParseCompressionOption(compression, &alg, &level);
131101

132102
#ifndef HAVE_LIBZ
133-
if (alg == COMPR_ALG_LIBZ)
103+
if (compression_spec.algorithm == PG_COMPRESSION_GZIP)
134104
pg_fatal("not built with zlib support");
135105
#endif
136106

137107
cs = (CompressorState *) pg_malloc0(sizeof(CompressorState));
138108
cs->writeF = writeF;
139-
cs->comprAlg = alg;
109+
cs->compression_spec = compression_spec;
140110

141111
/*
142112
* Perform compression algorithm specific initialization.
143113
*/
144114
#ifdef HAVE_LIBZ
145-
if (alg == COMPR_ALG_LIBZ)
146-
InitCompressorZlib(cs, level);
115+
if (cs->compression_spec.algorithm == PG_COMPRESSION_GZIP)
116+
InitCompressorZlib(cs, cs->compression_spec.level);
147117
#endif
148118

149119
return cs;
@@ -154,15 +124,12 @@ AllocateCompressor(int compression, WriteFunc writeF)
154124
* out with ahwrite().
155125
*/
156126
void
157-
ReadDataFromArchive(ArchiveHandle *AH, int compression, ReadFunc readF)
127+
ReadDataFromArchive(ArchiveHandle *AH, pg_compress_specification compression_spec,
128+
ReadFunc readF)
158129
{
159-
CompressionAlgorithm alg;
160-
161-
ParseCompressionOption(compression, &alg, NULL);
162-
163-
if (alg == COMPR_ALG_NONE)
130+
if (compression_spec.algorithm == PG_COMPRESSION_NONE)
164131
ReadDataFromArchiveNone(AH, readF);
165-
if (alg == COMPR_ALG_LIBZ)
132+
if (compression_spec.algorithm == PG_COMPRESSION_GZIP)
166133
{
167134
#ifdef HAVE_LIBZ
168135
ReadDataFromArchiveZlib(AH, readF);
@@ -179,18 +146,23 @@ void
179146
WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs,
180147
const void *data, size_t dLen)
181148
{
182-
switch (cs->comprAlg)
149+
switch (cs->compression_spec.algorithm)
183150
{
184-
case COMPR_ALG_LIBZ:
151+
case PG_COMPRESSION_GZIP:
185152
#ifdef HAVE_LIBZ
186153
WriteDataToArchiveZlib(AH, cs, data, dLen);
187154
#else
188155
pg_fatal("not built with zlib support");
189156
#endif
190157
break;
191-
case COMPR_ALG_NONE:
158+
case PG_COMPRESSION_NONE:
192159
WriteDataToArchiveNone(AH, cs, data, dLen);
193160
break;
161+
case PG_COMPRESSION_LZ4:
162+
/* fallthrough */
163+
case PG_COMPRESSION_ZSTD:
164+
pg_fatal("invalid compression method");
165+
break;
194166
}
195167
}
196168

@@ -201,7 +173,7 @@ void
201173
EndCompressor(ArchiveHandle *AH, CompressorState *cs)
202174
{
203175
#ifdef HAVE_LIBZ
204-
if (cs->comprAlg == COMPR_ALG_LIBZ)
176+
if (cs->compression_spec.algorithm == PG_COMPRESSION_GZIP)
205177
EndCompressorZlib(AH, cs);
206178
#endif
207179
free(cs);
@@ -453,20 +425,27 @@ cfopen_read(const char *path, const char *mode)
453425
{
454426
cfp *fp;
455427

428+
pg_compress_specification compression_spec = {0};
429+
456430
#ifdef HAVE_LIBZ
457431
if (hasSuffix(path, ".gz"))
458-
fp = cfopen(path, mode, 1);
432+
{
433+
compression_spec.algorithm = PG_COMPRESSION_GZIP;
434+
fp = cfopen(path, mode, compression_spec);
435+
}
459436
else
460437
#endif
461438
{
462-
fp = cfopen(path, mode, 0);
439+
compression_spec.algorithm = PG_COMPRESSION_NONE;
440+
fp = cfopen(path, mode, compression_spec);
463441
#ifdef HAVE_LIBZ
464442
if (fp == NULL)
465443
{
466444
char *fname;
467445

468446
fname = psprintf("%s.gz", path);
469-
fp = cfopen(fname, mode, 1);
447+
compression_spec.algorithm = PG_COMPRESSION_GZIP;
448+
fp = cfopen(fname, mode, compression_spec);
470449
free_keep_errno(fname);
471450
}
472451
#endif
@@ -479,26 +458,27 @@ cfopen_read(const char *path, const char *mode)
479458
* be a filemode as accepted by fopen() and gzopen() that indicates writing
480459
* ("w", "wb", "a", or "ab").
481460
*
482-
* If 'compression' is non-zero, a gzip compressed stream is opened, and
483-
* 'compression' indicates the compression level used. The ".gz" suffix
484-
* is automatically added to 'path' in that case.
461+
* If 'compression_spec.algorithm' is GZIP, a gzip compressed stream is opened,
462+
* and 'compression_spec.level' used. The ".gz" suffix is automatically added to
463+
* 'path' in that case.
485464
*
486465
* On failure, return NULL with an error code in errno.
487466
*/
488467
cfp *
489-
cfopen_write(const char *path, const char *mode, int compression)
468+
cfopen_write(const char *path, const char *mode,
469+
const pg_compress_specification compression_spec)
490470
{
491471
cfp *fp;
492472

493-
if (compression == 0)
494-
fp = cfopen(path, mode, 0);
473+
if (compression_spec.algorithm == PG_COMPRESSION_NONE)
474+
fp = cfopen(path, mode, compression_spec);
495475
else
496476
{
497477
#ifdef HAVE_LIBZ
498478
char *fname;
499479

500480
fname = psprintf("%s.gz", path);
501-
fp = cfopen(fname, mode, compression);
481+
fp = cfopen(fname, mode, compression_spec);
502482
free_keep_errno(fname);
503483
#else
504484
pg_fatal("not built with zlib support");
@@ -509,26 +489,27 @@ cfopen_write(const char *path, const char *mode, int compression)
509489
}
510490

511491
/*
512-
* Opens file 'path' in 'mode'. If 'compression' is non-zero, the file
492+
* Opens file 'path' in 'mode'. If compression is GZIP, the file
513493
* is opened with libz gzopen(), otherwise with plain fopen().
514494
*
515495
* On failure, return NULL with an error code in errno.
516496
*/
517497
cfp *
518-
cfopen(const char *path, const char *mode, int compression)
498+
cfopen(const char *path, const char *mode,
499+
const pg_compress_specification compression_spec)
519500
{
520501
cfp *fp = pg_malloc(sizeof(cfp));
521502

522-
if (compression != 0)
503+
if (compression_spec.algorithm == PG_COMPRESSION_GZIP)
523504
{
524505
#ifdef HAVE_LIBZ
525-
if (compression != Z_DEFAULT_COMPRESSION)
506+
if (compression_spec.level != Z_DEFAULT_COMPRESSION)
526507
{
527508
/* user has specified a compression level, so tell zlib to use it */
528509
char mode_compression[32];
529510

530511
snprintf(mode_compression, sizeof(mode_compression), "%s%d",
531-
mode, compression);
512+
mode, compression_spec.level);
532513
fp->compressedfp = gzopen(path, mode_compression);
533514
}
534515
else

src/bin/pg_dump/compress_io.h

+10-10
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@
2121
#define ZLIB_OUT_SIZE 4096
2222
#define ZLIB_IN_SIZE 4096
2323

24-
typedef enum
25-
{
26-
COMPR_ALG_NONE,
27-
COMPR_ALG_LIBZ
28-
} CompressionAlgorithm;
29-
3024
/* Prototype for callback function to WriteDataToArchive() */
3125
typedef void (*WriteFunc) (ArchiveHandle *AH, const char *buf, size_t len);
3226

@@ -46,8 +40,10 @@ typedef size_t (*ReadFunc) (ArchiveHandle *AH, char **buf, size_t *buflen);
4640
/* struct definition appears in compress_io.c */
4741
typedef struct CompressorState CompressorState;
4842

49-
extern CompressorState *AllocateCompressor(int compression, WriteFunc writeF);
50-
extern void ReadDataFromArchive(ArchiveHandle *AH, int compression,
43+
extern CompressorState *AllocateCompressor(const pg_compress_specification compression_spec,
44+
WriteFunc writeF);
45+
extern void ReadDataFromArchive(ArchiveHandle *AH,
46+
const pg_compress_specification compression_spec,
5147
ReadFunc readF);
5248
extern void WriteDataToArchive(ArchiveHandle *AH, CompressorState *cs,
5349
const void *data, size_t dLen);
@@ -56,9 +52,13 @@ extern void EndCompressor(ArchiveHandle *AH, CompressorState *cs);
5652

5753
typedef struct cfp cfp;
5854

59-
extern cfp *cfopen(const char *path, const char *mode, int compression);
55+
extern cfp *cfopen(const char *path, const char *mode,
56+
const pg_compress_specification compression_spec);
57+
extern cfp *cfdopen(int fd, const char *mode,
58+
pg_compress_specification compression_spec);
6059
extern cfp *cfopen_read(const char *path, const char *mode);
61-
extern cfp *cfopen_write(const char *path, const char *mode, int compression);
60+
extern cfp *cfopen_write(const char *path, const char *mode,
61+
const pg_compress_specification compression_spec);
6262
extern int cfread(void *ptr, int size, cfp *fp);
6363
extern int cfwrite(const void *ptr, int size, cfp *fp);
6464
extern int cfgetc(cfp *fp);

src/bin/pg_dump/pg_backup.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#ifndef PG_BACKUP_H
2424
#define PG_BACKUP_H
2525

26+
#include "common/compression.h"
2627
#include "fe_utils/simple_list.h"
2728
#include "libpq-fe.h"
2829

@@ -143,7 +144,8 @@ typedef struct _restoreOptions
143144

144145
int noDataForFailedTables;
145146
int exit_on_error;
146-
int compression;
147+
pg_compress_specification compression_spec; /* Specification for
148+
* compression */
147149
int suppressDumpWarnings; /* Suppress output of WARNING entries
148150
* to stderr */
149151
bool single_txn;
@@ -303,7 +305,8 @@ extern Archive *OpenArchive(const char *FileSpec, const ArchiveFormat fmt);
303305

304306
/* Create a new archive */
305307
extern Archive *CreateArchive(const char *FileSpec, const ArchiveFormat fmt,
306-
const int compression, bool dosync, ArchiveMode mode,
308+
const pg_compress_specification compression_spec,
309+
bool dosync, ArchiveMode mode,
307310
SetupWorkerPtrType setupDumpWorker);
308311

309312
/* The --list option */

0 commit comments

Comments
 (0)