mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-01-19 02:48:24 +00:00
POSIX: ensure file and directory inodes are different
this is just an in memory representation. POSIX wants different inode numbers for the same named file or directory.
This commit is contained in:
parent
5bb37d5905
commit
2dcb8cb93b
|
@ -103,7 +103,7 @@ func (dir *Dir) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
|
||||||
func (dir *Dir) newFile(name string) fs.Node {
|
func (dir *Dir) newFile(name string) fs.Node {
|
||||||
|
|
||||||
fileFullPath := util.NewFullPath(dir.FullPath(), name)
|
fileFullPath := util.NewFullPath(dir.FullPath(), name)
|
||||||
fileId := fileFullPath.AsInode()
|
fileId := fileFullPath.AsInode(false)
|
||||||
dir.wfs.handlesLock.Lock()
|
dir.wfs.handlesLock.Lock()
|
||||||
existingHandle, found := dir.wfs.handles[fileId]
|
existingHandle, found := dir.wfs.handles[fileId]
|
||||||
dir.wfs.handlesLock.Unlock()
|
dir.wfs.handlesLock.Unlock()
|
||||||
|
@ -122,7 +122,7 @@ func (dir *Dir) newFile(name string) fs.Node {
|
||||||
|
|
||||||
func (dir *Dir) newDirectory(fullpath util.FullPath) fs.Node {
|
func (dir *Dir) newDirectory(fullpath util.FullPath) fs.Node {
|
||||||
|
|
||||||
return &Dir{name: fullpath.Name(), wfs: dir.wfs, parent: dir, id: fullpath.AsInode()}
|
return &Dir{name: fullpath.Name(), wfs: dir.wfs, parent: dir, id: fullpath.AsInode(true)}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +316,6 @@ func (dir *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.
|
||||||
}
|
}
|
||||||
|
|
||||||
// resp.EntryValid = time.Second
|
// resp.EntryValid = time.Second
|
||||||
resp.Attr.Inode = fullFilePath.AsInode()
|
|
||||||
resp.Attr.Valid = time.Second
|
resp.Attr.Valid = time.Second
|
||||||
resp.Attr.Size = localEntry.FileSize
|
resp.Attr.Size = localEntry.FileSize
|
||||||
resp.Attr.Mtime = localEntry.Attr.Mtime
|
resp.Attr.Mtime = localEntry.Attr.Mtime
|
||||||
|
@ -342,10 +341,10 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
|
||||||
|
|
||||||
processEachEntryFn := func(entry *filer.Entry, isLast bool) {
|
processEachEntryFn := func(entry *filer.Entry, isLast bool) {
|
||||||
if entry.IsDirectory() {
|
if entry.IsDirectory() {
|
||||||
dirent := fuse.Dirent{Name: entry.Name(), Type: fuse.DT_Dir, Inode: dirPath.Child(entry.Name()).AsInode()}
|
dirent := fuse.Dirent{Name: entry.Name(), Type: fuse.DT_Dir, Inode: dirPath.Child(entry.Name()).AsInode(true)}
|
||||||
ret = append(ret, dirent)
|
ret = append(ret, dirent)
|
||||||
} else {
|
} else {
|
||||||
dirent := fuse.Dirent{Name: entry.Name(), Type: findFileType(uint16(entry.Attr.Mode)), Inode: dirPath.Child(entry.Name()).AsInode()}
|
dirent := fuse.Dirent{Name: entry.Name(), Type: findFileType(uint16(entry.Attr.Mode)), Inode: dirPath.Child(entry.Name()).AsInode(false)}
|
||||||
ret = append(ret, dirent)
|
ret = append(ret, dirent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -365,7 +364,7 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
|
||||||
|
|
||||||
// create proper . and .. directories
|
// create proper . and .. directories
|
||||||
ret = append(ret, fuse.Dirent{
|
ret = append(ret, fuse.Dirent{
|
||||||
Inode: dirPath.AsInode(),
|
Inode: dirPath.AsInode(true),
|
||||||
Name: ".",
|
Name: ".",
|
||||||
Type: fuse.DT_Dir,
|
Type: fuse.DT_Dir,
|
||||||
})
|
})
|
||||||
|
@ -375,7 +374,7 @@ func (dir *Dir) ReadDirAll(ctx context.Context) (ret []fuse.Dirent, err error) {
|
||||||
if string(dirPath) == dir.wfs.option.FilerMountRootPath {
|
if string(dirPath) == dir.wfs.option.FilerMountRootPath {
|
||||||
inode = dir.wfs.option.MountParentInode
|
inode = dir.wfs.option.MountParentInode
|
||||||
} else {
|
} else {
|
||||||
inode = util.FullPath(dir.parent.FullPath()).AsInode()
|
inode = util.FullPath(dir.parent.FullPath()).AsInode(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = append(ret, fuse.Dirent{
|
ret = append(ret, fuse.Dirent{
|
||||||
|
@ -444,7 +443,7 @@ func (dir *Dir) removeOneFile(req *fuse.RemoveRequest) error {
|
||||||
// remove current file handle if any
|
// remove current file handle if any
|
||||||
dir.wfs.handlesLock.Lock()
|
dir.wfs.handlesLock.Lock()
|
||||||
defer dir.wfs.handlesLock.Unlock()
|
defer dir.wfs.handlesLock.Unlock()
|
||||||
inodeId := filePath.AsInode()
|
inodeId := filePath.AsInode(false)
|
||||||
if fh, ok := dir.wfs.handles[inodeId]; ok {
|
if fh, ok := dir.wfs.handles[inodeId]; ok {
|
||||||
delete(dir.wfs.handles, inodeId)
|
delete(dir.wfs.handles, inodeId)
|
||||||
fh.isDeleted = true
|
fh.isDeleted = true
|
||||||
|
|
|
@ -84,11 +84,13 @@ func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamR
|
||||||
oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
|
oldParent, newParent := util.FullPath(resp.Directory), util.FullPath(resp.EventNotification.NewParentPath)
|
||||||
oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
|
oldName, newName := resp.EventNotification.OldEntry.Name, resp.EventNotification.NewEntry.Name
|
||||||
|
|
||||||
|
isDirectory := newEntry.IsDirectory()
|
||||||
|
|
||||||
oldPath := oldParent.Child(oldName)
|
oldPath := oldParent.Child(oldName)
|
||||||
newPath := newParent.Child(newName)
|
newPath := newParent.Child(newName)
|
||||||
oldFsNode := NodeWithId(oldPath.AsInode())
|
oldFsNode := NodeWithId(oldPath.AsInode(isDirectory))
|
||||||
newFsNode := NodeWithId(newPath.AsInode())
|
newFsNode := NodeWithId(newPath.AsInode(isDirectory))
|
||||||
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode()))
|
newDirNode, found := dir.wfs.Server.FindInternalNode(NodeWithId(newParent.AsInode(true)))
|
||||||
var newDir *Dir
|
var newDir *Dir
|
||||||
if found {
|
if found {
|
||||||
newDir = newDirNode.(*Dir)
|
newDir = newDirNode.(*Dir)
|
||||||
|
@ -113,17 +115,19 @@ func (dir *Dir) handleRenameResponse(ctx context.Context, resp *filer_pb.StreamR
|
||||||
})
|
})
|
||||||
|
|
||||||
// change file handle
|
// change file handle
|
||||||
inodeId := oldPath.AsInode()
|
if !isDirectory {
|
||||||
dir.wfs.handlesLock.Lock()
|
inodeId := oldPath.AsInode(isDirectory)
|
||||||
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
|
dir.wfs.handlesLock.Lock()
|
||||||
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
|
if existingHandle, found := dir.wfs.handles[inodeId]; found && existingHandle != nil {
|
||||||
delete(dir.wfs.handles, inodeId)
|
glog.V(4).Infof("opened file handle %s => %s", oldPath, newPath)
|
||||||
existingHandle.handle = newPath.AsInode()
|
delete(dir.wfs.handles, inodeId)
|
||||||
existingHandle.f.entry.Name = newName
|
existingHandle.handle = newPath.AsInode(isDirectory)
|
||||||
existingHandle.f.id = newPath.AsInode()
|
existingHandle.f.entry.Name = newName
|
||||||
dir.wfs.handles[newPath.AsInode()] = existingHandle
|
existingHandle.f.id = newPath.AsInode(isDirectory)
|
||||||
|
dir.wfs.handles[newPath.AsInode(isDirectory)] = existingHandle
|
||||||
|
}
|
||||||
|
dir.wfs.handlesLock.Unlock()
|
||||||
}
|
}
|
||||||
dir.wfs.handlesLock.Unlock()
|
|
||||||
|
|
||||||
} else if resp.EventNotification.OldEntry != nil {
|
} else if resp.EventNotification.OldEntry != nil {
|
||||||
// without new entry, only old entry name exists. This is the second step to delete old entry
|
// without new entry, only old entry name exists. This is the second step to delete old entry
|
||||||
|
|
|
@ -259,7 +259,7 @@ func (file *File) Fsync(ctx context.Context, req *fuse.FsyncRequest) error {
|
||||||
func (file *File) Forget() {
|
func (file *File) Forget() {
|
||||||
t := util.NewFullPath(file.dir.FullPath(), file.Name)
|
t := util.NewFullPath(file.dir.FullPath(), file.Name)
|
||||||
glog.V(4).Infof("Forget file %s", t)
|
glog.V(4).Infof("Forget file %s", t)
|
||||||
file.wfs.ReleaseHandle(t, fuse.HandleID(t.AsInode()))
|
file.wfs.ReleaseHandle(t, fuse.HandleID(t.AsInode(false)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (file *File) maybeLoadEntry(ctx context.Context) (entry *filer_pb.Entry, err error) {
|
func (file *File) maybeLoadEntry(ctx context.Context) (entry *filer_pb.Entry, err error) {
|
||||||
|
|
|
@ -18,16 +18,16 @@ type MetaCache struct {
|
||||||
// sync.RWMutex
|
// sync.RWMutex
|
||||||
visitedBoundary *bounded_tree.BoundedTree
|
visitedBoundary *bounded_tree.BoundedTree
|
||||||
uidGidMapper *UidGidMapper
|
uidGidMapper *UidGidMapper
|
||||||
invalidateFunc func(util.FullPath)
|
invalidateFunc func(fullpath util.FullPath, isDirectory bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMetaCache(dbFolder string, baseDir util.FullPath, uidGidMapper *UidGidMapper, invalidateFunc func(util.FullPath)) *MetaCache {
|
func NewMetaCache(dbFolder string, baseDir util.FullPath, uidGidMapper *UidGidMapper, invalidateFunc func(util.FullPath, bool)) *MetaCache {
|
||||||
return &MetaCache{
|
return &MetaCache{
|
||||||
localStore: openMetaStore(dbFolder),
|
localStore: openMetaStore(dbFolder),
|
||||||
visitedBoundary: bounded_tree.NewBoundedTree(baseDir),
|
visitedBoundary: bounded_tree.NewBoundedTree(baseDir),
|
||||||
uidGidMapper: uidGidMapper,
|
uidGidMapper: uidGidMapper,
|
||||||
invalidateFunc: func(fullpath util.FullPath) {
|
invalidateFunc: func(fullpath util.FullPath, isDirectory bool) {
|
||||||
invalidateFunc(fullpath)
|
invalidateFunc(fullpath, isDirectory)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,16 +40,16 @@ func SubscribeMetaEvents(mc *MetaCache, selfSignature int32, client filer_pb.Fil
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if message.OldEntry != nil && message.NewEntry != nil {
|
if message.OldEntry != nil && message.NewEntry != nil {
|
||||||
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
|
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
|
||||||
mc.invalidateFunc(oldKey)
|
mc.invalidateFunc(oldKey, message.OldEntry.IsDirectory)
|
||||||
if message.OldEntry.Name != message.NewEntry.Name {
|
if message.OldEntry.Name != message.NewEntry.Name {
|
||||||
newKey := util.NewFullPath(dir, message.NewEntry.Name)
|
newKey := util.NewFullPath(dir, message.NewEntry.Name)
|
||||||
mc.invalidateFunc(newKey)
|
mc.invalidateFunc(newKey, message.NewEntry.IsDirectory)
|
||||||
}
|
}
|
||||||
} else if message.OldEntry == nil && message.NewEntry != nil {
|
} else if message.OldEntry == nil && message.NewEntry != nil {
|
||||||
// no need to invaalidate
|
// no need to invaalidate
|
||||||
} else if message.OldEntry != nil && message.NewEntry == nil {
|
} else if message.OldEntry != nil && message.NewEntry == nil {
|
||||||
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
|
oldKey := util.NewFullPath(resp.Directory, message.OldEntry.Name)
|
||||||
mc.invalidateFunc(oldKey)
|
mc.invalidateFunc(oldKey, message.OldEntry.IsDirectory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,15 +109,15 @@ func NewSeaweedFileSystem(option *Option) *WFS {
|
||||||
wfs.chunkCache = chunk_cache.NewTieredChunkCache(256, option.getUniqueCacheDir(), option.CacheSizeMB, 1024*1024)
|
wfs.chunkCache = chunk_cache.NewTieredChunkCache(256, option.getUniqueCacheDir(), option.CacheSizeMB, 1024*1024)
|
||||||
}
|
}
|
||||||
|
|
||||||
wfs.metaCache = meta_cache.NewMetaCache(path.Join(option.getUniqueCacheDir(), "meta"), util.FullPath(option.FilerMountRootPath), option.UidGidMapper, func(filePath util.FullPath) {
|
wfs.metaCache = meta_cache.NewMetaCache(path.Join(option.getUniqueCacheDir(), "meta"), util.FullPath(option.FilerMountRootPath), option.UidGidMapper, func(filePath util.FullPath, isDirectory bool) {
|
||||||
|
|
||||||
fsNode := NodeWithId(filePath.AsInode())
|
fsNode := NodeWithId(filePath.AsInode(isDirectory))
|
||||||
if err := wfs.Server.InvalidateNodeData(fsNode); err != nil {
|
if err := wfs.Server.InvalidateNodeData(fsNode); err != nil {
|
||||||
glog.V(4).Infof("InvalidateNodeData %s : %v", filePath, err)
|
glog.V(4).Infof("InvalidateNodeData %s : %v", filePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
dir, name := filePath.DirAndName()
|
dir, name := filePath.DirAndName()
|
||||||
parent := NodeWithId(util.FullPath(dir).AsInode())
|
parent := NodeWithId(util.FullPath(dir).AsInode(true))
|
||||||
if dir == option.FilerMountRootPath {
|
if dir == option.FilerMountRootPath {
|
||||||
parent = NodeWithId(1)
|
parent = NodeWithId(1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,14 @@ func (fp FullPath) Child(name string) FullPath {
|
||||||
return FullPath(dir + "/" + noPrefix)
|
return FullPath(dir + "/" + noPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fp FullPath) AsInode() uint64 {
|
func (fp FullPath) AsInode(isDirectory bool) uint64 {
|
||||||
return uint64(HashStringToLong(string(fp)))
|
inode := uint64(HashStringToLong(string(fp)))
|
||||||
|
if isDirectory {
|
||||||
|
inode = inode - inode%2 // even
|
||||||
|
} else {
|
||||||
|
inode = inode - inode%2 + 1 // odd
|
||||||
|
}
|
||||||
|
return inode
|
||||||
}
|
}
|
||||||
|
|
||||||
// split, but skipping the root
|
// split, but skipping the root
|
||||||
|
|
Loading…
Reference in a new issue