update
This commit is contained in:
parent
7b1863109c
commit
ef751771d2
107 changed files with 9435 additions and 850 deletions
src/export/nfs
127
src/export/nfs/kvhandler.go
Normal file
127
src/export/nfs/kvhandler.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package nfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
|
||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/royalcat/kv"
|
||||
)
|
||||
|
||||
const lifetime = time.Hour * 24
|
||||
|
||||
// NewKvHandler provides a basic to/from-file handle cache that can be tuned with a smaller cache of active directory listings.
|
||||
func NewKvHandler(h nfs.Handler, fs nfs.Filesystem) (nfs.Handler, error) {
|
||||
activeHandles, err := kv.NewBadgerKVMarhsler[uuid.UUID, []string](path.Join(config.Config.Mounts.NFS.CachePath, "handlers"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// if s, ok := activeHandles.(kv.BadgerStore); ok {
|
||||
// db := s.BadgerDB()
|
||||
// enable with managed database
|
||||
// go func() {
|
||||
// for n := range time.NewTimer(lifetime / 2).C {
|
||||
// db.SetDiscardTs(uint64(n.Add(-lifetime).Unix()))
|
||||
// }
|
||||
// }()
|
||||
// }
|
||||
|
||||
return &CachingHandler{
|
||||
Handler: h,
|
||||
fs: fs,
|
||||
activeHandles: activeHandles,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CachingHandler implements to/from handle via an LRU cache.
|
||||
type CachingHandler struct {
|
||||
nfs.Handler
|
||||
|
||||
fs nfs.Filesystem
|
||||
activeHandles kv.Store[uuid.UUID, []string]
|
||||
}
|
||||
|
||||
// ToHandle takes a file and represents it with an opaque handle to reference it.
|
||||
// In stateless nfs (when it's serving a unix fs) this can be the device + inode
|
||||
// but we can generalize with a stateful local cache of handed out IDs.
|
||||
func (c *CachingHandler) ToHandle(_ nfs.Filesystem, path []string) []byte {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var id uuid.UUID
|
||||
c.activeHandles.Range(ctx, func(k uuid.UUID, v []string) bool {
|
||||
if slices.Equal(path, v) {
|
||||
id = k
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
if id != uuid.Nil {
|
||||
return id[:]
|
||||
}
|
||||
|
||||
id = uuid.New()
|
||||
|
||||
c.activeHandles.Set(ctx, id, path)
|
||||
|
||||
return id[:]
|
||||
}
|
||||
|
||||
// FromHandle converts from an opaque handle to the file it represents
|
||||
func (c *CachingHandler) FromHandle(fh []byte) (nfs.Filesystem, []string, error) {
|
||||
ctx := context.Background()
|
||||
|
||||
id, err := uuid.FromBytes(fh)
|
||||
if err != nil {
|
||||
return nil, []string{}, err
|
||||
}
|
||||
|
||||
paths, found, err := c.activeHandles.Get(ctx, id)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("kv error: %w", err)
|
||||
}
|
||||
|
||||
if found {
|
||||
return c.fs, paths, nil
|
||||
}
|
||||
|
||||
return nil, []string{}, &nfs.NFSStatusError{NFSStatus: nfs.NFSStatusStale}
|
||||
}
|
||||
|
||||
func (c *CachingHandler) InvalidateHandle(fs nfs.Filesystem, handle []byte) error {
|
||||
ctx := context.Background()
|
||||
//Remove from cache
|
||||
id, err := uuid.FromBytes(handle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.activeHandles.Delete(ctx, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
const maxInt = int(^uint(0) >> 1)
|
||||
|
||||
// HandleLimit exports how many file handles can be safely stored by this cache.
|
||||
func (c *CachingHandler) HandleLimit() int {
|
||||
return maxInt
|
||||
}
|
||||
|
||||
func hasPrefix(path, prefix []string) bool {
|
||||
if len(prefix) > len(path) {
|
||||
return false
|
||||
}
|
||||
for i, e := range prefix {
|
||||
if path[i] != e {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue