You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

118 lines
2.8 KiB

  1. /*
  2. *
  3. * Copyright 2017 gRPC authors.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. // Package gzip implements and registers the gzip compressor
  19. // during the initialization.
  20. // This package is EXPERIMENTAL.
  21. package gzip
  22. import (
  23. "compress/gzip"
  24. "fmt"
  25. "io"
  26. "io/ioutil"
  27. "sync"
  28. "google.golang.org/grpc/encoding"
  29. )
  30. // Name is the name registered for the gzip compressor.
  31. const Name = "gzip"
  32. func init() {
  33. c := &compressor{}
  34. c.poolCompressor.New = func() interface{} {
  35. return &writer{Writer: gzip.NewWriter(ioutil.Discard), pool: &c.poolCompressor}
  36. }
  37. encoding.RegisterCompressor(c)
  38. }
  39. type writer struct {
  40. *gzip.Writer
  41. pool *sync.Pool
  42. }
  43. // SetLevel updates the registered gzip compressor to use the compression level specified (gzip.HuffmanOnly is not supported).
  44. // NOTE: this function must only be called during initialization time (i.e. in an init() function),
  45. // and is not thread-safe.
  46. //
  47. // The error returned will be nil if the specified level is valid.
  48. func SetLevel(level int) error {
  49. if level < gzip.DefaultCompression || level > gzip.BestCompression {
  50. return fmt.Errorf("grpc: invalid gzip compression level: %d", level)
  51. }
  52. c := encoding.GetCompressor(Name).(*compressor)
  53. c.poolCompressor.New = func() interface{} {
  54. w, err := gzip.NewWriterLevel(ioutil.Discard, level)
  55. if err != nil {
  56. panic(err)
  57. }
  58. return &writer{Writer: w, pool: &c.poolCompressor}
  59. }
  60. return nil
  61. }
  62. func (c *compressor) Compress(w io.Writer) (io.WriteCloser, error) {
  63. z := c.poolCompressor.Get().(*writer)
  64. z.Writer.Reset(w)
  65. return z, nil
  66. }
  67. func (z *writer) Close() error {
  68. defer z.pool.Put(z)
  69. return z.Writer.Close()
  70. }
  71. type reader struct {
  72. *gzip.Reader
  73. pool *sync.Pool
  74. }
  75. func (c *compressor) Decompress(r io.Reader) (io.Reader, error) {
  76. z, inPool := c.poolDecompressor.Get().(*reader)
  77. if !inPool {
  78. newZ, err := gzip.NewReader(r)
  79. if err != nil {
  80. return nil, err
  81. }
  82. return &reader{Reader: newZ, pool: &c.poolDecompressor}, nil
  83. }
  84. if err := z.Reset(r); err != nil {
  85. c.poolDecompressor.Put(z)
  86. return nil, err
  87. }
  88. return z, nil
  89. }
  90. func (z *reader) Read(p []byte) (n int, err error) {
  91. n, err = z.Reader.Read(p)
  92. if err == io.EOF {
  93. z.pool.Put(z)
  94. }
  95. return n, err
  96. }
  97. func (c *compressor) Name() string {
  98. return Name
  99. }
  100. type compressor struct {
  101. poolCompressor sync.Pool
  102. poolDecompressor sync.Pool
  103. }