Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/vfs/zip/archive_test.go53
-rw-r--r--internal/vfs/zip/deflate_reader.go43
2 files changed, 92 insertions, 4 deletions
diff --git a/internal/vfs/zip/archive_test.go b/internal/vfs/zip/archive_test.go
index da778e62..58b7c74a 100644
--- a/internal/vfs/zip/archive_test.go
+++ b/internal/vfs/zip/archive_test.go
@@ -1,11 +1,16 @@
package zip
import (
+ "archive/zip"
+ "bytes"
"context"
+ "crypto/rand"
+ "io"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
+ "strconv"
"sync/atomic"
"testing"
"time"
@@ -419,3 +424,51 @@ func newZipFileServerURL(t *testing.T, zipFilePath string, requests *int64) (str
testServer.Close()
}
}
+
+func benchmarkArchiveRead(b *testing.B, size int64) {
+ zbuf := new(bytes.Buffer)
+
+ // create zip file of specified size
+ zw := zip.NewWriter(zbuf)
+ w, err := zw.Create("public/file.txt")
+ require.NoError(b, err)
+ _, err = io.CopyN(w, rand.Reader, size)
+ require.NoError(b, err)
+ require.NoError(b, zw.Close())
+
+ modtime := time.Now().Add(-time.Hour)
+
+ m := http.NewServeMux()
+ m.HandleFunc("/public.zip", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ http.ServeContent(w, r, "public.zip", modtime, bytes.NewReader(zbuf.Bytes()))
+ }))
+
+ ts := httptest.NewServer(m)
+ defer ts.Close()
+
+ fs := New(zipCfg).(*zipVFS)
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for n := 0; n < b.N; n++ {
+ z := newArchive(fs, time.Second)
+ err := z.openArchive(context.Background(), ts.URL+"/public.zip")
+ require.NoError(b, err)
+
+ f, err := z.Open(context.Background(), "file.txt")
+ require.NoError(b, err)
+
+ _, err = io.Copy(ioutil.Discard, f)
+ require.NoError(b, err)
+
+ require.NoError(b, f.Close())
+ }
+}
+
+func BenchmarkArchiveRead(b *testing.B) {
+ for _, size := range []int{32 * 1024, 64 * 1024, 1024 * 1024} {
+ b.Run(strconv.Itoa(size), func(b *testing.B) {
+ benchmarkArchiveRead(b, int64(size))
+ })
+ }
+}
diff --git a/internal/vfs/zip/deflate_reader.go b/internal/vfs/zip/deflate_reader.go
index 16a2d72e..87a7da0c 100644
--- a/internal/vfs/zip/deflate_reader.go
+++ b/internal/vfs/zip/deflate_reader.go
@@ -1,31 +1,66 @@
package zip
import (
+ "bufio"
"compress/flate"
+ "errors"
"io"
+ "sync"
)
+var ErrClosedReader = errors.New("deflatereader: reader is closed")
+
+var deflateReaderPool sync.Pool
+
// deflateReader wrapper to support reading compressed files.
// Implements the io.ReadCloser interface.
type deflateReader struct {
- reader io.ReadCloser
+ reader *bufio.Reader
+ closer io.Closer
flateReader io.ReadCloser
}
// Read from flateReader
func (r *deflateReader) Read(p []byte) (n int, err error) {
+ if r.closer == nil {
+ return 0, ErrClosedReader
+ }
+
return r.flateReader.Read(p)
}
// Close all readers
func (r *deflateReader) Close() error {
- r.reader.Close()
+ if r.closer == nil {
+ return ErrClosedReader
+ }
+
+ defer func() {
+ r.closer.Close()
+ r.closer = nil
+ deflateReaderPool.Put(r)
+ }()
+
return r.flateReader.Close()
}
+func (r *deflateReader) reset(rc io.ReadCloser) {
+ r.reader.Reset(rc)
+ r.closer = rc
+ r.flateReader.(flate.Resetter).Reset(r.reader, nil)
+}
+
func newDeflateReader(r io.ReadCloser) *deflateReader {
+ if dr, ok := deflateReaderPool.Get().(*deflateReader); ok {
+ dr.reset(r)
+ return dr
+ }
+
+ br := bufio.NewReader(r)
+
return &deflateReader{
- reader: r,
- flateReader: flate.NewReader(r),
+ reader: br,
+ closer: r,
+ flateReader: flate.NewReader(br),
}
}