Re: [PING] [PATCH v2] parallel pg_restore: avoid disk seeks when jumping short distance forward
Tom Lane <tgl@sss.pgh.pa.us>
From: Tom Lane <tgl@sss.pgh.pa.us>
To: Dimitrios Apostolou <jimis@gmx.net>
Cc: Nathan Bossart <nathandbossart@gmail.com>,
Thomas Munro <thomas.munro@gmail.com>,
pgsql-hackers@lists.postgresql.org
Date: 2025-10-10T20:26:57Z
Lists: pgsql-hackers
Attachments
- v1-improve-pg_dump-compress-buffering.patch (text/x-diff) patch v1
Dimitrios Apostolou <jimis@gmx.net> writes: > Question that remains: where is pg_dump setting this ~35B length block? I poked into that question, and found that the answer is some exceedingly brain-dead buffering logic in compress_zstd.c. It will dump its buffer during every loop iteration within _ZstdWriteCommon, no matter how much buffer space it has left; and each call to cs->writeF() produces a new "data block" in the output file. The amount of data fed to _ZstdWriteCommon per call is whatever the backend sends per "copy data" message, which is generally one table row. So if the table rows aren't too wide, or if they're highly compressible, you get these tiny data blocks. compress_lz4.c is equally broken, again buffering no bytes across calls; although liblz4 seems to do some buffering internally. I got blocks of around 300 bytes on the test case I was using. That's still ridiculous. compress_gzip.c is actually sanely implemented, and consistently produces blocks of 4096 bytes, which traces to DEFAULT_IO_BUFFER_SIZE in compress_io.h. If you choose --compress=none, you get data blocks that correspond exactly to table rows. We could imagine doing some internal buffering to amalgamate short rows into larger blocks, but I'm not entirely convinced it's worth messing with that case. The attached patch fixes the buffering logic in compress_zstd.c and compress_lz4.c. For zstd, most blocks are now 131591 bytes, which seems to be determined by ZSTD_CStreamOutSize() not by our code. For lz4, I see a range of block sizes but they're almost all around 64K. That's apparently emergent from the behavior of LZ4F_compressBound(): when told we want to supply it up to 4K at a time, it says it needs a buffer around 64K. I'm tempted to increase DEFAULT_IO_BUFFER_SIZE so that gzip also produces blocks in the vicinity of 64K, but we'd have to decouple the behavior of compress_lz4.c somehow, or it would want to produce blocks around a megabyte which might be excessive. (Or if it's not, we'd still want all these compression methods to choose similar block sizes, I'd think.) Anyway, these fixes should remove the need for pg_restore to look at quite so many places in the archive file. There may still be a need for altering the seek-versus-read behavior as you suggest, but I think we need to re-measure that tradeoff after fixing the pg_dump side. regards, tom lane
Commits
-
Avoid short seeks in pg_restore.
- fba60a1b107d 19 (unreleased) landed
-
Don't rely on zlib's gzgetc() macro.
- 277dec651472 19 (unreleased) cited
-
Add more TAP test coverage for pg_dump.
- 20ec9958921a 19 (unreleased) landed
-
Split 002_pg_dump.pl into two test files.
- 9dcf7f1172cd 19 (unreleased) landed
-
Align the data block sizes of pg_dump's various compression modes.
- 66ec01dc4124 19 (unreleased) landed
-
Fix serious performance problems in LZ4Stream_read_internal.
- 1f8062dd9668 19 (unreleased) landed
-
Fix poor buffering logic in pg_dump's lz4 and zstd compression code.
- fe8192a95e6c 19 (unreleased) landed
-
Fix issue with reading zero bytes in Gzip_read.
- bf18e9bd70de 17.7 landed
- a239c4a0c226 19 (unreleased) landed
- 6a4009747c36 18.1 landed
- 1518b7d76aad 16.11 landed
-
Restore test coverage of LZ4Stream_gets().
- eac2b1697d48 17.7 landed
- 661b320ed4e0 18.1 landed
- 26d1cd375f15 19 (unreleased) landed