gzip: Add ability to set compression level (#1891)
This commit is contained in:
@ -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)
|
||||
|
23
rpc_util.go
23
rpc_util.go
@ -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 {
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user