19
19
#include <signal.h>
20
20
#include <sys/stat.h>
21
21
#include <unistd.h>
22
+ #ifdef HAVE_LIBZ
23
+ #include <zlib.h>
24
+ #endif
22
25
23
26
#include "access/xlog_internal.h"
24
27
#include "common/file_perm.h"
@@ -45,6 +48,7 @@ static bool do_drop_slot = false;
45
48
static bool do_sync = true;
46
49
static bool synchronous = false;
47
50
static char * replication_slot = NULL ;
51
+ static WalCompressionMethod compression_method = COMPRESSION_NONE ;
48
52
static XLogRecPtr endpos = InvalidXLogRecPtr ;
49
53
50
54
@@ -63,16 +67,6 @@ disconnect_atexit(void)
63
67
PQfinish (conn );
64
68
}
65
69
66
- /* Routines to evaluate segment file format */
67
- #define IsCompressXLogFileName (fname ) \
68
- (strlen(fname) == XLOG_FNAME_LEN + strlen(".gz") && \
69
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
70
- strcmp((fname) + XLOG_FNAME_LEN, ".gz") == 0)
71
- #define IsPartialCompressXLogFileName (fname ) \
72
- (strlen(fname) == XLOG_FNAME_LEN + strlen(".gz.partial") && \
73
- strspn(fname, "0123456789ABCDEF") == XLOG_FNAME_LEN && \
74
- strcmp((fname) + XLOG_FNAME_LEN, ".gz.partial") == 0)
75
-
76
70
static void
77
71
usage (void )
78
72
{
@@ -92,7 +86,9 @@ usage(void)
92
86
printf (_ (" --synchronous flush write-ahead log immediately after writing\n" ));
93
87
printf (_ (" -v, --verbose output verbose messages\n" ));
94
88
printf (_ (" -V, --version output version information, then exit\n" ));
95
- printf (_ (" -Z, --compress=0-9 compress logs with given compression level\n" ));
89
+ printf (_ (" --compression-method=METHOD\n"
90
+ " method to compress logs\n" ));
91
+ printf (_ (" -Z, --compress=1-9 compress logs with given compression level\n" ));
96
92
printf (_ (" -?, --help show this help, then exit\n" ));
97
93
printf (_ ("\nConnection options:\n" ));
98
94
printf (_ (" -d, --dbname=CONNSTR connection string\n" ));
@@ -108,6 +104,60 @@ usage(void)
108
104
printf (_ ("%s home page: <%s>\n" ), PACKAGE_NAME , PACKAGE_URL );
109
105
}
110
106
107
+ /*
108
+ * Check if the filename looks like a WAL file, letting caller know if this
109
+ * WAL segment is partial and/or compressed.
110
+ */
111
+ static bool
112
+ is_xlogfilename (const char * filename , bool * ispartial ,
113
+ WalCompressionMethod * wal_compression_method )
114
+ {
115
+ size_t fname_len = strlen (filename );
116
+ size_t xlog_pattern_len = strspn (filename , "0123456789ABCDEF" );
117
+
118
+ /* File does not look like a WAL file */
119
+ if (xlog_pattern_len != XLOG_FNAME_LEN )
120
+ return false;
121
+
122
+ /* File looks like a completed uncompressed WAL file */
123
+ if (fname_len == XLOG_FNAME_LEN )
124
+ {
125
+ * ispartial = false;
126
+ * wal_compression_method = COMPRESSION_NONE ;
127
+ return true;
128
+ }
129
+
130
+ /* File looks like a completed gzip-compressed WAL file */
131
+ if (fname_len == XLOG_FNAME_LEN + strlen (".gz" ) &&
132
+ strcmp (filename + XLOG_FNAME_LEN , ".gz" ) == 0 )
133
+ {
134
+ * ispartial = false;
135
+ * wal_compression_method = COMPRESSION_GZIP ;
136
+ return true;
137
+ }
138
+
139
+ /* File looks like a partial uncompressed WAL file */
140
+ if (fname_len == XLOG_FNAME_LEN + strlen (".partial" ) &&
141
+ strcmp (filename + XLOG_FNAME_LEN , ".partial" ) == 0 )
142
+ {
143
+ * ispartial = true;
144
+ * wal_compression_method = COMPRESSION_NONE ;
145
+ return true;
146
+ }
147
+
148
+ /* File looks like a partial gzip-compressed WAL file */
149
+ if (fname_len == XLOG_FNAME_LEN + strlen (".gz.partial" ) &&
150
+ strcmp (filename + XLOG_FNAME_LEN , ".gz.partial" ) == 0 )
151
+ {
152
+ * ispartial = true;
153
+ * wal_compression_method = COMPRESSION_GZIP ;
154
+ return true;
155
+ }
156
+
157
+ /* File does not look like something we know */
158
+ return false;
159
+ }
160
+
111
161
static bool
112
162
stop_streaming (XLogRecPtr xlogpos , uint32 timeline , bool segment_finished )
113
163
{
@@ -213,33 +263,11 @@ FindStreamingStart(uint32 *tli)
213
263
{
214
264
uint32 tli ;
215
265
XLogSegNo segno ;
266
+ WalCompressionMethod wal_compression_method ;
216
267
bool ispartial ;
217
- bool iscompress ;
218
268
219
- /*
220
- * Check if the filename looks like an xlog file, or a .partial file.
221
- */
222
- if (IsXLogFileName (dirent -> d_name ))
223
- {
224
- ispartial = false;
225
- iscompress = false;
226
- }
227
- else if (IsPartialXLogFileName (dirent -> d_name ))
228
- {
229
- ispartial = true;
230
- iscompress = false;
231
- }
232
- else if (IsCompressXLogFileName (dirent -> d_name ))
233
- {
234
- ispartial = false;
235
- iscompress = true;
236
- }
237
- else if (IsPartialCompressXLogFileName (dirent -> d_name ))
238
- {
239
- ispartial = true;
240
- iscompress = true;
241
- }
242
- else
269
+ if (!is_xlogfilename (dirent -> d_name ,
270
+ & ispartial , & wal_compression_method ))
243
271
continue ;
244
272
245
273
/*
@@ -250,14 +278,14 @@ FindStreamingStart(uint32 *tli)
250
278
/*
251
279
* Check that the segment has the right size, if it's supposed to be
252
280
* completed. For non-compressed segments just check the on-disk size
253
- * and see if it matches a completed segment. For compressed segments,
254
- * look at the last 4 bytes of the compressed file, which is where the
255
- * uncompressed size is located for gz files with a size lower than
256
- * 4GB, and then compare it to the size of a completed segment. The 4
257
- * last bytes correspond to the ISIZE member according to
281
+ * and see if it matches a completed segment. For gzip- compressed
282
+ * segments, look at the last 4 bytes of the compressed file, which is
283
+ * where the uncompressed size is located for files with a size lower
284
+ * than 4GB, and then compare it to the size of a completed segment.
285
+ * The 4 last bytes correspond to the ISIZE member according to
258
286
* http://www.zlib.org/rfc-gzip.html.
259
287
*/
260
- if (!ispartial && ! iscompress )
288
+ if (!ispartial && wal_compression_method == COMPRESSION_NONE )
261
289
{
262
290
struct stat statbuf ;
263
291
char fullpath [MAXPGPATH * 2 ];
@@ -276,7 +304,7 @@ FindStreamingStart(uint32 *tli)
276
304
continue ;
277
305
}
278
306
}
279
- else if (!ispartial && iscompress )
307
+ else if (!ispartial && wal_compression_method == COMPRESSION_GZIP )
280
308
{
281
309
int fd ;
282
310
char buf [4 ];
@@ -457,7 +485,9 @@ StreamLog(void)
457
485
stream .synchronous = synchronous ;
458
486
stream .do_sync = do_sync ;
459
487
stream .mark_done = false;
460
- stream .walmethod = CreateWalDirectoryMethod (basedir , compresslevel ,
488
+ stream .walmethod = CreateWalDirectoryMethod (basedir ,
489
+ compression_method ,
490
+ compresslevel ,
461
491
stream .do_sync );
462
492
stream .partial_suffix = ".partial" ;
463
493
stream .replication_slot = replication_slot ;
@@ -510,6 +540,7 @@ main(int argc, char **argv)
510
540
{"status-interval" , required_argument , NULL , 's' },
511
541
{"slot" , required_argument , NULL , 'S' },
512
542
{"verbose" , no_argument , NULL , 'v' },
543
+ {"compression-method" , required_argument , NULL , 'I' },
513
544
{"compress" , required_argument , NULL , 'Z' },
514
545
/* action */
515
546
{"create-slot" , no_argument , NULL , 1 },
@@ -595,8 +626,20 @@ main(int argc, char **argv)
595
626
case 'v' :
596
627
verbose ++ ;
597
628
break ;
629
+ case 'I' :
630
+ if (pg_strcasecmp (optarg , "gzip" ) == 0 )
631
+ compression_method = COMPRESSION_GZIP ;
632
+ else if (pg_strcasecmp (optarg , "none" ) == 0 )
633
+ compression_method = COMPRESSION_NONE ;
634
+ else
635
+ {
636
+ pg_log_error ("invalid value \"%s\" for option %s" ,
637
+ optarg , "--compress-method" );
638
+ exit (1 );
639
+ }
640
+ break ;
598
641
case 'Z' :
599
- if (!option_parse_int (optarg , "-Z/--compress" , 0 , 9 ,
642
+ if (!option_parse_int (optarg , "-Z/--compress" , 1 , 9 ,
600
643
& compresslevel ))
601
644
exit (1 );
602
645
break ;
@@ -676,13 +719,37 @@ main(int argc, char **argv)
676
719
exit (1 );
677
720
}
678
721
679
- #ifndef HAVE_LIBZ
680
- if (compresslevel != 0 )
722
+
723
+ /*
724
+ * Compression-related options.
725
+ */
726
+ switch (compression_method )
681
727
{
682
- pg_log_error ("this build does not support compression" );
683
- exit (1 );
684
- }
728
+ case COMPRESSION_NONE :
729
+ if (compresslevel != 0 )
730
+ {
731
+ pg_log_error ("cannot use --compress with --compression-method=%s" ,
732
+ "none" );
733
+ fprintf (stderr , _ ("Try \"%s --help\" for more information.\n" ),
734
+ progname );
735
+ exit (1 );
736
+ }
737
+ break ;
738
+ case COMPRESSION_GZIP :
739
+ #ifdef HAVE_LIBZ
740
+ if (compresslevel == 0 )
741
+ {
742
+ pg_log_info ("no value specified for --compress, switching to default" );
743
+ compresslevel = Z_DEFAULT_COMPRESSION ;
744
+ }
745
+ #else
746
+ pg_log_error ("this build does not support compression with %s" ,
747
+ "gzip" );
748
+ exit (1 );
685
749
#endif
750
+ break ;
751
+ }
752
+
686
753
687
754
/*
688
755
* Check existence of destination folder.
0 commit comments