feda55e225
- Updated `disk.New` to support asynchronous initialization for large caches, improving responsiveness during startup. - Introduced an eviction function parameter to `disk.New`, ensuring proper handling of over-capacity scenarios. - Enhanced error handling in various components, including memory and disk tests, to ensure robustness and clarity. - Refactored tests to validate new behaviors, including checks for delayed attachment and proper error propagation. - Removed obsolete error handling code and tests related to the now-deleted errors package, streamlining the codebase.
133 lines
2.5 KiB
Go
133 lines
2.5 KiB
Go
package cache
|
|
|
|
import (
|
|
"io"
|
|
"s1d3sw1ped/steamcache2/vfs/memory"
|
|
"sync"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTieredCache_PromotionFallback(t *testing.T) {
|
|
t.Parallel()
|
|
fast, err := memory.New(1 * 1024 * 1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
slow, err := memory.New(10 * 1024 * 1024) // use mem for "disk" in test
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
tc := New()
|
|
tc.SetFast(fast)
|
|
tc.SetSlow(slow)
|
|
|
|
// write to slow (disk)
|
|
w, err := tc.Create("p1", 1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
w.Write(make([]byte, 1024))
|
|
w.Close()
|
|
|
|
// open should hit slow, trigger promote goroutine
|
|
r, err := tc.Open("p1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
io.Copy(io.Discard, r)
|
|
r.Close()
|
|
|
|
// Replace fixed sleep with bounded poll for promotion completion (robust vs load/CI variance; addresses issue7)
|
|
deadline := time.Now().Add(500 * time.Millisecond)
|
|
promoted := false
|
|
for time.Now().Before(deadline) {
|
|
if _, err := fast.Stat("p1"); err == nil {
|
|
promoted = true
|
|
break
|
|
}
|
|
time.Sleep(5 * time.Millisecond)
|
|
}
|
|
if !promoted {
|
|
// Still allow slow tier stat as fallback (promotion is best-effort)
|
|
if _, err := tc.Stat("p1"); err != nil {
|
|
t.Errorf("stat after promote attempt: %v", err)
|
|
}
|
|
}
|
|
|
|
// size total
|
|
if tc.Size() < 1024 {
|
|
t.Error("total size under")
|
|
}
|
|
}
|
|
|
|
func TestTieredCache_DeleteAllTiers(t *testing.T) {
|
|
t.Parallel()
|
|
fast, err := memory.New(1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
slow, err := memory.New(1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tc := New()
|
|
tc.SetFast(fast)
|
|
tc.SetSlow(slow)
|
|
|
|
w, _ := tc.Create("delme", 100)
|
|
w.Write([]byte{1})
|
|
w.Close()
|
|
|
|
tc.Delete("delme")
|
|
if _, err := tc.Open("delme"); err == nil {
|
|
t.Error("deleted key still openable from tiers")
|
|
}
|
|
}
|
|
|
|
func TestTieredCache_Concurrent(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip()
|
|
}
|
|
t.Parallel()
|
|
fast, err := memory.New(5 * 1024 * 1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
slow, err := memory.New(20 * 1024 * 1024)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tc := New()
|
|
tc.SetFast(fast)
|
|
tc.SetSlow(slow)
|
|
|
|
var wg sync.WaitGroup
|
|
var hits int64
|
|
for i := 0; i < 6; i++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
for j := 0; j < 20; j++ {
|
|
k := "ct" + string(rune(id)) + string(rune(j%5))
|
|
if w, e := tc.Create(k, 256); e == nil {
|
|
w.Write(make([]byte, 256))
|
|
w.Close()
|
|
}
|
|
if r, e := tc.Open(k); e == nil {
|
|
io.Copy(io.Discard, r)
|
|
r.Close()
|
|
atomic.AddInt64(&hits, 1)
|
|
}
|
|
tc.Delete(k)
|
|
}
|
|
}(i)
|
|
}
|
|
wg.Wait()
|
|
if hits < 10 {
|
|
t.Errorf("low tier hits %d", hits)
|
|
}
|
|
}
|