This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 4c35e2fe fix(parquet/compress): Gzip CompressBound (#886)
4c35e2fe is described below

commit 4c35e2fe1209912b29583ef84a68b2f6e3740a09
Author: Minh Vu <[email protected]>
AuthorDate: Thu Jul 2 21:08:04 2026 +0200

    fix(parquet/compress): Gzip CompressBound (#886)
    
    ### What changed
    
    `gzipCodec.CompressBound` now includes gzip framing overhead on top of
    the existing deflate growth estimate. The bound also leaves room for the
    stateless close block accepted by `EncodeLevel`.
    
    The regression test checks empty, one-byte, small, and random
    incompressible payloads across the gzip levels accepted by the codec.
    
    ### Why
    
    The previous bound could be smaller than real gzip output for tiny
    inputs because it did not account for gzip header and trailer bytes.
    Callers using `CompressBound` to size destination buffers could
    therefore under-allocate.
    
    ### Validation
    
    - `go test ./parquet/compress`
    - `go test -tags assert ./parquet/compress`
    -
    `PARQUET_TEST_DATA=/Users/hoangvu/Code/OSS/arrow-go/parquet-testing/data
    
PARQUET_TEST_BAD_DATA=/Users/hoangvu/Code/OSS/arrow-go/parquet-testing/bad_data
    go test ./parquet/...`
---
 parquet/compress/compress_test.go | 43 +++++++++++++++++++++++++++++++++++++++
 parquet/compress/gzip.go          |  9 +++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/parquet/compress/compress_test.go 
b/parquet/compress/compress_test.go
index c60c65d7..6b65f23b 100644
--- a/parquet/compress/compress_test.go
+++ b/parquet/compress/compress_test.go
@@ -24,6 +24,7 @@ import (
        "testing"
 
        "github.com/apache/arrow-go/v18/parquet/compress"
+       "github.com/klauspost/compress/gzip"
        "github.com/klauspost/compress/zstd"
        "github.com/stretchr/testify/assert"
 )
@@ -91,6 +92,48 @@ func TestCompressDataOneShot(t *testing.T) {
        }
 }
 
+func TestGzipCompressBound(t *testing.T) {
+       codec, err := compress.GetCodec(compress.Codecs.Gzip)
+       assert.NoError(t, err)
+
+       payloads := []struct {
+               name string
+               data []byte
+       }{
+               {"empty", nil},
+               {"one byte", []byte{0xab}},
+               {"small", []byte("gzip")},
+               {"incompressible", makeRandomData(128)},
+       }
+
+       levels := []struct {
+               name  string
+               level int
+       }{
+               {"default", gzip.DefaultCompression},
+               {"no compression", gzip.NoCompression},
+               {"best speed", gzip.BestSpeed},
+               {"best compression", gzip.BestCompression},
+               {"huffman only", gzip.HuffmanOnly},
+               {"stateless", gzip.StatelessCompression},
+       }
+
+       for _, payload := range payloads {
+               t.Run(payload.name, func(t *testing.T) {
+                       bound := codec.CompressBound(int64(len(payload.data)))
+                       for _, level := range levels {
+                               t.Run(level.name, func(t *testing.T) {
+                                       compressed := 
codec.EncodeLevel(make([]byte, 0, bound), payload.data, level.level)
+                                       assert.LessOrEqual(t, 
int64(len(compressed)), bound)
+
+                                       uncompressed := codec.Decode(nil, 
compressed)
+                                       assert.Equal(t, payload.data, 
append([]byte(nil), uncompressed...))
+                               })
+                       }
+               })
+       }
+}
+
 func TestCompressReaderWriter(t *testing.T) {
        tests := []struct {
                c compress.Compression
diff --git a/parquet/compress/gzip.go b/parquet/compress/gzip.go
index 4b43f8e9..562b5f4e 100644
--- a/parquet/compress/gzip.go
+++ b/parquet/compress/gzip.go
@@ -26,6 +26,12 @@ import (
 
 type gzipCodec struct{}
 
+const (
+       gzipHeaderSize              = 10
+       gzipTrailerSize             = 8
+       gzipStatelessCloseBlockSize = 5
+)
+
 func (gzipCodec) NewReader(r io.Reader) io.ReadCloser {
        ret, err := gzip.NewReader(r)
        if err != nil {
@@ -81,7 +87,8 @@ func (g gzipCodec) Encode(dst, src []byte) []byte {
 }
 
 func (gzipCodec) CompressBound(len int64) int64 {
-       return len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5
+       return len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 +
+               gzipHeaderSize + gzipTrailerSize + gzipStatelessCloseBlockSize
 }
 
 func (gzipCodec) NewWriter(w io.Writer) io.WriteCloser {

Reply via email to