From 7cdb75ab7923db02b0a5e2d363eb87f18f4d459f Mon Sep 17 00:00:00 2001 From: Jarek Kowalski Date: Wed, 16 Sep 2020 23:04:22 -0700 Subject: [PATCH] fuse: changed file read implementation to avoid OOM (#620) Changed file read implementation from ReadAll() to a Handle to avoid OOMing We don't have automated tests for this but I verified this by restoring 13GB file over fuse and memory usage never exceeded 400MB. --- internal/fusemount/fusefs.go | 47 ++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/internal/fusemount/fusefs.go b/internal/fusemount/fusefs.go index 8abdb0bdb..4b912fa0f 100644 --- a/internal/fusemount/fusefs.go +++ b/internal/fusemount/fusefs.go @@ -6,8 +6,10 @@ package fusemount import ( + "io" "io/ioutil" "os" + "sync" "bazil.org/fuse" fusefs "bazil.org/fuse/fs" @@ -36,6 +38,51 @@ type fuseFileNode struct { fuseNode } +var _ fusefs.NodeOpener = (*fuseFileNode)(nil) + +func (f *fuseFileNode) Open(ctx context.Context, req *fuse.OpenRequest, resp *fuse.OpenResponse) (fusefs.Handle, error) { + reader, err := f.entry.(fs.File).Open(ctx) + if err != nil { + return nil, err + } + + return &fuseFileHandle{reader: reader, size: f.entry.Size()}, nil +} + +type fuseFileHandle struct { + mu sync.Mutex + reader fs.Reader + size int64 +} + +func (f *fuseFileHandle) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error { + f.mu.Lock() + defer f.mu.Unlock() + + _, err := f.reader.Seek(req.Offset, io.SeekStart) + if err != nil { + return err + } + + n, err := f.reader.Read(resp.Data[:req.Size]) + if err != nil { + return err + } + + resp.Data = resp.Data[:n] + + return nil +} + +func (f *fuseFileHandle) Release(ctx context.Context, req *fuse.ReleaseRequest) error { + return f.reader.Close() +} + +var ( + _ fusefs.HandleReleaser = (*fuseFileHandle)(nil) + _ fusefs.HandleReader = (*fuseFileHandle)(nil) +) + func (f *fuseFileNode) ReadAll(ctx context.Context) ([]byte, error) { reader, err := f.entry.(fs.File).Open(ctx) if err != nil {