mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
mount: rewrite ReadDir to respect input.Offset to fix partial results
This commit is contained in:
parent
05602167f4
commit
cb422d96f7
|
@ -12,9 +12,22 @@ import (
|
||||||
|
|
||||||
type DirectoryHandleId uint64
|
type DirectoryHandleId uint64
|
||||||
|
|
||||||
|
const (
|
||||||
|
directoryStreamBaseOffset = 2 // . & ..
|
||||||
|
)
|
||||||
|
|
||||||
type DirectoryHandle struct {
|
type DirectoryHandle struct {
|
||||||
isFinished bool
|
isFinished bool
|
||||||
lastEntryName string
|
entryStream []*filer.Entry
|
||||||
|
entryStreamOffset uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dh *DirectoryHandle) reset() {
|
||||||
|
*dh = DirectoryHandle{
|
||||||
|
isFinished: false,
|
||||||
|
entryStream: []*filer.Entry{},
|
||||||
|
entryStreamOffset: directoryStreamBaseOffset,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type DirectoryHandleToInode struct {
|
type DirectoryHandleToInode struct {
|
||||||
|
@ -37,10 +50,8 @@ func (wfs *WFS) AcquireDirectoryHandle() (DirectoryHandleId, *DirectoryHandle) {
|
||||||
|
|
||||||
wfs.dhmap.Lock()
|
wfs.dhmap.Lock()
|
||||||
defer wfs.dhmap.Unlock()
|
defer wfs.dhmap.Unlock()
|
||||||
dh := &DirectoryHandle{
|
dh := new(DirectoryHandle)
|
||||||
isFinished: false,
|
dh.reset()
|
||||||
lastEntryName: "",
|
|
||||||
}
|
|
||||||
wfs.dhmap.dir2inode[DirectoryHandleId(fh)] = dh
|
wfs.dhmap.dir2inode[DirectoryHandleId(fh)] = dh
|
||||||
return DirectoryHandleId(fh), dh
|
return DirectoryHandleId(fh), dh
|
||||||
}
|
}
|
||||||
|
@ -51,11 +62,8 @@ func (wfs *WFS) GetDirectoryHandle(dhid DirectoryHandleId) *DirectoryHandle {
|
||||||
if dh, found := wfs.dhmap.dir2inode[dhid]; found {
|
if dh, found := wfs.dhmap.dir2inode[dhid]; found {
|
||||||
return dh
|
return dh
|
||||||
}
|
}
|
||||||
dh := &DirectoryHandle{
|
dh := new(DirectoryHandle)
|
||||||
isFinished: false,
|
dh.reset()
|
||||||
lastEntryName: "",
|
|
||||||
}
|
|
||||||
|
|
||||||
wfs.dhmap.dir2inode[dhid] = dh
|
wfs.dhmap.dir2inode[dhid] = dh
|
||||||
return dh
|
return dh
|
||||||
}
|
}
|
||||||
|
@ -130,13 +138,12 @@ func (wfs *WFS) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out *fus
|
||||||
}
|
}
|
||||||
|
|
||||||
func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPlusMode bool) fuse.Status {
|
func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPlusMode bool) fuse.Status {
|
||||||
|
|
||||||
dh := wfs.GetDirectoryHandle(DirectoryHandleId(input.Fh))
|
dh := wfs.GetDirectoryHandle(DirectoryHandleId(input.Fh))
|
||||||
if input.Offset == 0 {
|
if input.Offset == 0 {
|
||||||
dh.isFinished = false
|
dh.reset()
|
||||||
dh.lastEntryName = ""
|
} else if dh.isFinished && input.Offset >= directoryStreamBaseOffset {
|
||||||
} else {
|
entryCurrentIndex := input.Offset - dh.entryStreamOffset
|
||||||
if dh.isFinished {
|
if uint64(len(dh.entryStream)) <= entryCurrentIndex {
|
||||||
return fuse.OK
|
return fuse.OK
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -148,29 +155,17 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||||
}
|
}
|
||||||
|
|
||||||
var dirEntry fuse.DirEntry
|
var dirEntry fuse.DirEntry
|
||||||
if input.Offset == 0 {
|
processEachEntryFn := func(entry *filer.Entry) bool {
|
||||||
if !isPlusMode {
|
|
||||||
out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."})
|
|
||||||
out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
|
|
||||||
} else {
|
|
||||||
out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."})
|
|
||||||
out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
processEachEntryFn := func(entry *filer.Entry, isLast bool) bool {
|
|
||||||
dirEntry.Name = entry.Name()
|
dirEntry.Name = entry.Name()
|
||||||
dirEntry.Mode = toSyscallMode(entry.Mode)
|
dirEntry.Mode = toSyscallMode(entry.Mode)
|
||||||
|
inode := wfs.inodeToPath.Lookup(dirPath.Child(dirEntry.Name), entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, isPlusMode)
|
||||||
|
dirEntry.Ino = inode
|
||||||
if !isPlusMode {
|
if !isPlusMode {
|
||||||
inode := wfs.inodeToPath.Lookup(dirPath.Child(dirEntry.Name), entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, false)
|
|
||||||
dirEntry.Ino = inode
|
|
||||||
if !out.AddDirEntry(dirEntry) {
|
if !out.AddDirEntry(dirEntry) {
|
||||||
isEarlyTerminated = true
|
isEarlyTerminated = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
inode := wfs.inodeToPath.Lookup(dirPath.Child(dirEntry.Name), entry.Crtime.Unix(), entry.IsDirectory(), len(entry.HardLinkId) > 0, entry.Inode, true)
|
|
||||||
dirEntry.Ino = inode
|
|
||||||
entryOut := out.AddDirLookupEntry(dirEntry)
|
entryOut := out.AddDirLookupEntry(dirEntry)
|
||||||
if entryOut == nil {
|
if entryOut == nil {
|
||||||
isEarlyTerminated = true
|
isEarlyTerminated = true
|
||||||
|
@ -182,35 +177,58 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl
|
||||||
}
|
}
|
||||||
wfs.outputFilerEntry(entryOut, inode, entry)
|
wfs.outputFilerEntry(entryOut, inode, entry)
|
||||||
}
|
}
|
||||||
dh.lastEntryName = entry.Name()
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
entryChan := make(chan *filer.Entry, 128)
|
if input.Offset < directoryStreamBaseOffset {
|
||||||
var err error
|
if !isPlusMode {
|
||||||
go func() {
|
if input.Offset == 0 {
|
||||||
if err = meta_cache.EnsureVisited(wfs.metaCache, wfs, dirPath, entryChan); err != nil {
|
out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."})
|
||||||
glog.Errorf("dir ReadDirAll %s: %v", dirPath, err)
|
}
|
||||||
|
out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
|
||||||
|
} else {
|
||||||
|
if input.Offset == 0 {
|
||||||
|
out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "."})
|
||||||
|
}
|
||||||
|
out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".."})
|
||||||
}
|
}
|
||||||
close(entryChan)
|
input.Offset = directoryStreamBaseOffset
|
||||||
}()
|
|
||||||
hasData := false
|
|
||||||
for entry := range entryChan {
|
|
||||||
hasData = true
|
|
||||||
processEachEntryFn(entry, false)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return fuse.EIO
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hasData {
|
var lastEntryName string
|
||||||
listErr := wfs.metaCache.ListDirectoryEntries(context.Background(), dirPath, dh.lastEntryName, false, int64(math.MaxInt32), func(entry *filer.Entry) bool {
|
if input.Offset >= directoryStreamBaseOffset {
|
||||||
return processEachEntryFn(entry, false)
|
if input.Offset > directoryStreamBaseOffset {
|
||||||
})
|
entryPreviousIndex := (input.Offset - dh.entryStreamOffset) - 1
|
||||||
if listErr != nil {
|
if uint64(len(dh.entryStream)) > entryPreviousIndex {
|
||||||
glog.Errorf("list meta cache: %v", listErr)
|
lastEntryName = dh.entryStream[entryPreviousIndex].Name()
|
||||||
return fuse.EIO
|
dh.entryStream = dh.entryStream[entryPreviousIndex:]
|
||||||
|
dh.entryStreamOffset = input.Offset - 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
entryCurrentIndex := input.Offset - dh.entryStreamOffset
|
||||||
|
for uint64(len(dh.entryStream)) > entryCurrentIndex {
|
||||||
|
entry := dh.entryStream[entryCurrentIndex]
|
||||||
|
if processEachEntryFn(entry) {
|
||||||
|
lastEntryName = entry.Name()
|
||||||
|
entryCurrentIndex++
|
||||||
|
} else {
|
||||||
|
// early terminated
|
||||||
|
return fuse.OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
if err = meta_cache.EnsureVisited(wfs.metaCache, wfs, dirPath, nil); err != nil {
|
||||||
|
glog.Errorf("dir ReadDirAll %s: %v", dirPath, err)
|
||||||
|
}
|
||||||
|
listErr := wfs.metaCache.ListDirectoryEntries(context.Background(), dirPath, lastEntryName, false, int64(math.MaxInt32), func(entry *filer.Entry) bool {
|
||||||
|
dh.entryStream = append(dh.entryStream, entry)
|
||||||
|
return processEachEntryFn(entry)
|
||||||
|
})
|
||||||
|
if listErr != nil {
|
||||||
|
glog.Errorf("list meta cache: %v", listErr)
|
||||||
|
return fuse.EIO
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isEarlyTerminated {
|
if !isEarlyTerminated {
|
||||||
|
|
Loading…
Reference in a new issue