Skip to content

Commit 3bb3647

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
persist reorg
1 parent b4cfac6 commit 3bb3647

31 files changed

+115
-116
lines changed

benchmarks/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ require (
2020
)
2121

2222
replace github.com/codeGROOVE-dev/sfcache => ../
23+
24+
replace github.com/codeGROOVE-dev/sfcache/pkg/persist => ../pkg/persist

go.mod

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
module github.com/codeGROOVE-dev/sfcache
22

33
go 1.25.4
4+
5+
require github.com/codeGROOVE-dev/sfcache/pkg/persist v0.0.0
6+
7+
replace github.com/codeGROOVE-dev/sfcache/pkg/persist => ./pkg/persist

memory.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,7 @@ func (c *MemoryCache[K, V]) SetIfAbsent(key K, value V, ttl ...time.Duration) (V
6565
if len(ttl) > 0 {
6666
t = ttl[0]
6767
}
68-
expiry := c.expiry(t)
69-
var expiryNano int64
70-
if !expiry.IsZero() {
71-
expiryNano = expiry.UnixNano()
72-
}
73-
return c.memory.getOrSetMemory(key, value, expiryNano)
68+
return c.memory.getOrSetMemory(key, value, timeToNano(c.expiry(t)))
7469
}
7570

7671
// Set stores a value in the cache.
@@ -81,7 +76,7 @@ func (c *MemoryCache[K, V]) Set(key K, value V, ttl ...time.Duration) {
8176
if len(ttl) > 0 {
8277
t = ttl[0]
8378
}
84-
c.memory.setToMemory(key, value, c.expiryNano(t))
79+
c.memory.setToMemory(key, value, timeToNano(c.expiry(t)))
8580
}
8681

8782
// Delete removes a value from the cache.
@@ -106,17 +101,6 @@ func (*MemoryCache[K, V]) Close() {
106101
// No-op for memory-only cache
107102
}
108103

109-
// expiryNano returns the expiry time in nanoseconds (0 means no expiry).
110-
func (c *MemoryCache[K, V]) expiryNano(ttl time.Duration) int64 {
111-
if ttl <= 0 {
112-
ttl = c.defaultTTL
113-
}
114-
if ttl <= 0 {
115-
return 0
116-
}
117-
return time.Now().Add(ttl).UnixNano()
118-
}
119-
120104
// expiry returns the expiry time based on TTL and default TTL.
121105
func (c *MemoryCache[K, V]) expiry(ttl time.Duration) time.Time {
122106
if ttl <= 0 {

persist/cloudrun/go.mod

Lines changed: 0 additions & 17 deletions
This file was deleted.

persist/datastore/go.mod

Lines changed: 0 additions & 10 deletions
This file was deleted.

persist/localfs/go.mod

Lines changed: 0 additions & 7 deletions
This file was deleted.

persist/valkey/go.mod

Lines changed: 0 additions & 12 deletions
This file was deleted.

persistent.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"fmt"
66
"log/slog"
77
"time"
8+
9+
"github.com/codeGROOVE-dev/sfcache/pkg/persist"
810
)
911

1012
// PersistentCache is a cache backed by both memory and persistent storage.
@@ -15,7 +17,7 @@ type PersistentCache[K comparable, V any] struct {
1517
// cache.Store.Len(ctx)
1618
// cache.Store.Flush(ctx)
1719
// cache.Store.Cleanup(ctx, maxAge)
18-
Store PersistenceLayer[K, V]
20+
Store persist.Layer[K, V]
1921

2022
memory *s3fifo[K, V]
2123
defaultTTL time.Duration
@@ -41,7 +43,7 @@ type PersistentCache[K comparable, V any] struct {
4143
// cache.Set(ctx, "user:123", user, time.Hour) // explicit TTL
4244
// user, ok, err := cache.Get(ctx, "user:123")
4345
// storeCount, _ := cache.Store.Len(ctx)
44-
func Persistent[K comparable, V any](ctx context.Context, p PersistenceLayer[K, V], opts ...Option) (*PersistentCache[K, V], error) {
46+
func Persistent[K comparable, V any](ctx context.Context, p persist.Layer[K, V], opts ...Option) (*PersistentCache[K, V], error) {
4547
cfg := defaultConfig()
4648
for _, opt := range opts {
4749
opt(cfg)

persistent_test.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"sync"
77
"testing"
88
"time"
9+
10+
"github.com/codeGROOVE-dev/sfcache/pkg/persist"
911
)
1012

1113
// mockStore is a simple in-memory store for testing.
@@ -29,6 +31,18 @@ func newMockStore[K comparable, V any]() *mockStore[K, V] {
2931
}
3032
}
3133

34+
func (m *mockStore[K, V]) setFailGet(v bool) {
35+
m.mu.Lock()
36+
m.failGet = v
37+
m.mu.Unlock()
38+
}
39+
40+
func (m *mockStore[K, V]) setFailSet(v bool) {
41+
m.mu.Lock()
42+
m.failSet = v
43+
m.mu.Unlock()
44+
}
45+
3246
func (m *mockStore[K, V]) ValidateKey(key K) error {
3347
return nil
3448
}
@@ -87,8 +101,8 @@ func (m *mockStore[K, V]) Delete(ctx context.Context, key K) error {
87101
}
88102

89103
//nolint:gocritic // Channel returns are clearer without named results
90-
func (m *mockStore[K, V]) LoadRecent(ctx context.Context, limit int) (<-chan Entry[K, V], <-chan error) {
91-
entryCh := make(chan Entry[K, V], 10)
104+
func (m *mockStore[K, V]) LoadRecent(ctx context.Context, limit int) (<-chan persist.Entry[K, V], <-chan error) {
105+
entryCh := make(chan persist.Entry[K, V], 10)
92106
errCh := make(chan error, 1)
93107

94108
go func() {
@@ -115,7 +129,7 @@ func (m *mockStore[K, V]) LoadRecent(ctx context.Context, limit int) (<-chan Ent
115129
key = sk
116130
}
117131

118-
entryCh <- Entry[K, V]{
132+
entryCh <- persist.Entry[K, V]{
119133
Key: key,
120134
Value: entry.value,
121135
Expiry: entry.expiry,
@@ -360,7 +374,7 @@ func TestPersistentCache_Errors(t *testing.T) {
360374

361375
// Set returns error when persistence fails (by design)
362376
// Value is still in memory, but error is returned to caller
363-
store.failSet = true
377+
store.setFailSet(true)
364378
if err := cache.Set(ctx, "key1", 42, 0); err == nil {
365379
t.Error("Set should return error when persistence fails")
366380
}
@@ -375,7 +389,7 @@ func TestPersistentCache_Errors(t *testing.T) {
375389
}
376390

377391
// SetAsync logs persistence errors but doesn't return them
378-
store.failSet = true
392+
store.setFailSet(true)
379393
if err := cache.SetAsync(ctx, "key3", 300, 0); err != nil {
380394
t.Fatalf("SetAsync should not fail synchronously: %v", err)
381395
}
@@ -393,8 +407,8 @@ func TestPersistentCache_Errors(t *testing.T) {
393407
time.Sleep(50 * time.Millisecond)
394408

395409
// Get should work from memory even if persistence fails
396-
store.failGet = true
397-
store.failSet = false
410+
store.setFailGet(true)
411+
store.setFailSet(false)
398412
if err := cache.Set(ctx, "key2", 100, 0); err != nil {
399413
t.Fatalf("Set: %v", err)
400414
}
@@ -418,7 +432,7 @@ func TestPersistentCache_Delete_Errors(t *testing.T) {
418432
defer func() { _ = cache.Close() }() //nolint:errcheck // Test cleanup
419433

420434
// Store a value (with failSet = false)
421-
store.failSet = false
435+
store.setFailSet(false)
422436
if err := cache.Set(ctx, "key1", 42, 0); err != nil {
423437
t.Fatalf("Set: %v", err)
424438
}
@@ -433,7 +447,7 @@ func TestPersistentCache_Delete_Errors(t *testing.T) {
433447
}
434448

435449
// Now make persistence delete fail
436-
store.failSet = true // failSet affects Delete too in mock
450+
store.setFailSet(true) // failSet affects Delete too in mock
437451
err = cache.Delete(ctx, "key1")
438452
if err == nil {
439453
t.Error("Delete should return error when persistence fails")
@@ -492,7 +506,7 @@ func TestPersistentCache_Get_PersistenceLoadError(t *testing.T) {
492506
_ = store.Store(ctx, "key1", 42, time.Time{}) //nolint:errcheck // Test fixture
493507

494508
// Make persistence Load fail
495-
store.failGet = true
509+
store.setFailGet(true)
496510

497511
// Get should return error on persistence failure
498512
_, found, err := cache.Get(ctx, "key1")
File renamed without changes.

0 commit comments

Comments
 (0)