pgzip

repository·master·Indexed 22 days ago

https://github.com/klauspost/pgzip

A high-performance, parallelized Go implementation of gzip that serves as a drop-in replacement for the standard compress/gzip library. It utilizes multiple CPU cores for compression and decompression to speed up the processing of large datasets (typically >1MB). The library produces standard gzip files compatible with other gzip tools and provides features such as configurable concurrency via SetConcurrency, non-blocking decompression with NewReaderN, and the ability to retrieve the total uncompressed size.

Tokens
2.1K
Snippets
3
Records
18
Agent score
79%

What's inside pgzip

  1. How pgzip compression and decompression work

    master

    pgzip provides parallelized gzip operations:

    • Compression: Splits data into blocks that are compressed in parallel. This is highly effective for large datasets (over 1MB).
    • Decompression: Decompresses data ahead of the current reader in a separate goroutine. This acts as a buffer, ensuring that reads from your application are non-blocking if the decompressor can keep up. CRC calculation also runs in a separate goroutine.

    Because pgzip produces standard gzip files, you can compress with pgzip and decompress with any standard gzip tool, and vice versa.

  2. Use pgzip as a drop-in replacement for compress/gzip

    master

    You can use pgzip as a direct replacement for the standard library compress/gzip by changing your import statement. The API is designed to be compatible.

    Replace:

    import "compress/gzip"

    With:

    import gzip "github.com/klauspost/pgzip"
    import gzip "github.com/klauspost/pgzip"
  3. Install pgzip

    master

    To install pgzip, use the following Go command:

    go get github.com/klauspost/pgzip/...```
    
    You may also need to update the `github.com/klauspost/compress` dependency:
    
    ```bash
    go get -u github.com/klauspost/compress
    go get github.com/klauspost/pgzip/...
    go get -u github.com/klauspost/compress
  4. Configure decompression readahead with NewReaderN

    master

    pgzip decompression is modified to decompress ahead of the current reader, making reads non-blocking as long as the decompressor can keep ahead.

    To specify a custom readahead behavior, use pgzip.NewReaderN instead of the standard NewReader.

    Parameters:

    • r: The source io.Reader.
    • blockSize: The size of each block decoded.
    • blocks: The maximum number of blocks to be decoded ahead.

    This allows you to tune how much data is buffered and processed in the background.

  5. Configure compression concurrency with SetConcurrency

    master

    To optimize compression performance, you can control the block size and the number of parallel blocks using the SetConcurrency method on *pgzip.Writer.

    Parameters:

    • blockSize: The approximate size of each block.
    • blocks: The number of blocks to process in parallel.

    Default behavior: If you do not call SetConcurrency, the default is SetConcurrency(1MB, runtime.GOMAXPROCS(0)), which splits data into 1 MB blocks and processes up to the number of available CPU threads.

    Best Practices:

    • Only use pgzip for data amounts greater than 1MB to see benefits.
    • For optimal performance, use a block size of at least 100k.
    • Set the number of blocks to at least the number of CPU cores you want to utilize, ideally about twice that number.

    Note: pgzip writes standard gzip files, so the output is fully compatible with other gzip readers/writers.

    var b bytes.Buffer
    w := gzip.NewWriter(&b)
    w.SetConcurrency(100000, 10)
    w.Write([]byte("hello, world\n"))
    w.Close()
  6. Initialize a pgzip Writer

    master

    Use NewWriter to create a new Writer with the default compression level, or NewWriterLevel to specify a custom compression level. The Writer implements io.WriteCloser.

    Important:

    • It is the caller's responsibility to call Close() when finished. Writes may be buffered and not flushed until Close() or Flush() is called.
    • If you need to set fields in the Writer.Header (like Name, Comment, or Extra), you must do so before the first call to Write() or Close().
    • Header strings (Name and Comment) must be UTF-8 and contain only Latin-1 (ISO 8859-1) characters. Using NUL or non-Latin-1 runes will result in an error during Write().
  7. Configure Reader performance with NewReaderN

    master

    Use NewReaderN(r io.Reader, blockSize, blocks int) to fine-tune the decompression performance by controlling the prefetching behavior.

    • blockSize: The approximate size of each decompressed block.
    • blocks: The number of blocks to prefetch.

    Default values (if provided values are too small) are blockSize = 250000 and blocks = 16.

  8. Initialize a new gzip Reader with NewReader

    master

    Use NewReader(r io.Reader) to create a new Reader that decompresses data from the provided reader. This implementation uses buffering and prefetching to improve performance. It is the caller's responsibility to call Close() on the Reader when finished to release resources.

    Note: The implementation may read more data from the underlying reader than requested due to its internal buffering and readahead mechanism.

  9. Reuse a Writer with Reset

    master
    To avoid frequent allocations, you can reuse a Writer by calling Reset(w). This discards the current state and makes the Writer equivalent to a fresh one created via NewWriter, but targeting a new underlying io.Writer w.
  10. Configure concurrency with SetConcurrency

    master

    You can fine-tune the performance of the Writer by controlling the block size and the number of parallel compression tasks.

    By default, pgzip uses a block size of 1 MB (defaultBlockSize) and processes up to runtime.GOMAXPROCS(0) blocks in parallel.

    Use SetConcurrency(blockSize, blocks) to adjust these values.

    • blockSize: The approximate size of each data block. Must be greater than tailSize (16384 bytes).
    • blocks: The number of blocks to be processed in parallel. Must be greater than 0.
  11. Compress data with Writer.Write

    master

    The Write method writes compressed data to the underlying io.Writer.

    Key behaviors:

    • Non-blocking: The function returns quickly by handing off data to background goroutines. A nil error does not guarantee that compression has finished or succeeded; it only means the data was successfully queued.
    • Buffer Safety: The byte slice p passed to Write is copied. You are free to reuse the buffer immediately after the function returns.
    • Error Handling: Errors occurring during background compression are reported asynchronously. To catch these errors, you must call Flush() or Close(), which are guaranteed to return any errors encountered up to that point.
  12. Get the uncompressed size with UncompressedSize

    master
    The UncompressedSize() method returns the total number of uncompressed bytes written to the Writer. This is a pgzip-specific feature and is not part of the standard Go gzip package.