1010
1111Stupid fast in-memory Go cache with optional L2 persistence layer.
1212
13- ## Install
13+ Designed originally for persistently caching HTTP fetches in unreliable environments like Google Cloud Run, this cache has something for everyone.
1414
15- ``` bash
16- go get github.com/codeGROOVE-dev/bdcache
15+ ## Features
16+
17+ - ** Faster than a bat out of hell** - Best-in-class latency and throughput
18+ - ** S3-FIFO eviction** - Better hit-rates than LRU ([ learn more] ( https://s3fifo.com/ ) )
19+ - ** Pluggable persistence** - Bring your own database or use built-in backends:
20+ - [ ` persist/localfs ` ] ( persist/localfs ) - Local files (gob encoding, zero dependencies)
21+ - [ ` persist/datastore ` ] ( persist/datastore ) - Google Cloud Datastore
22+ - [ ` persist/valkey ` ] ( persist/valkey ) - Valkey/Redis
23+ - [ ` persist/cloudrun ` ] ( persist/cloudrun ) - Auto-detect Cloud Run
24+ - ** Per-item TTL** - Optional expiration
25+ - ** Graceful degradation** - Cache works even if persistence fails
26+ - ** Zero allocation reads** - minimal GC thrashing
27+ - ** Type safe** - Go generics
28+
29+ ## Usage
30+
31+ As a stupid-fast in-memory cache:
32+
33+ ``` go
34+ import " github.com/codeGROOVE-dev/bdcache"
35+
36+ // strings as keys, ints as values
37+ cache , _ := bdcache.New [string , int ](ctx)
38+ cache.Set (ctx, " answer" , 42 , 0 )
39+ val , found , err := cache.Get (ctx, " answer" )
1740```
1841
19- ## Use
42+ With local file persistence to survive restarts:
2043
2144``` go
2245import (
23- " github.com/codeGROOVE-dev/bdcache"
24- " github.com/codeGROOVE-dev/bdcache/persist/localfs"
46+ " github.com/codeGROOVE-dev/bdcache"
47+ " github.com/codeGROOVE-dev/bdcache/persist/localfs"
2548)
2649
27- // Memory only
28- cache , _ := bdcache.New [string , int ](ctx)
29- cache.Set (ctx, " answer" , 42 , 0 ) // Synchronous: returns after persistence completes
30- cache.SetAsync (ctx, " answer" , 42 , 0 ) // Async: returns immediately, persists in background
31- val , found , _ := cache.Get (ctx, " answer" )
50+ p , err := localfs.New [string , User ](" myapp" , " " )
51+ cache , _ := bdcache.New [string , User ](ctx, bdcache.WithPersistence (p))
3252
33- // With local file persistence
34- p , _ := localfs.New [string , User ](" myapp" , " " )
35- cache , _ := bdcache.New [string , User ](ctx,
36- bdcache.WithPersistence (p))
53+ cache.SetAsync (ctx, " answer" , 42 , 0 ) // Don't wait for the key to persist
54+ ```
3755
38- // With Valkey/Redis persistence
39- p , _ := valkey.New [string , User ](ctx, " myapp" , " localhost:6379" )
40- cache , _ := bdcache.New [string , User ](ctx,
41- bdcache.WithPersistence (p))
56+ A persistent cache suitable for Cloud Run or local development; uses Cloud Datastore if available
4257
43- // Cloud Run auto-detection (datastore in Cloud Run, localfs elsewhere)
58+ ``` go
4459p , _ := cloudrun.New [string , User ](ctx, " myapp" )
45- cache , _ := bdcache.New [string , User ](ctx,
46- bdcache.WithPersistence (p))
60+ cache , _ := bdcache.New [string , User ](ctx, bdcache.WithPersistence (p))
4761```
4862
49- ## Features
5063
51- - ** Faster than a bat out of hell** - Low latency, high throughput
52- - ** S3-FIFO eviction** - Better hit-rates than LRU ([ learn more] ( https://s3fifo.com/ ) )
53- - ** Pluggable persistence** - Bring your own database or use built-in backends:
54- - [ ` persist/localfs ` ] ( persist/localfs ) - Local files (gob encoding, zero dependencies)
55- - [ ` persist/datastore ` ] ( persist/datastore ) - Google Cloud Datastore
56- - [ ` persist/valkey ` ] ( persist/valkey ) - Valkey/Redis
57- - [ ` persist/cloudrun ` ] ( persist/cloudrun ) - Auto-detect Cloud Run
58- - ** Per-item TTL** - Optional expiration
59- - ** Graceful degradation** - Cache works even if persistence fails
60- - ** Zero allocation reads** - minimal GC thrashing
61- - ** Type safe** - Go generics
64+
6265
6366## Performance against the Competition
6467
@@ -71,8 +74,8 @@ Here's the results from an M4 MacBook Pro - run `make bench` to see the results
7174| Cache | Size=1% | Size=2.5% | Size=5% |
7275| ---------------| ---------| -----------| ---------|
7376| bdcache π‘ | 94.46% | 94.89% | 95.09% |
74- | otter 𦦠| 94.28 % | 94.69 % | 95.09% |
75- | ristretto β | 91.62 % | 92.45 % | 93.03 % |
77+ | otter 𦦠| 94.27 % | 94.68 % | 95.09% |
78+ | ristretto β | 91.63 % | 92.44 % | 93.02 % |
7679| tinylfu π¬ | 94.31% | 94.87% | 95.09% |
7780| freecache π | 94.03% | 94.15% | 94.75% |
7881| lru π | 94.10% | 94.84% | 95.09% |
@@ -83,113 +86,113 @@ Here's the results from an M4 MacBook Pro - run `make bench` to see the results
8386
8487| Cache | Get ns/op | Get B/op | Get allocs | Set ns/op | Set B/op | Set allocs |
8588| ---------------| -----------| ----------| ------------| -----------| ----------| ------------|
86- | bdcache π‘ | 9.0 | 0 | 0 | 21 .0 | 0 | 0 |
87- | lru π | 24 .0 | 0 | 0 | 23 .0 | 0 | 0 |
88- | ristretto β | 32 .0 | 14 | 0 | 67 .0 | 119 | 3 |
89- | otter 𦦠| 35 .0 | 0 | 0 | 140 .0 | 51 | 1 |
90- | freecache π | 73 .0 | 15 | 1 | 58 .0 | 4 | 0 |
91- | tinylfu π¬ | 88 .0 | 3 | 0 | 107 .0 | 175 | 3 |
89+ | bdcache π‘ | 9.0 | 0 | 0 | 20 .0 | 0 | 0 |
90+ | lru π | 22 .0 | 0 | 0 | 22 .0 | 0 | 0 |
91+ | ristretto β | 31 .0 | 14 | 0 | 68 .0 | 120 | 3 |
92+ | otter 𦦠| 34 .0 | 0 | 0 | 138 .0 | 51 | 1 |
93+ | freecache π | 71 .0 | 15 | 1 | 56 .0 | 4 | 0 |
94+ | tinylfu π¬ | 84 .0 | 3 | 0 | 105 .0 | 175 | 3 |
9295
93- π Get latency: +167 % faster than 2nd best (lru)
94- π Set latency: +9.5 % faster than 2nd best (lru)
96+ π Get latency: +144 % faster than 2nd best (lru)
97+ π Set latency: +10 % faster than 2nd best (lru)
9598
9699### Single-Threaded Throughput (mixed read/write)
97100
98101| Cache | Get QPS | Set QPS |
99102| ---------------| ------------| ------------|
100- | bdcache π‘ | 75.49M | 41.56M |
101- | lru π | 34.86M | 35.33M |
102- | ristretto β | 28.38M | 13.59M |
103- | otter 𦦠| 25.59M | 7.17M |
104- | freecache π | 12.79M | 15.80M |
105- | tinylfu π¬ | 10.77M | 8.94M |
103+ | bdcache π‘ | 79.25M | 43.15M |
104+ | lru π | 36.39M | 36.88M |
105+ | ristretto β | 28.22M | 13.46M |
106+ | otter 𦦠| 25.46M | 7.16M |
107+ | freecache π | 13.30M | 16.32M |
108+ | tinylfu π¬ | 11.32M | 9.34M |
106109
107- π Get throughput: +117 % faster than 2nd best (lru)
108- π Set throughput: +18 % faster than 2nd best (lru)
110+ π Get throughput: +118 % faster than 2nd best (lru)
111+ π Set throughput: +17 % faster than 2nd best (lru)
109112
110113### Concurrent Throughput (mixed read/write): 4 threads
111114
112115| Cache | Get QPS | Set QPS |
113116| ---------------| ------------| ------------|
114- | bdcache π‘ | 29.51M | 31.43M |
115- | otter 𦦠| 28.96M | 4.17M |
116- | ristretto β | 27.16M | 13.23M |
117- | freecache π | 25.06M | 21.94M |
118- | lru π | 9.43M | 9.59M |
119- | tinylfu π¬ | 5.51M | 4.85M |
117+ | bdcache π‘ | 29.62M | 29.92M |
118+ | ristretto β | 25.98M | 13.12M |
119+ | freecache π | 25.36M | 21.84M |
120+ | otter 𦦠| 23.14M | 3.99M |
121+ | lru π | 9.39M | 9.64M |
122+ | tinylfu π¬ | 5.75M | 4.91M |
120123
121- π Get throughput: +1.9 % faster than 2nd best (otter )
122- π Set throughput: +43 % faster than 2nd best (freecache)
124+ π Get throughput: +14 % faster than 2nd best (ristretto )
125+ π Set throughput: +37 % faster than 2nd best (freecache)
123126
124127### Concurrent Throughput (mixed read/write): 8 threads
125128
126129| Cache | Get QPS | Set QPS |
127130| ---------------| ------------| ------------|
128- | bdcache π‘ | 22.16M | 18.82M |
129- | otter 𦦠| 19.51M | 3.14M |
130- | ristretto β | 18.62M | 11.60M |
131- | freecache π | 16.60M | 15.92M |
132- | lru π | 7.62M | 7.75M |
133- | tinylfu π¬ | 4.95M | 4.26M |
131+ | bdcache π‘ | 22.19M | 18.68M |
132+ | otter 𦦠| 19.74M | 3.03M |
133+ | ristretto β | 18.82M | 11.39M |
134+ | freecache π | 16.83M | 16.30M |
135+ | lru π | 7.55M | 7.68M |
136+ | tinylfu π¬ | 4.95M | 4.15M |
134137
135- π Get throughput: +14 % faster than 2nd best (otter)
136- π Set throughput: +18 % faster than 2nd best (freecache)
138+ π Get throughput: +12 % faster than 2nd best (otter)
139+ π Set throughput: +15 % faster than 2nd best (freecache)
137140
138141### Concurrent Throughput (mixed read/write): 12 threads
139142
140143| Cache | Get QPS | Set QPS |
141144| ---------------| ------------| ------------|
142- | bdcache π‘ | 24.29M | 24.21M |
143- | ristretto β | 22.76M | 11.54M |
144- | otter 𦦠| 21.65M | 2.79M |
145- | freecache π | 17.25M | 16.53M |
146- | lru π | 7.58M | 7.62M |
147- | tinylfu π¬ | 4.51M | 3.87M |
145+ | bdcache π‘ | 24.49M | 24.03M |
146+ | ristretto β | 22.85M | 11.48M |
147+ | otter 𦦠| 21.77M | 2.92M |
148+ | freecache π | 17.45M | 16.70M |
149+ | lru π | 7.42M | 7.62M |
150+ | tinylfu π¬ | 4.55M | 3.70M |
148151
149- π Get throughput: +6.7 % faster than 2nd best (ristretto)
150- π Set throughput: +47 % faster than 2nd best (freecache)
152+ π Get throughput: +7.2 % faster than 2nd best (ristretto)
153+ π Set throughput: +44 % faster than 2nd best (freecache)
151154
152155### Concurrent Throughput (mixed read/write): 16 threads
153156
154157| Cache | Get QPS | Set QPS |
155158| ---------------| ------------| ------------|
156- | bdcache π‘ | 16.24M | 15.77M |
157- | otter 𦦠| 16.02M | 2.76M |
158- | ristretto β | 15.41M | 12.50M |
159- | freecache π | 15.05M | 14.61M |
160- | lru π | 7.45M | 7.47M |
161- | tinylfu π¬ | 4.71M | 3.61M |
159+ | bdcache π‘ | 15.96M | 15.55M |
160+ | otter 𦦠| 15.64M | 2.84M |
161+ | ristretto β | 15.59M | 12.31M |
162+ | freecache π | 15.24M | 14.72M |
163+ | lru π | 7.47M | 7.42M |
164+ | tinylfu π¬ | 4.71M | 3.43M |
162165
163- π Get throughput: +1.4 % faster than 2nd best (otter)
164- π Set throughput: +8.0 % faster than 2nd best (freecache)
166+ π Get throughput: +2.0 % faster than 2nd best (otter)
167+ π Set throughput: +5.6 % faster than 2nd best (freecache)
165168
166169### Concurrent Throughput (mixed read/write): 24 threads
167170
168171| Cache | Get QPS | Set QPS |
169172| ---------------| ------------| ------------|
170- | bdcache π‘ | 16.16M | 15.47M |
171- | otter 𦦠| 15.80M | 2.87M |
172- | ristretto β | 15.48M | 13.28M |
173- | freecache π | 14.92M | 14.36M |
174- | lru π | 7.69M | 7.59M |
175- | tinylfu π¬ | 5.03M | 3.84M |
173+ | bdcache π‘ | 15.93M | 15.41M |
174+ | otter 𦦠| 15.81M | 2.88M |
175+ | ristretto β | 15.57M | 13.20M |
176+ | freecache π | 14.58M | 14.10M |
177+ | lru π | 7.59M | 7.80M |
178+ | tinylfu π¬ | 4.96M | 3.73M |
176179
177- π Get throughput: +2.3 % faster than 2nd best (otter)
178- π Set throughput: +7.7 % faster than 2nd best (freecache)
180+ π Get throughput: +0.7 % faster than 2nd best (otter)
181+ π Set throughput: +9.2 % faster than 2nd best (freecache)
179182
180183### Concurrent Throughput (mixed read/write): 32 threads
181184
182185| Cache | Get QPS | Set QPS |
183186| ---------------| ------------| ------------|
184- | bdcache π‘ | 15.85M | 15.41M |
185- | otter 𦦠| 15.71M | 2.85M |
186- | ristretto β | 15.60M | 13.16M |
187- | freecache π | 14.33M | 14.13M |
188- | lru π | 7.70M | 8.07M |
189- | tinylfu π¬ | 5.32M | 2.99M |
190-
191- π Get throughput: +0.9 % faster than 2nd best (otter)
192- π Set throughput: +9.1 % faster than 2nd best (freecache)
187+ | bdcache π‘ | 16.68M | 15.38M |
188+ | otter 𦦠| 15.87M | 2.87M |
189+ | ristretto β | 15.55M | 13.50M |
190+ | freecache π | 14.64M | 13.84M |
191+ | lru π | 7.87M | 8.01M |
192+ | tinylfu π¬ | 5.12M | 3.01M |
193+
194+ π Get throughput: +5.1 % faster than 2nd best (otter)
195+ π Set throughput: +11 % faster than 2nd best (freecache)
193196
194197NOTE: Performance characteristics often have trade-offs. There are almost certainly workloads where other cache implementations are faster, but nobody blends speed and persistence the way that bdcache does.
195198
0 commit comments