vfs: Use fuse.Forget instead of cache TTL (#12)
* vfs: Use fuse.Forget instead of cache TTL Signed-off-by: Xuanwo <github@xuanwo.io> * Update docs Signed-off-by: Xuanwo <github@xuanwo.io>
This commit is contained in:
parent
2ce6125fbc
commit
0b64b1feef
14
README.md
14
README.md
|
@ -1,3 +1,15 @@
|
||||||
# BeyondFS
|
# BeyondFS
|
||||||
|
|
||||||
A high-performance, POSIX-ish File System based on [aos-dev/go-storage](https://github.com/aos-dev/go-storage).
|
A high-performance, POSIX-ish File System based on [beyondstorage/go-storage](https://github.com/beyondstorage/go-storage).
|
||||||
|
|
||||||
|
## Design
|
||||||
|
|
||||||
|
- Only cache metadata
|
||||||
|
- Sharable
|
||||||
|
- POSIX-ish
|
||||||
|
|
||||||
|
Refer to [RFC-5: BeyondFS Design](./docs/rfcs/5-beyond-fs-design.md) to know more.
|
||||||
|
|
||||||
|
## Current Status
|
||||||
|
|
||||||
|
We are working on [implement a POSIX-ish file system that only caches metadata locally](https://github.com/beyondstorage/beyond-fs/issues/8)
|
||||||
|
|
|
@ -166,6 +166,10 @@ func (fs *FS) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) Forget(nodeid, nlookup uint64) {
|
func (fs *FS) Forget(nodeid, nlookup uint64) {
|
||||||
|
err := fs.fs.DeleteInodeByID(nodeid)
|
||||||
|
if err != nil {
|
||||||
|
fs.logger.Error("forget", zap.Error(err))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
|
func (fs *FS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
|
||||||
|
|
|
@ -2,7 +2,6 @@ package meta
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/dgraph-io/badger/v3"
|
"github.com/dgraph-io/badger/v3"
|
||||||
)
|
)
|
||||||
|
@ -38,7 +37,7 @@ func (db badgerDB) Get(key []byte) (value []byte, err error) {
|
||||||
return v.ValueCopy(nil)
|
return v.ValueCopy(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db badgerDB) Set(key, value []byte, ttl time.Duration) (err error) {
|
func (db badgerDB) Set(key, value []byte) (err error) {
|
||||||
txn := db.db.NewTransaction(true)
|
txn := db.db.NewTransaction(true)
|
||||||
defer txn.Discard()
|
defer txn.Discard()
|
||||||
|
|
||||||
|
@ -47,10 +46,6 @@ func (db badgerDB) Set(key, value []byte, ttl time.Duration) (err error) {
|
||||||
Value: value,
|
Value: value,
|
||||||
}
|
}
|
||||||
|
|
||||||
if ttl != 0 {
|
|
||||||
e.ExpiresAt = uint64(time.Now().Add(ttl).Unix())
|
|
||||||
}
|
|
||||||
|
|
||||||
err = txn.SetEntry(e)
|
err = txn.SetEntry(e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -3,7 +3,6 @@ package meta
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkGet(b *testing.B) {
|
func BenchmarkGet(b *testing.B) {
|
||||||
|
@ -16,7 +15,7 @@ func BenchmarkGet(b *testing.B) {
|
||||||
key := bytes.Repeat([]byte{'a'}, 128)
|
key := bytes.Repeat([]byte{'a'}, 128)
|
||||||
value := bytes.Repeat([]byte{'a'}, 1024)
|
value := bytes.Repeat([]byte{'a'}, 1024)
|
||||||
|
|
||||||
err = srv.Set(key, value, time.Hour)
|
err = srv.Set(key, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Error(err)
|
b.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -38,6 +37,6 @@ func BenchmarkSet(b *testing.B) {
|
||||||
value := bytes.Repeat([]byte{'a'}, 1024)
|
value := bytes.Repeat([]byte{'a'}, 1024)
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
_ = srv.Set(key, value, time.Hour)
|
_ = srv.Set(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package meta
|
package meta
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Service interface {
|
type Service interface {
|
||||||
// Get will get the value with specified key.
|
// Get will get the value with specified key.
|
||||||
//
|
//
|
||||||
// value will be nil if key not found.
|
// value will be nil if key not found.
|
||||||
Get(key []byte) (value []byte, err error)
|
Get(key []byte) (value []byte, err error)
|
||||||
Set(key, value []byte, ttl time.Duration) (err error)
|
Set(key, value []byte) (err error)
|
||||||
Delete(key []byte) (err error)
|
Delete(key []byte) (err error)
|
||||||
PrefixDelete(prefix []byte) (err error)
|
PrefixDelete(prefix []byte) (err error)
|
||||||
Scan(prefix []byte) Iterator
|
Scan(prefix []byte) Iterator
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"github.com/beyondstorage/beyond-fs/meta"
|
"github.com/beyondstorage/beyond-fs/meta"
|
||||||
"github.com/beyondstorage/go-storage/v4/types"
|
"github.com/beyondstorage/go-storage/v4/types"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type dirHandleMap struct {
|
type dirHandleMap struct {
|
||||||
|
@ -58,8 +57,9 @@ func (dh *DirHandle) Next() (ino *Inode, err error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: maybe we can read data from cache instead.
|
||||||
ino = newInode(dh.ino.ID, o)
|
ino = newInode(dh.ino.ID, o)
|
||||||
err = dh.fs.SetInode(ino, time.Hour)
|
err = dh.fs.SetInode(ino)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
29
vfs/fs.go
29
vfs/fs.go
|
@ -2,14 +2,13 @@ package vfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go.uber.org/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
_ "github.com/beyondstorage/go-service-fs/v3"
|
_ "github.com/beyondstorage/go-service-fs/v3"
|
||||||
_ "github.com/beyondstorage/go-service-s3/v2"
|
_ "github.com/beyondstorage/go-service-s3/v2"
|
||||||
"github.com/beyondstorage/go-storage/v4/pairs"
|
"github.com/beyondstorage/go-storage/v4/pairs"
|
||||||
"github.com/beyondstorage/go-storage/v4/services"
|
"github.com/beyondstorage/go-storage/v4/services"
|
||||||
"github.com/beyondstorage/go-storage/v4/types"
|
"github.com/beyondstorage/go-storage/v4/types"
|
||||||
|
"go.uber.org/atomic"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/beyondstorage/beyond-fs/meta"
|
"github.com/beyondstorage/beyond-fs/meta"
|
||||||
|
@ -65,7 +64,7 @@ func NewFS(cfg *Config) (fs *FS, err error) {
|
||||||
o.ID = store.Metadata().WorkDir
|
o.ID = store.Metadata().WorkDir
|
||||||
o.Path = ""
|
o.Path = ""
|
||||||
o.Mode = types.ModeDir
|
o.Mode = types.ModeDir
|
||||||
err = fs.SetInode(newInode(1, o), 0)
|
err = fs.SetInode(newInode(1, o))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -85,6 +84,10 @@ func (fs *FS) Delete(parent uint64, name string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = fs.DeleteEntry(parent, name)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,13 +121,13 @@ func (fs *FS) DeleteDirHandle(dhid uint64) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fs *FS) SetInode(ino *Inode, ttl time.Duration) (err error) {
|
func (fs *FS) SetInode(ino *Inode) (err error) {
|
||||||
bs, err := ino.MarshalMsg(nil)
|
bs, err := ino.MarshalMsg(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("marshal inode: %w", err)
|
return fmt.Errorf("marshal inode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = fs.meta.Set(meta.InodeKey(ino.ID), bs, ttl)
|
err = fs.meta.Set(meta.InodeKey(ino.ID), bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("set inode: %w", err)
|
return fmt.Errorf("set inode: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -132,7 +135,7 @@ func (fs *FS) SetInode(ino *Inode, ttl time.Duration) (err error) {
|
||||||
// Don't set entry key for root directory.
|
// Don't set entry key for root directory.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
err = fs.meta.Set(meta.EntryKey(ino.ParentID, ino.Name), bs, ttl)
|
err = fs.meta.Set(meta.EntryKey(ino.ParentID, ino.Name), bs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("set entry: %w", err)
|
return fmt.Errorf("set entry: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -162,7 +165,11 @@ func (fs *FS) DeleteInode(ino *Inode) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("del inode: %w", err)
|
return fmt.Errorf("del inode: %w", err)
|
||||||
}
|
}
|
||||||
err = fs.meta.Delete(meta.EntryKey(ino.ParentID, ino.Name))
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs *FS) DeleteInodeByID(id uint64) (err error) {
|
||||||
|
err = fs.meta.Delete(meta.InodeKey(id))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("del inode: %w", err)
|
return fmt.Errorf("del inode: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -186,3 +193,11 @@ func (fs *FS) GetEntry(parent uint64, name string) (ino *Inode, err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fs *FS) DeleteEntry(parent uint64, name string) (err error) {
|
||||||
|
err = fs.meta.Delete(meta.EntryKey(parent, name))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("del inode: %w", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue