github.com/rbisecke/kafka-go@v0.4.27/compress/gzip/gzip.go (about)

     1  package gzip
     2  
     3  import (
     4  	"compress/gzip"
     5  	"io"
     6  	"sync"
     7  )
     8  
     9  var (
    10  	readerPool sync.Pool
    11  )
    12  
    13  // Codec is the implementation of a compress.Codec which supports creating
    14  // readers and writers for kafka messages compressed with gzip.
    15  type Codec struct {
    16  	// The compression level to configure on writers created by this codec.
    17  	// Acceptable values are defined in the standard gzip package.
    18  	//
    19  	// Default to gzip.DefaultCompressionLevel.
    20  	Level int
    21  
    22  	writerPool sync.Pool
    23  }
    24  
    25  // Code implements the compress.Codec interface.
    26  func (c *Codec) Code() int8 { return 1 }
    27  
    28  // Name implements the compress.Codec interface.
    29  func (c *Codec) Name() string { return "gzip" }
    30  
    31  // NewReader implements the compress.Codec interface.
    32  func (c *Codec) NewReader(r io.Reader) io.ReadCloser {
    33  	var err error
    34  	z, _ := readerPool.Get().(*gzip.Reader)
    35  	if z != nil {
    36  		err = z.Reset(r)
    37  	} else {
    38  		z, err = gzip.NewReader(r)
    39  	}
    40  	if err != nil {
    41  		if z != nil {
    42  			readerPool.Put(z)
    43  		}
    44  		return &errorReader{err: err}
    45  	}
    46  	return &reader{Reader: z}
    47  }
    48  
    49  // NewWriter implements the compress.Codec interface.
    50  func (c *Codec) NewWriter(w io.Writer) io.WriteCloser {
    51  	x := c.writerPool.Get()
    52  	z, _ := x.(*gzip.Writer)
    53  	if z == nil {
    54  		x, err := gzip.NewWriterLevel(w, c.level())
    55  		if err != nil {
    56  			return &errorWriter{err: err}
    57  		}
    58  		z = x
    59  	} else {
    60  		z.Reset(w)
    61  	}
    62  	return &writer{codec: c, Writer: z}
    63  }
    64  
    65  func (c *Codec) level() int {
    66  	if c.Level != 0 {
    67  		return c.Level
    68  	}
    69  	return gzip.DefaultCompression
    70  }
    71  
    72  type reader struct{ *gzip.Reader }
    73  
    74  func (r *reader) Close() (err error) {
    75  	if z := r.Reader; z != nil {
    76  		r.Reader = nil
    77  		err = z.Close()
    78  		// Pass it an empty reader, which is a zero-size value implementing the
    79  		// flate.Reader interface to avoid the construction of a bufio.Reader in
    80  		// the call to Reset.
    81  		//
    82  		// Note: we could also not reset the reader at all, but that would cause
    83  		// the underlying reader to be retained until the gzip.Reader is freed,
    84  		// which may not be desirable.
    85  		z.Reset(emptyReader{})
    86  		readerPool.Put(z)
    87  	}
    88  	return
    89  }
    90  
    91  type writer struct {
    92  	codec *Codec
    93  	*gzip.Writer
    94  }
    95  
    96  func (w *writer) Close() (err error) {
    97  	if z := w.Writer; z != nil {
    98  		w.Writer = nil
    99  		err = z.Close()
   100  		z.Reset(nil)
   101  		w.codec.writerPool.Put(z)
   102  	}
   103  	return
   104  }
   105  
   106  type emptyReader struct{}
   107  
   108  func (emptyReader) ReadByte() (byte, error) { return 0, io.EOF }
   109  
   110  func (emptyReader) Read([]byte) (int, error) { return 0, io.EOF }
   111  
   112  type errorReader struct{ err error }
   113  
   114  func (r *errorReader) Close() error { return r.err }
   115  
   116  func (r *errorReader) Read([]byte) (int, error) { return 0, r.err }
   117  
   118  type errorWriter struct{ err error }
   119  
   120  func (w *errorWriter) Close() error { return w.err }
   121  
   122  func (w *errorWriter) Write([]byte) (int, error) { return 0, w.err }