Skip to content

Commit

Permalink
gzip: Add ability to set compression level (grpc#1891)
Browse files Browse the repository at this point in the history
  • Loading branch information
yogeshpandey authored and dfawley committed Mar 20, 2018
1 parent 8124abf commit 2249df6
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 2 deletions.
21 changes: 21 additions & 0 deletions encoding/gzip/gzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package gzip

import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"sync"
Expand All @@ -46,6 +47,26 @@ type writer struct {
pool *sync.Pool
}

// SetLevel updates the registered gzip compressor to use the compression level specified (gzip.HuffmanOnly is not supported).
// NOTE: this function must only be called during initialization time (i.e. in an init() function),
// and is not thread-safe.
//
// The error returned will be nil if the specified level is valid.
func SetLevel(level int) error {
if level < gzip.DefaultCompression || level > gzip.BestCompression {
return fmt.Errorf("grpc: invalid gzip compression level: %d", level)
}
c := encoding.GetCompressor(Name).(*compressor)
c.poolCompressor.New = func() interface{} {
w, err := gzip.NewWriterLevel(ioutil.Discard, level)
if err != nil {
panic(err)
}
return &writer{Writer: w, pool: &c.poolCompressor}
}
return nil
}

func (c *compressor) Compress(w io.Writer) (io.WriteCloser, error) {
z := c.poolCompressor.Get().(*writer)
z.Writer.Reset(w)
Expand Down
21 changes: 19 additions & 2 deletions rpc_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"bytes"
"compress/gzip"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"math"
Expand Down Expand Up @@ -55,13 +56,29 @@ type gzipCompressor struct {

// NewGZIPCompressor creates a Compressor based on GZIP.
func NewGZIPCompressor() Compressor {
c, _ := NewGZIPCompressorWithLevel(gzip.DefaultCompression)
return c
}

// NewGZIPCompressorWithLevel is like NewGZIPCompressor but specifies the gzip compression level instead
// of assuming DefaultCompression.
//
// The error returned will be nil if the level is valid.
func NewGZIPCompressorWithLevel(level int) (Compressor, error) {
if level < gzip.DefaultCompression || level > gzip.BestCompression {
return nil, fmt.Errorf("grpc: invalid compression level: %d", level)
}
return &gzipCompressor{
pool: sync.Pool{
New: func() interface{} {
return gzip.NewWriter(ioutil.Discard)
w, err := gzip.NewWriterLevel(ioutil.Discard, level)
if err != nil {
panic(err)
}
return w
},
},
}
}, nil
}

func (c *gzipCompressor) Do(w io.Writer, p []byte) error {
Expand Down
25 changes: 25 additions & 0 deletions rpc_util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package grpc

import (
"bytes"
"compress/gzip"
"io"
"math"
"reflect"
Expand Down Expand Up @@ -120,6 +121,26 @@ func TestEncode(t *testing.T) {
}

func TestCompress(t *testing.T) {

bestCompressor, err := NewGZIPCompressorWithLevel(gzip.BestCompression)
if err != nil {
t.Fatalf("Could not initialize gzip compressor with best compression.")
}
bestSpeedCompressor, err := NewGZIPCompressorWithLevel(gzip.BestSpeed)
if err != nil {
t.Fatalf("Could not initialize gzip compressor with best speed compression.")
}

defaultCompressor, err := NewGZIPCompressorWithLevel(gzip.BestSpeed)
if err != nil {
t.Fatalf("Could not initialize gzip compressor with default compression.")
}

level5, err := NewGZIPCompressorWithLevel(5)
if err != nil {
t.Fatalf("Could not initialize gzip compressor with level 5 compression.")
}

for _, test := range []struct {
// input
data []byte
Expand All @@ -129,6 +150,10 @@ func TestCompress(t *testing.T) {
err error
}{
{make([]byte, 1024), NewGZIPCompressor(), NewGZIPDecompressor(), nil},
{make([]byte, 1024), bestCompressor, NewGZIPDecompressor(), nil},
{make([]byte, 1024), bestSpeedCompressor, NewGZIPDecompressor(), nil},
{make([]byte, 1024), defaultCompressor, NewGZIPDecompressor(), nil},
{make([]byte, 1024), level5, NewGZIPDecompressor(), nil},
} {
b := new(bytes.Buffer)
if err := test.cp.Do(b, test.data); err != test.err {
Expand Down

0 comments on commit 2249df6

Please sign in to comment.