Re: Add LZ4 compression in pg_dump
Justin Pryzby <pryzby@telsasoft.com>
On Wed, Mar 01, 2023 at 05:39:54PM +0100, Tomas Vondra wrote: > On 2/27/23 05:49, Justin Pryzby wrote: > > On Sat, Feb 25, 2023 at 08:05:53AM -0600, Justin Pryzby wrote: > >> On Fri, Feb 24, 2023 at 11:02:14PM -0600, Justin Pryzby wrote: > >>> I have some fixes (attached) and questions while polishing the patch for > >>> zstd compression. The fixes are small and could be integrated with the > >>> patch for zstd, but could be applied independently. > >> > >> One more - WriteDataToArchiveGzip() says: > > > > One more again. > > > > The LZ4 path is using non-streaming mode, which compresses each block > > without persistent state, giving poor compression for -Fc compared with > > -Fp. If the data is highly compressible, the difference can be orders > > of magnitude. > > > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -Z lz4 -Fp |wc -c > > 12351763 > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -Z lz4 -Fc |wc -c > > 21890708 > > > > That's not true for gzip: > > > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Z gzip -Fc |wc -c > > 2118869 > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Z gzip -Fp |wc -c > > 2115832 > > > > The function ought to at least use streaming mode, so each block/row > > isn't compressioned in isolation. 003 is a simple patch to use > > streaming mode, which improves the -Fc case: > > > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -Z lz4 -Fc |wc -c > > 15178283 > > > > However, that still flushes the compression buffer, writing a block > > header, for every row. With a single-column table, pg_dump -Fc -Z lz4 > > still outputs ~10% *more* data than with no compression at all. And > > that's for compressible data. > > > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Fc -Z lz4 |wc -c > > 12890296 > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Fc -Z none |wc -c > > 11890296 > > > > I think this should use the LZ4F API with frames, which are buffered to > > avoid outputting a header for every single row. The LZ4F format isn't > > compatible with the LZ4 format, so (unlike changing to the streaming > > API) that's not something we can change in a bugfix release. I consider > > this an Opened Item. > > > > With the LZ4F API in 004, -Fp and -Fc are essentially the same size > > (like gzip). (Oh, and the output is three times smaller, too.) > > > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Z lz4 -Fp |wc -c > > 4155448 > > $ ./src/bin/pg_dump/pg_dump -h /tmp postgres -t t1 -Z lz4 -Fc |wc -c > > 4156548 > > Thanks. Those are definitely interesting improvements/optimizations! > > I suggest we track them as a separate patch series - please add them to > the CF app (I guess you'll have to add them to 2023-07 at this point, > but we can get them in, I think). Thanks for looking. I'm not sure if I'm the best person to write/submit the patch to implement that for LZ4. Georgios, would you want to take on this change ? I think that needs to be changed for v16, since 1) LZ4F works so much better like this, and 2) we can't change it later without breaking compatibility of the dumpfiles by changing the header with another name other than "lz4". Also, I imagine we'd want to continue supporting the ability to *restore* a dumpfile using the old(current) format, which would be untestable code unless we also preserved the ability to write it somehow (like -Z lz4-old). One issue is that LZ4F_createCompressionContext() and LZ4F_compressBegin() ought to be called in InitCompressorLZ4(). It seems like it might *need* to be called there to avoid exactly the kind of issue that I reported with empty LOs with gzip. But InitCompressorLZ4() isn't currently passed the ArchiveHandle, so can't write the header. And LZ4CompressorState has a simple char *buf, and not an more elaborate data structure like zlib. You could work around that by keeping storing the "len" of the existing buffer, and flushing it in EndCompressorLZ4(), but that adds needless complexity to the Write and End functions. Maybe the Init function should be passed the AH. -- Justin
Commits
-
Advance input pointer when LZ4 compressing data
- 1a05c1d25299 16.0 landed
-
Null-terminate the output buffer of LZ4Stream_gets
- 3c18d90f8907 16.0 landed
-
Rework code defining default compression for dir/custom formats in pg_dump
- bedc1f0564d1 16.0 landed
-
pg_dump: Use only LZ4 frame format for compression
- 0070b66fef21 16.0 landed
-
Minor comment improvements for compress_lz4
- d0160ca11e31 16.0 landed
-
Unify buffer sizes in pg_dump compression API
- f081a48f9a91 16.0 landed
-
Improve type handling in pg_dump's compress file API
- d3b57755e60c 16.0 landed
-
Improve wording in pg_dump compression docs
- 6095069b40d7 16.0 landed
-
Fix condition in pg_dump TAP test
- 34ce11437497 16.0 landed
-
Add LZ4 compression to pg_dump
- 0da243fed087 16.0 landed
-
Introduce a generic pg_dump compression API
- e9960732a961 16.0 landed
-
Prepare pg_dump internals for additional compression methods
- 03d02f54a640 16.0 landed
-
Fix behavior with pg_restore -l and compressed dumps
- 783d8abc3b63 16.0 landed
-
Add 250c8ee07ed to git-blame-ignore-revs
- ff23b592ad66 16.0 cited
-
Provide test coverage in pg_dump for default behaviors with compression
- a7885c9bb22d 16.0 landed
-
Switch pg_dump to use compression specifications
- 5e73a6048849 16.0 landed
-
Refactor code parsing compression option values (-Z/--compress)
- d18655cc037a 16.0 landed
-
meson: Add some missing env settings for tests of pg_dump and pg_verifybackup
- 00ae5d6f588e 16.0 landed
-
Extend TAP tests of pg_dump to test for compression with gzip
- 98fe74218d97 15.0 landed
-
Clean up some dead code in pg_dump with tar format and gzip compression
- 8ac4c25a05d1 15.0 landed
-
Add TAP test in pg_dump with --format=tar and --compress
- edcedcc2c7bb 15.0 landed
-
Replace BASE_BACKUP COMPRESSION_LEVEL option with COMPRESSION_DETAIL.
- ffd53659c46a 15.0 cited
-
Refactor the pg_dump zlib code from pg_backup_custom.c to a separate file,
- bf9aa490db24 9.1.0 cited