From 2109a1c4511c729c6151fdbecef5c6d20fa73389 Mon Sep 17 00:00:00 2001 From: francisco souza <108725+fsouza@users.noreply.github.com> Date: Mon, 31 Oct 2022 21:54:24 -0400 Subject: [PATCH] backend/fs: introduce a lazy implementation of ReadSeekCloser --- internal/backend/fs.go | 10 ++----- internal/backend/lazy_file.go | 53 +++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 8 deletions(-) create mode 100644 internal/backend/lazy_file.go diff --git a/internal/backend/fs.go b/internal/backend/fs.go index ebe934af95..01f1ccef7d 100644 --- a/internal/backend/fs.go +++ b/internal/backend/fs.go @@ -285,18 +285,12 @@ func (s *storageFS) getObject(bucketName, objectName string) (StreamingObject, e } func openObjectAndSetSize(obj *StreamingObject, path string) error { - // file is expected to be closed by the caller by calling obj.Close() - file, err := os.Open(path) + info, err := os.Stat(path) if err != nil { return err } - info, err := file.Stat() - if err != nil { - return err - } - - obj.Content = file + obj.Content = newLazyReader(path) obj.Size = info.Size() return nil diff --git a/internal/backend/lazy_file.go b/internal/backend/lazy_file.go new file mode 100644 index 0000000000..8c30a31492 --- /dev/null +++ b/internal/backend/lazy_file.go @@ -0,0 +1,53 @@ +// Copyright 2022 Francisco Souza. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package backend + +import ( + "io" + "os" + "sync" +) + +type lazyReader struct { + filename string + once *sync.Once + f *os.File + err error +} + +func newLazyReader(filename string) io.ReadSeekCloser { + return &lazyReader{ + filename: filename, + once: &sync.Once{}, + } +} + +func (r *lazyReader) open() { + r.f, r.err = os.Open(r.filename) +} + +func (r *lazyReader) Read(p []byte) (int, error) { + r.once.Do(r.open) + if r.err != nil { + return 0, r.err + } + return r.f.Read(p) +} + +func (r *lazyReader) Seek(offset int64, whence int) (int64, error) { + r.once.Do(r.open) + if r.err != nil { + return 0, r.err + } + return r.f.Seek(offset, whence) +} + +func (r *lazyReader) Close() error { + r.once.Do(r.open) + if r.err != nil { + return r.err + } + return r.f.Close() +}