Skip to content
Snippets Groups Projects
Commit 5f2c138e authored by Arran Walker's avatar Arran Walker
Browse files

Add vfs deflate reader pool

parent ad8f7ff5
Branches ajwalker/deflate-pool
Tags
No related merge requests found
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))
})
}
}
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),
}
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment