FSHandler optimization: added WriteTo to fsFileReader. This should speed up io.Copy() from fsFileReader

This commit is contained in:
Aliaksandr Valialkin
2015-12-06 20:20:46 +02:00
parent bb1df8cf70
commit 0979f22779
3 changed files with 53 additions and 25 deletions
+24 -4
View File
@@ -140,20 +140,40 @@ func (r *fsFileReader) Close() error {
}
func (r *fsFileReader) Read(p []byte) (int, error) {
if r.ff.f != nil {
n, err := r.ff.f.ReadAt(p, r.offset)
ff := r.ff
if ff.f != nil {
n, err := ff.f.ReadAt(p, r.offset)
r.offset += int64(n)
return n, err
}
if r.offset == int64(len(r.ff.dirIndex)) {
if r.offset == int64(len(ff.dirIndex)) {
return 0, io.EOF
}
n := copy(p, r.ff.dirIndex[r.offset:])
n := copy(p, ff.dirIndex[r.offset:])
r.offset += int64(n)
return n, nil
}
func (r *fsFileReader) WriteTo(w io.Writer) (int64, error) {
if r.offset != 0 {
panic("BUG: WriteTo must not be called after Read")
}
ff := r.ff
var err error
if ff.f != nil {
r.offset, err = copyZeroAlloc(w, ff.f)
} else {
var n int
n, err = w.Write(ff.dirIndex)
r.offset = int64(n)
}
return r.offset, err
}
func (h *fsHandler) cleanCache() {
t := time.Now()
h.cacheLock.Lock()
+17
View File
@@ -91,6 +91,7 @@ func fsHandlerTest(t *testing.T, requestHandler RequestHandler, filenames []stri
}
ctx.URI().Update(name)
ctx.Response.Reset()
requestHandler(&ctx)
if ctx.Response.bodyStream == nil {
t.Fatalf("response body stream must be non-empty")
@@ -107,7 +108,23 @@ func fsHandlerTest(t *testing.T, requestHandler RequestHandler, filenames []stri
break
}
}
// verify index
ctx.URI().Update("/")
ctx.Response.Reset()
requestHandler(&ctx)
if ctx.Response.bodyStream == nil {
t.Fatalf("response body stream must be non-empty")
}
body, err := ioutil.ReadAll(ctx.Response.bodyStream)
if err != nil {
t.Fatalf("error when reading response body stream: %s", err)
}
if len(body) == 0 {
t.Fatalf("empty index file")
}
}
func TestStripPathSlashes(t *testing.T) {
testStripPathSlashes(t, "", 0, "")
testStripPathSlashes(t, "", 10, "")
+12 -21
View File
@@ -543,28 +543,8 @@ func writeBodyChunked(w *bufio.Writer, r io.Reader) error {
return err
}
var limitReaderPool sync.Pool
func writeBodyFixedSize(w *bufio.Writer, r io.Reader, size int) error {
vbuf := copyBufPool.Get()
if vbuf == nil {
vbuf = make([]byte, 4096)
}
buf := vbuf.([]byte)
vlr := limitReaderPool.Get()
if vlr == nil {
vlr = &io.LimitedReader{}
}
lr := vlr.(*io.LimitedReader)
lr.R = r
lr.N = int64(size)
n, err := io.CopyBuffer(w, lr, buf)
limitReaderPool.Put(vlr)
copyBufPool.Put(vbuf)
n, err := copyZeroAlloc(w, r)
if n != int64(size) && err == nil {
err = fmt.Errorf("read %d bytes from BodyStream instead of %d bytes", n, size)
}
@@ -580,6 +560,17 @@ func writeChunk(w *bufio.Writer, b []byte) error {
return err
}
func copyZeroAlloc(dst io.Writer, src io.Reader) (int64, error) {
vbuf := copyBufPool.Get()
if vbuf == nil {
vbuf = make([]byte, 4096)
}
buf := vbuf.([]byte)
n, err := io.CopyBuffer(dst, src, buf)
copyBufPool.Put(vbuf)
return n, err
}
var copyBufPool sync.Pool
// ErrBodyTooLarge is returned if either request or response body exceeds