summaryrefslogtreecommitdiff
path: root/workhorse/internal/git/info-refs.go
diff options
context:
space:
mode:
Diffstat (limited to 'workhorse/internal/git/info-refs.go')
-rw-r--r--workhorse/internal/git/info-refs.go37
1 files changed, 30 insertions, 7 deletions
diff --git a/workhorse/internal/git/info-refs.go b/workhorse/internal/git/info-refs.go
index 8390143b99b..b7f825839f8 100644
--- a/workhorse/internal/git/info-refs.go
+++ b/workhorse/internal/git/info-refs.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http"
+ "sync"
"github.com/golang/gddo/httputil"
grpccodes "google.golang.org/grpc/codes"
@@ -64,21 +65,43 @@ func handleGetInfoRefsWithGitaly(ctx context.Context, responseWriter *HttpRespon
return err
}
- var w io.Writer
-
+ var w io.WriteCloser = nopCloser{responseWriter}
if encoding == "gzip" {
- gzWriter := gzip.NewWriter(responseWriter)
- w = gzWriter
- defer gzWriter.Close()
+ gzWriter := getGzWriter(responseWriter)
+ defer putGzWriter(gzWriter)
+ w = gzWriter
responseWriter.Header().Set("Content-Encoding", "gzip")
- } else {
- w = responseWriter
}
if _, err = io.Copy(w, infoRefsResponseReader); err != nil {
return err
}
+ if err := w.Close(); err != nil {
+ return err
+ }
+
return nil
}
+
+var gzipPool = &sync.Pool{New: func() interface{} {
+ // Invariant: the inner writer is io.Discard. We do not want to retain
+ // response writers of past requests in the pool.
+ return gzip.NewWriter(io.Discard)
+}}
+
+func getGzWriter(w io.Writer) *gzip.Writer {
+ gzWriter := gzipPool.Get().(*gzip.Writer)
+ gzWriter.Reset(w)
+ return gzWriter
+}
+
+func putGzWriter(w *gzip.Writer) {
+ w.Reset(io.Discard) // Maintain pool invariant
+ gzipPool.Put(w)
+}
+
+type nopCloser struct{ io.Writer }
+
+func (nc nopCloser) Close() error { return nil }