mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-26 17:46:34 +03:00
FSHandler optimization: added WriteTo to fsFileReader. This should speed up io.Copy() from fsFileReader
This commit is contained in:
+24
-4
@@ -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()
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user