go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/grpc/prpc/compression.go (about) 1 // Copyright 2021 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package prpc 16 17 import ( 18 "bytes" 19 "io" 20 "sync" 21 22 "github.com/klauspost/compress/gzip" 23 ) 24 25 // gzipThreshold is the threshold to compress a blob. 26 // If the blob is larger than this, then compress it. 27 // The value is derived from 28 // https://webmasters.stackexchange.com/questions/31750/what-is-recommended-minimum-object-size-for-gzip-performance-benefits 29 const gzipThreshold = 1024 30 31 var ( 32 gzipWriters sync.Pool 33 gzipReaders sync.Pool 34 ) 35 36 func getGZipWriter(w io.Writer) *gzip.Writer { 37 if gw, _ := gzipWriters.Get().(*gzip.Writer); gw != nil { 38 gw.Reset(w) 39 return gw 40 } 41 return gzip.NewWriter(w) 42 } 43 44 func returnGZipWriter(gw *gzip.Writer) { 45 gzipWriters.Put(gw) 46 } 47 48 func getGZipReader(r io.Reader) (*gzip.Reader, error) { 49 if gr, _ := gzipReaders.Get().(*gzip.Reader); gr != nil { 50 if err := gr.Reset(gr); err != nil { 51 gzipReaders.Put(gr) // it is still good for reuse, even on errors 52 return nil, err 53 } 54 return gr, nil 55 } 56 return gzip.NewReader(r) 57 } 58 59 func returnGZipReader(gr *gzip.Reader) { 60 gzipReaders.Put(gr) 61 } 62 63 // compressBlob compresses data using gzip. 64 func compressBlob(data []byte) ([]byte, error) { 65 buf := bytes.NewBuffer(nil) 66 gz := getGZipWriter(buf) 67 defer returnGZipWriter(gz) 68 if _, err := gz.Write(data); err != nil { 69 return nil, err 70 } 71 if err := gz.Close(); err != nil { 72 return nil, err 73 } 74 return buf.Bytes(), nil 75 }