mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2026-10-21 09:48:11 +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
|
package plg_backend_local
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/mickael-kerjean/filestash/server/common"
|
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/user"
|
"os/user"
|
||||||
|
|
||||||
|
. "github.com/mickael-kerjean/filestash/server/common"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -112,7 +114,7 @@ func (this Local) Cat(path string) (io.ReadCloser, error) {
|
|||||||
f.Close()
|
f.Close()
|
||||||
return nil, ErrNotFound
|
return nil, ErrNotFound
|
||||||
}
|
}
|
||||||
return f, nil
|
return NewDirect(f, fs), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this Local) Mkdir(path string) error {
|
func (this Local) Mkdir(path string) error {
|
||||||
|
|||||||
Reference in New Issue
Block a user