cache: Short TTL negative cache for 404/410 depot objects
Stop re-fetching gone depot objects on every miss: store 404/410 in the existing VFS cache under the same key with a short TTL (default 5m).
This commit is contained in:
@@ -27,7 +27,7 @@ import (
|
||||
func TestCaching(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
|
||||
sc, err := New("localhost:8080", "1G", "1G", td, "", "lru", "lru", 200, 5, "0", nil)
|
||||
sc, err := New("localhost:8080", "1G", "1G", td, "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create SteamCache: %v", err)
|
||||
}
|
||||
@@ -132,7 +132,7 @@ func TestCaching(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCacheMissAndHit(t *testing.T) {
|
||||
sc, err := New("localhost:8080", "1MB", "1G", t.TempDir(), "", "lru", "lru", 200, 5, "0", nil)
|
||||
sc, err := New("localhost:8080", "1MB", "1G", t.TempDir(), "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create SteamCache: %v", err)
|
||||
}
|
||||
@@ -375,7 +375,7 @@ func TestServiceManagerExpandability(t *testing.T) {
|
||||
// Removed hash calculation tests since we switched to lightweight validation
|
||||
|
||||
func TestSteamKeySharding(t *testing.T) {
|
||||
sc, err := New("localhost:8080", "1MB", "1G", t.TempDir(), "", "lru", "lru", 200, 5, "0", nil)
|
||||
sc, err := New("localhost:8080", "1MB", "1G", t.TempDir(), "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create SteamCache: %v", err)
|
||||
}
|
||||
@@ -482,7 +482,7 @@ func TestErrorTypes(t *testing.T) {
|
||||
// TestMetrics tests the metrics functionality
|
||||
func TestMetrics(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
sc, err := New("localhost:8080", "1G", "1G", td, "", "lru", "lru", 200, 5, "0", nil)
|
||||
sc, err := New("localhost:8080", "1G", "1G", td, "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create SteamCache: %v", err)
|
||||
}
|
||||
@@ -501,6 +501,7 @@ func TestMetrics(t *testing.T) {
|
||||
sc.metrics.IncrementTotalRequests()
|
||||
sc.metrics.IncrementCacheHits()
|
||||
sc.metrics.IncrementCacheMisses()
|
||||
sc.metrics.IncrementNegativeCacheHits()
|
||||
sc.metrics.AddBytesServed(1024)
|
||||
sc.metrics.IncrementServiceRequests("steam")
|
||||
|
||||
@@ -514,6 +515,9 @@ func TestMetrics(t *testing.T) {
|
||||
if stats.CacheMisses != 1 {
|
||||
t.Error("Cache misses should be 1")
|
||||
}
|
||||
if stats.NegativeCacheHits != 1 {
|
||||
t.Error("Negative cache hits should be 1")
|
||||
}
|
||||
if stats.TotalBytesServed != 1024 {
|
||||
t.Error("Total bytes served should be 1024")
|
||||
}
|
||||
@@ -541,6 +545,9 @@ func TestMetrics(t *testing.T) {
|
||||
if stats.CacheHits != 0 {
|
||||
t.Error("After reset, cache hits should be 0")
|
||||
}
|
||||
if stats.NegativeCacheHits != 0 {
|
||||
t.Error("After reset, negative cache hits should be 0")
|
||||
}
|
||||
|
||||
// Phase 3: exercise newly exported WriteText (cheap coverage for promotion)
|
||||
rec := httptest.NewRecorder()
|
||||
@@ -551,6 +558,9 @@ func TestMetrics(t *testing.T) {
|
||||
if !bytes.Contains(rec.Body.Bytes(), []byte("total_requests")) {
|
||||
t.Error("WriteText output missing expected key")
|
||||
}
|
||||
if !bytes.Contains(rec.Body.Bytes(), []byte("negative_cache_hits")) {
|
||||
t.Error("WriteText output missing negative_cache_hits")
|
||||
}
|
||||
}
|
||||
|
||||
// Removed old TestKeyGeneration - replaced with TestURLHashing that uses SHA256
|
||||
@@ -570,7 +580,7 @@ func newTestCacheWithFakeUpstream(t *testing.T, h http.HandlerFunc, mem, disk st
|
||||
s := httptest.NewServer(h)
|
||||
t.Cleanup(s.Close)
|
||||
d := t.TempDir()
|
||||
sc, err := New("127.0.0.1:0", mem, disk, d, s.URL, "lru", "lru", 200, 10, "0", nil)
|
||||
sc, err := New("127.0.0.1:0", mem, disk, d, s.URL, "lru", "lru", 200, 10, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create SteamCache: %v", err)
|
||||
}
|
||||
@@ -732,7 +742,7 @@ func TestErrorMetrics(t *testing.T) {
|
||||
// Cover 503 capacity path + accounting skew: force Acquire err via canceled ctx.
|
||||
// Asserts Errors+RateLimited inc, Total unchanged (per documented design in code comment).
|
||||
tdCap := t.TempDir()
|
||||
scCap, err := New("127.0.0.1:0", "1MB", "0", tdCap, "", "lru", "lru", 200, 5, "0", nil)
|
||||
scCap, err := New("127.0.0.1:0", "1MB", "0", tdCap, "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("cap sc: %v", err)
|
||||
}
|
||||
@@ -796,7 +806,7 @@ func TestErrorMetrics(t *testing.T) {
|
||||
func TestExpandedErrorMetrics(t *testing.T) {
|
||||
t.Parallel()
|
||||
td := t.TempDir()
|
||||
sc, err := New("localhost:0", "1MB", "0", td, "", "lru", "lru", 10, 5, "0", nil)
|
||||
sc, err := New("localhost:0", "1MB", "0", td, "", "lru", "lru", 10, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("create: %v", err)
|
||||
}
|
||||
@@ -886,7 +896,7 @@ func TestNewInvalidSizes(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.mem+"_"+c.disk, func(t *testing.T) {
|
||||
sc, err := New("127.0.0.1:0", c.mem, c.disk, t.TempDir(), "", "lru", "lru", 10, 5, c.maxobj, nil)
|
||||
sc, err := New("127.0.0.1:0", c.mem, c.disk, t.TempDir(), "", "lru", "lru", 10, 5, c.maxobj, nil, "")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for bad size, got nil")
|
||||
}
|
||||
@@ -907,7 +917,7 @@ func TestNewRunShutdownHygiene(t *testing.T) {
|
||||
t.Skip("skips Run hygiene in -short per existing pattern")
|
||||
}
|
||||
d := t.TempDir()
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", d, "", "lru", "lru", 10, 5, "0", nil)
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", d, "", "lru", "lru", 10, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("new: %v", err)
|
||||
}
|
||||
@@ -1048,7 +1058,7 @@ func TestDiskOnlyDelayedAttach(t *testing.T) {
|
||||
}
|
||||
|
||||
// mem=0, disk>0 -> pure disk delayed path (go func)
|
||||
sc, err := New("localhost:0", "0", "10MB", diskPath, "", "lru", "lru", 10, 1, "0", nil)
|
||||
sc, err := New("localhost:0", "0", "10MB", diskPath, "", "lru", "lru", 10, 1, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("New disk-only: %v", err)
|
||||
}
|
||||
@@ -1109,7 +1119,7 @@ func TestDiskOnlyDelayedAttach(t *testing.T) {
|
||||
// TestDiskTierSignalMemoryOnly covers memory-only mode: DiskTierReady=1 (N/A, not
|
||||
// waiting on disk attach) and heartbeat header X-SteamCache-Disk-Tier: disabled.
|
||||
func TestDiskTierSignalMemoryOnly(t *testing.T) {
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", t.TempDir(), "", "lru", "lru", 10, 5, "0", nil)
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", t.TempDir(), "", "lru", "lru", 10, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("New memory-only: %v", err)
|
||||
}
|
||||
@@ -1142,7 +1152,7 @@ func TestDiskTierSignalMixedPendingReady(t *testing.T) {
|
||||
if err := os.MkdirAll(diskPath, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sc, err := New("127.0.0.1:0", "1MB", "10MB", diskPath, "", "lru", "lru", 10, 1, "0", nil)
|
||||
sc, err := New("127.0.0.1:0", "1MB", "10MB", diskPath, "", "lru", "lru", 10, 1, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("New mixed: %v", err)
|
||||
}
|
||||
@@ -1293,7 +1303,7 @@ func TestHostAllowedForDirectFetch(t *testing.T) {
|
||||
|
||||
func TestDirectFetchRejectsNonSteamHost(t *testing.T) {
|
||||
td := t.TempDir()
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", td, "", "lru", "lru", 200, 5, "0", nil)
|
||||
sc, err := New("127.0.0.1:0", "1MB", "0", td, "", "lru", "lru", 200, 5, "0", nil, "")
|
||||
if err != nil {
|
||||
t.Fatalf("New: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user