fs: added Directory.Child() method to look up children by name without necessarily loading all of them

This commit is contained in:
Jarek Kowalski committed 2019-12-30 19:21:17 -08:00
1 parent 194680adfc
commit 503fa74be5
10 files changed
+123

No files matched your search

+9
View File
@@ -21,6 +21,15 @@ type directory struct {
fs.Directory
}
func (d *directory) Child(ctx context.Context, name string) (fs.Entry, error) {
e, err := d.Directory.Child(ctx, name)
if err != nil {
return nil, err
}
return wrapWithContext(e, d.ctx), nil
}
func (d *directory) Readdir(ctx context.Context) (fs.Entries, error) {
entries, err := d.ctx.cacher.Readdir(ctx, d.Directory)
if err != nil {
+21
View File
@@ -2,6 +2,7 @@ package fs
import (
"context"
"errors"
"io"
"os"
"sort"
@@ -40,10 +41,30 @@ type File interface {
// Directory represents contents of a directory.
type Directory interface {
Entry
Child(ctx context.Context, name string) (Entry, error)
Readdir(ctx context.Context) (Entries, error)
Summary() *DirectorySummary
}
// ErrEntryNotFound is returned when an entry is not found.
var ErrEntryNotFound = errors.New("entry not found")
// ReadDirAndFindChild reads all entries from a directory and returns one by name.
// This is a convenience function that may be helpful in implementations of Directory.Child()
func ReadDirAndFindChild(ctx context.Context, d Directory, name string) (Entry, error) {
children, err := d.Readdir(ctx)
if err != nil {
return nil, err
}
e := children.FindByName(name)
if e == nil {
return nil, ErrEntryNotFound
}
return e, nil
}
// DirectorySummary represents summary information about a directory.
type DirectorySummary struct {
TotalFileSize int64 `json:"size"`
+15
View File
@@ -101,6 +101,21 @@ func (fsd *filesystemDirectory) Summary() *fs.DirectorySummary {
return nil
}
func (fsd *filesystemDirectory) Child(ctx context.Context, name string) (fs.Entry, error) {
fullPath := fsd.fullPath()
st, err := os.Stat(filepath.Join(fullPath, name))
if err != nil {
if os.IsNotExist(err) {
return nil, fs.ErrEntryNotFound
}
return nil, errors.Wrap(err, "unable to get child")
}
return entryFromChildFileInfo(st, fullPath)
}
func (fsd *filesystemDirectory) Readdir(ctx context.Context) (fs.Entries, error) {
fullPath := fsd.fullPath()
+41
View File
@@ -97,6 +97,47 @@ func TestFiles(t *testing.T) {
t.Logf("e[%v] = %v %v %v", i, e.Name(), e.Size(), e.Mode())
}
}
verifyChild(t, dir)
}
func verifyChild(t *testing.T, dir fs.Directory) {
ctx := context.Background()
child, err := dir.Child(ctx, "f3")
if err != nil {
t.Errorf("child error: %v", err)
}
if _, err = dir.Child(ctx, "f4"); err != fs.ErrEntryNotFound {
t.Errorf("unexpected child error: %v", err)
}
if got, want := child.Name(), "f3"; got != want {
t.Errorf("unexpected child name: %v, want %v", got, want)
}
if got, want := child.Size(), int64(3); got != want {
t.Errorf("unexpected child size: %v, want %v", got, want)
}
if _, err = fs.ReadDirAndFindChild(ctx, dir, "f4"); err != fs.ErrEntryNotFound {
t.Errorf("unexpected child error: %v", err)
}
// read child again, this time using ReadAndFindChild
child2, err := fs.ReadDirAndFindChild(ctx, dir, "f3")
if err != nil {
t.Errorf("child2 error: %v", err)
}
if got, want := child2.Name(), "f3"; got != want {
t.Errorf("unexpected child2 name: %v, want %v", got, want)
}
if got, want := child2.Size(), int64(3); got != want {
t.Errorf("unexpected child2 size: %v, want %v", got, want)
}
}
func assertNoError(t *testing.T, err error) {
+13
View File
@@ -22,6 +22,19 @@ type loggingDirectory struct {
fs.Directory
}
func (ld *loggingDirectory) Child(ctx context.Context, name string) (fs.Entry, error) {
t0 := time.Now()
entry, err := ld.Directory.Child(ctx, name)
dt := time.Since(t0)
ld.options.printf(ld.options.prefix+"Child(%v) took %v and returned %v", ld.relativePath, dt, err)
if err != nil {
return nil, err
}
return wrapWithOptions(entry, ld.options, ld.relativePath+"/"+entry.Name()), nil
}
func (ld *loggingDirectory) Readdir(ctx context.Context) (fs.Entries, error) {
t0 := time.Now()
entries, err := ld.Directory.Readdir(ctx)
+4
View File
@@ -173,6 +173,10 @@ func (imd *Directory) FailReaddir(err error) {
imd.readdirError = err
}
func (imd *Directory) Child(ctx context.Context, name string) (fs.Entry, error) {
return fs.ReadDirAndFindChild(ctx, imd, name)
}
// Readdir gets the contents of a directory.
func (imd *Directory) Readdir(ctx context.Context) (fs.Entries, error) {
if imd.readdirError != nil {
+4
View File
@@ -47,6 +47,10 @@ func (s *repositoryAllSources) Sys() interface{} {
return nil
}
func (s *repositoryAllSources) Child(ctx context.Context, name string) (fs.Entry, error) {
return fs.ReadDirAndFindChild(ctx, s, name)
}
func (s *repositoryAllSources) Readdir(ctx context.Context) (fs.Entries, error) {
srcs, err := snapshot.ListSources(ctx, s.rep)
if err != nil {
+4
View File
@@ -79,6 +79,10 @@ func (rd *repositoryDirectory) Summary() *fs.DirectorySummary {
return rd.summary
}
func (rd *repositoryDirectory) Child(ctx context.Context, name string) (fs.Entry, error) {
return fs.ReadDirAndFindChild(ctx, rd, name)
}
func (rd *repositoryDirectory) Readdir(ctx context.Context) (fs.Entries, error) {
r, err := rd.repo.Objects.Open(ctx, rd.metadata.ObjectID)
if err != nil {
@@ -47,6 +47,10 @@ func (s *sourceDirectories) Owner() fs.OwnerInfo {
return fs.OwnerInfo{}
}
func (s *sourceDirectories) Child(ctx context.Context, name string) (fs.Entry, error) {
return fs.ReadDirAndFindChild(ctx, s, name)
}
func (s *sourceDirectories) Readdir(ctx context.Context) (fs.Entries, error) {
sources, err := snapshot.ListSources(ctx, s.rep)
if err != nil {
@@ -67,3 +71,5 @@ func (s *sourceDirectories) Readdir(ctx context.Context) (fs.Entries, error) {
return result, nil
}
var _ fs.Directory = (*sourceDirectories)(nil)
+6
View File
@@ -56,6 +56,10 @@ func (s *sourceSnapshots) Summary() *fs.DirectorySummary {
return nil
}
func (s *sourceSnapshots) Child(ctx context.Context, name string) (fs.Entry, error) {
return fs.ReadDirAndFindChild(ctx, s, name)
}
func (s *sourceSnapshots) Readdir(ctx context.Context) (fs.Entries, error) {
manifests, err := snapshot.ListSnapshots(ctx, s.rep, s.src)
if err != nil {
@@ -94,3 +98,5 @@ func (s *sourceSnapshots) Readdir(ctx context.Context) (fs.Entries, error) {
return result, nil
}
var _ fs.Directory = (*sourceSnapshots)(nil)