Skip to content

Commit 3635b2b

Browse files
Thomas StrombergThomas Stromberg
authored andcommitted
add new go files
1 parent ae58588 commit 3635b2b

File tree

4 files changed

+1840
-0
lines changed

4 files changed

+1840
-0
lines changed

memory.go

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Package bdcache provides a high-performance cache with S3-FIFO eviction and optional persistence.
2+
package bdcache
3+
4+
import (
5+
"time"
6+
)
7+
8+
// MemoryCache is a fast in-memory cache without persistence.
9+
// All operations are context-free and never return errors.
10+
type MemoryCache[K comparable, V any] struct {
11+
memory *s3fifo[K, V]
12+
defaultTTL time.Duration
13+
}
14+
15+
// Memory creates a new memory-only cache.
16+
//
17+
// Example:
18+
//
19+
// cache := bdcache.Memory[string, User](
20+
// bdcache.WithSize(10000),
21+
// bdcache.WithTTL(time.Hour),
22+
// )
23+
// defer cache.Close()
24+
//
25+
// cache.Set("user:123", user) // uses default TTL
26+
// cache.Set("user:123", user, time.Hour) // explicit TTL
27+
// user, ok := cache.Get("user:123")
28+
func Memory[K comparable, V any](opts ...Option) *MemoryCache[K, V] {
29+
cfg := defaultConfig()
30+
for _, opt := range opts {
31+
opt(cfg)
32+
}
33+
34+
return &MemoryCache[K, V]{
35+
memory: newS3FIFO[K, V](cfg.size),
36+
defaultTTL: cfg.defaultTTL,
37+
}
38+
}
39+
40+
// Get retrieves a value from the cache.
41+
// Returns the value and true if found, or the zero value and false if not found.
42+
func (c *MemoryCache[K, V]) Get(key K) (V, bool) {
43+
return c.memory.getFromMemory(key)
44+
}
45+
46+
// GetOrSet retrieves a value from the cache, or computes and stores it if not found.
47+
// The loader function is only called if the key is not in the cache.
48+
// If no TTL is provided, the default TTL is used.
49+
func (c *MemoryCache[K, V]) GetOrSet(key K, loader func() V, ttl ...time.Duration) V {
50+
if val, ok := c.memory.getFromMemory(key); ok {
51+
return val
52+
}
53+
val := loader()
54+
c.Set(key, val, ttl...)
55+
return val
56+
}
57+
58+
// Set stores a value in the cache.
59+
// If no TTL is provided, the default TTL is used.
60+
// If no default TTL is configured, the item never expires.
61+
func (c *MemoryCache[K, V]) Set(key K, value V, ttl ...time.Duration) {
62+
var t time.Duration
63+
if len(ttl) > 0 {
64+
t = ttl[0]
65+
}
66+
expiry := c.expiry(t)
67+
c.memory.setToMemory(key, value, expiry)
68+
}
69+
70+
// Delete removes a value from the cache.
71+
func (c *MemoryCache[K, V]) Delete(key K) {
72+
c.memory.deleteFromMemory(key)
73+
}
74+
75+
// Len returns the number of items in the cache.
76+
func (c *MemoryCache[K, V]) Len() int {
77+
return c.memory.memoryLen()
78+
}
79+
80+
// Flush removes all entries from the cache.
81+
// Returns the number of entries removed.
82+
func (c *MemoryCache[K, V]) Flush() int {
83+
return c.memory.flushMemory()
84+
}
85+
86+
// Close releases resources held by the cache.
87+
// For MemoryCache this is a no-op, but provided for API consistency.
88+
func (*MemoryCache[K, V]) Close() {
89+
// No-op for memory-only cache
90+
}
91+
92+
// expiry returns the expiry time based on TTL and default TTL.
93+
func (c *MemoryCache[K, V]) expiry(ttl time.Duration) time.Time {
94+
if ttl <= 0 {
95+
ttl = c.defaultTTL
96+
}
97+
if ttl <= 0 {
98+
return time.Time{}
99+
}
100+
return time.Now().Add(ttl)
101+
}
102+
103+
// config holds configuration for both MemoryCache and PersistentCache.
104+
type config struct {
105+
size int
106+
defaultTTL time.Duration
107+
warmup int
108+
}
109+
110+
func defaultConfig() *config {
111+
return &config{
112+
size: 16384, // 2^14, divides evenly by numShards
113+
}
114+
}
115+
116+
// Option configures a MemoryCache or PersistentCache.
117+
type Option func(*config)
118+
119+
// WithSize sets the maximum number of items in the memory cache.
120+
func WithSize(n int) Option {
121+
return func(c *config) {
122+
c.size = n
123+
}
124+
}
125+
126+
// WithTTL sets the default TTL for cache items.
127+
// Items without an explicit TTL will use this value.
128+
func WithTTL(d time.Duration) Option {
129+
return func(c *config) {
130+
c.defaultTTL = d
131+
}
132+
}
133+
134+
// WithWarmup enables cache warmup by loading the N most recently updated entries
135+
// from persistence on startup. Only applies to PersistentCache.
136+
// By default, warmup is disabled (0). Set to a positive number to load that many entries.
137+
func WithWarmup(n int) Option {
138+
return func(c *config) {
139+
c.warmup = n
140+
}
141+
}

0 commit comments

Comments
 (0)