mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2025-10-21 17:47:25 +08:00
hardlink works now
This commit is contained in:
@@ -267,6 +267,9 @@ func (dir *Dir) Lookup(ctx context.Context, req *fuse.LookupRequest, resp *fuse.
|
||||
resp.Attr.Mode = os.FileMode(entry.Attributes.FileMode)
|
||||
resp.Attr.Gid = entry.Attributes.Gid
|
||||
resp.Attr.Uid = entry.Attributes.Uid
|
||||
if entry.HardLinkCounter > 0 {
|
||||
resp.Attr.Nlink = uint32(entry.HardLinkCounter)
|
||||
}
|
||||
|
||||
return node, nil
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package filesys
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/chrislusf/seaweedfs/weed/util"
|
||||
"os"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -13,9 +14,88 @@ import (
|
||||
"github.com/seaweedfs/fuse/fs"
|
||||
)
|
||||
|
||||
var _ = fs.NodeLinker(&Dir{})
|
||||
var _ = fs.NodeSymlinker(&Dir{})
|
||||
var _ = fs.NodeReadlinker(&File{})
|
||||
|
||||
func (dir *Dir) Link(ctx context.Context, req *fuse.LinkRequest, old fs.Node) (fs.Node, error) {
|
||||
|
||||
oldFile, ok := old.(*File)
|
||||
if !ok {
|
||||
glog.Errorf("old node is not a file: %+v", old)
|
||||
}
|
||||
|
||||
glog.V(4).Infof("Link: %v/%v -> %v/%v", oldFile.dir.FullPath(), oldFile.Name, dir.FullPath(), req.NewName)
|
||||
|
||||
if err := oldFile.maybeLoadEntry(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// update old file to hardlink mode
|
||||
var updateOldEntryRequest *filer_pb.UpdateEntryRequest
|
||||
var hardLinkId filer.HardLinkId
|
||||
if oldFile.entry.HardLinkId != 0 {
|
||||
hardLinkId = filer.HardLinkId(oldFile.entry.HardLinkId)
|
||||
} else {
|
||||
// CreateLink 1.1 : split source entry into hardlink+empty_entry
|
||||
hardLinkId = filer.HardLinkId(util.RandomInt64())
|
||||
updateOldEntryRequest = &filer_pb.UpdateEntryRequest{
|
||||
Directory: oldFile.dir.FullPath(),
|
||||
Entry: &filer_pb.Entry{
|
||||
Name: oldFile.entry.Name,
|
||||
IsDirectory: oldFile.entry.IsDirectory,
|
||||
HardLinkId: int64(hardLinkId),
|
||||
},
|
||||
Signatures: []int32{dir.wfs.signature},
|
||||
}
|
||||
}
|
||||
|
||||
// CreateLink 1.2 : update new file to hardlink mode
|
||||
request := &filer_pb.CreateEntryRequest{
|
||||
Directory: dir.FullPath(),
|
||||
Entry: &filer_pb.Entry{
|
||||
Name: req.NewName,
|
||||
IsDirectory: false,
|
||||
HardLinkId: int64(hardLinkId),
|
||||
},
|
||||
Signatures: []int32{dir.wfs.signature},
|
||||
}
|
||||
|
||||
// apply changes to the filer, and also apply to local metaCache
|
||||
err := dir.wfs.WithFilerClient(func(client filer_pb.SeaweedFilerClient) error {
|
||||
|
||||
dir.wfs.mapPbIdFromLocalToFiler(request.Entry)
|
||||
defer dir.wfs.mapPbIdFromFilerToLocal(request.Entry)
|
||||
|
||||
if updateOldEntryRequest != nil {
|
||||
if err := filer_pb.UpdateEntry(client, updateOldEntryRequest); err != nil {
|
||||
glog.V(0).Infof("Link %v/%v -> %s/%s: %v", oldFile.dir.FullPath(), oldFile.Name, dir.FullPath(), req.NewName, err)
|
||||
return fuse.EIO
|
||||
}
|
||||
dir.wfs.metaCache.UpdateEntry(context.Background(), filer.FromPbEntry(updateOldEntryRequest.Directory, updateOldEntryRequest.Entry))
|
||||
oldFile.entry.HardLinkId = int64(hardLinkId)
|
||||
}
|
||||
|
||||
if err := filer_pb.CreateEntry(client, request); err != nil {
|
||||
glog.V(0).Infof("Link %v/%v -> %s/%s: %v", oldFile.dir.FullPath(), oldFile.Name, dir.FullPath(), req.NewName, err)
|
||||
return fuse.EIO
|
||||
}
|
||||
dir.wfs.metaCache.InsertEntry(context.Background(), filer.FromPbEntry(request.Directory, request.Entry))
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// create new file node
|
||||
newNode := dir.newFile(req.NewName, request.Entry)
|
||||
newFile := newNode.(*File)
|
||||
if err := newFile.maybeLoadEntry(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newFile, err
|
||||
|
||||
}
|
||||
|
||||
func (dir *Dir) Symlink(ctx context.Context, req *fuse.SymlinkRequest) (fs.Node, error) {
|
||||
|
||||
glog.V(4).Infof("Symlink: %v/%v to %v", dir.FullPath(), req.NewName, req.Target)
|
||||
|
@@ -67,6 +67,9 @@ func (file *File) Attr(ctx context.Context, attr *fuse.Attr) error {
|
||||
attr.Uid = file.entry.Attributes.Uid
|
||||
attr.Blocks = attr.Size/blockSize + 1
|
||||
attr.BlockSize = uint32(file.wfs.option.ChunkSizeLimit)
|
||||
if file.entry.HardLinkCounter > 0 {
|
||||
attr.Nlink = uint32(file.entry.HardLinkCounter)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -250,7 +253,7 @@ func (file *File) Forget() {
|
||||
}
|
||||
|
||||
func (file *File) maybeLoadEntry(ctx context.Context) error {
|
||||
if file.entry == nil && file.isOpen <= 0 {
|
||||
if (file.entry == nil || file.entry.HardLinkId != 0) && file.isOpen <= 0 {
|
||||
entry, err := file.wfs.maybeLoadEntry(file.dir.FullPath(), file.Name)
|
||||
if err != nil {
|
||||
glog.V(3).Infof("maybeLoadEntry file %s/%s: %v", file.dir.FullPath(), file.Name, err)
|
||||
|
@@ -8,7 +8,6 @@ import (
|
||||
"github.com/chrislusf/seaweedfs/weed/filer"
|
||||
"github.com/chrislusf/seaweedfs/weed/filer/leveldb"
|
||||
"github.com/chrislusf/seaweedfs/weed/glog"
|
||||
"github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/chrislusf/seaweedfs/weed/util"
|
||||
"github.com/chrislusf/seaweedfs/weed/util/bounded_tree"
|
||||
)
|
||||
@@ -17,7 +16,7 @@ import (
|
||||
// e.g. fill fileId field for chunks
|
||||
|
||||
type MetaCache struct {
|
||||
localStore filer.FilerStore
|
||||
localStore filer.VirtualFilerStore
|
||||
sync.RWMutex
|
||||
visitedBoundary *bounded_tree.BoundedTree
|
||||
uidGidMapper *UidGidMapper
|
||||
@@ -31,7 +30,7 @@ func NewMetaCache(dbFolder string, uidGidMapper *UidGidMapper) *MetaCache {
|
||||
}
|
||||
}
|
||||
|
||||
func openMetaStore(dbFolder string) filer.FilerStore {
|
||||
func openMetaStore(dbFolder string) filer.VirtualFilerStore {
|
||||
|
||||
os.RemoveAll(dbFolder)
|
||||
os.MkdirAll(dbFolder, 0755)
|
||||
@@ -45,7 +44,7 @@ func openMetaStore(dbFolder string) filer.FilerStore {
|
||||
glog.Fatalf("Failed to initialize metadata cache store for %s: %+v", store.GetName(), err)
|
||||
}
|
||||
|
||||
return store
|
||||
return filer.NewFilerStoreWrapper(store)
|
||||
|
||||
}
|
||||
|
||||
@@ -56,7 +55,6 @@ func (mc *MetaCache) InsertEntry(ctx context.Context, entry *filer.Entry) error
|
||||
}
|
||||
|
||||
func (mc *MetaCache) doInsertEntry(ctx context.Context, entry *filer.Entry) error {
|
||||
filer_pb.BeforeEntrySerialization(entry.Chunks)
|
||||
return mc.localStore.InsertEntry(ctx, entry)
|
||||
}
|
||||
|
||||
@@ -94,7 +92,6 @@ func (mc *MetaCache) AtomicUpdateEntryFromFiler(ctx context.Context, oldPath uti
|
||||
func (mc *MetaCache) UpdateEntry(ctx context.Context, entry *filer.Entry) error {
|
||||
mc.Lock()
|
||||
defer mc.Unlock()
|
||||
filer_pb.BeforeEntrySerialization(entry.Chunks)
|
||||
return mc.localStore.UpdateEntry(ctx, entry)
|
||||
}
|
||||
|
||||
@@ -106,7 +103,6 @@ func (mc *MetaCache) FindEntry(ctx context.Context, fp util.FullPath) (entry *fi
|
||||
return nil, err
|
||||
}
|
||||
mc.mapIdFromFilerToLocal(entry)
|
||||
filer_pb.AfterEntryDeserialization(entry.Chunks)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -126,7 +122,6 @@ func (mc *MetaCache) ListDirectoryEntries(ctx context.Context, dirPath util.Full
|
||||
}
|
||||
for _, entry := range entries {
|
||||
mc.mapIdFromFilerToLocal(entry)
|
||||
filer_pb.AfterEntryDeserialization(entry.Chunks)
|
||||
}
|
||||
return entries, err
|
||||
}
|
||||
|
@@ -208,8 +208,14 @@ func (wfs *WFS) Statfs(ctx context.Context, req *fuse.StatfsRequest, resp *fuse.
|
||||
}
|
||||
|
||||
func (wfs *WFS) mapPbIdFromFilerToLocal(entry *filer_pb.Entry) {
|
||||
if entry.Attributes == nil {
|
||||
return
|
||||
}
|
||||
entry.Attributes.Uid, entry.Attributes.Gid = wfs.option.UidGidMapper.FilerToLocal(entry.Attributes.Uid, entry.Attributes.Gid)
|
||||
}
|
||||
func (wfs *WFS) mapPbIdFromLocalToFiler(entry *filer_pb.Entry) {
|
||||
if entry.Attributes == nil {
|
||||
return
|
||||
}
|
||||
entry.Attributes.Uid, entry.Attributes.Gid = wfs.option.UidGidMapper.LocalToFiler(entry.Attributes.Uid, entry.Attributes.Gid)
|
||||
}
|
||||
|
Reference in New Issue
Block a user