mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-19 16:14:39 +00:00
feature (plg_backend_local): speed improvements on linux
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package plg_backend_local
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
directChunk = 16 * 1024 * 1024
|
||||
directAlign = 4096
|
||||
directMinSize = 8 * 1024 * 1024
|
||||
)
|
||||
|
||||
type direct struct {
|
||||
f *os.File
|
||||
ch chan []byte
|
||||
done chan struct{}
|
||||
err error
|
||||
cur []byte
|
||||
}
|
||||
|
||||
func NewDirect(f *os.File, fs os.FileInfo) io.ReadCloser {
|
||||
if fs.Size() < directMinSize {
|
||||
return f
|
||||
}
|
||||
flags, err := unix.FcntlInt(f.Fd(), unix.F_GETFL, 0)
|
||||
if err != nil {
|
||||
return f
|
||||
} else if _, err = unix.FcntlInt(f.Fd(), unix.F_SETFL, flags|unix.O_DIRECT); err != nil {
|
||||
return f
|
||||
}
|
||||
return &direct{f: f, done: make(chan struct{})}
|
||||
}
|
||||
|
||||
func (this *direct) Seek(offset int64, whence int) (int64, error) {
|
||||
if this.ch != nil {
|
||||
return 0, errors.New("seek not supported after read")
|
||||
}
|
||||
return this.f.Seek(offset, whence)
|
||||
}
|
||||
|
||||
func (this *direct) Read(p []byte) (int, error) {
|
||||
if this.ch == nil {
|
||||
this.ch = make(chan []byte)
|
||||
go this.fill()
|
||||
}
|
||||
for len(this.cur) == 0 {
|
||||
b, ok := <-this.ch
|
||||
if !ok {
|
||||
return 0, this.err
|
||||
}
|
||||
this.cur = b
|
||||
}
|
||||
n := copy(p, this.cur)
|
||||
this.cur = this.cur[n:]
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (this *direct) fill() {
|
||||
defer close(this.ch)
|
||||
buf, next := alignedBuffer(directChunk), alignedBuffer(directChunk)
|
||||
start, err := this.f.Seek(0, io.SeekCurrent)
|
||||
pos := start - start%directAlign
|
||||
for err == nil {
|
||||
var n int
|
||||
n, err = this.f.ReadAt(buf, pos)
|
||||
skip := min(max(start-pos, 0), int64(n))
|
||||
select {
|
||||
case this.ch <- buf[skip:n]:
|
||||
case <-this.done:
|
||||
return
|
||||
}
|
||||
pos += int64(n)
|
||||
buf, next = next, buf
|
||||
}
|
||||
this.err = err
|
||||
}
|
||||
|
||||
func alignedBuffer(size int) []byte {
|
||||
b := make([]byte, size+directAlign)
|
||||
off := directAlign - int(uintptr(unsafe.Pointer(&b[0]))%directAlign)
|
||||
return b[off : off+size]
|
||||
}
|
||||
|
||||
func (this *direct) Close() error {
|
||||
close(this.done)
|
||||
return this.f.Close()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build !linux
|
||||
|
||||
package plg_backend_local
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func NewDirect(f *os.File, fs os.FileInfo) io.ReadCloser {
|
||||
return f
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package plg_backend_local
|
||||
|
||||
import (
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"io"
|
||||
"os"
|
||||
"os/user"
|
||||
|
||||
. "github.com/mickael-kerjean/filestash/server/common"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -112,7 +114,7 @@ func (this Local) Cat(path string) (io.ReadCloser, error) {
|
||||
f.Close()
|
||||
return nil, ErrNotFound
|
||||
}
|
||||
return f, nil
|
||||
return NewDirect(f, fs), nil
|
||||
}
|
||||
|
||||
func (this Local) Mkdir(path string) error {
|
||||
|
||||
Reference in New Issue
Block a user