mirror of
https://github.com/rclone/rclone.git
synced 2025-08-14 07:49:00 +02:00
serve nfs: implement on disk cache for file handles
This commit is contained in:
134
cmd/serve/nfs/cache_test.go
Normal file
134
cmd/serve/nfs/cache_test.go
Normal file
@ -0,0 +1,134 @@
|
||||
//go:build unix
|
||||
|
||||
package nfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/rclone/rclone/fs"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Check basic CRUD operations
|
||||
func testCacheCRUD(t *testing.T, h *Handler, c Cache, fileName string) {
|
||||
// Check reading a non existent handle returns an error
|
||||
_, _, err := c.FromHandle([]byte{10})
|
||||
assert.Error(t, err)
|
||||
|
||||
// Write a handle
|
||||
splitPath := []string{"dir", fileName}
|
||||
fh := c.ToHandle(h.billyFS, splitPath)
|
||||
assert.True(t, len(fh) > 0)
|
||||
|
||||
// Read the handle back
|
||||
newFs, newSplitPath, err := c.FromHandle(fh)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, h.billyFS, newFs)
|
||||
assert.Equal(t, splitPath, newSplitPath)
|
||||
|
||||
// Invalidate the handle
|
||||
err = c.InvalidateHandle(h.billyFS, fh)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Invalidate the handle twice
|
||||
err = c.InvalidateHandle(h.billyFS, fh)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check the handle is gone and returning stale handle error
|
||||
_, _, err = c.FromHandle(fh)
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, errStaleHandle, err)
|
||||
}
|
||||
|
||||
// Thrash the cache operations in parallel on different files
|
||||
func testCacheThrashDifferent(t *testing.T, h *Handler, c Cache) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 100; i++ {
|
||||
i := i
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
testCacheCRUD(t, h, c, fmt.Sprintf("file-%d", i))
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Thrash the cache operations in parallel on the same file
|
||||
func testCacheThrashSame(t *testing.T, h *Handler, c Cache) {
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 100; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
|
||||
// Write a handle
|
||||
splitPath := []string{"file"}
|
||||
fh := c.ToHandle(h.billyFS, splitPath)
|
||||
assert.True(t, len(fh) > 0)
|
||||
|
||||
// Read the handle back
|
||||
newFs, newSplitPath, err := c.FromHandle(fh)
|
||||
if err != nil {
|
||||
assert.Equal(t, errStaleHandle, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, h.billyFS, newFs)
|
||||
assert.Equal(t, splitPath, newSplitPath)
|
||||
}
|
||||
|
||||
// Invalidate the handle
|
||||
err = c.InvalidateHandle(h.billyFS, fh)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Check the handle is gone and returning stale handle error
|
||||
_, _, err = c.FromHandle(fh)
|
||||
if err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, errStaleHandle, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
// Quieten the flood of ERROR messages!
|
||||
ci := fs.GetConfig(context.Background())
|
||||
oldLogLevel := ci.LogLevel
|
||||
ci.LogLevel = fs.LogLevelEmergency
|
||||
defer func() {
|
||||
ci.LogLevel = oldLogLevel
|
||||
}()
|
||||
billyFS := &FS{nil} // place holder billyFS
|
||||
for _, cacheType := range []handleCache{cacheMemory, cacheDisk} {
|
||||
cacheType := cacheType
|
||||
t.Run(cacheType.String(), func(t *testing.T) {
|
||||
h := &Handler{
|
||||
billyFS: billyFS,
|
||||
}
|
||||
h.opt.HandleLimit = 1000
|
||||
h.opt.HandleCache = cacheType
|
||||
h.opt.HandleCacheDir = t.TempDir()
|
||||
c, err := h.getCache()
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("CRUD", func(t *testing.T) {
|
||||
testCacheCRUD(t, h, c, "file")
|
||||
})
|
||||
// NB the default caching handler is not thread safe!
|
||||
if cacheType != cacheMemory {
|
||||
t.Run("ThrashDifferent", func(t *testing.T) {
|
||||
testCacheThrashDifferent(t, h, c)
|
||||
})
|
||||
t.Run("ThrashSame", func(t *testing.T) {
|
||||
testCacheThrashSame(t, h, c)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user