gzip: Add ability to set compression level (#1891)

This commit is contained in:
yogeshpandey
2018-03-21 00:27:00 +05:30
committed by dfawley
parent 8124abf74e
commit 2249df6df9
3 changed files with 65 additions and 2 deletions

View File

@ -23,6 +23,7 @@ package gzip
import (
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"sync"
@ -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)

View File

@ -22,6 +22,7 @@ import (
"bytes"
"compress/gzip"
"encoding/binary"
"fmt"
"io"
"io/ioutil"
"math"
@ -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 {

View File

@ -20,6 +20,7 @@ package grpc
import (
"bytes"
"compress/gzip"
"io"
"math"
"reflect"
@ -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
@ -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 {