diff --git a/mem/file.go b/mem/file.go index 5a20730..d349225 100644 --- a/mem/file.go +++ b/mem/file.go @@ -31,6 +31,7 @@ type File struct { // atomic requires 64-bit alignment for struct field access at int64 readDirCount int64 + dirBuf []*FileData closed bool readOnly bool fileData *FileData @@ -150,7 +151,10 @@ func (f *File) Readdir(count int) (res []os.FileInfo, err error) { var outLength int64 f.fileData.Lock() - files := f.fileData.memDir.Files()[f.readDirCount:] + if f.dirBuf == nil { + f.dirBuf = f.fileData.memDir.Files() + } + files := f.dirBuf[f.readDirCount:] if count > 0 { if len(files) < count { outLength = int64(len(files)) diff --git a/mem/file_test.go b/mem/file_test.go index 998a5d0..d156190 100644 --- a/mem/file_test.go +++ b/mem/file_test.go @@ -2,6 +2,7 @@ package mem import ( "bytes" + "fmt" "io" "testing" "time" @@ -206,6 +207,49 @@ func TestFileDataSizeRace(t *testing.T) { } } +func TestFileReaddirBuffer(t *testing.T) { + dir := CreateDir("dir") + + const testFiles = 5 + for i := 0; i < testFiles; i++ { + fd := CreateFile(fmt.Sprintf("%d.txt", i)) + AddToMemDir(dir, fd) + } + + f := NewFileHandle(dir) + defer f.Close() + // Read part of all files + wantNames := 3 + names, err := f.Readdirnames(wantNames) + if err != nil { + t.Fatal(err) + } + if len(names) != wantNames { + t.Fatalf("got %d names %v, want %d", len(names), names, wantNames) + } + + // Remove half of files + for _, fd := range dir.memDir.Files()[:testFiles/2] { + RemoveFromMemDir(dir, fd) + } + + // Try to read more files than remaining + wantNames = testFiles - len(names) + names, err = f.Readdirnames(wantNames + 1) + if err != nil { + t.Fatal(err) + } + if len(names) != wantNames { + t.Fatalf("got %d names %v, want %d", len(names), names, wantNames) + } + + // End of directory + _, err = f.Readdirnames(testFiles + 1) + if err != io.EOF { + t.Fatal(err) + } +} + func TestFileReadAtSeekOffset(t *testing.T) { t.Parallel()