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 a01f0144 fix(parquet/compress): Brotli CompressBound (#884)
a01f0144 is described below
commit a01f0144bb9df50d547305e3e0081e4737c10d50
Author: Minh Vu <[email protected]>
AuthorDate: Fri Jul 3 20:33:43 2026 +0200
fix(parquet/compress): Brotli CompressBound (#884)
### What changed
Brotli `CompressBound` now returns the computed maximum compressed size
instead of the input length. The empty-input case is also handled before
the debug assertion so it remains valid with `-tags assert`.
### Why
The `Codec` contract says callers can use `CompressBound` to allocate a
destination buffer large enough for compressed output. Returning the
input length could under-report the bound for Brotli and cause callers
to allocate too little.
### Validation
- `go test ./parquet/compress`
- `go test -tags assert ./parquet/compress`
- `PARQUET_TEST_DATA=parquet-testing/data
PARQUET_TEST_BAD_DATA=parquet-testing/bad_data go test ./parquet/...`
---
parquet/compress/brotli.go | 8 ++++----
parquet/compress/compress_test.go | 22 ++++++++++++++++++++++
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/parquet/compress/brotli.go b/parquet/compress/brotli.go
index 82c1f7b0..536ebda8 100644
--- a/parquet/compress/brotli.go
+++ b/parquet/compress/brotli.go
@@ -85,17 +85,17 @@ func (brotliCodec) Decode(dst, src []byte) []byte {
// BrotliEncoderMaxCompressedSize
func (brotliCodec) CompressBound(len int64) int64 {
// [window bits / empty metadata] + N * [uncompressed] + [last empty]
+ if len == 0 {
+ return 2
+ }
debug.Assert(len > 0, "brotli compressbound should be > 0")
nlarge := len >> 14
overhead := 2 + (4 * nlarge) + 3 + 1
result := len + overhead
- if len == 0 {
- return 2
- }
if result < len {
return 0
}
- return len
+ return result
}
func (brotliCodec) NewWriter(w io.Writer) io.WriteCloser {
diff --git a/parquet/compress/compress_test.go
b/parquet/compress/compress_test.go
index 6b65f23b..019552dd 100644
--- a/parquet/compress/compress_test.go
+++ b/parquet/compress/compress_test.go
@@ -134,6 +134,28 @@ func TestGzipCompressBound(t *testing.T) {
}
}
+func TestBrotliCompressBound(t *testing.T) {
+ codec, err := compress.GetCodec(compress.Codecs.Brotli)
+ assert.NoError(t, err)
+
+ tests := []struct {
+ name string
+ len int64
+ want int64
+ }{
+ {"empty", 0, 2},
+ {"small", 1, 7},
+ {"before 16k boundary", 16*1024 - 1, 16*1024 + 5},
+ {"at 16k boundary", 16 * 1024, 16*1024 + 10},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equal(t, tt.want, codec.CompressBound(tt.len))
+ })
+ }
+}
+
func TestCompressReaderWriter(t *testing.T) {
tests := []struct {
c compress.Compression