no cache archive reader

This commit is contained in:
royalcat 2024-04-17 11:36:14 +03:00
parent bcda69daad
commit 5591f145a9
16 changed files with 579 additions and 272 deletions
src/export/nfs

View file

@ -4,8 +4,8 @@ import (
"context"
"fmt"
"path"
"slices"
"time"
"strings"
"sync"
"git.kmsign.ru/royalcat/tstor/pkg/go-nfs"
"git.kmsign.ru/royalcat/tstor/src/config"
@ -14,29 +14,51 @@ import (
"github.com/royalcat/kv"
)
const lifetime = time.Hour * 24
type handle []string
const sep = "\",\""
func (p handle) String() string {
return strings.Join(p, sep)
}
// MarshalBinary implements kv.Binary.
func (p handle) MarshalBinary() (data []byte, err error) {
return []byte(strings.Join(p, sep)), nil
}
// UnmarshalBinary implements kv.Binary.
func (p *handle) UnmarshalBinary(data []byte) error {
path := strings.Split(string(data), sep)
*p = path
return nil
}
var _ kv.Binary = (*handle)(nil)
func bytesToPath(path []string) string {
return strings.Join(path, sep)
}
// 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"))
activeHandles, err := kv.NewBadgerKVMarhsler[uuid.UUID, handle](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()))
// }
// }()
// }
reverseCache := map[string]uuid.UUID{}
activeHandles.Range(context.Background(), func(k uuid.UUID, v handle) bool {
reverseCache[v.String()] = k
return true
})
return &CachingHandler{
Handler: h,
fs: fs,
activeHandles: activeHandles,
reverseCache: reverseCache,
}, nil
}
@ -44,32 +66,36 @@ func NewKvHandler(h nfs.Handler, fs nfs.Filesystem) (nfs.Handler, error) {
type CachingHandler struct {
nfs.Handler
fs nfs.Filesystem
activeHandles kv.Store[uuid.UUID, []string]
mu sync.RWMutex
fs nfs.Filesystem
activeHandles kv.Store[uuid.UUID, handle]
reverseCache map[string]uuid.UUID
}
// 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
})
cacheKey := handle(path).String()
if cacheId, ok := c.reverseCache[cacheKey]; ok {
id = cacheId
}
if id != uuid.Nil {
return id[:]
}
id = uuid.New()
c.mu.Lock()
defer c.mu.Unlock()
id = uuid.New()
c.reverseCache[cacheKey] = id
c.activeHandles.Set(ctx, id, path)
return id[:]
@ -77,11 +103,14 @@ func (c *CachingHandler) ToHandle(_ nfs.Filesystem, path []string) []byte {
// FromHandle converts from an opaque handle to the file it represents
func (c *CachingHandler) FromHandle(fh []byte) (nfs.Filesystem, []string, error) {
c.mu.Lock()
defer c.mu.Unlock()
ctx := context.Background()
id, err := uuid.FromBytes(fh)
if err != nil {
return nil, []string{}, err
return nil, nil, err
}
paths, found, err := c.activeHandles.Get(ctx, id)
@ -93,7 +122,7 @@ func (c *CachingHandler) FromHandle(fh []byte) (nfs.Filesystem, []string, error)
return c.fs, paths, nil
}
return nil, []string{}, &nfs.NFSStatusError{NFSStatus: nfs.NFSStatusStale}
return nil, nil, &nfs.NFSStatusError{NFSStatus: nfs.NFSStatusStale}
}
func (c *CachingHandler) InvalidateHandle(fs nfs.Filesystem, handle []byte) error {
@ -103,8 +132,7 @@ func (c *CachingHandler) InvalidateHandle(fs nfs.Filesystem, handle []byte) erro
if err != nil {
return err
}
c.activeHandles.Delete(ctx, id)
return nil
return c.activeHandles.Delete(ctx, id)
}
const maxInt = int(^uint(0) >> 1)
@ -114,14 +142,14 @@ 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
}
// 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
// }